ColumnVectorData.h
// Astrophysics Science Division,
// NASA/ Goddard Space Flight Center
// HEASARC
// http://heasarc.gsfc.nasa.gov
// e-mail: ccfits@legacy.gsfc.nasa.gov
//
// Original author: Ben Dorman
#ifndef COLUMNVECTORDATA_H
#define COLUMNVECTORDATA_H 1
#ifdef _MSC_VER
#include "MSconfig.h"
#endif
#include "CCfits.h"
// valarray
#include <valarray>
// vector
#include <vector>
// Column
#include "Column.h"
#ifdef SSTREAM_DEFECT
#include <strstream>
#else
#include <sstream>
#endif
#include <memory>
#include <numeric>
#include <algorithm>
namespace CCfits {
class Table;
}
#include "FITS.h"
#include "FITSUtil.h"
using std::complex;
namespace CCfits {
template <typename T>
class ColumnVectorData : public Column //## Inherits: <unnamed>%38BAD1D4D370
{
public:
ColumnVectorData(const ColumnVectorData< T > &right);
ColumnVectorData (Table* p = 0);
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 = "");
~ColumnVectorData();
virtual void readData (long firstrow, long nelements, long firstelem = 1);
virtual ColumnVectorData<T>* clone () const;
virtual void setDimen ();
void setDataLimits (T* limits);
const T minLegalValue () const;
void minLegalValue (T value);
const T maxLegalValue () const;
void maxLegalValue (T value);
const T minDataValue () const;
void minDataValue (T value);
const T maxDataValue () const;
void maxDataValue (T value);
const std::vector<std::valarray<T> >& data () const;
void setData (const std::vector<std::valarray<T> >& value);
const std::valarray<T>& data (int i) const;
void data (int i, const std::valarray<T>& value);
// Additional Public Declarations
friend class Column;
protected:
// Additional Protected Declarations
private:
ColumnVectorData< T > & operator=(const ColumnVectorData< T > &right);
virtual bool compare (const Column &right) const;
void resizeDataObject (const std::vector<std::valarray<T> >& indata, size_t firstRow);
// Reads a specified number of column rows.
//
// There are no default arguments. The function
// Column::read(firstrow,firstelem,nelements)
// is designed for reading the whole column.
virtual void readColumnData (long first, long last, T* nullValue = 0);
virtual std::ostream& put (std::ostream& s) const;
void writeData (const std::valarray<T>& indata, long numRows, long firstRow = 1, T* nullValue = 0);
void writeData (const std::vector<std::valarray<T> >& indata, long firstRow = 1, T* nullValue = 0);
// Reads a specified number of column rows.
//
// There are no default arguments. The function
// Column::read(firstrow,firstelem,nelements)
// is designed for reading the whole column.
virtual void readRow (size_t row, T* nullValue = 0);
// Reads a variable row..
virtual void readVariableRow (size_t row, T* nullValue = 0);
void readColumnData (long firstrow, long nelements, long firstelem, T* nullValue = 0);
void writeData (const std::valarray<T>& indata, const std::vector<long>& vectorLengths, long firstRow = 1, T* nullValue = 0);
void writeFixedRow (const std::valarray<T>& data, long row, long firstElem = 1, T* nullValue = 0);
void writeFixedArray (T* data, long nElements, long nRows, long firstRow, T* nullValue = 0);
// Insert one or more blank rows into a FITS column.
virtual void insertRows (long first, long number = 1);
virtual void deleteRows (long first, long number = 1);
virtual size_t getStoredDataSize() const;
void doWrite (T* array, long row, long rowSize, long firstElem, T* nullValue);
// Additional Private Declarations
private: //## implementation
// Data Members for Class Attributes
T m_minLegalValue;
T m_maxLegalValue;
T m_minDataValue;
T m_maxDataValue;
// Data Members for Associations
std::vector<std::valarray<T> > m_data;
// Additional Implementation Declarations
};
// Parameterized Class CCfits::ColumnVectorData
template <typename T>
inline void ColumnVectorData<T>::readData (long firstrow, long nelements, long firstelem)
{
readColumnData(firstrow,nelements,firstelem,static_cast<T*>(0));
}
template <typename T>
inline const T ColumnVectorData<T>::minLegalValue () const
{
return m_minLegalValue;
}
template <typename T>
inline void ColumnVectorData<T>::minLegalValue (T value)
{
m_minLegalValue = value;
}
template <typename T>
inline const T ColumnVectorData<T>::maxLegalValue () const
{
return m_maxLegalValue;
}
template <typename T>
inline void ColumnVectorData<T>::maxLegalValue (T value)
{
m_maxLegalValue = value;
}
template <typename T>
inline const T ColumnVectorData<T>::minDataValue () const
{
return m_minDataValue;
}
template <typename T>
inline void ColumnVectorData<T>::minDataValue (T value)
{
m_minDataValue = value;
}
template <typename T>
inline const T ColumnVectorData<T>::maxDataValue () const
{
return m_maxDataValue;
}
template <typename T>
inline void ColumnVectorData<T>::maxDataValue (T value)
{
m_maxDataValue = value;
}
template <typename T>
inline const std::vector<std::valarray<T> >& ColumnVectorData<T>::data () const
{
return m_data;
}
template <typename T>
inline void ColumnVectorData<T>::setData (const std::vector<std::valarray<T> >& value)
{
m_data = value;
}
template <typename T>
inline const std::valarray<T>& ColumnVectorData<T>::data (int i) const
{
return m_data[i - 1];
}
template <typename T>
inline void ColumnVectorData<T>::data (int i, const std::valarray<T>& value)
{
if (m_data[i-1].size() != value.size())
m_data[i-1].resize(value.size());
m_data[i - 1] = value;
}
// Parameterized Class CCfits::ColumnVectorData
template <typename T>
ColumnVectorData<T>::ColumnVectorData(const ColumnVectorData<T> &right)
:Column(right),
m_minLegalValue(right.m_minLegalValue),
m_maxLegalValue(right.m_maxLegalValue),
m_minDataValue(right.m_minDataValue),
m_maxDataValue(right.m_maxDataValue),
m_data(right.m_data)
{
}
template <typename T>
ColumnVectorData<T>::ColumnVectorData (Table* p)
: Column(p),
m_minLegalValue(0),
m_maxLegalValue(0),
m_minDataValue(0),
m_maxDataValue(0),
m_data()
{
}
template <typename T>
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)
: Column(columnIndex,columnName,type,format,unit,p,rpt,w,comment),
m_minLegalValue(0),
m_maxLegalValue(0),
m_minDataValue(0),
m_maxDataValue(0),
m_data()
{
}
template <typename T>
ColumnVectorData<T>::~ColumnVectorData()
{
// valarray destructor should do all the work.
}
template <typename T>
bool ColumnVectorData<T>::compare (const Column &right) const
{
if ( !Column::compare(right) ) return false;
const ColumnVectorData<T>& that = static_cast<const ColumnVectorData<T>&>(right);
size_t n = m_data.size();
// m_data is of type valarray<T>.
if ( that.m_data.size() != n ) return false;
for (size_t i = 0; i < n ; i++)
{
const std::valarray<T>& thisValArray=m_data[i];
const std::valarray<T>& thatValArray=that.m_data[i];
size_t nn = thisValArray.size();
if (thatValArray.size() != nn ) return false;
for (size_t j = 0; j < nn ; j++ )
{
if (thisValArray[j] != thatValArray[j])
return false;
}
}
return true;
}
template <typename T>
ColumnVectorData<T>* ColumnVectorData<T>::clone () const
{
return new ColumnVectorData<T>(*this);
}
template <typename T>
void ColumnVectorData<T>::resizeDataObject (const std::vector<std::valarray<T> >& indata, size_t firstRow)
{
// the rows() call is the value before updating.
// the updateRows() call at the end sets the call to return the
// value from the fits pointer - which is changed by writeFixedArray
// or writeFixedRow.
const size_t lastInputRow(indata.size() + firstRow - 1);
const size_t newLastRow = std::max(lastInputRow,static_cast<size_t>(rows()));
// if the write instruction increases the rows, we need to add
// rows to the data member and preserve its current contents.
// rows() >= origNRows since it is the value for entire table,
// not just this column.
const size_t origNRows(m_data.size());
// This will always be an expansion. vector.resize() doesn't
// invalidate any data on an expansion.
if (newLastRow > origNRows) m_data.resize(newLastRow);
if (varLength())
{
// The incoming data will determine each row size, thus
// no need to preserve any existing values in the row.
// Each value will eventually be overwritten.
for (size_t iRow = firstRow-1; iRow < lastInputRow; ++iRow)
{
std::valarray<T>& current = m_data[iRow];
const size_t newSize = indata[iRow - (firstRow-1)].size();
if (current.size() != newSize)
current.resize(newSize);
}
}
else
{
// All row sizes in m_data should ALWAYS be either repeat(),
// or 0 if they haven't been initialized. This is true regardless
// of the incoming data row size.
// Perform LAZY initialization of m_data rows. Only
// expand a row valarray when it is first needed.
for (size_t iRow = firstRow-1; iRow < lastInputRow; ++iRow)
{
if (m_data[iRow].size() != repeat())
m_data[iRow].resize(repeat());
}
}
}
template <typename T>
void ColumnVectorData<T>::setDimen ()
{
int status(0);
FITSUtil:: auto_array_ptr<char> dimValue (new char[FLEN_VALUE]);
#ifdef SSTREAM_DEFECT
std::ostrstream key;
#else
std::ostringstream key;
#endif
key << "TDIM" << index();
#ifdef SSTREAM_DEFECT
fits_read_key_str(fitsPointer(), key.str(), dimValue.get(),0,&status);
#else
fits_read_key_str(fitsPointer(),const_cast<char*>(key.str().c_str()),dimValue.get(),0,&status);
#endif
if (status == 0)
{
dimen(String(dimValue.get()));
}
}
template <typename T>
void ColumnVectorData<T>::readColumnData (long first, long last, T* nullValue)
{
makeHDUCurrent();
if ( rows() < last )
{
std::cerr << "CCfits: More data requested than contained in table. ";
std::cerr << "Extracting complete column.\n";
last = rows();
}
long nelements = (last - first + 1)*repeat();
readColumnData(first,nelements,1,nullValue);
if (first <= 1 && last == rows()) isRead(true);
}
template <typename T>
std::ostream& ColumnVectorData<T>::put (std::ostream& s) const
{
// output header information
Column::put(s);
if ( FITS::verboseMode() )
{
s << " Column Legal limits: ( " << m_minLegalValue << "," << m_maxLegalValue << " )\n"
<< " Column Data limits: ( " << m_minDataValue << "," << m_maxDataValue << " )\n";
}
if (!m_data.empty())
{
for (size_t j = 0; j < m_data.size(); j++)
{
size_t n = m_data[j].size();
if ( n )
{
s << "Row " << j + 1 << " Vector Size " << n << '\n';
for (size_t k = 0; k < n - 1; k++)
{
s << m_data[j][k] << '\t';
}
s << m_data[j][n - 1] << '\n';
}
}
}
return s;
}
template <typename T>
void ColumnVectorData<T>::writeData (const std::valarray<T>& indata, long numRows, long firstRow, T* nullValue)
{
// This version of writeData is called by Column write functions which
// can only write the same number of elements to each row.
// For fixed width columns, this must be equal to the repeat value
// or an exception is thrown. For variable width, it only requires
// that indata.size()/numRows is an int.
// won't do anything if < 0, and will give divide check if == 0.
if (numRows <= 0) throw InvalidNumberOfRows(numRows);
#ifdef SSTREAM_DEFECT
std::ostrstream msgStr;
#else
std::ostringstream msgStr;
#endif
if (indata.size() % static_cast<size_t>(numRows))
{
msgStr << "To use this write function, input array size"
<<"\n must be exactly divisible by requested num rows: "
<< numRows;
throw InsufficientElements(msgStr.str());
}
const size_t cellsize = indata.size()/static_cast<size_t>(numRows);
if (!varLength() && cellsize != repeat() )
{
msgStr << "column: " << name()
<< "\n input data size: " << indata.size()
<< " required: " << numRows*repeat();
String msg(msgStr.str());
throw InsufficientElements(msg);
}
std::vector<std::valarray<T> > internalFormat(numRows);
// support writing equal row lengths to variable columns.
for (long j = 0; j < numRows; ++j)
{
internalFormat[j].resize(cellsize);
internalFormat[j] = indata[std::slice(cellsize*j,cellsize,1)];
}
// change the size of m_data based on the first row to be written
// and on the input data vector sizes.
writeData(internalFormat,firstRow,nullValue);
}
template <typename T>
void ColumnVectorData<T>::writeData (const std::vector<std::valarray<T> >& indata, long firstRow, T* nullValue)
{
// This is called directly by Column's writeArrays functions, and indirectly
// by both categories of write functions, ie. those which allow differing
// lengths per row and those that don't.
const size_t nInputRows(indata.size());
using std::valarray;
resizeDataObject(indata,firstRow);
// After the above call, can assume all m_data arrays to be written to
// have been properly resized whether we're dealing with fixed or
// variable length.
if (varLength())
{
// firstRow is 1-based, but all these internal row variables
// will be 0-based.
const size_t endRow = nInputRows + firstRow-1;
for (size_t iRow = firstRow-1; iRow < endRow; ++iRow)
{
m_data[iRow] = indata[iRow - (firstRow-1)];
// doWrite wants 1-based rows.
doWrite(&m_data[iRow][0], iRow+1, m_data[iRow].size(), 1, nullValue);
}
parent()->updateRows();
}
else
{
// Check for simplest case of all valarrays of size repeat().
// If any are greater, throw an error.
const size_t colRepeat = repeat();
bool allEqualRepeat = true;
for (size_t i=0; i<nInputRows; ++i)
{
const size_t sz = indata[i].size();
if (sz > colRepeat)
{
#ifdef SSTREAM_DEFECT
std::ostrstream oss;
#else
std::ostringstream oss;
#endif
oss << " vector column length " << colRepeat
<<", input valarray length " << sz;
throw InvalidRowParameter(oss.str());
}
if (sz < colRepeat)
allEqualRepeat = false;
}
if (allEqualRepeat)
{
// concatenate the valarrays and write.
const size_t nElements (colRepeat*nInputRows);
FITSUtil::CVAarray<T> convert;
FITSUtil::auto_array_ptr<T> pArray(convert(indata));
T* array = pArray.get();
// if T is complex, then CVAarray returns a
// C-array of complex objects. But FITS requires an array of complex's
// value_type.
// This writes to the file and also calls updateRows.
writeFixedArray(array,nElements,nInputRows,firstRow,nullValue);
for (size_t j = 0; j < nInputRows ; ++j)
{
const valarray<T>& input = indata[j];
valarray<T>& current = m_data[j + firstRow - 1];
// current should be resized by resizeDataObject.
current = input;
}
}
else
{
// Some input arrays have fewer than colRepeat elements.
const size_t endRow = nInputRows + firstRow-1;
for (size_t iRow = firstRow-1; iRow<endRow; ++iRow)
{
// resizeDataObject should already have resized all
// corresponding m_data rows to repeat().
const valarray<T>& input = indata[iRow-(firstRow-1)];
writeFixedRow(input, iRow, 1, nullValue);
}
parent()->updateRows();
}
} // end if !varLength
}
template <typename T>
void ColumnVectorData<T>::readRow (size_t row, T* nullValue)
{
makeHDUCurrent();
if ( row > static_cast<size_t>(rows()) )
{
#ifdef SSTREAM_DEFECT
std::ostrstream msg;
#else
std::ostringstream msg;
#endif
msg << " row requested: " << row << " row range: 1 - " << rows();
#ifdef SSTREAM_DEFECT
msg << std::ends;
#endif
throw Column::InvalidRowNumber(msg.str());
}
// this is really for documentation purposes. I expect the optimizer will
// remove this redundant definition .
bool variable(type() < 0);
long nelements(repeat());
if (variable)
{
readVariableRow(row,nullValue);
}
else
{
readColumnData(row,nelements,1,nullValue);
}
}
template <typename T>
void ColumnVectorData<T>::readVariableRow (size_t row, T* nullValue)
{
int status(0);
long offset(0);
long repeat(0);
if (fits_read_descript(fitsPointer(),index(),static_cast<long>(row),
&repeat,&offset,&status)) throw FitsError(status);
readColumnData(row,repeat,1,nullValue);
}
template <typename T>
void ColumnVectorData<T>::readColumnData (long firstrow, long nelements, long firstelem, T* nullValue)
{
int status=0;
FITSUtil::auto_array_ptr<T> pArray(new T[nelements]);
T* array = pArray.get();
int anynul(0);
if (fits_read_col(fitsPointer(), abs(type()),index(), firstrow, firstelem,
nelements, nullValue, array, &anynul, &status) != 0)
throw FitsError(status);
size_t countRead = 0;
const size_t ONE = 1;
if (m_data.size() != static_cast<size_t>(rows())) m_data.resize(rows());
size_t vectorSize(0);
if (!varLength())
{
vectorSize = std::max(repeat(),ONE); // safety check.
}
else
{
// assume that the user specified the correct length for
// variable columns. This should be ok since readVariableColumns
// uses fits_read_descripts to return this information from the
// fits pointer, and this is passed as nelements here.
vectorSize = nelements;
}
size_t n = nelements;
int i = firstrow;
int ii = i - 1;
while ( countRead < n)
{
std::valarray<T>& current = m_data[ii];
if (current.size() != vectorSize) current.resize(vectorSize);
int elementsInFirstRow = vectorSize-firstelem + 1;
bool lastRow = ( (nelements - countRead) < vectorSize);
if (lastRow)
{
int elementsInLastRow = nelements - countRead;
std::valarray<T> ttmp(array + vectorSize*(ii-firstrow) + elementsInFirstRow,
elementsInLastRow);
for (int kk = 0; kk < elementsInLastRow; kk++) current[kk] = ttmp[kk];
countRead += elementsInLastRow;
}
// what to do with complete rows
else
{
if (firstelem == 1 || (firstelem > 1 && i > firstrow) )
{
std::valarray<T> ttmp(array + vectorSize*(ii - firstrow) +
elementsInFirstRow,vectorSize);
current = ttmp;
ii++;
i++;
countRead += vectorSize;
}
else
{
if (i == firstrow)
{
std::valarray<T> ttmp(array,elementsInFirstRow);
for (size_t kk = firstelem ; kk < vectorSize ; kk++)
current[kk] = ttmp[kk-firstelem];
countRead += elementsInFirstRow;
i++;
ii++;
}
}
}
}
}
template <typename T>
void ColumnVectorData<T>::writeData (const std::valarray<T>& indata, const std::vector<long>& vectorLengths, long firstRow, T* nullValue)
{
// Called from Column write functions which allow differing lengths
// for each row.
using namespace std;
const size_t N(vectorLengths.size());
vector<long> sums(N);
// pre-calculate partial sums of vector lengths for use as array offsets.
partial_sum(vectorLengths.begin(),vectorLengths.end(),sums.begin());
// check that sufficient data have been supplied to carry out the entire operation.
if (indata.size() < static_cast<size_t>(sums[N-1]) )
{
#ifdef SSTREAM_DEFECT
ostrstream msgStr;
#else
ostringstream msgStr;
#endif
msgStr << " input data size: " << indata.size() << " vector length sum: " << sums[N-1];
#ifdef SSTREAM_DEFECT
msgStr << std::ends;
#endif
String msg(msgStr.str());
throw InsufficientElements(msg);
}
vector<valarray<T> > vvArray(N);
long& last = sums[0];
vvArray[0].resize(last);
for (long jj = 0; jj < last; ++jj) vvArray[0][jj] = indata[jj];
for (size_t j = 1; j < N; ++j)
{
valarray<T>& __tmp = vvArray[j];
// these make the code much more readable
long& first = sums[j-1];
long& jlast = sums[j];
__tmp.resize(jlast - first);
for (long k = first; k < jlast; ++k)
{
__tmp[k - first] = indata[k];
}
}
writeData(vvArray,firstRow,nullValue);
}
template <typename T>
void ColumnVectorData<T>::writeFixedRow (const std::valarray<T>& data, long row, long firstElem, T* nullValue)
{
// This is to be called only for FIXED length vector columns. It will
// throw if data.size()+firstElem goes beyond the repeat value.
// If data.size() is less than repeat, it leaves the remaining values
// undisturbed both in the file and in m_data storage.
#ifdef SSTREAM_DEFECT
std::ostrstream msgStr;
#else
std::ostringstream msgStr;
#endif
if (varLength())
{
msgStr <<"Calling ColumnVectorData::writeFixedRow for a variable length column.\n";
throw FitsFatal(msgStr.str());
}
std::valarray<T>& storedRow = m_data[row];
long inputSize = static_cast<long>(data.size());
long storedSize(storedRow.size());
if (storedSize != static_cast<long>(repeat()))
{
msgStr<<"stored array size vs. column width mismatch in ColumnVectorData::writeFixedRow.\n";
throw FitsFatal(msgStr.str());
}
if (inputSize + firstElem - 1 > storedSize)
{
msgStr << " requested write " << firstElem << " to "
<< firstElem + inputSize - 1 << " exceeds vector length " << repeat();
throw InvalidRowParameter(msgStr.str());
}
// CANNOT give a strong exception safety guarantee because writing
// data changes the file. Any corrective action that could be taken
// [e.g. holding initial contents of the row and writing it back after
// an exception is thrown] could in principle throw the same exception
// we are trying to protect from.
// routine does however give the weak guarantee (no resource leaks).
// It's never a good thing to cast away a const, but doWrite calls the
// CFITSIO write functions which take a non-const pointer (though
// it shouldn't actually modify the array), and I'd rather not
// copy the entire valarray just to avoid this problem.
std::valarray<T>& lvData = const_cast<std::valarray<T>&>(data);
T* inPointer = &lvData[0];
doWrite(inPointer, row+1, inputSize, firstElem, nullValue);
// Writing to disk was successful, now update FITS object and return.
const size_t offset = static_cast<size_t>(firstElem) - 1;
for (size_t iElem=0; iElem < static_cast<size_t>(inputSize); ++iElem)
{
// This doesn't require inPointer's non-constness. It's just
// used here to speed things up a bit.
storedRow[iElem + offset] = inPointer[iElem];
}
}
template <typename T>
void ColumnVectorData<T>::writeFixedArray (T* data, long nElements, long nRows, long firstRow, T* nullValue)
{
int status(0);
// check for sanity of inputs, then write to file.
// this function writes only complete rows to a table with
// fixed width rows.
if ( nElements < nRows*static_cast<long>(repeat()) )
{
#ifdef SSTREAM_DEFECT
std::ostrstream msgStr;
#else
std::ostringstream msgStr;
#endif
msgStr << " input array size: " << nElements << " required " << nRows*repeat();
String msg(msgStr.str());
throw Column::InsufficientElements(msg);
}
if (nullValue)
{
if (fits_write_colnull(fitsPointer(),abs(type()),index(),firstRow,
1,nElements,data,nullValue,&status)) throw FitsError(status);
}
else
{
if (fits_write_col(fitsPointer(),abs(type()),index(),firstRow,
1,nElements,data,&status)) throw FitsError(status);
}
parent()->updateRows();
}
template <typename T>
void ColumnVectorData<T>::insertRows (long first, long number)
{
if (first >= 0 && first <= static_cast<long>(m_data.size()))
{
typename std::vector<std::valarray<T> >::iterator in;
if (first !=0)
{
in = m_data.begin()+first;
}
else
{
in = m_data.begin();
}
// non-throwing operations.
m_data.insert(in,number,std::valarray<T>(T(),0));
}
}
template <typename T>
void ColumnVectorData<T>::deleteRows (long first, long number)
{
// Don't assume the calling routine (ie. Table's deleteRows)
// knows Column's current m_data size. m_data may still be
// size 0 if no read operations have been performed on Column.
// Therefore perform range checking before erasing.
const long curSize = static_cast<long>(m_data.size());
if (curSize>0 && first <= curSize)
{
const long last = std::min(curSize, first-1+number);
m_data.erase(m_data.begin()+first-1,m_data.begin()+last);
}
}
template <typename T>
size_t ColumnVectorData<T>::getStoredDataSize() const
{
return m_data.size();
}
template <typename T>
void ColumnVectorData<T>::setDataLimits (T* limits)
{
m_minLegalValue = limits[0];
m_maxLegalValue = limits[1];
m_minDataValue = std::max(limits[2],limits[0]);
m_maxDataValue = std::min(limits[3],limits[1]);
}
template <typename T>
void ColumnVectorData<T>::doWrite (T* array, long row, long rowSize, long firstElem, T* nullValue)
{
int status(0);
// internal functioning of write_colnull forbids its use for writing
// variable width columns. If a nullvalue argument was supplied it will
// be ignored.
if ( !varLength())
{
if (fits_write_colnull(fitsPointer(),type(),index(),row, firstElem, rowSize,
array, nullValue,&status)) throw FitsError(status);
}
else
{
if (fits_write_col(fitsPointer(),abs(type()),index(),row,firstElem,rowSize,
array,&status)) throw FitsError(status);
}
}
// Additional Declarations
// all functions that operate on complex data that call cfitsio
// need to be specialized. The signature containing complex<T>* objects
// is unfortunate, perhaps, for this purpose, but the user will access
// rw operations through standard library containers.
#if SPEC_TEMPLATE_IMP_DEFECT || SPEC_TEMPLATE_DECL_DEFECT
template <>
inline void ColumnVectorData<complex<float> >::setDataLimits (complex<float>* limits)
{
m_minLegalValue = limits[0];
m_maxLegalValue = limits[1];
m_minDataValue = limits[2];
m_maxDataValue = limits[3];
}
#else
template <>
void
ColumnVectorData<complex<float> >::setDataLimits (complex<float>* limits);
#endif
#if SPEC_TEMPLATE_IMP_DEFECT || SPEC_TEMPLATE_DECL_DEFECT
template <>
inline void ColumnVectorData<complex<double> >::setDataLimits (complex<double>* limits)
{
m_minLegalValue = limits[0];
m_maxLegalValue = limits[1];
m_minDataValue = limits[2];
m_maxDataValue = limits[3];
}
#else
template <>
void
ColumnVectorData<complex<double> >::setDataLimits (complex<double>* limits);
#endif
#if SPEC_TEMPLATE_IMP_DEFECT || SPEC_TEMPLATE_DECL_DEFECT
template <>
inline void ColumnVectorData<std::complex<float> >::readColumnData(long firstRow,
long nelements, long firstElem, std::complex<float>* null )
{
int status=0;
float nulval (0);
FITSUtil::auto_array_ptr<float> pArray(new float[2*nelements]);
float* array = pArray.get();
int anynul(0);
if (fits_read_col_cmp(fitsPointer(),index(),firstRow, firstElem,
nelements,nulval,array,&anynul,&status) ) throw FitsError(status);
if (m_data.size() != static_cast<size_t>(rows())) m_data.resize(rows());
std::valarray<std::complex<float> > readData(nelements);
for (long j = 0; j < nelements; ++j)
{
readData[j] = std::complex<float>(array[2*j],array[2*j+1]);
}
size_t countRead = 0;
const size_t ONE = 1;
if (m_data.size() != static_cast<size_t>(rows())) m_data.resize(rows());
size_t vectorSize(0);
if (!varLength())
{
vectorSize = std::max(repeat(),ONE); // safety check.
}
else
{
// assume that the user specified the correct length for
// variable columns. This should be ok since readVariableColumns
// uses fits_read_descripts to return this information from the
// fits pointer, and this is passed as nelements here.
vectorSize = nelements;
}
size_t n = nelements;
int i = firstRow;
int ii = i - 1;
while ( countRead < n)
{
std::valarray<complex<float> >& current = m_data[ii];
if (current.size() != vectorSize) current.resize(vectorSize,0.);
int elementsInFirstRow = vectorSize-firstElem + 1;
bool lastRow = ( (nelements - countRead) < vectorSize);
if (lastRow)
{
int elementsInLastRow = nelements - countRead;
std::copy(&readData[countRead],&readData[0]+nelements,&current[0]);
countRead += elementsInLastRow;
}
// what to do with complete rows. if firstElem == 1 the
else
{
if (firstElem == 1 || (firstElem > 1 && i > firstRow) )
{
current = readData[std::slice(vectorSize*(ii-firstRow)+
elementsInFirstRow,vectorSize,1)];
++ii;
++i;
countRead += vectorSize;
}
else
{
if (i == firstRow)
{
std::copy(&readData[0],&readData[0]+elementsInFirstRow,
&current[firstElem]);
countRead += elementsInFirstRow;
++i;
++ii;
}
}
}
}
}
#else
template <>
void ColumnVectorData<complex<float> >::readColumnData(long firstRow,
long nelements,
long firstElem, complex<float>* null);
#endif
#if SPEC_TEMPLATE_IMP_DEFECT || SPEC_TEMPLATE_DECL_DEFECT
template <>
inline void ColumnVectorData<complex<double> >::readColumnData (long firstRow,
long nelements,long firstElem,
complex<double>* nullValue)
{
// duplicated for each complex type to work around imagined or
// actual compiler deficiencies.
int status=0;
double nulval (0);
FITSUtil::auto_array_ptr<double> pArray(new double[2*nelements]);
double* array = pArray.get();
int anynul(0);
if (fits_read_col_dblcmp(fitsPointer(),index(),firstRow, firstElem,
nelements,nulval,array,&anynul,&status) ) throw FitsError(status);
if (m_data.size() != static_cast<size_t>(rows())) m_data.resize(rows());
std::valarray<std::complex<double> > readData(nelements);
for (long j = 0; j < nelements; ++j)
{
readData[j] = std::complex<double>(array[2*j],array[2*j+1]);
}
size_t countRead = 0;
const size_t ONE = 1;
if (m_data.size() != static_cast<size_t>(rows())) m_data.resize(rows());
size_t vectorSize(0);
if (!varLength())
{
vectorSize = std::max(repeat(),ONE); // safety check.
}
else
{
// assume that the user specified the correct length for
// variable columns. This should be ok since readVariableColumns
// uses fits_read_descripts to return this information from the
// fits pointer, and this is passed as nelements here.
vectorSize = nelements;
}
size_t n = nelements;
int i = firstRow;
int ii = i - 1;
while ( countRead < n)
{
std::valarray<std::complex<double> >& current = m_data[ii];
if (current.size() != vectorSize) current.resize(vectorSize,0.);
int elementsInFirstRow = vectorSize-firstElem + 1;
bool lastRow = ( (nelements - countRead) < vectorSize);
if (lastRow)
{
int elementsInLastRow = nelements - countRead;
std::copy(&readData[countRead],&readData[0]+nelements,&current[0]);
countRead += elementsInLastRow;
}
// what to do with complete rows. if firstElem == 1 the
else
{
if (firstElem == 1 || (firstElem > 1 && i > firstRow) )
{
current = readData[std::slice(vectorSize*(ii-firstRow)+
elementsInFirstRow,vectorSize,1)];
++ii;
++i;
countRead += vectorSize;
}
else
{
if (i == firstRow)
{
std::copy(&readData[0],&readData[0]+elementsInFirstRow,
&current[firstElem]);
countRead += elementsInFirstRow;
++i;
++ii;
}
}
}
}
}
#else
template <>
void ColumnVectorData<complex<double> >::readColumnData (long firstRow,
long nelements,
long firstElem, complex<double>* null);
#endif
#if SPEC_TEMPLATE_IMP_DEFECT || SPEC_TEMPLATE_DECL_DEFECT
template <>
inline void ColumnVectorData<complex<float> >::writeFixedArray
(complex<float>* data, long nElements, long nRows, long firstRow,
complex<float>* nullValue)
{
int status(0);
// check for sanity of inputs, then write to file.
// this function writes only complete rows to a table with
// fixed width rows.
if ( nElements < nRows*static_cast<long>(repeat()) )
{
#ifdef SSTREAM_DEFECT
std::ostrstream msgStr;
#else
std::ostringstream msgStr;
#endif
msgStr << " input array size: " << nElements
<< " required " << nRows*repeat();
#ifdef SSTREAM_DEFECT
msgStr << std::ends;
#endif
String msg(msgStr.str());
throw Column::InsufficientElements(msg);
}
FITSUtil::auto_array_ptr<float> realData(new float[2*nElements]);
for (int j = 0; j < nElements; ++j)
{
realData[2*j] = data[j].real();
realData[2*j+1] = data[j].imag();
}
if (fits_write_col_cmp(fitsPointer(),index(),firstRow,
1,nElements,realData.get(),&status)) throw FitsError(status);
parent()->updateRows();
}
#else
template <>
void ColumnVectorData<complex<float> >::writeFixedArray
(complex<float>* data, long nElements, long nRows, long firstRow, std::complex<float>* null);
#endif
#if SPEC_TEMPLATE_IMP_DEFECT || SPEC_TEMPLATE_DECL_DEFECT
template <>
inline void ColumnVectorData<complex<double> >::writeFixedArray
(complex<double>* data, long nElements, long nRows, long firstRow,
complex<double>* nullValue)
{
int status(0);
// check for sanity of inputs, then write to file.
// this function writes only complete rows to a table with
// fixed width rows.
if ( nElements < nRows*static_cast<long>(repeat()) )
{
#ifdef SSTREAM_DEFECT
std::ostrstream msgStr;
#else
std::ostringstream msgStr;
#endif
msgStr << " input array size: " << nElements
<< " required " << nRows*repeat();
#ifdef SSTREAM_DEFECT
msgStr << std::ends;
#endif
String msg(msgStr.str());
throw Column::InsufficientElements(msg);
}
FITSUtil::auto_array_ptr<double> realData(new double[2*nElements]);
for (int j = 0; j < nElements; ++j)
{
realData[2*j] = data[j].real();
realData[2*j+1] = data[j].imag();
}
if (fits_write_col_dblcmp(fitsPointer(),index(),firstRow,
1,nElements,realData.get(),&status)) throw FitsError(status);
parent()->updateRows();
}
#else
template <>
void ColumnVectorData<complex<double> >::writeFixedArray
(complex<double>* data, long nElements, long nRows, long firstRow,
std::complex<double>* null);
#endif
#ifdef SPEC_TEMPLATE_DECL_DEFECT
template <>
inline void
ColumnVectorData<std::complex<float> >::doWrite
(std::complex<float>* data, long row, long rowSize, long firstElem, std::complex<float>* nullValue )
{
int status(0);
FITSUtil::auto_array_ptr<float> carray( new float[2*rowSize]);
for ( long j = 0 ; j < rowSize; ++ j)
{
carray[2*j] = data[j].real();
carray[2*j + 1] = data[j].imag();
}
if (fits_write_col_cmp(fitsPointer(),index(),row,firstElem,rowSize,
carray.get(),&status)) throw FitsError(status);
}
template <>
inline void
ColumnVectorData<std::complex<double> >::doWrite
(std::complex<double>* data, long row, long rowSize, long firstElem, std::complex<double>* nullValue )
{
int status(0);
FITSUtil::auto_array_ptr<double> carray( new double[2*rowSize]);
for ( long j = 0 ; j < rowSize; ++ j)
{
carray[2*j] = data[j].real();
carray[2*j + 1] = data[j].imag();
}
if (fits_write_col_dblcmp(fitsPointer(),index(),row,firstElem,rowSize,
carray.get(),&status)) throw FitsError(status);
}
#else
template<>
void
ColumnVectorData<complex<float> >::doWrite
( complex<float>* data, long row, long rowSize, long firstElem, complex<float>* nullValue);
template<>
void
ColumnVectorData<complex<double> >::doWrite
( complex<double>* data, long row, long rowSize, long firstElem, complex<double>* nullValue );
#endif
} // namespace CCfits
#endif
CCfits::Column::put
virtual std::ostream & put(std::ostream &s) const
internal implementation of &lt;&lt; operator.
Definition: Column.cxx:302
CCfits::FITS::verboseMode
static bool verboseMode()
return verbose setting for library
Definition: FITS.h:862
CCfits::ValueType
ValueType
CCfits value types and their CFITSIO equivalents (in caps)
Definition: CCfits.h:81
CCfits::Column::Column
Column(const Column &right)
copy constructor, used in copying Columns to standard library containers.
Definition: Column.cxx:171