CCfits 2.7
ColumnVectorData.h
1// Astrophysics Science Division,
2// NASA/ Goddard Space Flight Center
3// HEASARC
4// http://heasarc.gsfc.nasa.gov
5// e-mail: ccfits@legacy.gsfc.nasa.gov
6//
7// Original author: Ben Dorman
8
9#ifndef COLUMNVECTORDATA_H
10#define COLUMNVECTORDATA_H 1
11#ifdef _MSC_VER
12#include "MSconfig.h"
13#endif
14#include "CCfits.h"
15
16// valarray
17#include <valarray>
18// vector
19#include <vector>
20// Column
21#include "Column.h"
22
23#ifdef SSTREAM_DEFECT
24#include <strstream>
25#else
26#include <sstream>
27#endif
28
29#include <memory>
30#include <numeric>
31#include <algorithm>
32
33namespace CCfits {
34
35 class Table;
36
37}
38
39#include "FITS.h"
40#include "FITSUtil.h"
41using std::complex;
42
43
44namespace CCfits {
45
46
47
48 template <typename T>
49 class ColumnVectorData : public Column //## Inherits: <unnamed>%38BAD1D4D370
50 {
51
52 public:
53 ColumnVectorData(const ColumnVectorData< T > &right);
54 ColumnVectorData (Table* p = 0);
55 ColumnVectorData (int columnIndex, const string &columnName, ValueType type, const string &format, const string &unit, Table* p, int rpt = 1, long w = 1, const string &comment = "");
56 ~ColumnVectorData();
57
58 virtual void readData (long firstrow, long nelements, long firstelem = 1);
59 virtual ColumnVectorData<T>* clone () const;
60 virtual void setDimen ();
61 void setDataLimits (T* limits);
62 const T minLegalValue () const;
63 void minLegalValue (T value);
64 const T maxLegalValue () const;
65 void maxLegalValue (T value);
66 const T minDataValue () const;
67 void minDataValue (T value);
68 const T maxDataValue () const;
69 void maxDataValue (T value);
70 const std::vector<std::valarray<T> >& data () const;
71 void setData (const std::vector<std::valarray<T> >& value);
72 const std::valarray<T>& data (int i) const;
73 void data (int i, const std::valarray<T>& value);
74
75 // Additional Public Declarations
76 friend class Column;
77 protected:
78 // Additional Protected Declarations
79
80 private:
81 ColumnVectorData< T > & operator=(const ColumnVectorData< T > &right);
82
83 virtual bool compare (const Column &right) const;
84 void resizeDataObject (const std::vector<std::valarray<T> >& indata, size_t firstRow);
85 // Reads a specified number of column rows.
86 //
87 // There are no default arguments. The function
88 // Column::read(firstrow,firstelem,nelements)
89 // is designed for reading the whole column.
90 virtual void readColumnData (long first, long last, T* nullValue = 0);
91 virtual std::ostream& put (std::ostream& s) const;
92 void writeData (const std::valarray<T>& indata, long numRows, long firstRow = 1, T* nullValue = 0);
93 void writeData (const std::vector<std::valarray<T> >& indata, long firstRow = 1, T* nullValue = 0);
94 // Reads a specified number of column rows.
95 //
96 // There are no default arguments. The function
97 // Column::read(firstrow,firstelem,nelements)
98 // is designed for reading the whole column.
99 virtual void readRow (size_t row, T* nullValue = 0);
100 // Reads a variable row..
101 virtual void readVariableRow (size_t row, T* nullValue = 0);
102 void readColumnData (long firstrow, long nelements, long firstelem, T* nullValue = 0);
103 void writeData (const std::valarray<T>& indata, const std::vector<long>& vectorLengths, long firstRow = 1, T* nullValue = 0);
104 void writeFixedRow (const std::valarray<T>& data, long row, long firstElem = 1, T* nullValue = 0);
105 void writeFixedArray (T* data, long nElements, long nRows, long firstRow, T* nullValue = 0);
106 // Insert one or more blank rows into a FITS column.
107 virtual void insertRows (long first, long number = 1);
108 virtual void deleteRows (long first, long number = 1);
109 virtual size_t getStoredDataSize() const;
110 void doWrite (T* array, long row, long rowSize, long firstElem, T* nullValue);
111
112 // Additional Private Declarations
113
114 private: //## implementation
115 // Data Members for Class Attributes
116 T m_minLegalValue;
117 T m_maxLegalValue;
118 T m_minDataValue;
119 T m_maxDataValue;
120
121 // Data Members for Associations
122 std::vector<std::valarray<T> > m_data;
123
124 // Additional Implementation Declarations
125
126 };
127
128 // Parameterized Class CCfits::ColumnVectorData
129
130 template <typename T>
131 inline void ColumnVectorData<T>::readData (long firstrow, long nelements, long firstelem)
132 {
133 readColumnData(firstrow,nelements,firstelem,static_cast<T*>(0));
134 }
135
136 template <typename T>
137 inline const T ColumnVectorData<T>::minLegalValue () const
138 {
139 return m_minLegalValue;
140 }
141
142 template <typename T>
143 inline void ColumnVectorData<T>::minLegalValue (T value)
144 {
145 m_minLegalValue = value;
146 }
147
148 template <typename T>
149 inline const T ColumnVectorData<T>::maxLegalValue () const
150 {
151 return m_maxLegalValue;
152 }
153
154 template <typename T>
155 inline void ColumnVectorData<T>::maxLegalValue (T value)
156 {
157 m_maxLegalValue = value;
158 }
159
160 template <typename T>
161 inline const T ColumnVectorData<T>::minDataValue () const
162 {
163 return m_minDataValue;
164 }
165
166 template <typename T>
167 inline void ColumnVectorData<T>::minDataValue (T value)
168 {
169 m_minDataValue = value;
170 }
171
172 template <typename T>
173 inline const T ColumnVectorData<T>::maxDataValue () const
174 {
175 return m_maxDataValue;
176 }
177
178 template <typename T>
179 inline void ColumnVectorData<T>::maxDataValue (T value)
180 {
181 m_maxDataValue = value;
182 }
183
184 template <typename T>
185 inline const std::vector<std::valarray<T> >& ColumnVectorData<T>::data () const
186 {
187 return m_data;
188 }
189
190 template <typename T>
191 inline void ColumnVectorData<T>::setData (const std::vector<std::valarray<T> >& value)
192 {
193 m_data = value;
194 }
195
196 template <typename T>
197 inline const std::valarray<T>& ColumnVectorData<T>::data (int i) const
198 {
199 return m_data[i - 1];
200 }
201
202 template <typename T>
203 inline void ColumnVectorData<T>::data (int i, const std::valarray<T>& value)
204 {
205 if (m_data[i-1].size() != value.size())
206 m_data[i-1].resize(value.size());
207 m_data[i - 1] = value;
208 }
209
210 // Parameterized Class CCfits::ColumnVectorData
211
212 template <typename T>
213 ColumnVectorData<T>::ColumnVectorData(const ColumnVectorData<T> &right)
214 :Column(right),
215 m_minLegalValue(right.m_minLegalValue),
216 m_maxLegalValue(right.m_maxLegalValue),
217 m_minDataValue(right.m_minDataValue),
218 m_maxDataValue(right.m_maxDataValue),
219 m_data(right.m_data)
220 {
221 }
222
223 template <typename T>
224 ColumnVectorData<T>::ColumnVectorData (Table* p)
225 : Column(p),
226 m_minLegalValue(0),
227 m_maxLegalValue(0),
228 m_minDataValue(0),
229 m_maxDataValue(0),
230 m_data()
231 {
232 }
233
234 template <typename T>
235 ColumnVectorData<T>::ColumnVectorData (int columnIndex, const string &columnName, ValueType type, const string &format, const string &unit, Table* p, int rpt, long w, const string &comment)
236 : Column(columnIndex,columnName,type,format,unit,p,rpt,w,comment),
237 m_minLegalValue(0),
238 m_maxLegalValue(0),
239 m_minDataValue(0),
240 m_maxDataValue(0),
241 m_data()
242 {
243 }
244
245
246 template <typename T>
247 ColumnVectorData<T>::~ColumnVectorData()
248 {
249 // valarray destructor should do all the work.
250 }
251
252
253 template <typename T>
254 bool ColumnVectorData<T>::compare (const Column &right) const
255 {
256 if ( !Column::compare(right) ) return false;
257 const ColumnVectorData<T>& that = static_cast<const ColumnVectorData<T>&>(right);
258 size_t n = m_data.size();
259 // m_data is of type valarray<T>.
260 if ( that.m_data.size() != n ) return false;
261 for (size_t i = 0; i < n ; i++)
262 {
263 const std::valarray<T>& thisValArray=m_data[i];
264 const std::valarray<T>& thatValArray=that.m_data[i];
265 size_t nn = thisValArray.size();
266 if (thatValArray.size() != nn ) return false;
267
268 for (size_t j = 0; j < nn ; j++ )
269 {
270 if (thisValArray[j] != thatValArray[j])
271 return false;
272 }
273 }
274 return true;
275 }
276
277 template <typename T>
278 ColumnVectorData<T>* ColumnVectorData<T>::clone () const
279 {
280 return new ColumnVectorData<T>(*this);
281 }
282
283 template <typename T>
284 void ColumnVectorData<T>::resizeDataObject (const std::vector<std::valarray<T> >& indata, size_t firstRow)
285 {
286 // the rows() call is the value before updating.
287 // the updateRows() call at the end sets the call to return the
288 // value from the fits pointer - which is changed by writeFixedArray
289 // or writeFixedRow.
290
291 const size_t lastInputRow(indata.size() + firstRow - 1);
292 const size_t newLastRow = std::max(lastInputRow,static_cast<size_t>(rows()));
293
294 // if the write instruction increases the rows, we need to add
295 // rows to the data member and preserve its current contents.
296
297 // rows() >= origNRows since it is the value for entire table,
298 // not just this column.
299 const size_t origNRows(m_data.size());
300 // This will always be an expansion. vector.resize() doesn't
301 // invalidate any data on an expansion.
302 if (newLastRow > origNRows) m_data.resize(newLastRow);
303
304 if (varLength())
305 {
306 // The incoming data will determine each row size, thus
307 // no need to preserve any existing values in the row.
308 // Each value will eventually be overwritten.
309 for (size_t iRow = firstRow-1; iRow < lastInputRow; ++iRow)
310 {
311 std::valarray<T>& current = m_data[iRow];
312 const size_t newSize = indata[iRow - (firstRow-1)].size();
313 if (current.size() != newSize)
314 current.resize(newSize);
315 }
316 }
317 else
318 {
319 // All row sizes in m_data should ALWAYS be either repeat(),
320 // or 0 if they haven't been initialized. This is true regardless
321 // of the incoming data row size.
322
323 // Perform LAZY initialization of m_data rows. Only
324 // expand a row valarray when it is first needed.
325 for (size_t iRow = firstRow-1; iRow < lastInputRow; ++iRow)
326 {
327 if (m_data[iRow].size() != repeat())
328 m_data[iRow].resize(repeat());
329 }
330 }
331 }
332
333 template <typename T>
334 void ColumnVectorData<T>::setDimen ()
335 {
336 int status(0);
337 FITSUtil:: auto_array_ptr<char> dimValue (new char[FLEN_VALUE]);
338
339#ifdef SSTREAM_DEFECT
340 std::ostrstream key;
341#else
342 std::ostringstream key;
343#endif
344 key << "TDIM" << index();
345
346#ifdef SSTREAM_DEFECT
347 fits_read_key_str(fitsPointer(), key.str(), dimValue.get(),0,&status);
348#else
349 fits_read_key_str(fitsPointer(),const_cast<char*>(key.str().c_str()),dimValue.get(),0,&status);
350#endif
351
352 if (status == 0)
353 {
354 dimen(String(dimValue.get()));
355 }
356 }
357
358 template <typename T>
359 void ColumnVectorData<T>::readColumnData (long first, long last, T* nullValue)
360 {
361 makeHDUCurrent();
362
363
364 if ( rows() < last )
365 {
366 std::cerr << "CCfits: More data requested than contained in table. ";
367 std::cerr << "Extracting complete column.\n";
368 last = rows();
369 }
370
371 long nelements = (last - first + 1)*repeat();
372
373
374 readColumnData(first,nelements,1,nullValue);
375 if (first <= 1 && last == rows()) isRead(true);
376 }
377
378 template <typename T>
379 std::ostream& ColumnVectorData<T>::put (std::ostream& s) const
380 {
381 // output header information
382 Column::put(s);
383 if ( FITS::verboseMode() )
384 {
385 s << " Column Legal limits: ( " << m_minLegalValue << "," << m_maxLegalValue << " )\n"
386 << " Column Data limits: ( " << m_minDataValue << "," << m_maxDataValue << " )\n";
387 }
388 if (!m_data.empty())
389 {
390 for (size_t j = 0; j < m_data.size(); j++)
391 {
392 size_t n = m_data[j].size();
393 if ( n )
394 {
395 s << "Row " << j + 1 << " Vector Size " << n << '\n';
396 for (size_t k = 0; k < n - 1; k++)
397 {
398 s << m_data[j][k] << '\t';
399 }
400 s << m_data[j][n - 1] << '\n';
401 }
402 }
403 }
404
405 return s;
406 }
407
408 template <typename T>
409 void ColumnVectorData<T>::writeData (const std::valarray<T>& indata, long numRows, long firstRow, T* nullValue)
410 {
411 // This version of writeData is called by Column write functions which
412 // can only write the same number of elements to each row.
413 // For fixed width columns, this must be equal to the repeat value
414 // or an exception is thrown. For variable width, it only requires
415 // that indata.size()/numRows is an int.
416
417 // won't do anything if < 0, and will give divide check if == 0.
418 if (numRows <= 0) throw InvalidNumberOfRows(numRows);
419
420#ifdef SSTREAM_DEFECT
421 std::ostrstream msgStr;
422#else
423 std::ostringstream msgStr;
424#endif
425 if (indata.size() % static_cast<size_t>(numRows))
426 {
427 msgStr << "To use this write function, input array size"
428 <<"\n must be exactly divisible by requested num rows: "
429 << numRows;
430 throw InsufficientElements(msgStr.str());
431 }
432 const size_t cellsize = indata.size()/static_cast<size_t>(numRows);
433
434 if (!varLength() && cellsize != repeat() )
435 {
436 msgStr << "column: " << name()
437 << "\n input data size: " << indata.size()
438 << " required: " << numRows*repeat();
439 String msg(msgStr.str());
440 throw InsufficientElements(msg);
441 }
442
443 std::vector<std::valarray<T> > internalFormat(numRows);
444
445 // support writing equal row lengths to variable columns.
446
447 for (long j = 0; j < numRows; ++j)
448 {
449 internalFormat[j].resize(cellsize);
450 internalFormat[j] = indata[std::slice(cellsize*j,cellsize,1)];
451 }
452
453 // change the size of m_data based on the first row to be written
454 // and on the input data vector sizes.
455
456 writeData(internalFormat,firstRow,nullValue);
457 }
458
459 template <typename T>
460 void ColumnVectorData<T>::writeData (const std::vector<std::valarray<T> >& indata, long firstRow, T* nullValue)
461 {
462 // This is called directly by Column's writeArrays functions, and indirectly
463 // by both categories of write functions, ie. those which allow differing
464 // lengths per row and those that don't.
465 const size_t nInputRows(indata.size());
466 using std::valarray;
467
468 resizeDataObject(indata,firstRow);
469 // After the above call, can assume all m_data arrays to be written to
470 // have been properly resized whether we're dealing with fixed or
471 // variable length.
472
473 if (varLength())
474 {
475 // firstRow is 1-based, but all these internal row variables
476 // will be 0-based.
477 const size_t endRow = nInputRows + firstRow-1;
478 for (size_t iRow = firstRow-1; iRow < endRow; ++iRow)
479 {
480 m_data[iRow] = indata[iRow - (firstRow-1)];
481 // doWrite wants 1-based rows.
482 doWrite(&m_data[iRow][0], iRow+1, m_data[iRow].size(), 1, nullValue);
483 }
484 parent()->updateRows();
485 }
486 else
487 {
488 // Check for simplest case of all valarrays of size repeat().
489 // If any are greater, throw an error.
490 const size_t colRepeat = repeat();
491 bool allEqualRepeat = true;
492 for (size_t i=0; i<nInputRows; ++i)
493 {
494 const size_t sz = indata[i].size();
495 if (sz > colRepeat)
496 {
497#ifdef SSTREAM_DEFECT
498 std::ostrstream oss;
499#else
500 std::ostringstream oss;
501#endif
502 oss << " vector column length " << colRepeat
503 <<", input valarray length " << sz;
504 throw InvalidRowParameter(oss.str());
505 }
506 if (sz < colRepeat)
507 allEqualRepeat = false;
508 }
509
510 if (allEqualRepeat)
511 {
512 // concatenate the valarrays and write.
513 const size_t nElements (colRepeat*nInputRows);
514 FITSUtil::CVAarray<T> convert;
515 FITSUtil::auto_array_ptr<T> pArray(convert(indata));
516 T* array = pArray.get();
517
518 // if T is complex, then CVAarray returns a
519 // C-array of complex objects. But FITS requires an array of complex's
520 // value_type.
521
522 // This writes to the file and also calls updateRows.
523 writeFixedArray(array,nElements,nInputRows,firstRow,nullValue);
524
525 for (size_t j = 0; j < nInputRows ; ++j)
526 {
527 const valarray<T>& input = indata[j];
528 valarray<T>& current = m_data[j + firstRow - 1];
529 // current should be resized by resizeDataObject.
530 current = input;
531 }
532 }
533 else
534 {
535 // Some input arrays have fewer than colRepeat elements.
536 const size_t endRow = nInputRows + firstRow-1;
537 for (size_t iRow = firstRow-1; iRow<endRow; ++iRow)
538 {
539 // resizeDataObject should already have resized all
540 // corresponding m_data rows to repeat().
541 const valarray<T>& input = indata[iRow-(firstRow-1)];
542 writeFixedRow(input, iRow, 1, nullValue);
543 }
544 parent()->updateRows();
545 }
546
547 } // end if !varLength
548 }
549
550 template <typename T>
551 void ColumnVectorData<T>::readRow (size_t row, T* nullValue)
552 {
553 makeHDUCurrent();
554
555
556
557 if ( row > static_cast<size_t>(rows()) )
558 {
559#ifdef SSTREAM_DEFECT
560 std::ostrstream msg;
561#else
562 std::ostringstream msg;
563#endif
564 msg << " row requested: " << row << " row range: 1 - " << rows();
565#ifdef SSTREAM_DEFECT
566 msg << std::ends;
567#endif
568
569 throw Column::InvalidRowNumber(msg.str());
570 }
571
572 // this is really for documentation purposes. I expect the optimizer will
573 // remove this redundant definition .
574 bool variable(type() < 0);
575
576
577 long nelements(repeat());
578
579 if (variable)
580 {
581 readVariableRow(row,nullValue);
582 }
583 else
584 {
585 readColumnData(row,nelements,1,nullValue);
586 }
587 }
588
589 template <typename T>
590 void ColumnVectorData<T>::readVariableRow (size_t row, T* nullValue)
591 {
592 int status(0);
593 long offset(0);
594 long repeat(0);
595 if (fits_read_descript(fitsPointer(),index(),static_cast<long>(row),
596 &repeat,&offset,&status)) throw FitsError(status);
597 readColumnData(row,repeat,1,nullValue);
598 }
599
600 template <typename T>
601 void ColumnVectorData<T>::readColumnData (long firstrow, long nelements, long firstelem, T* nullValue)
602 {
603 int status=0;
604
605 FITSUtil::auto_array_ptr<T> pArray(new T[nelements]);
606 T* array = pArray.get();
607 int anynul(0);
608
609
610
611 if (fits_read_col(fitsPointer(), abs(type()),index(), firstrow, firstelem,
612 nelements, nullValue, array, &anynul, &status) != 0)
613 throw FitsError(status);
614
615 size_t countRead = 0;
616 const size_t ONE = 1;
617
618 if (m_data.size() != static_cast<size_t>(rows())) m_data.resize(rows());
619 size_t vectorSize(0);
620 if (!varLength())
621 {
622
623 vectorSize = std::max(repeat(),ONE); // safety check.
624
625 }
626 else
627 {
628 // assume that the user specified the correct length for
629 // variable columns. This should be ok since readVariableColumns
630 // uses fits_read_descripts to return this information from the
631 // fits pointer, and this is passed as nelements here.
632 vectorSize = nelements;
633 }
634 size_t n = nelements;
635
636 int i = firstrow;
637 int ii = i - 1;
638 while ( countRead < n)
639 {
640 std::valarray<T>& current = m_data[ii];
641 if (current.size() != vectorSize) current.resize(vectorSize);
642 int elementsInFirstRow = vectorSize-firstelem + 1;
643 bool lastRow = ( (nelements - countRead) < vectorSize);
644 if (lastRow)
645 {
646 int elementsInLastRow = nelements - countRead;
647 std::valarray<T> ttmp(array + vectorSize*(ii-firstrow) + elementsInFirstRow,
648 elementsInLastRow);
649 for (int kk = 0; kk < elementsInLastRow; kk++) current[kk] = ttmp[kk];
650 countRead += elementsInLastRow;
651
652 }
653 // what to do with complete rows
654 else
655 {
656 if (firstelem == 1 || (firstelem > 1 && i > firstrow) )
657 {
658 std::valarray<T> ttmp(array + vectorSize*(ii - firstrow) +
659 elementsInFirstRow,vectorSize);
660 current = ttmp;
661 ii++;
662 i++;
663 countRead += vectorSize;
664 }
665 else
666 {
667 if (i == firstrow)
668 {
669 std::valarray<T> ttmp(array,elementsInFirstRow);
670 for (size_t kk = firstelem ; kk < vectorSize ; kk++)
671 current[kk] = ttmp[kk-firstelem];
672 countRead += elementsInFirstRow;
673 i++;
674 ii++;
675 }
676 }
677 }
678 }
679 }
680
681 template <typename T>
682 void ColumnVectorData<T>::writeData (const std::valarray<T>& indata, const std::vector<long>& vectorLengths, long firstRow, T* nullValue)
683 {
684 // Called from Column write functions which allow differing lengths
685 // for each row.
686 using namespace std;
687 const size_t N(vectorLengths.size());
688 vector<long> sums(N);
689 // pre-calculate partial sums of vector lengths for use as array offsets.
690 partial_sum(vectorLengths.begin(),vectorLengths.end(),sums.begin());
691 // check that sufficient data have been supplied to carry out the entire operation.
692 if (indata.size() < static_cast<size_t>(sums[N-1]) )
693 {
694#ifdef SSTREAM_DEFECT
695 ostrstream msgStr;
696#else
697 ostringstream msgStr;
698#endif
699 msgStr << " input data size: " << indata.size() << " vector length sum: " << sums[N-1];
700#ifdef SSTREAM_DEFECT
701 msgStr << std::ends;
702#endif
703
704 String msg(msgStr.str());
705 throw InsufficientElements(msg);
706 }
707
708 vector<valarray<T> > vvArray(N);
709 long& last = sums[0];
710 vvArray[0].resize(last);
711 for (long jj = 0; jj < last; ++jj) vvArray[0][jj] = indata[jj];
712
713 for (size_t j = 1; j < N; ++j)
714 {
715 valarray<T>& __tmp = vvArray[j];
716 // these make the code much more readable
717 long& first = sums[j-1];
718 long& jlast = sums[j];
719 __tmp.resize(jlast - first);
720 for (long k = first; k < jlast; ++k)
721 {
722 __tmp[k - first] = indata[k];
723 }
724 }
725
726 writeData(vvArray,firstRow,nullValue);
727 }
728
729 template <typename T>
730 void ColumnVectorData<T>::writeFixedRow (const std::valarray<T>& data, long row, long firstElem, T* nullValue)
731 {
732
733 // This is to be called only for FIXED length vector columns. It will
734 // throw if data.size()+firstElem goes beyond the repeat value.
735 // If data.size() is less than repeat, it leaves the remaining values
736 // undisturbed both in the file and in m_data storage.
737
738#ifdef SSTREAM_DEFECT
739 std::ostrstream msgStr;
740#else
741 std::ostringstream msgStr;
742#endif
743 if (varLength())
744 {
745 msgStr <<"Calling ColumnVectorData::writeFixedRow for a variable length column.\n";
746 throw FitsFatal(msgStr.str());
747 }
748
749 std::valarray<T>& storedRow = m_data[row];
750 long inputSize = static_cast<long>(data.size());
751 long storedSize(storedRow.size());
752 if (storedSize != static_cast<long>(repeat()))
753 {
754 msgStr<<"stored array size vs. column width mismatch in ColumnVectorData::writeFixedRow.\n";
755 throw FitsFatal(msgStr.str());
756 }
757
758 if (inputSize + firstElem - 1 > storedSize)
759 {
760 msgStr << " requested write " << firstElem << " to "
761 << firstElem + inputSize - 1 << " exceeds vector length " << repeat();
762 throw InvalidRowParameter(msgStr.str());
763 }
764
765 // CANNOT give a strong exception safety guarantee because writing
766 // data changes the file. Any corrective action that could be taken
767 // [e.g. holding initial contents of the row and writing it back after
768 // an exception is thrown] could in principle throw the same exception
769 // we are trying to protect from.
770
771 // routine does however give the weak guarantee (no resource leaks).
772
773 // It's never a good thing to cast away a const, but doWrite calls the
774 // CFITSIO write functions which take a non-const pointer (though
775 // it shouldn't actually modify the array), and I'd rather not
776 // copy the entire valarray just to avoid this problem.
777 std::valarray<T>& lvData = const_cast<std::valarray<T>&>(data);
778 T* inPointer = &lvData[0];
779 doWrite(inPointer, row+1, inputSize, firstElem, nullValue);
780
781 // Writing to disk was successful, now update FITS object and return.
782 const size_t offset = static_cast<size_t>(firstElem) - 1;
783 for (size_t iElem=0; iElem < static_cast<size_t>(inputSize); ++iElem)
784 {
785 // This doesn't require inPointer's non-constness. It's just
786 // used here to speed things up a bit.
787 storedRow[iElem + offset] = inPointer[iElem];
788 }
789 }
790
791 template <typename T>
792 void ColumnVectorData<T>::writeFixedArray (T* data, long nElements, long nRows, long firstRow, T* nullValue)
793 {
794 int status(0);
795
796 // check for sanity of inputs, then write to file.
797 // this function writes only complete rows to a table with
798 // fixed width rows.
799
800
801 if ( nElements < nRows*static_cast<long>(repeat()) )
802 {
803#ifdef SSTREAM_DEFECT
804 std::ostrstream msgStr;
805#else
806 std::ostringstream msgStr;
807#endif
808 msgStr << " input array size: " << nElements << " required " << nRows*repeat();
809 String msg(msgStr.str());
810
811 throw Column::InsufficientElements(msg);
812 }
813
814 if (nullValue)
815 {
816 if (fits_write_colnull(fitsPointer(),abs(type()),index(),firstRow,
817 1,nElements,data,nullValue,&status)) throw FitsError(status);
818 }
819 else
820 {
821 if (fits_write_col(fitsPointer(),abs(type()),index(),firstRow,
822 1,nElements,data,&status)) throw FitsError(status);
823 }
824
825 parent()->updateRows();
826 }
827
828 template <typename T>
829 void ColumnVectorData<T>::insertRows (long first, long number)
830 {
831 if (first >= 0 && first <= static_cast<long>(m_data.size()))
832 {
833 typename std::vector<std::valarray<T> >::iterator in;
834 if (first !=0)
835 {
836 in = m_data.begin()+first;
837 }
838 else
839 {
840 in = m_data.begin();
841 }
842
843 // non-throwing operations.
844 m_data.insert(in,number,std::valarray<T>(T(),0));
845 }
846 }
847
848 template <typename T>
849 void ColumnVectorData<T>::deleteRows (long first, long number)
850 {
851 // Don't assume the calling routine (ie. Table's deleteRows)
852 // knows Column's current m_data size. m_data may still be
853 // size 0 if no read operations have been performed on Column.
854 // Therefore perform range checking before erasing.
855 const long curSize = static_cast<long>(m_data.size());
856 if (curSize>0 && first <= curSize)
857 {
858 const long last = std::min(curSize, first-1+number);
859 m_data.erase(m_data.begin()+first-1,m_data.begin()+last);
860 }
861
862 }
863
864 template <typename T>
865 size_t ColumnVectorData<T>::getStoredDataSize() const
866 {
867 return m_data.size();
868 }
869
870 template <typename T>
871 void ColumnVectorData<T>::setDataLimits (T* limits)
872 {
873 m_minLegalValue = limits[0];
874 m_maxLegalValue = limits[1];
875 m_minDataValue = std::max(limits[2],limits[0]);
876 m_maxDataValue = std::min(limits[3],limits[1]);
877 }
878
879 template <typename T>
880 void ColumnVectorData<T>::doWrite (T* array, long row, long rowSize, long firstElem, T* nullValue)
881 {
882 int status(0);
883 // internal functioning of write_colnull forbids its use for writing
884 // variable width columns. If a nullvalue argument was supplied it will
885 // be ignored.
886 if ( !varLength())
887 {
888 if (fits_write_colnull(fitsPointer(),type(),index(),row, firstElem, rowSize,
889 array, nullValue,&status)) throw FitsError(status);
890 }
891 else
892 {
893 if (fits_write_col(fitsPointer(),abs(type()),index(),row,firstElem,rowSize,
894 array,&status)) throw FitsError(status);
895
896 }
897 }
898
899 // Additional Declarations
900
901 // all functions that operate on complex data that call cfitsio
902 // need to be specialized. The signature containing complex<T>* objects
903 // is unfortunate, perhaps, for this purpose, but the user will access
904 // rw operations through standard library containers.
905
906
907
908
909
910#if SPEC_TEMPLATE_IMP_DEFECT || SPEC_TEMPLATE_DECL_DEFECT
911template <>
912inline void ColumnVectorData<complex<float> >::setDataLimits (complex<float>* limits)
913 {
914 m_minLegalValue = limits[0];
915 m_maxLegalValue = limits[1];
916 m_minDataValue = limits[2];
917 m_maxDataValue = limits[3];
918 }
919#else
920template <>
921 void
922 ColumnVectorData<complex<float> >::setDataLimits (complex<float>* limits);
923#endif
924
925#if SPEC_TEMPLATE_IMP_DEFECT || SPEC_TEMPLATE_DECL_DEFECT
926template <>
927inline void ColumnVectorData<complex<double> >::setDataLimits (complex<double>* limits)
928 {
929 m_minLegalValue = limits[0];
930 m_maxLegalValue = limits[1];
931 m_minDataValue = limits[2];
932 m_maxDataValue = limits[3];
933 }
934#else
935 template <>
936 void
937 ColumnVectorData<complex<double> >::setDataLimits (complex<double>* limits);
938#endif
939
940
941#if SPEC_TEMPLATE_IMP_DEFECT || SPEC_TEMPLATE_DECL_DEFECT
942 template <>
943 inline void ColumnVectorData<std::complex<float> >::readColumnData(long firstRow,
944 long nelements, long firstElem, std::complex<float>* null )
945 {
946 int status=0;
947 float nulval (0);
948 FITSUtil::auto_array_ptr<float> pArray(new float[2*nelements]);
949 float* array = pArray.get();
950 int anynul(0);
951
952 if (fits_read_col_cmp(fitsPointer(),index(),firstRow, firstElem,
953 nelements,nulval,array,&anynul,&status) ) throw FitsError(status);
954
955 if (m_data.size() != static_cast<size_t>(rows())) m_data.resize(rows());
956
957 std::valarray<std::complex<float> > readData(nelements);
958 for (long j = 0; j < nelements; ++j)
959 {
960 readData[j] = std::complex<float>(array[2*j],array[2*j+1]);
961 }
962 size_t countRead = 0;
963 const size_t ONE = 1;
964
965 if (m_data.size() != static_cast<size_t>(rows())) m_data.resize(rows());
966 size_t vectorSize(0);
967 if (!varLength())
968 {
969 vectorSize = std::max(repeat(),ONE); // safety check.
970 }
971 else
972 {
973 // assume that the user specified the correct length for
974 // variable columns. This should be ok since readVariableColumns
975 // uses fits_read_descripts to return this information from the
976 // fits pointer, and this is passed as nelements here.
977 vectorSize = nelements;
978 }
979 size_t n = nelements;
980
981 int i = firstRow;
982 int ii = i - 1;
983 while ( countRead < n)
984 {
985 std::valarray<complex<float> >& current = m_data[ii];
986 if (current.size() != vectorSize) current.resize(vectorSize,0.);
987 int elementsInFirstRow = vectorSize-firstElem + 1;
988 bool lastRow = ( (nelements - countRead) < vectorSize);
989 if (lastRow)
990 {
991 int elementsInLastRow = nelements - countRead;
992 std::copy(&readData[countRead],&readData[0]+nelements,&current[0]);
993 countRead += elementsInLastRow;
994 }
995 // what to do with complete rows. if firstElem == 1 the
996 else
997 {
998 if (firstElem == 1 || (firstElem > 1 && i > firstRow) )
999 {
1000 current = readData[std::slice(vectorSize*(ii-firstRow)+
1001 elementsInFirstRow,vectorSize,1)];
1002 ++ii;
1003 ++i;
1004 countRead += vectorSize;
1005 }
1006 else
1007 {
1008 if (i == firstRow)
1009 {
1010 std::copy(&readData[0],&readData[0]+elementsInFirstRow,
1011 &current[firstElem]);
1012 countRead += elementsInFirstRow;
1013 ++i;
1014 ++ii;
1015 }
1016 }
1017 }
1018 }
1019 }
1020#else
1021template <>
1022void ColumnVectorData<complex<float> >::readColumnData(long firstRow,
1023 long nelements,
1024 long firstElem, complex<float>* null);
1025#endif
1026
1027#if SPEC_TEMPLATE_IMP_DEFECT || SPEC_TEMPLATE_DECL_DEFECT
1028 template <>
1029 inline void ColumnVectorData<complex<double> >::readColumnData (long firstRow,
1030 long nelements,long firstElem,
1031 complex<double>* nullValue)
1032 {
1033
1034 // duplicated for each complex type to work around imagined or
1035 // actual compiler deficiencies.
1036 int status=0;
1037 double nulval (0);
1038 FITSUtil::auto_array_ptr<double> pArray(new double[2*nelements]);
1039 double* array = pArray.get();
1040 int anynul(0);
1041
1042 if (fits_read_col_dblcmp(fitsPointer(),index(),firstRow, firstElem,
1043 nelements,nulval,array,&anynul,&status) ) throw FitsError(status);
1044
1045 if (m_data.size() != static_cast<size_t>(rows())) m_data.resize(rows());
1046
1047 std::valarray<std::complex<double> > readData(nelements);
1048 for (long j = 0; j < nelements; ++j)
1049 {
1050 readData[j] = std::complex<double>(array[2*j],array[2*j+1]);
1051 }
1052 size_t countRead = 0;
1053 const size_t ONE = 1;
1054
1055 if (m_data.size() != static_cast<size_t>(rows())) m_data.resize(rows());
1056 size_t vectorSize(0);
1057 if (!varLength())
1058 {
1059 vectorSize = std::max(repeat(),ONE); // safety check.
1060 }
1061 else
1062 {
1063 // assume that the user specified the correct length for
1064 // variable columns. This should be ok since readVariableColumns
1065 // uses fits_read_descripts to return this information from the
1066 // fits pointer, and this is passed as nelements here.
1067 vectorSize = nelements;
1068 }
1069 size_t n = nelements;
1070
1071 int i = firstRow;
1072 int ii = i - 1;
1073 while ( countRead < n)
1074 {
1075 std::valarray<std::complex<double> >& current = m_data[ii];
1076 if (current.size() != vectorSize) current.resize(vectorSize,0.);
1077 int elementsInFirstRow = vectorSize-firstElem + 1;
1078 bool lastRow = ( (nelements - countRead) < vectorSize);
1079 if (lastRow)
1080 {
1081 int elementsInLastRow = nelements - countRead;
1082 std::copy(&readData[countRead],&readData[0]+nelements,&current[0]);
1083 countRead += elementsInLastRow;
1084 }
1085 // what to do with complete rows. if firstElem == 1 the
1086 else
1087 {
1088 if (firstElem == 1 || (firstElem > 1 && i > firstRow) )
1089 {
1090 current = readData[std::slice(vectorSize*(ii-firstRow)+
1091 elementsInFirstRow,vectorSize,1)];
1092 ++ii;
1093 ++i;
1094 countRead += vectorSize;
1095 }
1096 else
1097 {
1098 if (i == firstRow)
1099 {
1100 std::copy(&readData[0],&readData[0]+elementsInFirstRow,
1101 &current[firstElem]);
1102 countRead += elementsInFirstRow;
1103 ++i;
1104 ++ii;
1105 }
1106 }
1107 }
1108 }
1109 }
1110#else
1111template <>
1112void ColumnVectorData<complex<double> >::readColumnData (long firstRow,
1113 long nelements,
1114 long firstElem, complex<double>* null);
1115#endif
1116
1117#if SPEC_TEMPLATE_IMP_DEFECT || SPEC_TEMPLATE_DECL_DEFECT
1118 template <>
1119 inline void ColumnVectorData<complex<float> >::writeFixedArray
1120 (complex<float>* data, long nElements, long nRows, long firstRow,
1121 complex<float>* nullValue)
1122 {
1123
1124 int status(0);
1125
1126 // check for sanity of inputs, then write to file.
1127 // this function writes only complete rows to a table with
1128 // fixed width rows.
1129
1130
1131 if ( nElements < nRows*static_cast<long>(repeat()) )
1132 {
1133#ifdef SSTREAM_DEFECT
1134 std::ostrstream msgStr;
1135#else
1136 std::ostringstream msgStr;
1137#endif
1138 msgStr << " input array size: " << nElements
1139 << " required " << nRows*repeat();
1140#ifdef SSTREAM_DEFECT
1141 msgStr << std::ends;
1142#endif
1143
1144
1145 String msg(msgStr.str());
1146
1147 throw Column::InsufficientElements(msg);
1148 }
1149
1150 FITSUtil::auto_array_ptr<float> realData(new float[2*nElements]);
1151
1152 for (int j = 0; j < nElements; ++j)
1153 {
1154 realData[2*j] = data[j].real();
1155 realData[2*j+1] = data[j].imag();
1156 }
1157
1158
1159
1160 if (fits_write_col_cmp(fitsPointer(),index(),firstRow,
1161 1,nElements,realData.get(),&status)) throw FitsError(status);
1162
1163 parent()->updateRows();
1164 }
1165#else
1166template <>
1167void ColumnVectorData<complex<float> >::writeFixedArray
1168 (complex<float>* data, long nElements, long nRows, long firstRow, std::complex<float>* null);
1169#endif
1170
1171#if SPEC_TEMPLATE_IMP_DEFECT || SPEC_TEMPLATE_DECL_DEFECT
1172 template <>
1173 inline void ColumnVectorData<complex<double> >::writeFixedArray
1174 (complex<double>* data, long nElements, long nRows, long firstRow,
1175 complex<double>* nullValue)
1176 {
1177 int status(0);
1178
1179 // check for sanity of inputs, then write to file.
1180 // this function writes only complete rows to a table with
1181 // fixed width rows.
1182
1183
1184 if ( nElements < nRows*static_cast<long>(repeat()) )
1185 {
1186#ifdef SSTREAM_DEFECT
1187 std::ostrstream msgStr;
1188#else
1189 std::ostringstream msgStr;
1190#endif
1191 msgStr << " input array size: " << nElements
1192 << " required " << nRows*repeat();
1193#ifdef SSTREAM_DEFECT
1194 msgStr << std::ends;
1195#endif
1196
1197 String msg(msgStr.str());
1198
1199 throw Column::InsufficientElements(msg);
1200 }
1201
1202 FITSUtil::auto_array_ptr<double> realData(new double[2*nElements]);
1203
1204 for (int j = 0; j < nElements; ++j)
1205 {
1206 realData[2*j] = data[j].real();
1207 realData[2*j+1] = data[j].imag();
1208 }
1209
1210
1211
1212 if (fits_write_col_dblcmp(fitsPointer(),index(),firstRow,
1213 1,nElements,realData.get(),&status)) throw FitsError(status);
1214
1215 parent()->updateRows();
1216
1217 }
1218#else
1219template <>
1220void ColumnVectorData<complex<double> >::writeFixedArray
1221 (complex<double>* data, long nElements, long nRows, long firstRow,
1222 std::complex<double>* null);
1223#endif
1224
1225#ifdef SPEC_TEMPLATE_DECL_DEFECT
1226 template <>
1227 inline void
1228 ColumnVectorData<std::complex<float> >::doWrite
1229 (std::complex<float>* data, long row, long rowSize, long firstElem, std::complex<float>* nullValue )
1230 {
1231 int status(0);
1232 FITSUtil::auto_array_ptr<float> carray( new float[2*rowSize]);
1233 for ( long j = 0 ; j < rowSize; ++ j)
1234 {
1235 carray[2*j] = data[j].real();
1236 carray[2*j + 1] = data[j].imag();
1237 }
1238 if (fits_write_col_cmp(fitsPointer(),index(),row,firstElem,rowSize,
1239 carray.get(),&status)) throw FitsError(status);
1240 }
1241
1242
1243 template <>
1244 inline void
1245 ColumnVectorData<std::complex<double> >::doWrite
1246 (std::complex<double>* data, long row, long rowSize, long firstElem, std::complex<double>* nullValue )
1247 {
1248 int status(0);
1249 FITSUtil::auto_array_ptr<double> carray( new double[2*rowSize]);
1250 for ( long j = 0 ; j < rowSize; ++ j)
1251 {
1252 carray[2*j] = data[j].real();
1253 carray[2*j + 1] = data[j].imag();
1254 }
1255 if (fits_write_col_dblcmp(fitsPointer(),index(),row,firstElem,rowSize,
1256 carray.get(),&status)) throw FitsError(status);
1257
1258 }
1259
1260#else
1261template<>
1262void
1263ColumnVectorData<complex<float> >::doWrite
1264 ( complex<float>* data, long row, long rowSize, long firstElem, complex<float>* nullValue);
1265
1266template<>
1267void
1268ColumnVectorData<complex<double> >::doWrite
1269 ( complex<double>* data, long row, long rowSize, long firstElem, complex<double>* nullValue );
1270#endif
1271} // namespace CCfits
1272
1273
1274#endif
Column(const Column &right)
copy constructor, used in copying Columns to standard library containers.
Definition Column.cxx:171
const String & unit() const
get units of data in Column (TUNITn keyword)
Definition Column.h:1527
const String & comment() const
retrieve comment for Column
Definition Column.h:1517
const String & format() const
return TFORMn keyword
Definition Column.h:1522
ValueType type() const
returns the data type of the column
Definition Column.h:1437
Namespace enclosing all CCfits classes and globals definitions.
Definition AsciiTable.cxx:26
ValueType
CCfits value types and their CFITSIO equivalents (in caps)
Definition CCfits.h:81