source: Sophya/trunk/SophyaExt/FitsIOServer/swfitsdtable.cc@ 3534

Last change on this file since 3534 was 3395, checked in by ansari, 18 years ago

Correction pour faire fonction SwFitsDataTable en multi-threads - mais ne fonctionne toujours pas , Reza 23/11/2007

File size: 14.3 KB
Line 
1#include "swfitsdtable.h"
2#include "fitshdtable.h"
3#include "pexceptions.h"
4#include "thsafeop.h"
5
6namespace SOPHYA {
7
8/*!
9 \class SwFitsDataTable
10 \ingroup FitsIOServer
11 This class can be used to organize data in table (row-column) form.
12 Each column holds homogeneous data (same data type), while different
13 columns can be used for different data types
14 (integer, float, string ...).
15 A Fits file binary table is used as swap space.
16
17 \warning
18 - When creating a table, the output fits file (FitsInOutFile) must not be closed
19 (destroyed) before the SwFitsDataTable object is destroyed. The destructor writes
20 out any pending buffer to the fits file.
21 - It is not possible to make a complete (deep) copy of a SwFitsDataTable
22 Copy constructor and equal operator shares the data.
23 - The min/max values for column data are not updated when reading from a fits file.
24 In this case, the Show() method (or ostream& << operator) will compute min/max
25 values. This operation will take some time for large tables.
26 - The SwFitsDataTable operation (AddRow()/GetRow() ) is NOT thread safe
27
28 \sa SOPHYA::MuTyV
29 \sa SOPHYA::DataTableRow
30 \sa SOPHYA::DataTable
31 \sa SOPHYA::SwSegDataBlock SOPHYA::FitsDataSwapper
32
33 \code
34 #include "swfitsdtable.h"
35 // ...
36 {
37 // ---- Creation of the table
38 // Create the swap stream
39 FitsInOutFile so("myswtable.fits", FitsInOutFile::Fits_Create);
40 SwFitsDataTable dt(so, 16, true);
41 // define table columns
42 dt.AddFloatColumn("X0_f");
43 dt.AddFloatColumn("X1_f");
44 dt.AddDoubleColumn("X0X0pX1X1_d");
45 // Fill the table
46 r_8 x[5];
47 for(int i=0; i<63; i++) {
48 x[0] = (i%9)-4.; x[1] = (i/9)-3.; x[2] = x[0]*x[0]+x[1]*x[1];
49 dt.AddLine(x);
50 }
51 // Printing table info
52 cout << dt ;
53 // The destructor will Swap out data still in memory
54 }
55 {
56 // ---- Accessing information from a previously created table
57 FitsInOutFile si("myswtable.fits", FitsInOutFile::Fits_ReadOnly);
58 // Position the fits file on the first extension (BinTable)
59 si.MoveAbsToHDU(2);
60 SwFitsDataTable dt(si, 512, false);
61 // Printing table info
62 cout << dt ;
63 }
64 \endcode
65*/
66//! Default constructor with optional specification of block (or segment) size
67SwFitsDataTable::SwFitsDataTable(sa_size_t segsz)
68 : BaseDataTable(segsz) , mFgCreate(false) , mFgDefDone(false)
69{
70}
71/*!
72 \brief Construcor with specification of the \b FitsInOutFile swap stream.
73 if fgcreate == true, creates an empty table (the fits file should then be
74 opened for writing).
75 if fgcreate == false , the table is initialized (read in) from the current HDU.
76*/
77SwFitsDataTable::SwFitsDataTable(FitsInOutFile & os, sa_size_t segsz, bool fgcreate)
78 : BaseDataTable(segsz) ,
79 mSwF(os) , mFgCreate(fgcreate) , mFgDefDone(false)
80{
81 if (!fgcreate) { // Lecture de la table
82 FitsHandler<BaseDataTable> fio(*this);
83 fio.Read(os);
84 mFgDefDone = true;
85 }
86}
87
88/*!
89 \brief Construcor with specification of the FITS file name, as a Read-only file.
90 The FITS file is opened and the table is initialized (read in) from HDU \b hdunum
91*/
92 SwFitsDataTable::SwFitsDataTable(string fitsname, int hdunum, sa_size_t segsz)
93 : BaseDataTable(segsz) ,
94 mSwF(fitsname, FitsInOutFile::Fits_RO) , mFgCreate(false) , mFgDefDone(true)
95{
96 // Lecture de la table
97 FitsHandler<BaseDataTable> fio(*this);
98 mSwF.MoveAbsToHDU(hdunum);
99 fio.Read(mSwF);
100}
101
102//! copy constructor - shares the data (and copies the thread safety state)
103SwFitsDataTable::SwFitsDataTable(SwFitsDataTable const & a)
104 : BaseDataTable(a.SegmentSize()),
105 mSwF(a.mSwF) , mFgCreate(a.mFgCreate) , mFgDefDone(a.mFgDefDone)
106{
107 // Attention(Reza Nov07): le mFgDefDone doit etre en principe partage entre les objets
108 Share(a);
109}
110//! Destructor - Deletes / closes the input PPF swap stream
111SwFitsDataTable::~SwFitsDataTable()
112{
113 if (mFgCreate) {
114 SwapOutAll();
115 // Ecriture de SegmentSize et autre elements de DVList
116 mSwF.WriteHeaderRecords(Info());
117 MuTyV mtv = SegmentSize();
118 mSwF.WriteKey("SEGMSIZE",mtv," SOPHYA::DataTable SegmentSize");
119 mtv = "SOPHYA::SwFitsDataTable";
120 mSwF.WriteKey("SOPCLSNM",mtv," Object class name ");
121 }
122}
123
124void SwFitsDataTable::Share(SwFitsDataTable const & a)
125{
126 // On recopie la taille de segment
127 mSegSz = a.SegmentSize();
128 if (a.NVar() == 0) return; // Table sans colonne
129
130 // On copie la structure de table
131 CopyStructure(a);
132 if (a.IsThreadSafe()) SetThreadSafe(true);
133 else SetThreadSafe(false);
134
135 //
136 // Update nombre d'entree, ...
137 mNEnt = a.mNEnt;
138 mNSeg = a.mNSeg;
139 if (a.mInfo) mInfo = new DVList(*(a.mInfo));
140
141 // mis a jour des tableax min-max
142 mMin = a.mMin;
143 mMax = a.mMax;
144 mMinMaxNEnt = a.mMinMaxNEnt;
145
146 // Et on partage les donnees des colonnes
147 for (size_t kk=0; kk<mNames.size(); kk++) {
148 sa_size_t sk = mNames[kk].ser;
149 sa_size_t ska = a.mNames[kk].ser;
150 switch (mNames[kk].type) {
151 case IntegerField :
152 mICols[sk] = a.mICols[ska];
153 break;
154 case LongField :
155 mLCols[sk] = a.mLCols[ska];
156 break;
157 case FloatField :
158 mFCols[sk] = a.mFCols[ska];
159 break;
160 case DoubleField :
161 case DateTimeField :
162 mDCols[sk] = a.mDCols[ska];
163 break;
164 case ComplexField :
165 mYCols[sk] = a.mYCols[ska];
166 break;
167 case DoubleComplexField :
168 mZCols[sk] = a.mZCols[ska];
169 break;
170 case StringField :
171 mSCols[sk] = a.mSCols[ska];
172 break;
173 default:
174 throw ForbiddenError("SwFitsDataTable::Share() : unknown column type ");
175 break;
176 }
177 }
178}
179void SwFitsDataTable::SwapOutAll() const
180{
181 if (NRows() < 1) return;
182 // Et on vide les buffers de swap
183 for (size_t kk=0; kk<mNames.size(); kk++) {
184 sa_size_t sk = mNames[kk].ser;
185 switch (mNames[kk].type) {
186 case IntegerField :
187 mICols[sk].SwapOutBuffer();
188 break;
189 case LongField :
190 mLCols[sk].SwapOutBuffer();
191 break;
192 case FloatField :
193 mFCols[sk].SwapOutBuffer();
194 break;
195 case DoubleField :
196 case DateTimeField :
197 mDCols[sk].SwapOutBuffer();
198 break;
199 case ComplexField :
200 mYCols[sk].SwapOutBuffer();
201 break;
202 case DoubleComplexField :
203 mZCols[sk].SwapOutBuffer();
204 break;
205 case StringField :
206 mSCols[sk].SwapOutBuffer();
207 break;
208 default:
209 throw ForbiddenError("SwFitsDataTable::SwapOutAll() : unknown column type ");
210 break;
211 }
212 }
213}
214
215void SwFitsDataTable::Clear()
216{
217 if ( (NVar() == 0) && (NEntry() == 0)) return;
218 mNEnt = 0;
219 mNSeg = 0;
220 if (mVarD) delete[] mVarD;
221 mVarD = NULL;
222 if (mVarMTV) delete[] mVarMTV;
223 mVarMTV = NULL;
224 mNames.clear();
225 if (mInfo) delete mInfo;
226 mInfo = NULL;
227 if (mThS) delete mThS;
228 mThS = NULL;
229 mFgCreate = mFgDefDone = false;
230
231 mMin.clear();
232 mMax.clear();
233 mMinMaxNEnt.clear();
234 mIColsP.clear();
235 mLColsP.clear();
236 mFColsP.clear();
237 mDColsP.clear();
238 mYColsP.clear();
239 mZColsP.clear();
240 mSColsP.clear();
241
242 mIColIdx.clear();
243 mLColIdx.clear();
244 mFColIdx.clear();
245 mDColIdx.clear();
246 mYColIdx.clear();
247 mZColIdx.clear();
248 mSColIdx.clear();
249
250 mICols.clear();
251 mLCols.clear();
252 mFCols.clear();
253 mDCols.clear();
254 mYCols.clear();
255 mZCols.clear();
256 mSCols.clear();
257
258}
259
260
261/*!
262 Implements the action defined in the BaseDataTable interface.
263 In the current implementation, throws an exception (ParmError)
264 if the table contains some data already.
265*/
266sa_size_t SwFitsDataTable::AddColumn(FieldType ft, string const & cnom)
267{
268 return AddColRd(ft, cnom, -1, NULL);
269}
270/*!
271 Adds a column to the table. If swpos != NULL, the swapper is initialized
272 for reading data from the fits file. This method can be called
273 by FitsHandler<BaseDataTable> with non zero swpos.
274*/
275sa_size_t SwFitsDataTable::AddColRd(FieldType ft, string const & cnom,
276 int colidx, vector<int_8> const * swpos)
277{
278 if (NEntry() > 0)
279 throw ParmError("SwFitsDataTable::AddColumn() Table contains already data ");
280 CheckColName(cnom);
281 sa_size_t ser;
282 sa_size_t idx = NVar();
283 if (colidx < 1) colidx = idx+1;
284
285 switch (ft) {
286 case IntegerField :
287 {
288 ser = mICols.size();
289 FITSDataSwapper<int_4> ISwapper(mSwF, colidx, this);
290 if (swpos)
291 mICols.push_back(SwSegDataBlock<int_4>(ISwapper, *swpos, mSegSz));
292 else
293 mICols.push_back(SwSegDataBlock<int_4>(ISwapper, mSegSz));
294 mIColIdx.push_back(idx);
295 mIColsP.push_back(NULL);
296 for(sa_size_t kk=0; kk<mICols.size(); kk++)
297 mIColsP[kk] = &(mICols[kk]);
298 break;
299 }
300 case LongField :
301 {
302 ser = mLCols.size();
303 FITSDataSwapper<int_8> LSwapper(mSwF, colidx, this);
304 if (swpos)
305 mLCols.push_back(SwSegDataBlock<int_8>(LSwapper, *swpos, mSegSz));
306 else
307 mLCols.push_back(SwSegDataBlock<int_8>(LSwapper, mSegSz));
308 mLColIdx.push_back(idx);
309 mLColsP.push_back(NULL);
310 for(sa_size_t kk=0; kk<mLCols.size(); kk++)
311 mLColsP[kk] = &(mLCols[kk]);
312 break;
313 }
314 case FloatField :
315 {
316 ser = mFCols.size();
317 FITSDataSwapper<r_4> FSwapper(mSwF, colidx, this);
318 if (swpos)
319 mFCols.push_back(SwSegDataBlock<r_4>(FSwapper, *swpos, mSegSz));
320 else
321 mFCols.push_back(SwSegDataBlock<r_4>(FSwapper, mSegSz));
322 mFColIdx.push_back(idx);
323 mFColsP.push_back(NULL);
324 for(sa_size_t kk=0; kk<mFCols.size(); kk++)
325 mFColsP[kk] = &(mFCols[kk]);
326 break;
327 }
328 case DoubleField :
329 case DateTimeField :
330 {
331 ser = mDCols.size();
332 FITSDataSwapper<r_8> DSwapper(mSwF, colidx, this);
333 if (swpos)
334 mDCols.push_back(SwSegDataBlock<r_8>(DSwapper, *swpos, mSegSz));
335 else
336 mDCols.push_back(SwSegDataBlock<r_8>(DSwapper, mSegSz));
337 mDColIdx.push_back(idx);
338 mDColsP.push_back(NULL);
339 for(sa_size_t kk=0; kk<mDCols.size(); kk++)
340 mDColsP[kk] = &(mDCols[kk]);
341 break;
342 }
343 case ComplexField :
344 {
345 ser = mYCols.size();
346 FITSDataSwapper< complex<r_4> > YSwapper(mSwF, colidx, this);
347 if (swpos)
348 mYCols.push_back(SwSegDataBlock< complex<r_4> >(YSwapper, *swpos, mSegSz));
349 else
350 mYCols.push_back(SwSegDataBlock< complex<r_4> >(YSwapper, mSegSz));
351 mYColIdx.push_back(idx);
352 mYColsP.push_back(NULL);
353 for(sa_size_t kk=0; kk<mYCols.size(); kk++)
354 mYColsP[kk] = &(mYCols[kk]);
355 break;
356 }
357 case DoubleComplexField :
358 {
359 ser = mZCols.size();
360 FITSDataSwapper< complex<r_8> > ZSwapper(mSwF, colidx, this);
361 if (swpos)
362 mZCols.push_back(SwSegDataBlock< complex<r_8> >(ZSwapper, *swpos, mSegSz));
363 else
364 mZCols.push_back(SwSegDataBlock< complex<r_8> >(ZSwapper, mSegSz));
365 mZColIdx.push_back(idx);
366 mZColsP.push_back(NULL);
367 for(sa_size_t kk=0; kk<mZCols.size(); kk++)
368 mZColsP[kk] = &(mZCols[kk]);
369 break;
370 }
371 case StringField :
372 {
373 ser = mSCols.size();
374 FITSDataSwapper< string > SSwapper(mSwF, colidx, this);
375 if (swpos)
376 mSCols.push_back(SwSegDataBlock< string >(SSwapper, *swpos, mSegSz));
377 else
378 mSCols.push_back(SwSegDataBlock< string >(SSwapper, mSegSz));
379 mSColIdx.push_back(idx);
380 mSColsP.push_back(NULL);
381 for(sa_size_t kk=0; kk<mSCols.size(); kk++)
382 mSColsP[kk] = &(mSCols[kk]);
383 break;
384 }
385 default:
386 throw ParmError("SwFitsDataTable::AddColumn() unknown field type ");
387 break;
388 }
389 colst col;
390 col.nom = cnom;
391 col.type = ft;
392 col.ser = ser;
393 mNames.push_back(col);
394 // On est oblige de calculer les min-max lors du remplissage
395 // On ne peut pas en effet 'relire' le swap pendant l'ecriture
396 mMin.push_back(9.E39);
397 mMax.push_back(-9.E39);
398 mMinMaxNEnt.push_back(0);
399
400 return NVar();
401}
402
403
404/*!
405 \brief Writes table definition (column name/type) to the FITS file
406
407 It is not possible to add columns once the table definition is
408 written to the fits file. Returns number of table columns.
409 Although AddRow() checks and perform this operation automatically,
410 it is advised to do it explicitely, before using an SwFitsDataTable
411 for filling in multi-thread programs.
412*/
413sa_size_t SwFitsDataTable::WriteTableDefinitionToFits()
414{
415 if (!mFgDefDone && (NRows() == 0)) {
416 FitsHandler<BaseDataTable> fio(*this);
417 fio.Write(mSwF);
418 mFgDefDone = true;
419 }
420 return NVar();
421}
422
423//! Adds a line (or row to the table) with r_8* input data.
424/*!
425 The min/max values for each column is updated, in addition
426 to the actions performed by the base class AddRow().
427 The table is also created on the FITS file at the first call to AddRow(),
428 by calling WriteTableDefinitionToFits() , if not already done.
429*/
430sa_size_t SwFitsDataTable::AddRow(const r_8* data)
431{
432 if (mThS) mThS->lock(); // tread-safety
433 if (!mFgDefDone && (NRows() == 0)) { // On cree la definition de la table FITS au premier appel
434 FitsHandler<BaseDataTable> fio(*this);
435 fio.Write(mSwF);
436 mFgDefDone = true;
437 }
438 // On est oblige de calculer les min-max lors du remplissage
439 // On ne peut pas en effet 'relire' le swap pendant l'ecriture
440 for(sa_size_t k=0; k<NVar(); k++) {
441 double x = data[k];
442 if (x < mMin[k]) mMin[k] = x;
443 if (x > mMax[k]) mMax[k] = x;
444 mMinMaxNEnt[k]++;
445 }
446 if (mThS) mThS->unlock(); // tread-safety
447 return BaseDataTable::AddRow(data);
448}
449
450
451//! Adds a row (or line to the table) with input data as an array of MuTyV
452/*!
453 The min/max values for each column is updated, in addition
454 to the actions performed by the base class AddRow().
455 The table is also created on the FITS file at the first call to AddRow()
456*/
457sa_size_t SwFitsDataTable::AddRow(const MuTyV * data)
458{
459 if (mThS) mThS->lock(); // tread-safety
460 if (!mFgDefDone && (NRows() == 0)) { // On cree la definition de la table FITS au premier appel
461 FitsHandler<BaseDataTable> fio(*this);
462 fio.Write(mSwF);
463 mFgDefDone = true;
464 }
465 // On est oblige de calculer les min-max lors du remplissage
466 // On ne peut pas en effet 'relire' le swap pendant l'ecriture
467 for(sa_size_t k=0; k<NVar(); k++) {
468 double x = (double)data[k];
469 if (x < mMin[k]) mMin[k] = x;
470 if (x > mMax[k]) mMax[k] = x;
471 mMinMaxNEnt[k]++;
472 }
473 if (mThS) mThS->unlock(); // tread-safety
474 return BaseDataTable::AddRow(data);
475}
476
477//! Adds a row (or line) to the table with input data as DataTableRow object
478/*!
479 The min/max values for each column is updated, in addition
480 to the actions performed by the base class AddRow().
481 The table is also created on the FITS file at the first call to AddRow()
482*/
483sa_size_t SwFitsDataTable::AddRow(DataTableRow const& data)
484{
485 if ( data.Size() != NCols() )
486 throw SzMismatchError(" SwFitsDataTable::AddRow() - data.Size() != NCols() ");
487 return AddRow(data.MTVPtr());
488}
489
490} // FIN namespace SOPHYA
Note: See TracBrowser for help on using the repository browser.