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