26 #include "FitsError.h" 
   39         Image(
const Image< T > &right);
 
   40         Image (
const std::valarray<T>& imageArray = std::valarray<T>());
 
   42         Image< T > & operator=(
const Image< T > &right);
 
   44         const std::valarray<T>& readImage (fitsfile* fPtr, 
long first, 
long nElements, T* nullValue, 
const std::vector<long>& naxes, 
bool& nulls);
 
   45         const std::valarray<T>& readImage (fitsfile* fPtr, 
const std::vector<long>& firstVertex, 
const std::vector<long>& lastVertex, 
const std::vector<long>& stride, T* nullValue, 
const std::vector<long>& naxes, 
bool& nulls);
 
   47         void writeImage (fitsfile* fPtr, 
long first, 
long nElements, 
const std::valarray<T>& inData, 
const std::vector<long>& naxes, 
long& newNaxisN, T* nullValue = 0);
 
   48         void writeImage (fitsfile* fPtr, 
const std::vector<long>& firstVertex, 
const std::vector<long>& lastVertex, 
const std::vector<long>& stride, 
const std::valarray<T>& inData, 
const std::vector<long>& naxes, 
long& newNaxisN);
 
   49         void writeImage (fitsfile* fPtr, 
const std::vector<long>& firstVertex, 
const std::vector<long>& lastVertex, 
const std::valarray<T>& inData, 
const std::vector<long>& naxes, 
long& newNaxisN);
 
   54         void scalingHasChanged();
 
   58         const std::valarray< T >& image () 
const;
 
   66         std::valarray<T>& image ();
 
   67         void prepareForSubset (
const std::vector<long>& naxes, 
const std::vector<long>& firstVertex, 
const std::vector<long>& lastVertex, 
const std::vector<long>& stride, 
const std::valarray<T>& inData, std::valarray<T>& subset);
 
   68         void loop (
size_t iDim, 
const std::vector<long>& firstVertex, 
const std::vector<long>& lastVertex, 
const std::vector<long>& stride, 
size_t iPos, 
const std::vector<size_t>& incr, 
const std::valarray<T>& inData, 
size_t& iDat, 
const std::vector<size_t>& subIncr, std::valarray<T>& subset, 
size_t iSub);
 
   69         bool isNullValChanged(T* newNull) 
const;
 
   70         void setLastNullInfo(T* newNull);
 
   85         std::valarray< T > m_fullImageCache;
 
   86         std::valarray<T> m_currentRead;
 
   95   inline bool Image<T>::isRead ()
 const 
  100   template <
typename T>
 
  101   inline const std::valarray< T >& Image<T>::image ()
 const 
  103     return m_fullImageCache;
 
  109   template <
typename T>
 
  110   Image<T>::Image(
const Image<T> &right)
 
  111         : m_isRead(right.m_isRead),
 
  112           m_usingNullVal(right.m_usingNullVal),
 
  113           m_lastNullVal(right.m_lastNullVal),
 
  114           m_fullImageCache(right.m_fullImageCache),
 
  115           m_currentRead(right.m_currentRead)
 
  119   template <
typename T>
 
  120   Image<T>::Image (
const std::valarray<T>& imageArray)
 
  122           m_usingNullVal(false),
 
  124           m_fullImageCache(imageArray),
 
  130   template <
typename T>
 
  136   template <
typename T>
 
  137   Image<T> & Image<T>::operator=(
const Image<T> &right)
 
  140      m_isRead = right.m_isRead;
 
  141      m_usingNullVal = right.m_usingNullVal,
 
  142      m_lastNullVal = right.m_lastNullVal,
 
  143      m_fullImageCache.resize(right.m_fullImageCache.size());
 
  144      m_fullImageCache = right.m_fullImageCache;
 
  145      m_currentRead.resize(right.m_currentRead.size());
 
  146      m_currentRead = right.m_currentRead;
 
  151   template <
