7c6c84a93782d6aea4f2f96a24d30c3f901ba808
[ctsim.git] / include / imagefile.h
1 #ifndef IDF_H
2 #define IDF_H
3
4 #include <string>
5 #include <sys/types.h>
6 #include <unistd.h>
7 #include <fstream>
8 #include <iostream>
9 #include "ctsupport.h"
10 #include "fnetorderstream.h"
11 #include "array2d.h"
12
13 using namespace std;
14
15
16 class Array2dFileLabel
17 {
18 public:
19     kfloat64 m_calcTime;
20     kuint16 m_labelType;
21     kuint16 m_year;
22     kuint16 m_month;
23     kuint16 m_day;
24     kuint16 m_hour;
25     kuint16 m_minute;
26     kuint16 m_second;
27     string m_strLabel;
28     mutable string m_strDate;
29
30     static const int L_EMPTY = 0;
31     static const int L_HISTORY = 1;
32     static const int L_USER = 2;
33
34     Array2dFileLabel(); 
35
36     Array2dFileLabel(const char* const str, double ctime = 0.);
37
38     Array2dFileLabel(const int type, const char* const str, double ctime = 0.);
39
40     ~Array2dFileLabel();
41
42     const string& getLabelString (void) const
43         { return m_strLabel; }
44
45     kfloat64 getCalcTime (void) const
46         { return m_calcTime; }
47
48     kfloat64 getLabelType (void) const
49         { return m_labelType; }
50
51     string& setLabelString (const char* const str)
52         { m_strLabel = str; return (m_strLabel); }
53
54     string& setLabelString (const string& str)
55         { m_strLabel = str; return (m_strLabel); }
56
57     const string& getDateString () const;
58
59 private:
60     void init (void);
61     Array2dFileLabel (const Array2dFileLabel&);
62     Array2dFileLabel& operator= (const Array2dFileLabel&);
63 };
64
65
66 template<class T>
67 class Array2dFile 
68 {
69 private:
70   void init (void);
71
72   bool headerWrite (void);
73
74   bool headerRead (void);
75
76   bool arrayDataRead (void);
77
78   bool labelSeek (unsigned int label_num);
79
80   Array2dFile (const Array2dFile& rhs);        // copy constructor
81   Array2dFile& operator= (const Array2dFile&); // assignment operator
82
83  protected:
84   kuint16 signature;
85   kuint16 num_labels;
86   kuint16 headersize;
87   string  filename;
88   int file_id;
89   frnetorderstream *m_pFS;
90   bool bHeaderWritten;
91   bool bDataWritten;
92
93   kuint16 mPixelSize;
94   kuint16 axis_increment_known;
95   kfloat64 mIncX, mIncY;
96   kuint16 axis_extent_known;
97   kfloat64 mMinX, mMaxX, mMinY, mMaxY;
98   kfloat64 mOffsetPV, mScalePV;
99   kuint16 mPixelType;
100   kuint32 mNX;
101   kuint32 mNY;
102
103
104 public:
105
106   Array2d<T> array;
107
108   static const int INT8 = 1;
109   static const int UINT8 = 2;
110   static const int INT16 = 3;
111   static const int UINT16 = 4;
112   static const int INT32 = 5;
113   static const int UINT32 = 6;
114   static const int FLOAT32 = 7;
115   static const int FLOAT64 = 8;
116
117   Array2dFile (unsigned int nx, unsigned int ny);
118   Array2dFile (const char* const filename);
119   Array2dFile (const char* const filename, unsigned int nx, unsigned int ny);
120   ~Array2dFile ();
121
122   unsigned int getNumLabels (void) const
123       { return num_labels; }
124
125   bool labelRead (Array2dFileLabel& label, unsigned int label_num);
126
127   void labelAdd (const Array2dFileLabel& label);
128
129   void labelAdd (const char* const m_strLabel, double calc_time=0.);
130
131   void labelAdd (int type, const char* const m_strLabel, double calc_time=0.);
132
133   void labelsCopy (Array2dFile& file, const char* const idStr = NULL);
134
135   void fileClose (void);
136
137   void setPixelType (int type)
138       { mPixelType = type; }
139
140   kuint32 nx (void) const
141       { return mNX; }
142
143   kuint32 ny (void) const
144       { return mNY; }
145
146   void setAxisIncrement (double mIncX, double mIncY);
147
148   void setAxisExtent (double mMinX, double mMaxX, double mMinY, double mMaxY);
149
150   void getPixelValueRange (T& pvmin, T& pvmax) const;
151       
152   void doPixelOffsetScale (double offset, double scale);
153
154   void printLabels (ostream& os);
155
156   T** getArray (void) const
157       { return (array.getArray()); }
158
159   bool arrayDataWrite (void);
160
161   void arrayDataClear (void);
162
163   bool fileRead (void);
164
165   bool fileCreate (void);
166
167   const string& GetFilename (void) const 
168       {  return filename; }
169 };
170
171
172 template<class T>
173 Array2dFile<T>::Array2dFile (unsigned int x, unsigned int y)
174 {
175     init();
176     mNX = x;
177     mNY = y;
178     array.initSetSize(mNX, mNY);
179 }
180
181 template<class T>
182 Array2dFile<T>::Array2dFile (const char * const str, unsigned int x, unsigned int y)
183   : filename(str)
184 {
185     init();
186     mNX = x;
187     mNY = y;
188     array.initSetSize(mNX, mNY);
189 }
190
191 template<class T>
192 Array2dFile<T>::Array2dFile (const char * const str)
193   : filename(str)
194 {
195     init();
196 }
197
198 template<class T>
199 void
200 Array2dFile<T>::init (void)
201 {
202   mPixelSize = sizeof(T);
203   signature = ('I' * 256 + 'F');
204   mNX = 0;
205   mNY = 0;
206   headersize = 0;
207   num_labels = 0;
208   axis_increment_known = false;
209   axis_extent_known = false;
210   mIncX = mMinY = 0;
211   mMinX = mMaxX = mMinY = mMaxY = 0;
212   mOffsetPV = 0;
213   mScalePV = 1;
214   m_pFS = NULL;
215
216 #if 0
217   const type_info& t_id = typeid(T);
218   cout << t_id.name() << endl;
219   const type_info& comp_id = typeid(T);
220
221   if (t_id == comp_id)
222       mPixelType = FLOAT64;
223   else if (t_id == typeid(kfloat32))
224     mPixelType = FLOAT32;
225   else if (t_id == typeid(kint32))
226     mPixelType = INT32;
227   else if (t_id == typeid(kuint32))
228     mPixelType = UINT32;
229   else if (t_id == typeid(kint16))
230     mPixelType = INT16;
231   else if (t_id == typeid(kuint16))
232     mPixelType = UINT16;
233   else if (t_id == typeid(kint8))
234     mPixelType = INT8;
235   else if (t_id == typeid(kuint8))
236     mPixelType = UINT8;
237   else
238 #endif
239       mPixelType = 0;
240
241   bHeaderWritten = false;
242   bDataWritten = false;
243 }
244
245 template<class T>
246 Array2dFile<T>::~Array2dFile (void)
247 {
248     fileClose ();
249 }
250
251
252 template<class T>
253 void
254 Array2dFile<T>::fileClose (void)
255 {
256   if (m_pFS) {
257       headerWrite ();
258       m_pFS->close ();
259       m_pFS = NULL;
260   }
261 }
262
263 template<class T>
264 bool
265 Array2dFile<T>::fileCreate (void)
266 {
267   m_pFS = new frnetorderstream (filename.c_str(), ios::out | ios::in | ios::trunc | ios::binary);
268   if (! m_pFS) {
269       sys_error (ERR_WARNING, "Error opening file %s for writing [fileCreate]", filename.c_str());
270       return (false);
271   }
272   headerWrite();
273   return (true);
274 }
275
276 template<class T>
277 bool
278 Array2dFile<T>::fileRead (void)
279 {
280   m_pFS = new frnetorderstream (filename.c_str(), ios::out | ios::in | ios::binary | ios::nocreate);
281   if (m_pFS->fail()) {
282     sys_error (ERR_WARNING, "Unable to open file %s [fileRead]", filename.c_str());
283     return (false);
284   }
285
286   if (! headerRead())
287       return false;
288
289   array.initSetSize(mNX, mNY);
290
291   arrayDataRead();
292
293   return (true);
294 }
295
296 template<class T>
297 void
298 Array2dFile<T>::setAxisIncrement (double incX, double incY)
299 {
300     axis_increment_known = true;
301     mIncX = incX;
302     mIncY = incY;
303 }
304
305 template<class T>
306 void 
307 Array2dFile<T>::setAxisExtent (double minX, double maxX, double minY, double maxY)
308 {
309     axis_extent_known = true;
310     mMinX = minX;
311     mMaxY = maxX;
312     mMinX = minX;
313     mMaxY = maxY;
314 }
315
316 template<class T>
317 void 
318 Array2dFile<T>::getPixelValueRange (T& pvmin, T& pvmax) const
319 {
320     T** da = array.getArray();
321     if (da) {
322         pvmax = pvmin = da[0][0];
323         for (int ix = 0; ix < mNX; ix++)
324             for (int iy = 0; iy < mNY; iy++)
325                 if (pvmax < da[ix][iy])
326                     pvmax = da[ix][iy];
327                 else if (pvmin > da[ix][iy])
328                     pvmin = da[ix][iy];
329     }
330 }
331
332 template<class T>
333 void
334 Array2dFile<T>::doPixelOffsetScale (double offset, double scale)
335 {
336     T** ad = array.getArray();
337     if (ad) {
338         mOffsetPV = offset;
339         mScalePV = scale;
340
341         for (unsigned int ix = 0; ix < mNX; ix++) 
342             for (unsigned int iy = 0; iy < mNY; iy++)
343                 ad[ix][iy] = (ad[ix][iy] - offset) * scale;
344     }
345 }
346
347 template<class T>
348 bool
349 Array2dFile<T>::headerRead (void)
350 {
351   if (! m_pFS) {
352     sys_error (ERR_WARNING, "Tried to read header with file closed [headerRead]");
353     return (false);
354   }
355
356   m_pFS->seekg (0);
357   kuint16 file_signature;
358   kuint16 file_mPixelSize;
359   kuint16 file_mPixelType;
360
361   m_pFS->readInt16 (headersize);
362   m_pFS->readInt16 (file_signature);
363   m_pFS->readInt16 (num_labels);
364   m_pFS->readInt16 (file_mPixelType);
365   m_pFS->readInt16 (file_mPixelSize);
366   m_pFS->readInt32 (mNX);
367   m_pFS->readInt32 (mNY);
368   m_pFS->readInt16 (axis_increment_known);
369   m_pFS->readFloat64 (mIncX);
370   m_pFS->readFloat64 (mIncY);
371   m_pFS->readInt16 (axis_extent_known);
372   m_pFS->readFloat64 (mMinX);
373   m_pFS->readFloat64 (mMaxX);
374   m_pFS->readFloat64 (mMinY);
375   m_pFS->readFloat64 (mMaxY);
376   m_pFS->readFloat64 (mOffsetPV);
377   m_pFS->readFloat64 (mScalePV);
378
379   int read_headersize = m_pFS->tellg();
380   if (read_headersize != headersize) {
381     sys_error (ERR_WARNING, "Read headersize %d != file headersize %d", read_headersize, headersize);
382     return (false);
383   }
384   if (file_signature != signature) {
385     sys_error (ERR_WARNING, "File signature %d != true signature %d", file_signature, signature);
386     return (false);
387   }
388   if (file_mPixelType != mPixelType) {
389     sys_error (ERR_WARNING, "File pixel type %d != class pixel type %d", file_mPixelType, mPixelType);
390     return (false);
391   }
392   if (file_mPixelSize != mPixelSize) {
393     sys_error (ERR_WARNING, "File pixel size %d != class pixel size %d", file_mPixelSize, mPixelSize);
394     return (false);
395   }
396
397   return (true);
398 }
399
400 template<class T>
401 bool
402 Array2dFile<T>::headerWrite (void)
403 {
404   if (! m_pFS) {
405     sys_error (ERR_WARNING, "Tried to write header with file closed");
406     return (false);
407   }
408
409   m_pFS->seekp (0);
410   m_pFS->writeInt16 (headersize);
411   m_pFS->writeInt16 (signature);
412   m_pFS->writeInt16 (num_labels);
413   m_pFS->writeInt16 (mPixelType);
414   m_pFS->writeInt16 (mPixelSize);
415   m_pFS->writeInt32 (mNX);
416   m_pFS->writeInt32 (mNY);
417   m_pFS->writeInt16 (axis_increment_known);
418   m_pFS->writeFloat64 (mIncX);
419   m_pFS->writeFloat64 (mIncY);
420   m_pFS->writeInt16 (axis_extent_known);
421   m_pFS->writeFloat64 (mMinX);
422   m_pFS->writeFloat64 (mMaxX);
423   m_pFS->writeFloat64 (mMinY);
424   m_pFS->writeFloat64 (mMaxY);
425   m_pFS->writeFloat64 (mOffsetPV);
426   m_pFS->writeFloat64 (mScalePV);
427
428   headersize = m_pFS->tellp();
429   m_pFS->writeInt16 (headersize);
430   
431   return (true);
432 }
433
434 template<class T>
435 bool
436 Array2dFile<T>::arrayDataWrite (void)
437 {
438   if (! m_pFS) {
439     sys_error (ERR_WARNING, "Tried to arrayDataWrite with !m_pFS");
440     return (false);
441   }
442
443   T** da = array.getArray();
444   if (! da) 
445       return (false);
446
447   m_pFS->seekp (headersize);
448   for (unsigned int ix = 0; ix < mNX; ix++) {
449       if (NativeBigEndian()) {
450           for (unsigned int iy = 0; iy < mNY; iy++) {
451               T value = da[ix][iy];
452               ConvertReverseNetworkOrder (&value, sizeof(T));
453               m_pFS->write (&value, mPixelSize);
454           }
455       } else 
456           m_pFS->write (da[ix], sizeof(T) * mNY);
457   }
458
459   return (true);
460 }
461
462 template<class T>
463 bool
464 Array2dFile<T>::arrayDataRead (void)
465 {
466   if (! m_pFS) {
467     sys_error (ERR_WARNING, "Tried to arrayDataRead with !m_pFS");
468     return (false);
469   }
470
471   T** da = array.getArray();
472   if (! da) 
473       return (false);
474
475   m_pFS->seekg (headersize);
476   T pixelBuffer;
477   for (int ix = 0; ix < mNX; ix++) {
478       if (NativeBigEndian()) {
479           for (unsigned int iy = 0; iy < mNY; iy++) {
480               m_pFS->read (&pixelBuffer, mPixelSize);
481               ConvertReverseNetworkOrder (&pixelBuffer, sizeof(T));
482               da[ix][iy] = pixelBuffer;
483           } 
484       } else
485           m_pFS->read (da[ix], sizeof(T) * mNY);
486   }
487
488
489   return (true);
490 }
491
492 template<class T>
493 bool
494 Array2dFile<T>::labelSeek (unsigned int label_num)
495 {
496   if (label_num > num_labels) {
497     sys_error (ERR_WARNING, "label_num %d > num_labels %d [labelSeek]");
498     return (false);
499   }
500
501   if (array.getArray() == NULL) {    // Could not have written data if array not allocated
502     sys_error (ERR_WARNING, "array == NULL [labelSeek]");
503     return (false);
504   }
505
506   off_t pos = headersize + array.sizeofArray();
507   m_pFS->seekg (pos);
508
509   for (int i = 0; i < label_num; i++)
510       {
511           pos += 22;  // Skip to string length
512           m_pFS->seekg (pos);
513               
514           kuint16 strlength;
515           m_pFS->readInt16 (strlength);
516           pos += 2 + strlength;  // Skip label string length + data
517           m_pFS->seekg (pos);
518       }
519   
520   if (! m_pFS)
521       return false;
522
523   return (true);
524 }
525
526 template<class T>
527 bool
528 Array2dFile<T>::labelRead (Array2dFileLabel& label, unsigned int label_num)
529 {
530   if (label_num >= num_labels) {
531     sys_error (ERR_WARNING, "Trying to read past number of labels [labelRead]");
532     return (false);
533   }
534
535   if (! labelSeek (label_num)) {
536     sys_error (ERR_WARNING, "Error calling labelSeek");
537     return (false);
538   }
539
540   m_pFS->readInt16 (label.m_labelType);
541   m_pFS->readInt16 (label.m_year);
542   m_pFS->readInt16 (label.m_month);
543   m_pFS->readInt16 (label.m_day);
544   m_pFS->readInt16 (label.m_hour);
545   m_pFS->readInt16 (label.m_minute);
546   m_pFS->readInt16 (label.m_second);
547   m_pFS->readFloat64 (label.m_calcTime);
548
549   kuint16 strlength;
550   m_pFS->readInt16 (strlength);
551   char str [strlength+1];
552   m_pFS->read (str, strlength);
553   str[strlength] = 0;
554   label.m_strLabel = str;
555
556   return (true);
557 }
558
559
560 template<class T>
561 void
562 Array2dFile<T>::labelAdd (const char* const lstr, double calc_time=0.)
563 {
564   labelAdd (Array2dFileLabel::L_HISTORY, lstr, calc_time);
565 }
566
567 template<class T>
568 void
569 Array2dFile<T>::labelAdd (int type, const char* const lstr, double calc_time=0.)
570 {
571   Array2dFileLabel label (type, lstr, calc_time);
572
573   labelAdd (label);
574 }
575
576 template<class T>
577 void
578 Array2dFile<T>::labelAdd (const Array2dFileLabel& label)
579 {
580   labelSeek (num_labels);
581   
582   m_pFS->writeInt16 (label.m_labelType);
583   m_pFS->writeInt16 (label.m_year);
584   m_pFS->writeInt16 (label.m_month);
585   m_pFS->writeInt16 (label.m_day);
586   m_pFS->writeInt16 (label.m_hour);
587   m_pFS->writeInt16 (label.m_minute);
588   m_pFS->writeInt16 (label.m_second);
589   m_pFS->writeFloat64 (label.m_calcTime);
590   kuint16 strlength = label.m_strLabel.length();
591   m_pFS->writeInt16 (strlength);
592   m_pFS->write (label.m_strLabel.c_str(), strlength);
593
594   num_labels++;
595
596   headerWrite();
597 }
598
599 template<class T>
600 void
601 Array2dFile<T>::labelsCopy (Array2dFile& copyFile, const char* const idStr)
602 {
603     string id = idStr;
604     for (int i = 0; i < copyFile.getNumLabels(); i++) {
605       Array2dFileLabel l;
606       copyFile.labelRead (l, i);
607       string lstr = l.getLabelString();
608       lstr = idStr + lstr;
609       l.setLabelString (lstr);
610       labelAdd (l);
611     }
612 }
613
614 template<class T>
615 void 
616 Array2dFile<T>::arrayDataClear (void)
617 {
618     T** v = array.getArray();
619     if (v) {
620         for (unsigned int ix = 0; ix < mNX; ix++)
621             for (unsigned int iy = 0; iy < mNY; iy++)
622                 v[ix][iy] = 0;
623     }
624 }
625
626 template<class T>
627 void
628 Array2dFile<T>::printLabels (ostream& os)
629 {
630     int nlabels = getNumLabels();
631
632     for (int i = 0; i < nlabels; i++) {
633         Array2dFileLabel label;
634         labelRead (label, i);
635
636         if (label.getLabelType() == Array2dFileLabel::L_HISTORY) {
637             os << "History: " << endl;
638             os << "  " << label.getLabelString() << endl;
639             os << "  calc time = " << label.getCalcTime() << " secs" << endl;
640             os << "  Timestamp = " << label.getDateString() << endl;
641         } else if (label.getLabelType() == Array2dFileLabel::L_USER) {
642             os << "Note: " <<  label.getLabelString() << endl;
643             os << "  Timestamp = %s" << label.getDateString() << endl;
644         }
645         os << endl;
646     }
647 }
648
649 #ifdef HAVE_MPI
650 #include <mpi++.h>
651 #endif
652
653 class F32Image : public Array2dFile<kfloat32>
654 {
655 public:
656   F32Image (const char* const fname, unsigned int nx, unsigned int ny)
657       : Array2dFile<kfloat32>::Array2dFile (fname, nx, ny)
658   {
659       setPixelType (FLOAT32);
660   }
661
662   F32Image (unsigned int nx, unsigned int ny)
663       : Array2dFile<kfloat32>::Array2dFile (nx, ny)
664   {
665       setPixelType (FLOAT32);
666   }
667
668   F32Image (const char* const fname)
669       : Array2dFile<kfloat32>::Array2dFile (fname)
670   {
671       setPixelType (FLOAT32);
672   }
673
674 #ifdef HAVE_MPI
675   MPI::Datatype getMPIDataType (void) const
676       { return MPI::FLOAT; }
677 #endif
678
679  private:
680   F32Image (const F32Image& rhs);             //copy constructor
681   F32Image& operator= (const F32Image& rhs);  // assignment operator
682 };
683
684
685 class F64Image : public Array2dFile<kfloat64>
686 {
687  public:
688
689   F64Image (const char* const fname, unsigned int nx, unsigned int ny)
690       : Array2dFile<kfloat64>::Array2dFile (fname, nx, ny)
691   {
692       setPixelType (FLOAT64);
693   }
694
695   F64Image (unsigned int nx, unsigned int ny)
696       : Array2dFile<kfloat64>::Array2dFile (nx, ny)
697   {
698       setPixelType (FLOAT64);
699   }
700
701   F64Image (const char* const fname)
702       : Array2dFile<kfloat64>::Array2dFile (fname)
703   {
704       setPixelType (FLOAT64);
705   }
706
707 #ifdef HAVE_MPI
708   MPI::Datatype getMPIDataType (void) const
709       { return MPI::DOUBLE; }
710 #endif
711  private:
712   F64Image (const F64Image& rhs);             //copy constructor
713   F64Image& operator= (const F64Image& rhs);  // assignment operator
714 };
715
716 #undef IMAGEFILE_64_BITS
717 #ifdef IMAGEFILE_64_BITS
718 typedef F64Image   ImageFileBase;
719 typedef kfloat64   ImageFileValue;
720 typedef kfloat64*  ImageFileColumn;
721 typedef kfloat64** ImageFileArray;
722 #else
723 typedef F32Image   ImageFileBase;
724 typedef kfloat32   ImageFileValue;
725 typedef kfloat32*  ImageFileColumn;
726 typedef kfloat32** ImageFileArray;
727 #endif
728
729
730 class ImageFile : public ImageFileBase
731 {
732  public:
733   ImageFile (const char* const fname, unsigned int nx, unsigned int ny)
734       : ImageFileBase (fname, nx, ny)
735   {}
736
737   ImageFile (unsigned int nx, unsigned int ny)
738       : ImageFileBase (nx, ny)
739   {}
740
741   ImageFile (const char* const fname)
742       : ImageFileBase (fname)
743   {}
744
745   void filterResponse (const char* const domainName, double bw, const char* const filterName, double filt_param);
746
747   void statistics (double& min, double& max, double& mean, double& mode, double& median, double& stddev) const;
748
749   void printStatistics (ostream& os) const;
750
751   bool comparativeStatistics (const ImageFile& imComp, double& d, double& r, double& e) const;
752
753   bool printComparativeStatistics (const ImageFile& imComp, ostream& os) const;
754
755   int display (void);
756
757   int displayScaling (const int scaleFactor, ImageFileValue pmin, ImageFileValue pmax);
758
759 };
760
761
762 #endif
763
764
765