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