typename T>
 
  152   const std::valarray<T>& Image<T>::readImage (fitsfile* fPtr, 
long first, 
long nElements, T* nullValue, 
const std::vector<long>& naxes, 
bool& nulls)
 
  156         m_currentRead.resize(0);
 
  157         return m_currentRead;
 
  159      unsigned long init(1);
 
  160      unsigned long nTotalElements(std::accumulate(naxes.begin(),naxes.end(),init,
 
  161                      std::multiplies<long>()));
 
  165         string errMsg(
"*** CCfits Error: For image read, lowest allowed value for first element is 1.\n");
 
  167         throw FitsException(errMsg, silent);
 
  170      unsigned long start = (
unsigned long)first - 1;
 
  171      if (start >= nTotalElements)
 
  173         string errMsg(
"*** CCfits Error: For image read, starting element is out of range.\n");
 
  175         throw FitsException(errMsg, silent);
 
  179         string errMsg(
"*** CCfits Error: Negative nElements value specified for image read.\n");
 
  181         throw FitsException(errMsg, silent);
 
  183      const unsigned long elementsRequested = (
unsigned long)nElements;
 
  187      FITSUtil::MatchType<T> imageType;
 
  190      unsigned long elementsToRead(std::min(elementsRequested,
 
  191                      nTotalElements - start));
 
  192      if ( elementsToRead < elementsRequested)
 
  195                      "***CCfits Warning: data request exceeds image size, truncating\n"; 
 
  197      const bool isFullRead = (elementsToRead == nTotalElements);
 
  198      const bool isDifferentNull = isNullValChanged(nullValue);
 
  199      if (!m_isRead || isDifferentNull)
 
  205            m_fullImageCache.resize(elementsToRead);
 
  206            if (fits_read_img(fPtr,imageType(),first,elementsToRead,
 
  207                nullValue,&m_fullImageCache[0],&any,&status) != 0) 
throw FitsError(status);
 
  215            m_fullImageCache.resize(0);
 
  216            m_currentRead.resize(elementsToRead);
 
  217            if (fits_read_img(fPtr,imageType(),first,elementsToRead,
 
  218                nullValue,&m_currentRead[0],&any,&status) != 0) 
throw FitsError(status);
 
  221         setLastNullInfo(nullValue);
 
  227             m_currentRead.resize((
size_t)elementsToRead);
 
  230             m_currentRead = m_fullImageCache[std::slice((
size_t)start, (
size_t)elementsToRead,1)];
 
  234         return m_fullImageCache;
 
  236      return m_currentRead;
 
  240   template <
typename T>
 
  241   const std::valarray<T>& Image<T>::readImage (fitsfile* fPtr, 
const std::vector<long>& firstVertex, 
const std::vector<long>& lastVertex, 
const std::vector<long>& stride, T* nullValue, 
const std::vector<long>& naxes, 
bool& nulls)
 
  243      const size_t N = naxes.size();
 
  246         m_currentRead.resize(0);
 
  247         return m_currentRead;
 
  249      if (N != firstVertex.size() || N != lastVertex.size() || N != stride.size())
 
  251         string errMsg(
"*** CCfits Error: Image read function requires that naxes, firstVertex,");
 
  252         errMsg += 
