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

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

Adaptation a ThSafeOp (thread-safety) pour BaseDataTable, Reza 22/11/2007

File size: 13.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
27 \sa SOPHYA::MuTyV
28 \sa SOPHYA::DataTableRow
29 \sa SOPHYA::DataTable
30 \sa SOPHYA::SwSegDataBlock SOPHYA::FitsDataSwapper
31
32 \code
33 #include "swfitsdtable.h"
34 // ...
35 {
36 // ---- Creation of the table
37 // Create the swap stream
38 FitsInOutFile so("myswtable.fits", FitsInOutFile::Fits_Create);
39 SwFitsDataTable dt(so, 16);
40 // define table columns
41 dt.AddFloatColumn("X0_f");
42 dt.AddFloatColumn("X1_f");
43 dt.AddDoubleColumn("X0X0pX1X1_d");
44 // Fill the table
45 r_8 x[5];
46 for(int i=0; i<63; i++) {
47 x[0] = (i%9)-4.; x[1] = (i/9)-3.; x[2] = x[0]*x[0]+x[1]*x[1];
48 dt.AddLine(x);
49 }
50 // Printing table info
51 cout << dt ;
52 // The destructor will Swap out data still in memory
53 }
54 {
55 // ---- Accessing information from a previously created table
56 SwFitsDataTable dt;
57 FitsInOutFile si("myswtable.fits", FitsInOutFile::Fits_ReadOnly);
58 // Position the fits file on the first extension (BinTable)
59 si.MoveAbsToHDU(2);
60 // Reading in the table (initialisation)
61 si >> dt;
62 // Printing table info
63 cout << dt ;
64 }
65 \endcode
66*/
67//! Default constructor with optional specification of block (or segment) size
68SwFitsDataTable::SwFitsDataTable(sa_size_t segsz)
69 : BaseDataTable(segsz)
70{
71 mFgCreate = false;
72}
73/*!
74 \brief Construcor with specification of the \b FitsInOutFile swap stream.
75 if fgcreate == true, creates an empty table (the fits file should then be
76 opened for writing).
77 if fgcreate == false , the table is initialized (read in) from the current HDU.
78*/
79SwFitsDataTable::SwFitsDataTable(FitsInOutFile & os, sa_size_t segsz, bool fgcreate)
80 : BaseDataTable(segsz) ,
81 mSwF(os) , mFgCreate(fgcreate)
82{
83 if (!fgcreate) { // Lecture de la table
84 FitsHandler<BaseDataTable> fio(*this);
85 fio.Read(os);
86 }
87}
88
89/*!
90 \brief Construcor with specification of the FITS file name.
91 if fgcreate == false , the FITS file is opened and the table is
92 initialized (read in) from HDU \b hdunum
93*/
94SwFitsDataTable::SwFitsDataTable(string fitsname, int hdunum, sa_size_t segsz)
95 : BaseDataTable(segsz) ,
96 mSwF(fitsname, FitsInOutFile::Fits_RO)
97{
98 // Lecture de la table
99 FitsHandler<BaseDataTable> fio(*this);
100 mSwF.MoveAbsToHDU(hdunum);
101 fio.Read(mSwF);
102}
103
104//! copy constructor - shares the data (and copies the thread safety state)
105SwFitsDataTable::SwFitsDataTable(SwFitsDataTable const & a)
106 : BaseDataTable(a.SegmentSize()),
107 mSwF(a.mSwF) , mFgCreate(a.mFgCreate)
108{
109 Share(a);
110}
111//! Destructor - Deletes / closes the input PPF swap stream
112SwFitsDataTable::~SwFitsDataTable()
113{
114 if (mFgCreate) {
115 SwapOutAll();
116 // Ecriture de SegmentSize et autre elements de DVList
117 mSwF.WriteHeaderRecords(Info());
118 MuTyV mtv = SegmentSize();
119 mSwF.WriteKey("SEGMSIZE",mtv," SOPHYA::DataTable SegmentSize");
120 mtv = "SOPHYA::SwFitsDataTable";
121 mSwF.WriteKey("SOPCLSNM",mtv," Object class name ");
122 }
123}
124
125void SwFitsDataTable::Share(SwFitsDataTable const & a)
126{
127 // On recopie la taille de segment
128 mSegSz = a.SegmentSize();
129 if (a.NVar() == 0) return; // Table sans colonne
130
131 // On copie la structure de table
132 CopyStructure(a);
133 if (a.IsThreadSafe()) SetThreadSafe(true);
134 else SetThreadSafe(false);
135
136 //
137 // Update nombre d'entree, ...
138 mNEnt = a.mNEnt;
139 mNSeg = a.mNSeg;
140 if (a.mInfo) mInfo = new DVList(*(a.mInfo));
141
142 // mis a jour des tableax min-max
143 mMin = a.mMin;
144 mMax = a.mMax;
145 mMinMaxNEnt = a.mMinMaxNEnt;
146
147 // Et on partage les donnees des colonnes
148 for (size_t kk=0; kk<mNames.size(); kk++) {
149 sa_size_t sk = mNames[kk].ser;
150 sa_size_t ska = a.mNames[kk].ser;
151 switch (mNames[kk].type) {
152 case IntegerField :
153 mICols[sk] = a.mICols[ska];
154 break;
155 case LongField :
156 mLCols[sk] = a.mLCols[ska];
157 break;
158 case FloatField :
159 mFCols[sk] = a.mFCols[ska];
160 break;
161 case DoubleField :
162 case DateTimeField :
163 mDCols[sk] = a.mDCols[ska];
164 break;
165 case ComplexField :
166 mYCols[sk] = a.mYCols[ska];
167 break;
168 case DoubleComplexField :
169 mZCols[sk] = a.mZCols[ska];
170 break;
171 case StringField :
172 mSCols[sk] = a.mSCols[ska];
173 break;
174 default:
175 throw ForbiddenError("SwFitsDataTable::Share() : unknown column type ");
176 break;
177 }
178 }
179}
180void SwFitsDataTable::SwapOutAll() const
181{
182 if (NRows() < 1) return;
183 // Et on vide les buffers de swap
184 for (size_t kk=0; kk<mNames.size(); kk++) {
185 sa_size_t sk = mNames[kk].ser;
186 switch (mNames[kk].type) {
187 case IntegerField :
188 mICols[sk].SwapOutBuffer();
189 break;
190 case LongField :
191 mLCols[sk].SwapOutBuffer();
192 break;
193 case FloatField :
194 mFCols[sk].SwapOutBuffer();
195 break;
196 case DoubleField :
197 case DateTimeField :
198 mDCols[sk].SwapOutBuffer();
199 break;
200 case ComplexField :
201 mYCols[sk].SwapOutBuffer();
202 break;
203 case DoubleComplexField :
204 mZCols[sk].SwapOutBuffer();
205 break;
206 case StringField :
207 mSCols[sk].SwapOutBuffer();
208 break;
209 default:
210 throw ForbiddenError("SwFitsDataTable::SwapOutAll() : unknown column type ");
211 break;
212 }
213 }
214}
215
216void SwFitsDataTable::Clear()
217{
218 if ( (NVar() == 0) && (NEntry() == 0)) return;
219 mNEnt = 0;
220 mNSeg = 0;
221 if (mVarD) delete[] mVarD;
222 mVarD = NULL;
223 if (mVarMTV) delete[] mVarMTV;
224 mVarMTV = NULL;
225 mNames.clear();
226 if (mInfo) delete mInfo;
227 mInfo = NULL;
228 if (mThS) delete mThS;
229 mThS = NULL;
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//! Adds a line (or row to the table) with r_8* input data.
404/*!
405 The min/max values for each column is updated, in addition
406 to the actions performed by the base class AddRow().
407 The table is also created on the FITS file at the first call to AddRow()
408*/
409sa_size_t SwFitsDataTable::AddRow(const r_8* data)
410{
411 if (mThS) mThS->lock(); // tread-safety
412 if (NRows() == 0) { // On cree la definition de la table FITS au premier appel
413 FitsHandler<BaseDataTable> fio(*this);
414 fio.Write(mSwF);
415 }
416 // On est oblige de calculer les min-max lors du remplissage
417 // On ne peut pas en effet 'relire' le swap pendant l'ecriture
418 for(sa_size_t k=0; k<NVar(); k++) {
419 double x = data[k];
420 if (x < mMin[k]) mMin[k] = x;
421 if (x > mMax[k]) mMax[k] = x;
422 mMinMaxNEnt[k]++;
423 }
424 if (mThS) mThS->unlock(); // tread-safety
425 return BaseDataTable::AddRow(data);
426}
427
428//! Adds a row (or line to the table) with input data as an array of MuTyV
429/*!
430 The min/max values for each column is updated, in addition
431 to the actions performed by the base class AddRow().
432 The table is also created on the FITS file at the first call to AddRow()
433*/
434sa_size_t SwFitsDataTable::AddRow(const MuTyV * data)
435{
436 if (mThS) mThS->lock(); // tread-safety
437 if (NRows() == 0) { // On cree la definition de la table FITS au premier appel
438 FitsHandler<BaseDataTable> fio(*this);
439 fio.Write(mSwF);
440 }
441 // On est oblige de calculer les min-max lors du remplissage
442 // On ne peut pas en effet 'relire' le swap pendant l'ecriture
443 for(sa_size_t k=0; k<NVar(); k++) {
444 double x = (double)data[k];
445 if (x < mMin[k]) mMin[k] = x;
446 if (x > mMax[k]) mMax[k] = x;
447 mMinMaxNEnt[k]++;
448 }
449 if (mThS) mThS->unlock(); // tread-safety
450 return BaseDataTable::AddRow(data);
451}
452
453//! Adds a row (or line) to the table with input data as DataTableRow object
454/*!
455 The min/max values for each column is updated, in addition
456 to the actions performed by the base class AddRow().
457 The table is also created on the FITS file at the first call to AddRow()
458*/
459sa_size_t SwFitsDataTable::AddRow(DataTableRow const& data)
460{
461 if ( data.Size() != NCols() )
462 throw SzMismatchError(" SwFitsDataTable::AddRow() - data.Size() != NCols() ");
463 return AddRow(data.MTVPtr());
464}
465
466} // FIN namespace SOPHYA
Note: See TracBrowser for help on using the repository browser.