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