"       \nlastVertex, and stride vectors all be the same size.\n";
 
  254         throw FitsException(errMsg, silent);
 
  257      FITSUtil::CVarray<long> carray;
 
  260      long requestedSize=1;
 
  263      for (
size_t j = 0; j < N; ++j)
 
  266         requestedSize *= ((lastVertex[j] - firstVertex[j])/stride[j] + 1);
 
  267         nTotalSize *= naxes[j];
 
  268         if (firstVertex[j] < 1 || lastVertex[j] > naxes[j])
 
  270            string errMsg(
"*** CCfits Error: Out-of-bounds vertex value.\n");
 
  272            throw FitsException(errMsg,silent);
 
  274         if (firstVertex[j] > lastVertex[j])
 
  276            string errMsg(
"*** CCfits Error: firstVertex values must not be larger than corresponding lastVertex values.\n");
 
  278            throw FitsException(errMsg,silent);
 
  281      const bool isFullRead = (requestedSize == nTotalSize);
 
  282      const bool isDifferentNull = isNullValChanged(nullValue);
 
  283      if (!m_isRead || isDifferentNull)
 
  286         FITSUtil::auto_array_ptr<long> pFpixel(carray(firstVertex));
 
  287         FITSUtil::auto_array_ptr<long> pLpixel(carray(lastVertex));
 
  288         FITSUtil::auto_array_ptr<long> pStride(carray(stride));
 
  290         FITSUtil::MatchType<T> imageType;
 
  294            m_fullImageCache.resize(requestedSize);
 
  295            if (fits_read_subset(fPtr,imageType(),
 
  296                                    pFpixel.get(),pLpixel.get(),
 
  297                                    pStride.get(),nullValue,&m_fullImageCache[0],&any,&status) != 0)
 
  298               throw FitsError(status);        
 
  303            m_currentRead.resize(requestedSize);
 
  304            if (fits_read_subset(fPtr,imageType(),
 
  305                                    pFpixel.get(),pLpixel.get(),
 
  306                                    pStride.get(),nullValue,&m_currentRead[0],&any,&status) != 0)
 
  307               throw FitsError(status);        
 
  310         setLastNullInfo(nullValue); 
 
  321            std::valarray<size_t> gsliceLength(
size_t(0),N);
 
  322            std::valarray<size_t> gsliceStride(
size_t(0),N);
 
  324            std::vector<long> naxesProducts(N);
 
  326            for (
size_t i=0; i<N; ++i)
 
  328               naxesProducts[i] = accum;
 
  332            for (
size_t i=0; i<N; ++i)
 
  334               startPos += 
static_cast<size_t>((firstVertex[i]-1)*naxesProducts[i]);
 
  336               const size_t gsPos = N-1-i;
 
  338               gsliceLength[gsPos] = 
static_cast<size_t>((1 + (lastVertex[i]-firstVertex[i])/stride[i]));
 
  339               gsliceStride[gsPos] = 
static_cast<size_t>(stride[i]*naxesProducts[i]);
 
  341            m_currentRead.resize(requestedSize);
 
  342            m_currentRead = m_fullImageCache[std::gslice(startPos, gsliceLength, gsliceStride)];  
 
  346         return m_fullImageCache;
 
  347      return m_currentRead;
 
  350   template <
typename T>
 
  351   void Image<T>::writeImage (fitsfile* fPtr, 
long first, 
long nElements, 
const std::valarray<T>& inData, 
const std::vector<long>& naxes, 
long& newNaxisN, T* nullValue)
 
  354      if (first < 1 || nElements < 1)
 
  356         string errMsg(
"*** CCfits Error: first and nElements values must be > 0\n");
 
  358         throw FitsException(errMsg, silent);
 
  360      FITSUtil::CAarray<T> convert;
 
  361      FITSUtil::auto_array_ptr<T>    pArray(convert(inData));                     
 
  362      T* array = pArray.get();
 
  367      FITSUtil::MatchType<T> imageType;
 
  368      long type(imageType());
 
  370      if (fits_write_imgnull(fPtr,type,first,nElements,array,
 
  371                      nullValue,&status)!= 0)
 
  373         throw FitsError(status);        
 
  375      const size_t nDim=naxes.size();
 
  377      for (
size_t i=0; i<nDim; ++i)
 
  378         origTotSize *= naxes[i];
 
  379      const long highestOutputElem = first + nElements - 1;
 
  380      if (highestOutputElem > origTotSize)
 
  383         std::ostringstream oss;
 
  384         oss <<
"NAXIS" << nDim;
 
  385         string keyname(oss.str());
 
  386         long newVal = 1 + (highestOutputElem-1)/(origTotSize/naxes[nDim-1]);
 
  387         if (newVal != naxes[nDim-1])
 
  389            if (fits_update_key(fPtr,TLONG,(
char *)keyname.c_str(),&newVal,0,&status) != 0)
 
  391               throw FitsError(status);
 
  396      if (fits_flush_file(fPtr,&status) != 0)
 
  397         throw FitsError(status);
 
  401   template <
typename T>
 
  402   void Image<T>::writeImage (fitsfile* fPtr, 
const std::vector<long>& firstVertex, 
const std::vector<long>& lastVertex, 
const std::vector<long>& stride, 
const std::valarray<T>& inData, 
const std::vector<long>& naxes, 
long& newNaxisN)
 
  405         const size_t nDim = naxes.size();
 
  406         FITSUtil::auto_array_ptr<long> pFPixel(
new long[nDim]);
 
  407         FITSUtil::auto_array_ptr<long> pLPixel(
new long[nDim]);
 
  408         std::valarray<T> subset;
 
  411         prepareForSubset(naxes,firstVertex,lastVertex,stride,inData,subset);
 
  413         long* fPixel = pFPixel.get();
 
  414         long* lPixel = pLPixel.get();
 
  415         for (
size_t i=0; i<nDim; ++i)
 
  417            fPixel[i] = firstVertex[i];
 
  418            lPixel[i] = lastVertex[i];
 
  421         FITSUtil::CAarray<T> convert;
 
  422         FITSUtil::auto_array_ptr<T> pArray(convert(subset));
 
  423         T* array = pArray.get();
 
  424         FITSUtil::MatchType<T> imageType;        
 
  427         if ( fits_write_subset(fPtr,imageType(),fPixel,lPixel,array,&status) )
 
  428             throw FitsError(status);
 
  430         if (lPixel[nDim-1] > naxes[nDim-1])
 
  432            std::ostringstream oss;
 
  433            oss << 
"NAXIS" << nDim;
 
  434            string keyname(oss.str());
 
  435            long newVal = lPixel[nDim-1];
 
  436            if (fits_update_key(fPtr,TLONG,(
char *)keyname.c_str(),&newVal,0,&status) != 0)
 
  438               throw FitsError(status);
 
  440            newNaxisN = lPixel[nDim-1];
 
  442         if (fits_flush_file(fPtr,&status) != 0)
 
  443            throw FitsError(status);
 
  447   template <
typename T>
 
  448   std::valarray<T>& Image<T>::image ()
 
  451     return m_fullImageCache;
 
  454   template <
typename T>
 
  455   void Image<T>::prepareForSubset (
const std::vector<long>& naxes, 
const std::vector<long>& firstVertex, 
const std::vector<long>& lastVertex, 
const std::vector<long>& stride, 
const std::valarray<T>& inData, std::valarray<T>& subset)
 
  459     const size_t N = naxes.size();
 
  460     if (N != firstVertex.size() || N != lastVertex.size() || N != stride.size())
 
  462        string errMsg(
"*** CCfits Error: Image write function requires that naxes, firstVertex,");
 
  463        errMsg += 
"       \nlastVertex, and stride vectors all be the same size.\n";
 
  465        throw FitsException(errMsg, silent);
 
  467     for (
size_t i=0; i<N; ++i)
 
  472           throw FitsException(
"*** CCfits Error: Invalid naxes value sent to image write function.\n", silent);
 
  474        string rangeErrMsg(
"*** CCfits Error: Out-of-range value sent to image write function in arg: ");
 
  475        if (firstVertex[i] < 1 || (firstVertex[i] > naxes[i] && i != N-1)) 
 
  478           rangeErrMsg += 
"firstVertex\n";
 
  479           throw FitsException(rangeErrMsg, silent);
 
  481        if (lastVertex[i] < firstVertex[i] || (lastVertex[i] > naxes[i] && i != N-1))
 
  484           rangeErrMsg += 
"lastVertex\n";
 
  485           throw FitsException(rangeErrMsg, silent);
 
  490           rangeErrMsg += 
"stride\n";
 
  491           throw FitsException(rangeErrMsg, silent);
 
  498     size_t subSizeWithStride = 1;
 
  500     std::vector<size_t> subIncr(N);
 
  501     for (
size_t i=0; i<N; ++i)
 
  503        subIncr[i] = nPoints;
 
  504        nPoints *= 
static_cast<size_t>(1+lastVertex[i]-firstVertex[i]);
 
  505        subSizeWithStride *= 
static_cast<size_t>(1+(lastVertex[i]-firstVertex[i])/stride[i]);
 
  507     subset.resize(nPoints, 0);
 
  509     if (subSizeWithStride != inData.size())
 
  512        string errMsg(
"*** CCfits Error: Data array size is not consistent with the values");
 
  513        errMsg += 
"\n      in range and stride vectors sent to the image write function.\n";
 
  514        throw FitsException(errMsg, silent);
 
  517     size_t startPoint = 0;
 
  519     std::vector<size_t> incr(N);
 
  520     for (
size_t j = 0; j < N; ++j)
 
  522        startPoint += dimMult*(firstVertex[j]-1);
 
  524        dimMult *= 
static_cast<size_t>(naxes[j]);
 
  527     size_t inDataPos = 0;
 
  529     loop(N-1, firstVertex, lastVertex, stride, startPoint, incr, inData, inDataPos, subIncr, subset, iSub);           
 
  532   template <
typename T>
 
  533   void Image<T>::loop (
size_t iDim, 
const std::vector<long>& firstVertex, 
const std::vector<long>& lastVertex, 
const std::vector<long>& stride, 
size_t iPos, 
const std::vector<size_t>& incr, 
const std::valarray<T>& inData, 
size_t& iDat, 
const std::vector<size_t>& subIncr, std::valarray<T>& subset, 
size_t iSub)
 
  535      size_t start = 
static_cast<size_t>(firstVertex[iDim]);
 
  536      size_t stop = 
static_cast<size_t>(lastVertex[iDim]);
 
  537      size_t skip = 
static_cast<size_t>(stride[iDim]);
 
  540         size_t length = stop - start + 1;
 
  541         for (
size_t i=0; i<length; i+=skip)
 
  543            subset[i+iSub] = inData[iDat++];
 
  548         size_t jump = incr[iDim]*skip;
 
  549         size_t subJump = subIncr[iDim]*skip;
 
  550         for (
size_t i=start; i<=stop; i+=skip)
 
  552            loop(iDim-1, firstVertex, lastVertex, stride, iPos, incr, inData, iDat, subIncr, subset, iSub);
 
  559   template <
typename T>
 
  560   bool Image<T>::isNullValChanged(T* newNull)
 const 
  562      bool isChanged = 
false;
 
  569            if (newVal != m_lastNullVal)
 
  577         if (newNull && (*newNull != 0))
 
  584   template <
typename T>
 
  585   void Image<T>::setLastNullInfo(T* newNull)
 
  587      if (!newNull || *newNull == 0)
 
  589         m_usingNullVal = 
false;
 
  594         m_usingNullVal = 
true;
 
  595         m_lastNullVal = *newNull;
 
  599   template <
typename T>
 
  600   void Image<T>::writeImage (fitsfile* fPtr, 
const std::vector<long>& firstVertex, 
const std::vector<long>& lastVertex, 
const std::valarray<T>& inData, 
const std::vector<long>& naxes, 
long& newNaxisN)
 
  602      std::vector<long> stride(firstVertex.size(), 1);
 
  603      writeImage(fPtr, firstVertex, lastVertex, stride, inData, naxes, newNaxisN);
 
  606   template <
typename T>
 
  607   void Image<T>::scalingHasChanged()
 
  612   template <
typename T>
 
  613   void Image<T>::resetRead()