mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
HCIobservation.hpp
Go to the documentation of this file.
1 /** \file HCIobservation.hpp
2  * \author Jared R. Males
3  * \brief Defines the basic high contrast imaging data type.
4  * \ingroup hc_imaging_files
5  * \ingroup image_processing_files
6  *
7  */
8 
9 #ifndef __HCIobservation_hpp__
10 #define __HCIobservation_hpp__
11 
12 #include <vector>
13 #include <map>
14 #include <string>
15 #include <fstream>
16 
17 #include <sys/stat.h>
18 
19 #include "../mxlib.hpp"
20 
21 #include "../mxException.hpp"
22 
23 #include "../math/templateBLAS.hpp"
24 #include "../sys/timeUtils.hpp"
25 #include "../ioutils/fileUtils.hpp"
26 #include "../ioutils/readColumns.hpp"
27 #include "../ioutils/fits/fitsFile.hpp"
28 #include "../ipc/ompLoopWatcher.hpp"
29 
30 #include "eigenImage.hpp"
31 #include "eigenCube.hpp"
32 #include "imageFilters.hpp"
33 #include "imageMasks.hpp"
34 #include "imageTransforms.hpp"
35 #include "imageUtils.hpp"
36 
37 namespace mx
38 {
39 
40 namespace improc
41 {
42 
43 
44 
45 ///Namespace for high contrast imaging enums.
46 /** \ingroup hc_imaging_enums
47  */
48 namespace HCI
49 {
50  ///Possible combination methods
51  /** \ingroup hc_imaging_enums
52  */
53  enum combineMethods{ noCombine, ///< Do not combine the images.
54  medianCombine, ///< Combine with the median.
55  meanCombine, ///< Combine with the mean.
56  sigmaMeanCombine, ///< Combine with the sigma clipped mean.
57  debug};
58 
59  /// Get the string name of the combineMethod integer
60  /**
61  * \returns a string with the name of the combineMethod
62  */
63  std::string combineMethodStr( int method /**< [in] one of the combineMethods enum members */);
64 
65  /// Get the combineMethod from the corresponding string name
66  /**
67  * \returns the combineMethods enum member corresponding to the string name.
68  */
69  int combineMethodFmStr( const std::string & method /**< [in] the string name of the combineMethod */);
70 
71 }
72 
73 /// The basic high contrast imaging data type
74 /** This class manages file reading, resizing, co-adding, pre-processing (masking and filtering),
75  * and final image combination.
76  *
77  * \tparam _realT is the floating point type in which to do all arithmetic.
78  *
79  * \ingroup hc_imaging
80  */
81 template<typename _realT>
83 {
84 
85  ///The arithmetic type used for calculations. Does not have to match the type in images on disk.
86  typedef _realT realT;
87 
88  ///The Eigen image array type basted on realT
89  typedef Eigen::Array<realT, Eigen::Dynamic, Eigen::Dynamic> eigenImageT;
90 
91  ///\name Construction and Initialization
92  /** @{
93  */
94  ///Default c'tor
96 
97  ///Construct and load the target file list.
98  /** Populates the \ref m_fileList vector by searching on disk for files which match
99  * "dir/prefix*.ext". See \ref load_fileList
100  *
101  */
102  HCIobservation( const std::string &dir, ///< [in] the directory to search.
103  const std::string &prefix, ///< [in] the initial part of the file name. Can be empty "".
104  const std::string &ext ///< [in] the extension to append to the file name, must include the '.'.
105  );
106 
107  /// Construct using a file containing the target file list
108  /** Populates the \ref m_fileList vector by reading the file, which should be a single
109  * column of new-line delimited file names.
110  */
111  explicit HCIobservation( const std::string & fileListFile /**< [in] a file name path to read.*/ );
112 
113  ///Construct and load the target file list and the RDI file list
114  /** Populates the \ref m_fileList vector by searching on disk for files which match
115  * "dir/prefix*.ext". See \ref load_fileList
116  *
117  * Populates the \ref m_RDIfileList vector by searching on disk for files which match
118  * "RDIdir/RDIprefix*.RDIext". See \ref load_RDIfileList
119  */
120  HCIobservation( const std::string &dir, ///< [in] the directory to search.
121  const std::string &prefix, ///< [in] the initial part of the file name. Can be empty "".
122  const std::string &ext, ///< [in] the extension to append to the file name, must include the '.'.
123  const std::string &RDIdir, ///< [in] the directory to search for the reference files.
124  const std::string &RDIprefix, ///< [in] the initial part of the file name for the reference files. Can be empty "".
125  const std::string &RDIext="" ///< [in] [optional] the extension to append to the RDI file name, must include the '.'. If empty "" then same extension as target files is used.
126  );
127 
128  /// Construct using a file containing the target file list and a file containing the RDI target file list
129  /** Populates the \ref m_fileList vector by reading the file, which should be a single
130  * column of new-line delimited file names.
131  *
132  * Populates the \ref m_RDIfileList vector by reading the file, which should be a single
133  * column of new-line delimited file names.
134  */
135  HCIobservation( const std::string & fileListFile, ///< [in] a file name path to read for the target file names.
136  const std::string & RDIfileListFile ///< [in] a file name path to read for the reference file names.
137  );
138 
139  /// Load the file list
140  /** Populates the \ref m_fileList vector by searching on disk for files which match the given parameters.
141  * Uses \ref mx::getFileNames to search for all files which match "dir/prefix*.ext".
142  *
143  */
144  void load_fileList( const std::string &dir, ///< [in] the directory to search.
145  const std::string &prefix, ///< [in] the initial part of the file name. Can be empty "".
146  const std::string &ext ///< [in] the extension to append to the file name, which must include the '.'. Can be empty "".
147  );
148 
149  /// Load the file list from a file
150  /** Populates the \ref m_fileList vector by reading the file, which should be a single
151  * column of new-line delimited file names.
152  *
153  */
154  void load_fileList( const std::string & fileListFile /**< [in] a file name path to read.*/ );
155 
156  /// Load the RDI basis file list
157  /** Populates the \ref m_RDIfileList vector by searching on disk for files which match the given parameters.
158  * Uses \ref mx::getFileNames to search for all files which match "dir/prefix*.ext".
159  *
160  */
161  void load_RDIfileList( const std::string &dir, ///< [in] the directory to search.
162  const std::string &prefix, ///< [in] the initial part of the file name. Can be empty "".
163  const std::string &ext ///< [in] the extension to append to the file name, which must include the '.'. Can be empty "".
164  );
165 
166  /// Load the RDI basis file list from a file
167  /** Populates the \ref m_fileList vector by reading the file, which should be a single
168  * column of new-line delimited file names.
169  *
170  */
171  void load_RDIfileList( const std::string & fileListFile /**< [in] a file name path to read.*/ );
172 
173 
174  ///@}
175 
176 
177  ///\name The Input Target Images
178  /** @{
179  */
180 
181  ///The target image cube
183 
184  int m_Nims {0}; ///<Number of images in m_tgtIms
185  int m_Nrows {0}; ///<Number of rows of the images in m_tgtIms
186  int m_Ncols {0}; ///<Number of columns of the images in m_tgtIms
187  int m_Npix {0}; ///<Pixels per image, that is Nrows*Ncols
188 
189  ///Vector of target image times, in MJD.
190  std::vector<double> m_imageMJD;
191 
192  ///Vector of FITS headers, one per file, populated with the values for the keywords.
193  std::vector<fits::fitsHeader> m_heads;
194 
195  ///Whether or not the m_fileList has been read.
196  bool m_filesRead {false};
197 
198  ///Whether or not the specified files have been deleted from m_fileList
199  bool m_filesDeleted {false};
200 
201  ///Vector to hold the image weights read from the m_weightFile.
202  /** After readWeights is executed by readFiles, this will contain the normalized weights.
203  * \todo check how comboWeights are handled in coadding
204  */
205  std::vector<realT> m_comboWeights;
206 
207  ///@}
208 
209  ///\name The Input Reference Images
210  /** @{
211  */
212 
213  ///The optional reference image cube
215 
216  ///Vector of reference image times, in MJD.
217  std::vector<double> m_RDIimageMJD;
218 
219  ///Vector of FITS headers, one per reference file, populated with the values for the keywords.
220  std::vector<fits::fitsHeader> m_RDIheads;
221 
222  ///Whether or not the reference files have been read.
223  bool m_RDIfilesRead {false};
224 
225  ///Whether or not the specified files have been deleted from m_RDIfileList
226  bool m_RDIfilesDeleted {false};
227 
228  ///@}
229 
230  ///\name The Reduced Data
231  /** @{
232  */
233  ///The PSF subtracted images
234  /** This is a vector of cubes so that it can contain results from different reductions,
235  * e.g. different modes when using KLIP.
236  */
237  std::vector<eigenCube<realT> > m_psfsub;
238 
239  ///The final combined images, one for each cube in psfsub.
241 
242  ///@}
243 
244 
245  /** \name Target File Reading
246  * Options to control which files are read, how they are read, what meta data is extracted
247  * from FITS headers, sizing and masking, etc.
248  * @{
249  */
250 
251  ///The list of files to read in.
252  /** This can be set on construction or by calling \ref load_fileList
253  */
254  std::vector<std::string> m_fileList;
255 
256  ///Specify how many files from m_fileList to delete from the front of the list
257  int m_deleteFront {0};
258 
259  ///Specify how many files from m_fileList to delete from the back of the list
260  int m_deleteBack {0};
261 
262  ///File containing 2 space-delimited columns of fileVame qualityValue pairs.
263  /** If this is not empty and \ref qualityThreshold is > 0, then only images where
264  * qualityValue >= qualityThreshold are read and processed.
265  *
266  * The only restriction on qualityThreshold is that it is > 0. It is intendend to be
267  * something like Strehl ratio.
268  */
269  std::string m_qualityFile;
270 
271  ///Threshold to apply to qualityValues read from \ref qualityFile.
272  /** If <= 0, then thresholding is not performed.
273  */
275 
276  ///Just prints the names and qualities of the files which pass threshold, and stop.
277  /** Useful mainly for debugging.
278  */
279  bool m_thresholdOnly {false};
280 
281  ///Name of the keyword to use for the image date.
282  /** Specifies the keyword corresponding to the date. This is
283  * the "DATE" keyword for file write time, and usually "DATE-OBS" for actual observation time.
284  *
285  * Default is "DATE-OBS".
286  *
287  * If empty "", then image date is not read.
288  */
289  std::string m_MJDKeyword {"DATE-OBS"};
290 
291  ///Whether or not the date is in ISO 8601 format
292  bool m_MJDisISO8601 {true};
293 
294  ///If the date is not ISO 8601, this specifies the conversion to Julian Days (i.e. seconds to days)
296 
297  ///Vector of FITS header keywords to read from the files in m_fileList.
298  std::vector<std::string> m_keywords;
299 
300  ///Set the image size. Images are cut down to this size after reading.
301  /** Set to <= 0 to use images uncut.
302  *
303  * Image sizes are not increased if this is larger than their size on disk.
304  */
305  int m_imSize {0};
306 
307  ///Read the list of files, cut to size, and preprocess.
308  /**
309  * \returns 0 on success, -1 on error.
310  */
311  int readFiles();
312 
313  /// Perform post-read actions for the target images, for use by derived classes
314  virtual int postReadFiles();
315 
316  /// Perform post-coadd actions for the target images, for use by derived classes.
317  /**
318  * \returns 0 on success
319  * \returns <0 on error.
320  */
321  virtual int postCoadd();
322 
323  ///@}
324 
325  /** \name Reference File Reading
326  * For RDI, Options to control which files are read, how they are read, what meta data is extracted
327  * from FITS headers, sizing and masking, etc.
328  * @{
329  */
330 
331  ///The list of files to read in for the RDI basis.
332  /** This is set by calling \ref load_RDIfileList
333  */
334  std::vector<std::string> m_RDIfileList;
335 
336  ///Specify how many files from m_RDIfileList to delete from the front of the list
338 
339  ///Specify how many files from m_RDIfileList to delete from the back of the list
341 
342  ///File containing 2 space-delimited columns of fileMame qualityValue pairs for the reference images.
343  /** If this is not empty and \ref m_RDIqualityThreshold is > 0, then only images where
344  * qualityValue >= qualityThreshold are read and processed.
345  *
346  * The only restriction on m_RDIqualityThreshold is that it is > 0. It is intendend to be
347  * something like Strehl ratio.
348  */
349  std::string m_RDIqualityFile;
350 
351  ///Threshold to apply to qualityValues read from \ref qualityFile.
352  /** If <= 0, then thresholding is not performed.
353  */
355 
356  ///Vector of FITS header keywords to read from the files in m_fileList.
357  std::vector<std::string> m_RDIkeywords;
358 
359  /// Read the list of reference files, cut to size, and preprocess.
360  /** The target files must be read with \ref readFiles() before calling this method.
361  *
362  * \returns 0 on success, -1 on error.
363  */
364  int readRDIFiles();
365 
366  ///Perform post-read actions for the RDI images, for use by derived classes
367  virtual int postRDIReadFiles();
368 
369  ///Perform post-coadd actions, for use by derived classes.
370  /** A key example is to update keywords after the averaging occurs in coaddImages().
371  *
372  * \returns 0 on success
373  * \returns <0 on error.
374  */
375  virtual int postRDICoadd();
376 
377 
378  ///@}
379  //--RDI
380 
381  /** \name Thresholding
382  * Thresholds are applied to a list of files before it is read, based on the image qualities supplied.
383  * @{
384  */
385 
386  /// Read the image qualities from a qualityFile and apply the threshold to a fileList
387  /** This is called by readFiles().
388  *
389  * \returns 0 on success, -1 on error.
390  */
391  int threshold( std::vector<std::string> & fileList, ///< [in.out] the fileList to threshold
392  const std::string & qualityFile, ///< [in] the path to the file containing qualities, one per file.
393  realT qualityThreshold ///< [in] the quality threshold to apply
394  );
395 
396  ///@}
397 
398  /** \name Coadding
399  * These parameters control whether and how the images are coadded after being read. Coadding can
400  * be done up to a given number of images, and/or a given elapsed time.
401  *
402  * Averages the values of given Keywords as well.
403  * @{
404  */
405 
406  ///Determine how to coadd the raw images.
407  /** Possibilities are
408  * - HCI::noCombine -- [default] do not combine. This turns off coadding.
409  * - HCI::medianCombine -- coadded image is the median
410  * - HCI::meanCombine -- coadded image is the simple mean
411  *
412  * No other types of combination are currently supported for coadding.
413  */
415 
416  ///Maximum number of images to coadd
417  int m_coaddMaxImno {0};
418 
419  ///Maximum elapsed time over which to coadd the images.
421 
422  ///The values of these keywords will be averaged and replaced.
423  std::vector<std::string> m_coaddKeywords;
424 
425  ///Coadd the images
426  void coaddImages( int coaddCombineMethod,
427  int coaddMaxImno,
428  int coaddMaxTime,
429  std::vector<std::string> & coaddKeywords,
430  std::vector<double> & imageMJD,
431  std::vector<fits::fitsHeader> & heads,
432  eigenCube<realT> & ims
433  );
434 
435  ///@} -- coadding
436 
437 
438  /** \name Masking
439  * A 1/0 mask can be supplied, which is used in pre-processing and in image combination.
440  * @{
441  */
442 
443  ///Specify a mask file to apply
444  /**No mask is applied if this is empty.
445  */
446  std::string m_maskFile;
447 
448  eigenImageT m_mask; ///< The mask
449 
450  eigenCube<realT> m_maskCube; ///< A cube of masks, one for each input image, which may be modified versions (e.g. rotated) of mask.
451 
452  ///Read the mask file, resizing to imSize if needed.
453  void readMask();
454 
455  ///Populate the mask cube which is used for post-processing. Derived classes can do this as appropriate, e.g. by rotating the mask.
456  virtual void makeMaskCube();
457 
458 
459  ///@}
460 
461 
462 
463 public:
464 
465  /** \name Pre-Processing
466  * These options control the pre-processing masking and filtering.
467  * They are performed in the following order:
468  * -# mask applied (enabled by m_preProcess_mask
469  * -# radial profile subtraction (enabled by m_preProcess_subradprof)
470  * -# mask applied (enabled by m_preProcess_mask
471  * -# symmetric median unsharp mask (m_preProcess_gaussUSM_fwhm)
472  * -# symmetric Gaussian unsharp mask (m_preProcess_gaussUSM_fwhm)
473  * -# mask applied (enabled by m_preProcess_mask
474  * -# azimuthal unsharp mask (m_preProcess_azUSM_azW, and m_preProcess_azUSM_radW)
475  * -# mask applied (enabled by m_preProcess_mask)
476  * @{
477  */
478 
479  bool m_skipPreProcess {false}; ///<Don't do any of the pre-processing steps (including coadding).
480 
481  bool m_preProcess_beforeCoadd {false}; ///<controls whether pre-processing takes place before or after coadding
482 
483  bool m_preProcess_mask {true}; ///<If true, the mask is applied during each pre-processing step.
484 
485  bool m_preProcess_subradprof {false}; ///<If true, a radial profile is subtracted from each image.
486 
487  /// Azimuthal boxcar width for azimuthal unsharp mask [pixels]
488  /** If this is 0 then azimuthal-USM is not performed.
489  */
491 
492  /// Mazimum azimuthal boxcar width for azimuthal unsharp mask [degrees]
493  /** Limits width close to center, preventing wrap-around. Default is 45 degrees. Set to 0 for no maximum.
494  */
496 
497  /// Radial boxcar width for azimuthal unsharp mask [pixels]
498  /** If this is 0 then azimuthal-USM is not performed.
499  */
501 
502  ///Kernel FWHM for symmetric box median unsharp mask (USM)
503  /** USM is not performed if this is 0.
504  */
506 
507  ///Kernel FWHM for symmetric Gaussian unsharp mask (USM)
508  /** USM is not performed if this is 0.
509  */
511 
512  ///Set path and file prefix to output the pre-processed images.
513  /** If empty, then pre-processed images are not output.
514  */
516 
517  /// If true, then we stop after pre-processing.
518  bool m_preProcess_only {false};
519 
520  ///Do the pre-processing
521  void preProcess( eigenCube<realT> & ims /**< [in] the image cube, should be either m_tgtIms or m_refIms */);
522 
523  ///@}
524 
525  /** \name Image Combination
526  * These options control how the final image combination is performed.
527  * @{
528  */
529 
530 
531  ///Determine how to combine the PSF subtracted images
532  /** Possibilities are
533  * - HCI::noCombine -- do not combine
534  * - HCI::medianCombine -- [default] final image is the median
535  * - HCI::meanCombine -- final image is the simple mean
536  * - HCI::weightedMeanCombine -- final image is the weighted mean. m_weightFile must be provided.
537  * - HCI::sigmaMeanCombine -- final image is sigma clipped mean. If m_sigmaThreshold <= 0, then it reverts to meanCombine.
538  */
540 
541  ///Specifies a file containing the image weights, for combining with weighted mean.
542  /** This 2-column space-delimited ASCII file containing filenames and weights. It must be specified before readFiles()
543  * is executed. In readFiles this is loaded after the m_fileList is cutdown and matched to the remaining files.
544  */
545  std::string m_weightFile;
546 
547 
548 
549  /// The standard deviation threshold used if combineMethod == HCI::sigmaMeanCombine.
551 
552  /// The minimum fraction of good (un-masked) pixels to include in the final combination (0.0 to 1.0). If not met, then the pixel will be NaN-ed.
554 
555  ///Read the image weights from m_weightFile
556  /** This is called by readFiles().
557  *
558  * \returns 0 on success, -1 on error.
559  */
560  int readWeights();
561 
562  ///Combine the images into a single final image.
563  /** Images are combined by the method specified in \ref combineMethod
564  */
565  void combineFinim();
566 
567  ///@}
568 
569  /** \name Output
570  * These options control the ouput of the final combined images and the individual PSF subtracted images.
571  * @{
572  */
573 
574  ///Set whether the final combined image is written to disk
575  int m_doWriteFinim {1};
576 
577  ///The directory where to write output files.
578  std::string m_outputDir;
579 
580  ///The base file name of the output final image
581  /** The complete name is formed by combining with a sequential number and the ".fits" extension.
582  * that is: m_finimName0000.fits. This behavior can be modified with m_exactFinimName.
583  */
584  std::string m_finimName {"finim_"};
585 
586  ///Use m_finimName exactly as specified, without appending a number or an extension.
587  /** Output is still FITS format, regardless of extension. This will overwrite
588  * an existing file without asking.
589  */
590  bool m_exactFinimName {false};
591 
592  ///Controls whether or not the individual PSF subtracted images are written to disk.
593  /** - true -- write to disk
594  * - false -- [default] don't write to disk
595  */
596  bool m_doOutputPSFSub {false};
597 
598  ///Prefix of the FITS file names used to write individual PSF subtracted images to disk if m_doOutputPSFSub is true.
599  std::string m_PSFSubPrefix;
600 
601  /// Output the pre-processed target images
602  void outputPreProcessed();
603 
604  ///Output the pre-processed reference images
606 
607  /// Fill in the HCIobservation standard FITS header
608  /**
609  */
610  void stdFitsHeader(fits::fitsHeader & head /**< [in.out] the fistHeader structure which will have cards appended to it. */);
611 
612  ///Write the final combined image to disk
613  /**
614  */
615  void writeFinim(fits::fitsHeader * addHead = 0);
616 
617  ///Write the PSF subtracted images to disk
618  /**
619  */
620  void outputPSFSub(fits::fitsHeader * addHead = 0);
621 
622 
623  ///@}
624 
625 
626 
627  /// Read in already PSF-subtracted files
628  /** Used to take up final processing after applying some non-klipReduce processing steps to
629  * PSF-subtracted images.
630  */
631  int readPSFSub( const std::string & dir,
632  const std::string & prefix,
633  const std::string & ext,
634  size_t nReductions
635  );
636 
637 
638 
639 
640 
641 
642 
643 
644 
645 
646 
647 
648 
649  double t_begin {0};
650  double t_end {0};
651 
652  double t_load_begin {0};
653  double t_load_end {0};
654 
655  double t_coadd_begin {0};
656  double t_coadd_end {0};
657 
658  double t_preproc_begin {0};
659  double t_preproc_end {0};
660 
661  double t_azusm_begin {0};
662  double t_azusm_end {0};
663 
664  double t_gaussusm_begin {0};
665  double t_gaussusm_end {0};
666 
667 
668  double t_combo_begin {0};
669  double t_combo_end {0};
670 
671 };
672 
673 // -- construction and initialization
674 
675 template<typename _realT>
677 {
678 }
679 
680 template<typename _realT>
681 HCIobservation<_realT>::HCIobservation( const std::string & dir,
682  const std::string & prefix,
683  const std::string & ext
684  )
685 {
686  load_fileList(dir, prefix, ext);
687 }
688 
689 template<typename _realT>
690 HCIobservation<_realT>::HCIobservation(const std::string & fileListFile)
691 {
692  load_fileList(fileListFile);
693 }
694 
695 
696 template<typename _realT>
697 HCIobservation<_realT>::HCIobservation( const std::string & dir,
698  const std::string & prefix,
699  const std::string & ext,
700  const std::string & RDIdir,
701  const std::string & RDIprefix,
702  const std::string & RDIext
703  )
704 {
705  std::cerr << "HCI 6\n";
706 
707  load_fileList(dir, prefix, ext);
708 
709  std::string re;
710  if(RDIext == "") re = ext;
711  else re = RDIext;
712 
713  load_RDIfileList(RDIdir, RDIprefix, re);
714 }
715 
716 
717 
718 template<typename _realT>
719 HCIobservation<_realT>::HCIobservation( const std::string & fileListFile,
720  const std::string & RDIfileListFile
721  )
722 {
723  load_fileList( fileListFile);
724  load_RDIfileList( RDIfileListFile);
725 }
726 
727 template<typename _realT>
728 void HCIobservation<_realT>::load_fileList( const std::string & dir,
729  const std::string & prefix,
730  const std::string & ext
731  )
732 {
733  m_fileList = ioutils::getFileNames(dir, prefix, "", ext);
734  m_filesDeleted = false;
735 }
736 
737 template<typename _realT>
738 void HCIobservation<_realT>::load_fileList(const std::string & fileListFile)
739 {
740  ioutils::readColumns(fileListFile, m_fileList);
741  m_filesDeleted = false;
742 }
743 
744 template<typename _realT>
745 void HCIobservation<_realT>::load_RDIfileList( const std::string & dir,
746  const std::string & prefix,
747  const std::string & ext
748  )
749 {
750  m_RDIfileList = ioutils::getFileNames(dir, prefix, "", ext);
751  m_RDIfilesDeleted = false;
752 }
753 
754 template<typename _realT>
755 void HCIobservation<_realT>::load_RDIfileList( const std::string & fileListFile )
756 {
757  ioutils::readColumns(fileListFile, m_RDIfileList);
758  m_RDIfilesDeleted = false;
759 }
760 
761 // --< construction and initialization
762 
763 
764 template<typename _realT>
766 {
767  if(m_fileList.size() == 0)
768  {
769  mxError("HCIobservation", MXE_FILENOTFOUND, "The target fileList has 0 length, there are no files to be read.");
770  return -1;
771  }
772 
773  //First make the list deletions
774  if(!m_filesDeleted)
775  {
776  if(m_deleteFront > 0)
777  {
778  m_fileList.erase(m_fileList.begin(), m_fileList.begin()+m_deleteFront);
779  }
780 
781  if(m_deleteBack > 0)
782  {
783  m_fileList.erase(m_fileList.end()-m_deleteBack, m_fileList.end());
784  }
785  m_filesDeleted = true;
786  }
787 
788  if( m_fileList.size() == 0)
789  {
790  mxError("HCIobservation", MXE_FILENOTFOUND, "The target fileList has 0 length, there are no files to be read after deletions.");
791  return -1;
792  }
793 
794  if(m_qualityFile != "")
795  {
796  std::cerr << "Thresholding target images...";
797  size_t origsize = m_fileList.size();
798 
799  if( threshold(m_fileList, m_qualityFile, m_qualityThreshold) < 0) return -1;
800 
801  if( m_fileList.size() == 0)
802  {
803  mxError("HCIobservation", MXE_FILENOTFOUND, "The fileList has 0 length, there are no files to be read after thresholding.");
804  return -1;
805  }
806 
807  std::cerr << "Done. Selected " << m_fileList.size() << " out of " << origsize << "\n";
808 
809 
810  if(m_thresholdOnly)
811  {
812  std::cout << "#Files which passed thresholding:\n";
813  for(size_t i=0; i<m_fileList.size(); ++i)
814  {
815  std::cout << m_fileList[i] << "\n";
816  }
817 
818  exit(0);
819  }
820  }
821 
822 
823  if(m_weightFile != "")
824  {
825  if(readWeights() < 0) return -1;
826  }
827 
828  /*----- Append the HCI keywords to propagate them if needed -----*/
829 
830  fits::fitsHeader head;
831 
832  if(m_MJDKeyword != "") head.append(m_MJDKeyword);
833 
834  for(size_t i=0;i<m_keywords.size();++i)
835  {
836  if(head.count(m_keywords[i]) == 0) head.append(m_keywords[i]);
837  }
838 
839  m_heads.clear(); //This is necessary to make sure heads.resize() copies head on a 2nd call
840  m_heads.resize(m_fileList.size(), head);
841 
842  /*----- Read in first image to test size -----*/
843 
844  Eigen::Array<realT, Eigen::Dynamic, Eigen::Dynamic> im;
845 
846  fits::fitsFile<realT> f(m_fileList[0]);
847 
848  f.read(im);
849 
850  //We set imSize to match the first image, but we make it a square.
851  if(m_imSize == 0)
852  {
853  m_imSize = im.rows();
854  if(m_imSize > im.cols()) m_imSize = im.cols();
855  }
856  else
857  {
858  //Now make sure we don't read too much.
859  if(m_imSize > im.rows()) m_imSize = im.rows();
860  if(m_imSize > im.cols()) m_imSize = im.cols();
861  }
862 
863  //And now set the read size so we only read what we want.
864  //the +0.1 is just to make sure we don't have a problem with precision (we shouldn't)/
865  f.setReadSize( floor(0.5*(im.rows()-1) - 0.5*(m_imSize-1) +0.1), floor(0.5*(im.cols()-1.0) - 0.5*(m_imSize-1.0)+0.1), m_imSize, m_imSize);
866  im.resize(m_imSize, m_imSize);
867 
868  /**** Right here is we got to coadd.
869  */
870 
871  //But if not we just do it
872  m_tgtIms.resize(im.rows(), im.cols(), m_fileList.size());
873 
874  t_load_begin = sys::get_curr_time();
875 
876  f.read(m_tgtIms.data(), m_heads, m_fileList);
877 
878  f.setReadSize();
879 
880  /* read in the image timestamps, depending on how MJD is stored in the header */
881  if(m_MJDKeyword != "")
882  {
883  m_imageMJD.resize(m_heads.size());
884 
885  if(m_MJDisISO8601)
886  {
887  for(size_t i=0;i<m_imageMJD.size();++i)
888  {
889  m_imageMJD[i] = sys::ISO8601date2mjd(m_heads[i][m_MJDKeyword].String());
890  }
891  }
892  else
893  {
894  for(size_t i=0;i<m_imageMJD.size();++i)
895  {
896  m_imageMJD[i] = m_heads[i][m_MJDKeyword].template value<realT>()*m_MJDUnits;
897  }
898  }
899  }
900 
901  t_load_end = sys::get_curr_time();
902 
903  m_Nims = m_tgtIms.planes();
904  m_Nrows = m_tgtIms.rows();
905  m_Ncols = m_tgtIms.cols();
906  m_Npix = m_tgtIms.rows()*m_tgtIms.cols();
907 
908  std::cerr << "loading complete\n";
909 
910  std::cerr << "zero-ing NaNs\n";
911  zeroNaNCube(m_tgtIms);
912  std::cerr << "done\n";
913 
914  /*** Now do the post-read actions ***/
915  if( postReadFiles() < 0) return -1;
916 
917  /*** Read in the mask if present ***/
918  readMask();
919 
920 
921  /*** Now begin processing ***/
922  if(!m_skipPreProcess)
923  {
924  /*** Now do any pre-processing ***/
925  if(m_preProcess_beforeCoadd) preProcess(m_tgtIms);
926 
927  if(m_coaddCombineMethod != HCI::noCombine)
928  {
929  std::cerr << "Coadding target images...\n";
930  coaddImages(m_coaddCombineMethod, m_coaddMaxImno, m_coaddMaxTime, m_coaddKeywords, m_imageMJD, m_heads, m_tgtIms);
931 
932  m_Nims = m_tgtIms.planes();
933  m_Nrows = m_tgtIms.rows();
934  m_Ncols = m_tgtIms.cols();
935  m_Npix = m_tgtIms.rows()*m_tgtIms.cols();
936 
937  if( postCoadd() < 0)
938  {
939  std::cerr << "Post coadd error " << __FILE__ << " " << __LINE__ << "\n";
940  return -1;
941  }
942  std::cerr << "Done.\n";
943 
944  //Re-make the mask cube if we coadded...
945  if( m_maskFile != "")
946  {
947  makeMaskCube();
948  }
949  }
950 
951  /*** Now do any pre-processing if not done already***/
952  if(!m_preProcess_beforeCoadd) preProcess(m_tgtIms);
953 
954  outputPreProcessed();
955  }
956 
957 
958  m_filesRead = true;
959 
960  return 0;
961 } //readFiles()
962 
963 template<typename _realT>
965 {
966  return 0;
967 }
968 
969 template<typename _realT>
971 {
972  return 0;
973 }
974 
975 //------------------- readRDIFiles
976 template<typename _realT>
978 {
979 
980  /* First check if the target files have been read */
981  if(m_Nrows == 0 || m_Ncols == 0)
982  {
983  mxError("HCIobservation", MXE_PARAMNOTSET, "The target image size must be set before reading RDI files.");
984  return -1;
985  }
986 
987  if(m_RDIfileList.size() == 0)
988  {
989  mxError("HCIobservation", MXE_FILENOTFOUND, "The RDI fileList has 0 length, there are no files to be read.");
990  return -1;
991  }
992 
993  //First make the list deletions
994  if(!m_RDIfilesDeleted)
995  {
996  if(m_RDIdeleteFront > 0)
997  {
998  m_RDIfileList.erase(m_RDIfileList.begin(), m_RDIfileList.begin()+m_RDIdeleteFront);
999  }
1000 
1001  if(m_RDIdeleteBack > 0)
1002  {
1003  m_RDIfileList.erase(m_RDIfileList.end()-m_RDIdeleteBack, m_RDIfileList.end());
1004  }
1005  m_RDIfilesDeleted = true;
1006  }
1007 
1008  if( m_RDIfileList.size() == 0)
1009  {
1010  mxError("HCIobservation", MXE_FILENOTFOUND, "The RDI fileList has 0 length, there are no files to be read after deletions.");
1011  return -1;
1012  }
1013 
1014  if(m_RDIqualityFile != "")
1015  {
1016  std::cerr << "Thresholding RDI images...";
1017  size_t origsize = m_RDIfileList.size();
1018 
1019  if( threshold(m_RDIfileList, m_RDIqualityFile, m_RDIqualityThreshold) < 0) return -1;
1020 
1021  if( m_RDIfileList.size() == 0)
1022  {
1023  mxError("HCIobservation", MXE_FILENOTFOUND, "The fileList has 0 length, there are no files to be read after thresholding.");
1024  return -1;
1025  }
1026 
1027  std::cerr << "Done. Selected " << m_RDIfileList.size() << " out of " << origsize << "\n";
1028 
1029  }
1030 
1031 
1032  /*----- Append the HCI keywords to propagate them if needed -----*/
1033 
1034  fits::fitsHeader head;
1035 
1036  if(m_MJDKeyword != "") head.append(m_MJDKeyword); //Currently assuming the MJD keyword will be the same
1037 
1038  for(size_t i=0;i<m_RDIkeywords.size();++i)
1039  {
1040  head.append(m_RDIkeywords[i]);
1041  }
1042 
1043  m_RDIheads.clear(); //This is necessary to make sure heads.resize() copies head on a 2nd call
1044  m_RDIheads.resize(m_RDIfileList.size(), head);
1045 
1046 
1047  /*----- Read in first image to adjust size ----*/
1048  Eigen::Array<realT, Eigen::Dynamic, Eigen::Dynamic> im;
1049 
1050  fits::fitsFile<realT> f(m_RDIfileList[0]);
1051 
1052  f.read(im);
1053 
1054  if(im.rows() < m_imSize || im.cols() < m_imSize)
1055  {
1056  mxError("HCIobservation", MXE_SIZEERR, "The reference images are too small, do not match the target images.");
1057  return -1;
1058  }
1059 
1060  //And now set the read size so we only read what we want.
1061  //the +0.1 is just to make sure we don't have a problem with precision (we shouldn't)/
1062  f.setReadSize( floor(0.5*(im.rows()-1) - 0.5*(m_imSize-1) +0.1), floor(0.5*(im.cols()-1.0) - 0.5*(m_imSize-1.0)+0.1), m_imSize, m_imSize);
1063 
1064  m_refIms.resize(m_imSize, m_imSize, m_RDIfileList.size());
1065 
1066  t_load_begin = sys::get_curr_time();
1067 
1068  f.read(m_refIms.data(), m_RDIheads, m_RDIfileList);
1069 
1070  f.setReadSize();
1071 
1072  if(m_MJDKeyword != "")
1073  {
1074  m_RDIimageMJD.resize(m_RDIheads.size());
1075 
1076  if(m_MJDisISO8601)
1077  {
1078  for(size_t i=0;i<m_RDIimageMJD.size();++i)
1079  {
1080  m_RDIimageMJD[i] = sys::ISO8601date2mjd(m_RDIheads[i][m_MJDKeyword].String());
1081  }
1082  }
1083  else
1084  {
1085  for(size_t i=0;i<m_RDIimageMJD.size();++i)
1086  {
1087  m_RDIimageMJD[i] = m_RDIheads[i][m_MJDKeyword].template value<realT>()*m_MJDUnits;
1088  }
1089  }
1090  }
1091 
1092  t_load_end = sys::get_curr_time();
1093 
1094  std::cerr << "loading complete\n";
1095 
1096  std::cerr << "zero-ing NaNs\n";
1097  zeroNaNCube(m_refIms);
1098  std::cerr << "Done.\n";
1099 
1100  /*** Now do the post-read actions ***/
1101  if( postRDIReadFiles() < 0) return -1;
1102 
1103  /*** Now begin processing ***/
1104  if(!m_skipPreProcess)
1105  {
1106  /*** Now do any pre-processing ***/
1107  if(m_preProcess_beforeCoadd) preProcess(m_refIms);
1108 
1109  if(m_coaddCombineMethod != HCI::noCombine)
1110  {
1111  std::cerr << "Coadding reference images...\n";
1112  coaddImages(m_coaddCombineMethod, m_coaddMaxImno, m_coaddMaxTime, m_coaddKeywords, m_RDIimageMJD, m_RDIheads, m_refIms);
1113 
1114  if( postRDICoadd() < 0)
1115  {
1116  std::cerr << "Post coadd error " << __FILE__ << " " << __LINE__ << "\n";
1117  return -1;
1118  }
1119  std::cerr << "Done.\n";
1120  }
1121 
1122  /*** Now do any pre-processing if not done already***/
1123  if(!m_preProcess_beforeCoadd) preProcess(m_refIms);
1124 
1125  //outputRDIPreProcessed();
1126  }
1127 
1128 
1129  m_RDIfilesRead = true;
1130 
1131  return 0;
1132 } //readRDIFiles()
1133 
1134 template<typename _realT>
1136 {
1137  return 0;
1138 }
1139 
1140 template<typename _realT>
1142 {
1143  return 0;
1144 }
1145 
1146 template<typename _realT>
1147 int HCIobservation<_realT>::threshold( std::vector<std::string> & fileList,
1148  const std::string & qualityFile,
1149  realT qualityThreshold
1150  )
1151 {
1152  if(qualityFile == "")
1153  {
1154  mxError("HCIobservation::threshold", MXE_PARAMNOTSET, "qualityFile not set");
1155  return -1;
1156  }
1157 
1158  int origsize = fileList.size();
1159 
1160  std::vector<std::string> qfileNames;
1161  std::vector<realT> imQ;
1162 
1163  //Read the quality file and load it into a map
1164  ioutils::readColumns(qualityFile, qfileNames, imQ);
1165 
1166  std::map<std::string, realT> quality;
1167  for(size_t i=0;i<qfileNames.size();++i) quality[ioutils::pathFilename(qfileNames[i].c_str())] = imQ[i];
1168 
1169  realT q;
1170 
1171  for(size_t i=0; i<fileList.size(); ++i)
1172  {
1173  try
1174  {
1175  q = quality.at(ioutils::pathFilename(fileList[i].c_str()));
1176  }
1177  catch(...)
1178  {
1179  q = qualityThreshold - 1; //Cause it to be erased
1180  }
1181 
1182  if (q < qualityThreshold)
1183  {
1184  fileList.erase(fileList.begin()+i);
1185  --i;
1186  }
1187  }
1188 
1189  return 0;
1190 }
1191 
1192 template<typename _realT>
1193 void HCIobservation<_realT>::coaddImages( int coaddCombineMethod,
1194  int coaddMaxImno,
1195  int coaddMaxTime,
1196  std::vector<std::string> & coaddKeywords,
1197  std::vector<double> & imageMJD,
1198  std::vector<fits::fitsHeader> & heads,
1199  eigenCube<realT> & ims
1200  )
1201 {
1202  std::cerr << "***************************************************************\n";
1203  std::cerr << " *** WARNING *** \n";
1204  std::cerr << " coadding is poorly tested. proceed with caution. \n";
1205  std::cerr << "***************************************************************\n";
1206 
1207 
1208  //Validate setup
1209  if(coaddMaxImno <=0 && coaddMaxTime <= 0) return;
1210 
1211  //Validate combine method
1212  if(coaddCombineMethod == HCI::noCombine) return;
1213 
1214  int Nims = ims.planes();
1215  int Nrows = ims.rows();
1216  int Ncols = ims.cols();
1217 
1218  t_coadd_begin = sys::get_curr_time();
1219 
1220  std::vector<eigenImageT> coadds;
1221 
1222  //We do all math here in double, to avoid losing precision
1223  std::vector<double> avgMJD;
1224  std::vector<std::vector<double> > avgVals;
1225 
1226  int combineMethod = HCI::medianCombine;
1227  if( coaddCombineMethod == HCI::meanCombine) combineMethod = HCI::meanCombine;
1228 
1229  //Index range of images for next coadd
1230  int im0, imF;
1231  im0 = 0;
1232  imF = 1;
1233 
1234  //Accumulate images to coadd into a cube
1235  eigenCube<realT> imsToCoadd;
1236 
1237  //Temporary for combination.
1238  eigenImageT coadd;
1239 
1240  //Accumulate values
1241  double initMJD;
1242  std::vector<double> initVals;
1243  initVals.resize(coaddKeywords.size());
1244 
1245  while(im0 < Nims)
1246  {
1247  //Initialize the accumulators
1248  initMJD = imageMJD[im0];
1249 
1250  for(size_t i=0;i< coaddKeywords.size(); ++i)
1251  {
1252  initVals[i] = heads[im0][coaddKeywords[i]].value<double>();
1253  }
1254 
1255  //Now increment imF, then test whether each variable is now outside the range
1256  bool increment = true;
1257  while(increment == true)
1258  {
1259  ++imF;
1260 
1261  if(imF >= Nims)
1262  {
1263  imF = Nims;
1264  increment = false;
1265  break;
1266  }
1267 
1268  if(imF-im0 > coaddMaxImno && coaddMaxImno > 0)
1269  {
1270  --imF;
1271  increment = false;
1272  break;
1273  }
1274 
1275  ///\todo this should really include end of exposure too.
1276  if( (imageMJD[imF] - imageMJD[im0])*86400.0 > coaddMaxTime && coaddMaxTime > 0)
1277  {
1278  --imF;
1279  increment = false;
1280  break;
1281  }
1282 
1283  }//while(increment == true)
1284  //At this point, imF is the first image NOT to include in the next coadd.
1285 
1286  //Now actually do the accumulation
1287  ///\todo this needs to handle averaging of angles
1288  for(int imno = im0+1; imno < imF; ++imno)
1289  {
1290  initMJD += imageMJD[imno];
1291 
1292  for(size_t i=0;i<coaddKeywords.size(); ++i)
1293  {
1294  initVals[i] += heads[imno][coaddKeywords[i]].value<double>();
1295  }
1296  }
1297 
1298 
1299 
1300  //And then turn them into an average
1301  initMJD /= (imF - im0);
1302  for(size_t i=0;i<coaddKeywords.size(); ++i)
1303  {
1304  initVals[i] /= (imF-im0);
1305  }
1306 
1307  //Extract the images into the temporary
1308  imsToCoadd.resize(Nrows, Ncols, imF-im0);
1309  for(int i =0; i < (imF-im0); ++i)
1310  {
1311  imsToCoadd.image(i) = ims.image(im0 + i);
1312  }
1313 
1314 
1315  //Here do the combine and insert into the vector
1316  if(combineMethod == HCI::medianCombine)
1317  {
1318  imsToCoadd.median(coadd);
1319  }
1320  if(combineMethod == HCI::meanCombine)
1321  {
1322  imsToCoadd.mean(coadd);
1323  }
1324  coadds.push_back(coadd);
1325 
1326  //Insert the new averages
1327  avgMJD.push_back(initMJD);
1328  avgVals.push_back(initVals);
1329 
1330  im0 = imF;
1331  imF = im0 + 1;
1332  }//while(im0 < Nims)
1333 
1334  //Now resize ims and copy the coadds to the new cube
1335  ims.resize(Nrows, Ncols, coadds.size());
1336  Nims = coadds.size();
1337 
1338  for(int i=0;i<Nims;++i) ims.image(i) = coadds[i];
1339 
1340  //Now deal with imageMJD and headers
1341  imageMJD.erase(imageMJD.begin()+Nims, imageMJD.end());
1342  heads.erase(heads.begin()+Nims, heads.end());
1343 
1344  for(int i=0;i<Nims;++i)
1345  {
1346  imageMJD[i] = avgMJD[i];
1347  for(size_t j=0;j<coaddKeywords.size(); ++j)
1348  {
1349  heads[i][coaddKeywords[j]].value(avgVals[i][j]);
1350  }
1351  }
1352 
1353  t_coadd_end = sys::get_curr_time();
1354 
1355 
1356 }//void HCIobservation<_realT>::coaddImages()
1357 
1358 template<typename _realT>
1360 {
1361  /*** Load the mask ***/
1362  if( m_maskFile != "")
1363  {
1364  std::cerr << "creating mask cube\n";
1366  ff.read(m_mask, m_maskFile);
1367 
1368  ///\todo here re-size mask if needed to match imSize
1369  if(m_mask.rows() > m_imSize || m_mask.cols() > m_imSize)
1370  {
1371  eigenImageT tmask = m_mask.block( (int)(0.5*(m_mask.rows()-1) - 0.5*(m_imSize-1)), (int)(0.5*(m_mask.rows()-1) - 0.5*(m_imSize-1)), m_imSize, m_imSize);
1372  m_mask = tmask;
1373  }
1374 
1375  makeMaskCube();
1376  }
1377 
1378 }
1379 
1380 template<typename _realT>
1382 {
1383  if( m_mask.rows() != m_Nrows || m_mask.cols() != m_Ncols)
1384  {
1385  std::cerr << "\nMask is not the same size as images.\n\n";
1386  exit(-1);
1387  }
1388  m_maskCube.resize( m_Nrows, m_Ncols, m_Nims);
1389 
1390  for(int i=0; i< m_Nims; ++i)
1391  {
1392  m_maskCube.image(i) = m_mask;
1393  }
1394 
1395 }
1396 
1397 template<typename _realT>
1399 {
1400  t_preproc_begin = sys::get_curr_time();
1401 
1402  //The mask is applied first, and then after each subsequent P.P. step.
1403  if( m_maskFile != "" && m_preProcess_mask)
1404  {
1405  std::cerr << "Masking . . .\n";
1406  #pragma omp parallel for
1407  for(int i=0;i<ims.planes(); ++i)
1408  {
1409  ims.image(i) *= m_mask;
1410  }
1411  std::cerr << "done\n";
1412  }
1413 
1414  if( m_preProcess_subradprof )
1415  {
1416  std::cerr << "subtracting radial profile . . .\n";
1417 
1418  #pragma omp parallel
1419  {
1420  eigenImageT rp;
1421 
1422  #pragma omp for
1423  for(int i=0;i<ims.planes(); ++i)
1424  {
1425  Eigen::Map<Eigen::Array<realT, Eigen::Dynamic, Eigen::Dynamic> > imRef(ims.image(i));
1426  radprofim(rp, imRef, true);
1427  }
1428  }
1429 
1430  std::cerr << "done\n";
1431 
1432  if( m_maskFile != "" && m_preProcess_mask)
1433  {
1434  std::cerr << "Masking . . .\n";
1435  #pragma omp parallel for
1436  for(int i=0;i<ims.planes(); ++i)
1437  {
1438  ims.image(i) *= m_mask;
1439  }
1440  std::cerr << "done\n";
1441  }
1442  }
1443 
1444  if( m_preProcess_medianUSM_fwhm > 0 )
1445  {
1446  std::cerr << "applying median USM . . .\n";
1447 
1448  eigenImageT medmask;
1449  medmask.resize(ims.rows(), ims.cols());
1450  medmask.setConstant(1);
1451 
1452  for(int z = 0; z < (int)(0.5*m_preProcess_medianUSM_fwhm); ++z)
1453  {
1454  medmask.row(z) = 0;
1455  medmask.row(medmask.rows()-1-z) = 0;
1456  medmask.col(z) = 0;
1457  medmask.col(medmask.cols()-1-z) = 0;
1458  }
1459 
1460  #pragma omp parallel
1461  {
1462  eigenImageT fim, im;
1463  fim.resize(ims.rows(), ims.cols());
1464  im.resize(ims.rows(), ims.cols());
1465 
1466  #pragma omp for
1467  for(int i=0;i<ims.planes(); ++i)
1468  {
1469  im = ims.image(i);
1470  medianSmooth(fim, im, m_preProcess_medianUSM_fwhm);
1471  ims.image(i) = (im-fim)*medmask;
1472  }
1473  }
1474 
1475  if( m_maskFile != "" && m_preProcess_mask)
1476  {
1477  std::cerr << "Masking . . .\n";
1478  #pragma omp parallel for
1479  for(int i=0;i<ims.planes(); ++i)
1480  {
1481  ims.image(i) *= m_mask;
1482  }
1483 
1484  }
1485  std::cerr << "done\n";
1486  }
1487 
1488  if( m_preProcess_gaussUSM_fwhm > 0 )
1489  {
1490  std::cerr << "applying Gauss USM . . .\n";
1491  t_gaussusm_begin = sys::get_curr_time();
1492 
1493  #pragma omp parallel for
1494  for(int i=0;i<ims.planes(); ++i)
1495  {
1496  eigenImageT fim, im;
1497  im = ims.image(i);
1498  filterImage(fim, im, gaussKernel<eigenImage<_realT>,2>(m_preProcess_gaussUSM_fwhm), 0.5*(ims.cols()-1) - m_preProcess_gaussUSM_fwhm*4);
1499  im = (im-fim);
1500  ims.image(i) = im;
1501  }
1502 
1503  if( m_maskFile != "" && m_preProcess_mask)
1504  {
1505  std::cerr << "Masking . . .\n";
1506  #pragma omp parallel for
1507  for(int i=0;i<ims.planes(); ++i)
1508  {
1509  ims.image(i) *= m_mask;
1510  }
1511 
1512  }
1513  t_gaussusm_end = sys::get_curr_time();
1514  std::cerr << "done\n";
1515  }
1516 
1517  if( m_preProcess_azUSM_azW && m_preProcess_azUSM_radW )
1518  {
1519  ipc::ompLoopWatcher<> status( ims.planes(), std::cerr);
1520 
1521  std::cerr << "applying azimuthal USM . . .\n";
1522  t_azusm_begin = sys::get_curr_time();
1523  #pragma omp parallel for
1524  for(int i=0;i<ims.planes(); ++i)
1525  {
1526  eigenImageT fim, im;
1527  im = ims.image(i);
1528  medianFilterImage(fim, im, azBoxKernel<eigenImage<realT>>(m_preProcess_azUSM_radW, m_preProcess_azUSM_azW, m_preProcess_azUSM_maxAz));
1529  im = (im-fim);
1530  ims.image(i) = im;
1531  status.incrementAndOutputStatus();
1532  }
1533 
1534  if( m_maskFile != "" && m_preProcess_mask)
1535  {
1536  std::cerr << "Masking . . .\n";
1537  #pragma omp parallel for
1538  for(int i=0;i<ims.planes(); ++i)
1539  {
1540  ims.image(i) *= m_mask;
1541  }
1542  }
1543 
1544  t_azusm_end = sys::get_curr_time();
1545  std::cerr << "done (" << t_azusm_end - t_azusm_begin << " sec) \n";
1546  }
1547 
1548  t_preproc_end = sys::get_curr_time();
1549 
1550 } //void HCIobservation<_realT>::preProcess()
1551 
1552 template<typename _realT>
1554 {
1555  std::ifstream fin;
1556  std::string str;
1557 
1558  if(m_weightFile == "")
1559  {
1560  mxError("HCIobservation::readWeights", MXE_PARAMNOTSET, "m_weightFile not set");
1561  return -1;
1562  }
1563 
1564  //Read the weight file and load it into a map
1565  std::vector<std::string> wfileNames;
1566  std::vector<realT> imW;
1567 
1568  if( ioutils::readColumns(m_weightFile, wfileNames, imW) < 0) return -1;
1569 
1570  if(imW.size() < m_fileList.size())
1571  {
1572  mxError("HCIobservation::readWeights", MXE_SIZEERR, "not enough weights specified");
1573  return -1;
1574  }
1575 
1576  std::map<std::string, realT> weights;
1577  for(size_t i=0;i<wfileNames.size();++i) weights[ioutils::pathFilename(wfileNames[i].c_str())] = imW[i];
1578 
1579  m_comboWeights.resize(m_fileList.size());
1580 
1581  realT wi;
1582  realT weightSum = 0;
1583  for(size_t i=0; i<m_fileList.size(); ++i)
1584  {
1585  try
1586  {
1587  wi = weights.at(ioutils::pathFilename(m_fileList[i].c_str()));
1588  }
1589  catch(...)
1590  {
1591  mxError("HCIobservation::readWeights", MXE_NOTFOUND, "Weight for a file in m_fileList not found.");
1592  return -1;
1593  }
1594  m_comboWeights[i] = wi;
1595  weightSum += wi;
1596  }
1597 
1598  //Finally normalize the weights
1599  for(size_t i=0; i< m_comboWeights.size(); ++i)
1600  {
1601  m_comboWeights[i] /= weightSum;
1602  }
1603 
1604  return 0;
1605 } //int HCIobservation<_realT>::readWeights()
1606 
1607 template<typename _realT>
1609 {
1610  if(m_combineMethod == HCI::noCombine) return;
1611 
1612  t_combo_begin = sys::get_curr_time();
1613 
1614  //Validate the combineMethod setting
1615  int method = HCI::medianCombine;
1616 
1617  if(m_combineMethod == HCI::medianCombine)
1618  {
1619  method = HCI::medianCombine;
1620  }
1621  else if(m_combineMethod == HCI::meanCombine)
1622  {
1623  method = HCI::meanCombine;
1624  }
1625  else if(m_combineMethod == HCI::sigmaMeanCombine)
1626  {
1627  if(m_sigmaThreshold > 0)
1628  {
1629  method = HCI::sigmaMeanCombine;
1630  }
1631  else
1632  {
1633  method = HCI::meanCombine;
1634  }
1635  }
1636  else if(m_combineMethod == HCI::debug)
1637  {
1638  method = HCI::debug;
1639  }
1640 
1641  //Create and size temporary image for averaging
1642  eigenImageT tfinim;
1643 
1644  m_finim.resize(m_psfsub[0].rows(), m_psfsub[0].cols(), m_psfsub.size());
1645 
1646  //Now cycle through each set of psf subtractions
1647  for(size_t n= 0; n < m_psfsub.size(); ++n)
1648  {
1649  if(method == HCI::medianCombine)
1650  {
1651  m_psfsub[n].median(tfinim);
1652  m_finim.image(n) = tfinim;
1653  }
1654  else if(method == HCI::meanCombine)
1655  {
1656  if(m_comboWeights.size() == (size_t) m_Nims)
1657  {
1658  if( m_maskFile != "" )
1659  {
1660  m_psfsub[n].mean(tfinim, m_comboWeights, m_maskCube, m_minGoodFract);
1661  }
1662  else
1663  {
1664  m_psfsub[n].mean(tfinim, m_comboWeights);
1665  }
1666  }
1667  else
1668  {
1669  if( m_maskFile != "" )
1670  {
1671  m_psfsub[n].mean(tfinim, m_maskCube, m_minGoodFract);
1672  }
1673  else
1674  {
1675  m_psfsub[n].mean(tfinim);
1676  }
1677  }
1678  m_finim.image(n) = tfinim;
1679  }
1680  else if(method == HCI::sigmaMeanCombine)
1681  {
1682  if(m_comboWeights.size() == (size_t) m_Nims)
1683  {
1684  if( m_maskFile != "" )
1685  {
1686  m_psfsub[n].sigmaMean(tfinim, m_comboWeights, m_maskCube, m_sigmaThreshold, m_minGoodFract);
1687  }
1688  else
1689  {
1690  m_psfsub[n].sigmaMean(tfinim, m_comboWeights, m_sigmaThreshold);
1691  }
1692  }
1693  else
1694  {
1695  if( m_maskFile != "" )
1696  {
1697  m_psfsub[n].sigmaMean(tfinim, m_maskCube, m_sigmaThreshold, m_minGoodFract);
1698  }
1699  else
1700  {
1701  m_psfsub[n].sigmaMean(tfinim, m_sigmaThreshold);
1702  }
1703  }
1704  m_finim.image(n) = tfinim;
1705  }
1706  else if(method == HCI::debug)
1707  {
1708  m_finim.image(n) = m_psfsub[n].image(0);
1709  }
1710  }
1711 
1712  t_combo_end = sys::get_curr_time();
1713 } //void HCIobservation<_realT>::combineFinim()
1714 
1715 template<typename _realT>
1717 {
1718  if(m_preProcess_outputPrefix == "") return;
1719 
1720  std::string bname, fname;
1721 
1723 
1724  /** \todo Should add a HISTORY card here */
1725  for(int i=0; i< m_Nims; ++i)
1726  {
1727  bname = m_fileList[i];
1728  fname = m_preProcess_outputPrefix + ioutils::pathFilename(bname.c_str()) + ".fits";
1729  ff.write(fname, m_tgtIms.image(i).data(), m_Ncols, m_Nrows, 1, m_heads[i]);
1730  }
1731 } //void HCIobservation<_realT>::outputPreProcessed()
1732 
1733 template<typename _realT>
1735 {
1736  head.append("", fits::fitsCommentType(), "----------------------------------------");
1737  head.append("", fits::fitsCommentType(), "mx::HCIobservation parameters:");
1738  head.append("", fits::fitsCommentType(), "----------------------------------------");
1739 
1740  head.append<int>("FDELFRNT", m_deleteFront, "images deleted from front of file list");
1741  head.append<int>("FDELBACK", m_deleteBack, "images deleted from back of file list");
1742 
1743 
1744  head.append("QFILE", ioutils::pathFilename(m_qualityFile.c_str()), "quality file for thresholding");
1745  head.append<realT>("QTHRESH", m_qualityThreshold, "quality threshold");
1746  head.append<int>("NUMIMS", m_Nims, "number of images processed");
1747 
1748  head.append<int>("IMSIZE", m_imSize, "image size after reading");
1749 
1750  head.append<std::string>("COADMTHD", HCI::combineMethodStr(m_coaddCombineMethod), "coadd combination method");
1751  if(m_coaddCombineMethod != HCI::noCombine)
1752  {
1753  head.append<int>("COADIMNO", m_coaddMaxImno, "max number of images in each coadd");
1754  head.append<realT>("COADTIME", m_coaddMaxTime, "max time in each coadd");
1755  }
1756  else
1757  {
1758  head.append<int>("COADIMNO", 0, "max number of images in each coadd");
1759  head.append<realT>("COADTIME", 0, "max time in each coadd");
1760  }
1761 
1762  head.append("MASKFILE", m_maskFile, "mask file");
1763 
1764  head.append<int>("PREPROC BEFORE", m_preProcess_beforeCoadd, "pre-process before coadd flag");
1765  head.append<int>("PREPROC MASK", m_preProcess_mask, "pre-process mask flag");
1766  head.append<int>("PREPROC SUBRADPROF", m_preProcess_subradprof, "pre-process subtract radial profile flag");
1767  head.append<realT>("PREPROC AZUSM AZWIDTH", m_preProcess_azUSM_azW, "pre-process azimuthal USM azimuthal width [pixels]");
1768  head.append<realT>("PREPROC AZUSM MAXAZ", m_preProcess_azUSM_maxAz, "pre-process azimuthal USM maximum azimuthal width [degrees]");
1769  head.append<realT>("PREPROC AZUSM RADWIDTH", m_preProcess_azUSM_radW, "pre-process azimuthal USM radial width [pixels]");
1770  head.append<realT>("PREPROC MEDIANUSM FWHM", m_preProcess_medianUSM_fwhm, "pre-process median USM fwhm [pixels]");
1771  head.append<realT>("PREPROC GAUSSUSM FWHM", m_preProcess_gaussUSM_fwhm, "pre-process Gaussian USM fwhm [pixels]");
1772 
1773 }
1774 
1775 template<typename _realT>
1777 {
1778  std::string fname = m_finimName;
1779 
1780  if(m_outputDir != "")
1781  {
1782  mkdir(m_outputDir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
1783 
1784  fname = m_outputDir + "/" + fname;
1785  }
1786 
1787  if(!m_exactFinimName)
1788  {
1789  fname = ioutils::getSequentialFilename(fname, ".fits");
1790  }
1791 
1792  fits::fitsHeader head;
1793 
1794  //Add HCIobservation standard header:
1795  stdFitsHeader(head);
1796 
1797  //Now add the final combination details:
1798  head.append<std::string>("COMBMTHD", HCI::combineMethodStr(m_combineMethod), "combination method");
1799 
1800  if(m_weightFile != "")
1801  head.append("WEIGHTF", m_weightFile, "file containing weights for combination");
1802 
1803 
1804  if(m_combineMethod == HCI::sigmaMeanCombine)
1805  head.append<realT>("SIGMAT", m_sigmaThreshold, "threshold for sigma clipping");
1806 
1807  if(addHead)
1808  {
1809  head.append(*addHead);
1810  }
1811 
1812  fits::fitsHeaderGitStatus(head, "mxlib_uncomp", MXLIB_UNCOMP_CURRENT_SHA1, MXLIB_UNCOMP_REPO_MODIFIED);
1813 
1815 
1816  f.write(fname, m_finim, head);
1817 
1818  std::cerr << "Final image written to: " << fname << "\n";
1819 } //void HCIobservation<_realT>::writeFinim(fits::fitsHeader * addHead)
1820 
1821 template<typename _realT>
1823 {
1824 
1825 
1826  std::string fname;
1827 
1828  fits::fitsHeader head;
1829 
1830  //Add the HCIobservation standard fits header
1831  stdFitsHeader(head);
1832 
1833 
1834  if(addHead)
1835  {
1836  head.append(*addHead);
1837  }
1838 
1839  fits::fitsHeaderGitStatus(head, "mxlib_uncomp", MXLIB_UNCOMP_CURRENT_SHA1, MXLIB_UNCOMP_REPO_MODIFIED);
1840 
1842 
1843  std::ofstream wout;
1844 
1845  if(m_comboWeights.size() > 0)
1846  {
1847  fname = m_PSFSubPrefix + "weights.dat";
1848  if(m_outputDir != "")
1849  {
1850  mkdir(m_outputDir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
1851  fname = m_outputDir + "/" + fname;
1852  }
1853  wout.open(fname);
1854  std::cerr << "writing comboWeights: " << fname << "\n";
1855  }
1856 
1857  char num[256];
1858  for(size_t n=0; n<m_psfsub.size(); ++n)
1859  {
1860  for(int p=0; p< m_psfsub[n].planes(); ++p)
1861  {
1862  snprintf(num, 256, "_%03zu_%05d.fits",n,p);
1863  fname = m_PSFSubPrefix + num;
1864 
1865  if(m_outputDir != "")
1866  {
1867  mkdir(m_outputDir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
1868  fname = m_outputDir + "/" + fname;
1869  }
1870 
1871  fits::fitsHeader h = head;
1872 
1873  h.append(m_heads[p]);
1874 
1875 
1876  f.write(fname, m_psfsub[n].image(p).data(), m_psfsub[n].rows(), m_psfsub[n].cols(), 1, h);
1877 
1878  if(m_comboWeights.size() > 0 && n == 0)
1879  {
1880  wout << fname << " " << m_comboWeights[p] << "\n";
1881  }
1882  }
1883  }
1884 
1885  if(m_comboWeights.size() > 0)
1886  {
1887  wout.close();
1888  }
1889 } //void HCIobservation<_realT>::outputPSFSub(fits::fitsHeader * addHead)
1890 
1891 
1892 
1893 
1894 
1895 template<typename _realT>
1896 int HCIobservation<_realT>::readPSFSub( const std::string & dir,
1897  const std::string & prefix,
1898  const std::string & ext,
1899  size_t nReductions
1900  )
1901 {
1902 
1903 
1904  m_psfsub.resize(nReductions);
1905 
1906  //Load first file to condigure based on its header.
1907  std::vector<std::string> flist = ioutils::getFileNames(dir, prefix, "000", ext);
1908  fits::fitsHeader fh;
1909  eigenImage<realT> im;
1911 
1912  ff.read(im, fh, flist[0]);
1913 
1914  if(fh.count("FDELFRNT") == 0)
1915  {
1916  mxError("KLIPReduction", MXE_PARAMNOTSET, "FDELFRNT not found in FITS header.");
1917  return -1;
1918  }
1919  m_deleteFront = fh["FDELFRNT"].value<int>();
1920  std::cerr << "deleteFront: " << m_deleteFront << "\n";
1921 
1922  if(fh.count("FDELBACK") == 0)
1923  {
1924  mxError("KLIPReduction", MXE_PARAMNOTSET, "FDELBACK not found in FITS header.");
1925  return -1;
1926  }
1927  m_deleteBack = fh["FDELBACK"].value<int>();
1928  std::cerr << "deleteBack: " << m_deleteBack << "\n";
1929 
1930  if(fh.count("QFILE") == 0)
1931  {
1932  mxError("KLIPReduction", MXE_PARAMNOTSET, "QFILE not found in FITS header.");
1933  return -1;
1934  }
1935  m_qualityFile = fh["QFILE"].String();
1936  std::cerr << "qualityFile: " << m_qualityFile << "\n";
1937 
1938  if(fh.count("QTHRESH") == 0)
1939  {
1940  mxError("KLIPReduction", MXE_PARAMNOTSET, "QTHRESH not found in FITS header.");
1941  return -1;
1942  }
1943  m_qualityThreshold = fh["QTHRESH"].value<realT>();
1944  std::cerr << "qualityThreshold: " << m_qualityThreshold << "\n";
1945 
1946  if(fh.count("COADMTHD") == 0)
1947  {
1948  mxError("KLIPReduction", MXE_PARAMNOTSET, "COADMTHD not found in FITS header.");
1949  return -1;
1950  }
1951  m_coaddCombineMethod = HCI::combineMethodFmStr(fh["COADMTHD"].String());
1952  std::cerr << "coaddCombineMethod: " << m_coaddCombineMethod << "\n";
1953 
1954  if(fh.count("COADIMNO") != 0)
1955  {
1956  m_coaddMaxImno = fh["COADIMNO"].value<int>();
1957  std::cerr << "coaddMaxImno: " << m_coaddMaxImno << "\n";
1958  }
1959 
1960  if(fh.count("COADTIME") != 0)
1961  {
1962  m_coaddMaxImno = fh["COADTIME"].value<realT>();
1963  std::cerr << "coaddMaxtime: " << m_coaddMaxTime << "\n";
1964  }
1965 
1966  if(m_maskFile == "")
1967  {
1968  if(fh.count("MASKFILE") == 0)
1969  {
1970  mxError("KLIPReduction", MXE_PARAMNOTSET, "MASKFILE not found in FITS header and not set in configuration.");
1971  return -1;
1972  }
1973  m_maskFile = fh["MASKFILE"].String();
1974  }
1975  std::cerr << "maskFile: " << m_maskFile << "\n";
1976 
1977  if(fh.count("PPBEFORE") == 0)
1978  {
1979  mxError("KLIPReduction", MXE_PARAMNOTSET, "PPBEFORE not found in FITS header.");
1980  return -1;
1981  }
1982  m_preProcess_beforeCoadd = fh["PPBEFORE"].value<int>();
1983  std::cerr << "preProcess_beforeCoadd: " << m_preProcess_beforeCoadd << "\n";
1984 
1985  if(fh.count("PPMASK") == 0)
1986  {
1987  mxError("KLIPReduction", MXE_PARAMNOTSET, "PPMASK not found in FITS header.");
1988  return -1;
1989  }
1990  m_preProcess_mask = fh["PPMASK"].value<int>();
1991  std::cerr << "preProcess_mask: " << m_preProcess_mask << "\n";
1992 
1993  if(fh.count("PPSUBRAD") == 0)
1994  {
1995  mxError("KLIPReduction", MXE_PARAMNOTSET, "PPSUBRAD not found in FITS header.");
1996  return -1;
1997  }
1998  m_preProcess_subradprof = fh["PPSUBRAD"].value<int>();
1999  std::cerr << "preProcess_subradprof: " << m_preProcess_subradprof << "\n";
2000 
2001  if(fh.count("PPAUSMAW") == 0)
2002  {
2003  mxError("KLIPReduction", MXE_PARAMNOTSET, "PPAUSMAW not found in FITS header.");
2004  return -1;
2005  }
2006  m_preProcess_azUSM_azW = fh["PPAUSMAW"].value<realT>();
2007  std::cerr << "preProcess_azUSM_azW: " << m_preProcess_azUSM_azW << "\n";
2008 
2009  if(fh.count("PPAUSMRW") == 0)
2010  {
2011  mxError("KLIPReduction", MXE_PARAMNOTSET, "PPAUSMRW not found in FITS header.");
2012  return -1;
2013  }
2014  m_preProcess_azUSM_radW = fh["PPAUSMRW"].value<realT>();
2015  std::cerr << "preProcess_azUSM_radW: " << m_preProcess_azUSM_radW << "\n";
2016 
2017  if(fh.count("PPGUSMFW") == 0)
2018  {
2019  mxError("KLIPReduction", MXE_PARAMNOTSET, "PPGUSMFW not found in FITS header.");
2020  return -1;
2021  }
2022  m_preProcess_gaussUSM_fwhm = fh["PPGUSMFW"].value<realT>();
2023  std::cerr << "preProcess_gaussUSM_fwhm: " << m_preProcess_gaussUSM_fwhm << "\n";
2024 
2025 
2026  fits::fitsHeader head;
2027 
2028  if(m_MJDKeyword != "") head.append(m_MJDKeyword);
2029 
2030  for(size_t i=0;i<m_keywords.size();++i)
2031  {
2032  head.append(m_keywords[i]);
2033  }
2034 
2035  for(size_t n =0; n<nReductions; ++n)
2036  {
2037  char nstr[5];
2038  int nwr = snprintf(nstr, sizeof(nstr), "%03zu", n);
2039  if(nwr < 0 || n >= sizeof(nstr))
2040  {
2041  std::cerr << "possibly bad formatting in filename\n";
2042  }
2043 
2044 
2045  std::string nprefix = prefix + "_" + nstr + "_";
2046  load_fileList(dir, nprefix, ext);
2047 
2048  if(m_fileList.size() == 0)
2049  {
2050  mxError("HCIobservation", MXE_FILENOTFOUND, "The m_fileList has 0 length, there are no files to be read.");
2051  return -1;
2052  }
2053 
2054  Eigen::Array<realT, Eigen::Dynamic, Eigen::Dynamic> im;
2055 
2056  fits::fitsFile<realT> f(m_fileList[0]);
2057 
2058  fits::fitsHeader fh = head;
2059  f.read(im, fh);
2060 
2061  if(n == 0)
2062  {
2063  std::cerr << fh["FAKEPA"].String() << "\n";
2064  }
2065 
2066  //We set imSize to match the first image, but we make it a square.
2067  if(m_imSize == 0)
2068  {
2069  m_imSize = im.rows();
2070  if(m_imSize > im.cols()) m_imSize = im.cols();
2071  }
2072  else
2073  {
2074  //Now make sure we don't read too much.
2075  if(m_imSize > im.rows()) m_imSize = im.rows();
2076  if(m_imSize > im.cols()) m_imSize = im.cols();
2077  }
2078 
2079  //the +0.1 is just to make sure we don't have a problem with precision (we shouldn't)/
2080  f.setReadSize( floor(0.5*(im.rows()-1) - 0.5*(m_imSize-1) +0.1), floor(0.5*(im.cols()-1.0) - 0.5*(m_imSize-1.0)+0.1), m_imSize, m_imSize);
2081  im.resize(m_imSize, m_imSize);
2082 
2083  if(n > 0)
2084  {
2085  if(m_fileList.size() != (size_t) m_Nims)
2086  {
2087  mxError("HCIobservation", MXE_INVALIDARG, "Different number of images in reductions.");
2088  return -1;
2089  }
2090  if(m_Nrows != im.rows())
2091  {
2092  mxError("HCIobservation", MXE_INVALIDARG, "Different number of rows in reductions.");
2093  return -1;
2094  }
2095  if(m_Ncols != im.cols())
2096  {
2097  mxError("HCIobservation", MXE_INVALIDARG, "Different number of cols in reductions.");
2098  return -1;
2099  }
2100  }
2101  else
2102  {
2103  std::cerr << "found " << nReductions << " sets of " << m_fileList.size() << " " << im.rows() << " x " << im.cols() << " files\n";
2104  }
2105  m_Nims = m_fileList.size();
2106  m_Nrows = im.rows();
2107  m_Ncols = im.cols();
2108  m_Npix = im.rows()*im.cols();
2109 
2110  m_psfsub[n].resize(m_Nrows, m_Ncols, m_Nims);
2111 
2112  m_heads.clear(); //This is necessary to make sure heads.resize() copies head on a 2nd call
2113  m_heads.resize(m_fileList.size(), head);
2114 
2115  t_load_begin = sys::get_curr_time();
2116 
2117  f.read(m_psfsub[n].data(), m_heads, m_fileList);
2118 
2119  f.setReadSize();
2120 
2121  if(m_MJDKeyword != "")
2122  {
2123  m_imageMJD.resize(m_heads.size());
2124 
2125  if(m_MJDisISO8601)
2126  {
2127  for(size_t i=0;i<m_imageMJD.size();++i)
2128  {
2129  m_imageMJD[i] = sys::ISO8601date2mjd(m_heads[i][m_MJDKeyword].String());
2130  }
2131  }
2132  else
2133  {
2134  for(size_t i=0;i<m_imageMJD.size();++i)
2135  {
2136  m_imageMJD[i] = m_heads[i][m_MJDKeyword].template value<realT>()*m_MJDUnits;
2137  }
2138  }
2139  }
2140 
2141  t_load_end = sys::get_curr_time();
2142 
2143  for(size_t n=0; n<m_psfsub.size(); ++n)
2144  {
2145  zeroNaNCube(m_psfsub[n]);
2146  }
2147 
2148  }
2149 
2150  if(m_weightFile != "")
2151  {
2152  std::vector<std::string> fn;
2153  ioutils::readColumns(m_weightFile, fn, m_comboWeights);
2154 
2155  std::cerr << "read: " << m_weightFile << " (" << m_comboWeights.size() << ")\n";
2156  }
2157 
2158  /*** Now do the post-read actions ***/
2159  if( postReadFiles() < 0) return -1;
2160 
2161  readMask();
2162 
2163  m_filesRead = true;
2164 
2165  return 0;
2166 }
2167 
2168 
2169 ///@}
2170 
2171 extern template class HCIobservation<float>;
2172 extern template class HCIobservation<double>;
2173 
2174 } //namespace improc
2175 } //namespace mx
2176 
2177 #endif //__HCIobservation_hpp__
Class to manage interactions with a FITS file.
Definition: fitsFile.hpp:54
int write(const dataT *im, int d1, int d2, int d3, fitsHeader *head)
Write the contents of a raw array to the FITS file.
Definition: fitsFile.hpp:1301
void setReadSize()
Set to read all the pixels in the file.
Definition: fitsFile.hpp:1464
int read(dataT *data)
Read the contents of the FITS file into an array.
Definition: fitsFile.hpp:828
Class to manage a complete fits header.
Definition: fitsHeader.hpp:52
size_t count(const std::string &keyword)
Get number of cards with a given keyword.
Definition: fitsHeader.cpp:97
void append(fitsHeaderCard card)
Append a fitsHeaderCard to the end of the header.
Definition: fitsHeader.cpp:156
void median(eigenT &mim)
Calculate the median image of the cube.
Definition: eigenCube.hpp:548
void mean(eigenT &mim)
Calculate the mean image of the cube.
Definition: eigenCube.hpp:423
Eigen::Map< Eigen::Array< dataT, Eigen::Dynamic, Eigen::Dynamic > > image(Index n)
Returns a 2D Eigen::Eigen::Map pointed at the specified image.
Definition: eigenCube.hpp:376
A class to track the number of iterations in an OMP parallelized loop.
void incrementAndOutputStatus()
Increment and output status.
An image cube with an Eigen API.
Tools for using the eigen library for image processing.
int readColumns(const std::string &fname, arrTs &... arrays)
Read in columns from a text file.
constexpr units::realT h()
Planck Constant.
Definition: constants.hpp:91
Eigen::Array< scalarT, -1, -1 > eigenImage
Definition of the eigenImage type, which is an alias for Eigen::Array.
Definition: eigenImage.hpp:44
std::string getSequentialFilename(const std::string &basename, const std::string &extension="", const int startat=0, int ndigit=4)
Get the next file in a numbered sequence.
Definition: fileUtils.cpp:213
std::vector< std::string > getFileNames(const std::string &directory, const std::string &prefix, const std::string &substr, const std::string &extension)
Get a list of file names from the specified directory, specifying a prefix, a substring to match,...
Definition: fileUtils.cpp:85
std::string pathFilename(const std::string &fname)
Get the base filename.
Definition: fileUtils.cpp:71
void fitsHeaderGitStatus(fitsHeader &head, const std::string &repoName, const char *sha1, int modified)
Write the status of a Git repository to HISTORY in a FITS header.
Definition: fitsHeader.cpp:267
combineMethods
Possible combination methods.
@ sigmaMeanCombine
Combine with the sigma clipped mean.
@ noCombine
Do not combine the images.
@ meanCombine
Combine with the mean.
@ medianCombine
Combine with the median.
int medianSmooth(imageTout &imOut, int &xMax, int &yMax, typename imageTout::Scalar &pMax, const imageTin &imIn, int medianFullWidth)
Smooth an image using the median in a rectangular box. Also Determines the location and value of the ...
void filterImage(imageOutT &fim, imageInT im, kernelT kernel, int maxr=0)
Filter an image with a mean kernel.
void zeroNaNCube(cubeT &imc)
Zero any NaNs in an image cube.
Definition: imageUtils.hpp:93
void radprofim(radprofT &radprofIm, eigenImT1 &im, const eigenImT2 &rad, const eigenImT3 *mask, bool subtract, bool mean=false)
Form a radial profile image, and optionally subtract it from the input.
typeT get_curr_time(timespec &tsp)
Get the current system time in seconds.
Definition: timeUtils.hpp:63
double ISO8601date2mjd(const std::string &fdate)
Parse an ISO8601 date of the form "YYYY-MM-DDTHH:MM:SS.S" and return the modified Julian date (MJD)
Definition: timeUtils.cpp:132
Image filters (smoothing, radial profiles, etc.)
Declares and defines functions to work with image masks.
Image interpolation and transformation.
Header for the image processing utilities.
int combineMethodFmStr(const std::string &method)
Get the combineMethod from the corresponding string name.
std::string combineMethodStr(int method)
Get the string name of the combineMethod integer.
The mxlib c++ namespace.
Definition: mxError.hpp:107
The basic high contrast imaging data type.
int m_imSize
Set the image size. Images are cut down to this size after reading.
int m_RDIdeleteBack
Specify how many files from m_RDIfileList to delete from the back of the list.
bool m_preProcess_only
If true, then we stop after pre-processing.
_realT realT
The arithmetic type used for calculations. Does not have to match the type in images on disk.
std::vector< std::string > m_coaddKeywords
The values of these keywords will be averaged and replaced.
bool m_thresholdOnly
Just prints the names and qualities of the files which pass threshold, and stop.
void stdFitsHeader(fits::fitsHeader &head)
Fill in the HCIobservation standard FITS header.
std::string m_weightFile
Specifies a file containing the image weights, for combining with weighted mean.
std::vector< std::string > m_RDIfileList
The list of files to read in for the RDI basis.
std::vector< std::string > m_RDIkeywords
Vector of FITS header keywords to read from the files in m_fileList.
bool m_preProcess_mask
If true, the mask is applied during each pre-processing step.
std::string m_RDIqualityFile
File containing 2 space-delimited columns of fileMame qualityValue pairs for the reference images.
eigenCube< realT > m_tgtIms
The target image cube.
bool m_RDIfilesRead
Whether or not the reference files have been read.
std::vector< double > m_RDIimageMJD
Vector of reference image times, in MJD.
realT m_MJDUnits
If the date is not ISO 8601, this specifies the conversion to Julian Days (i.e. seconds to days)
int m_preProcess_medianUSM_fwhm
Kernel FWHM for symmetric box median unsharp mask (USM)
bool m_exactFinimName
Use m_finimName exactly as specified, without appending a number or an extension.
int readRDIFiles()
Read the list of reference files, cut to size, and preprocess.
void writeFinim(fits::fitsHeader *addHead=0)
Write the final combined image to disk.
std::vector< fits::fitsHeader > m_RDIheads
Vector of FITS headers, one per reference file, populated with the values for the keywords.
std::string m_preProcess_outputPrefix
Set path and file prefix to output the pre-processed images.
int m_Nrows
Number of rows of the images in m_tgtIms.
void load_RDIfileList(const std::string &dir, const std::string &prefix, const std::string &ext)
Load the RDI basis file list.
int readPSFSub(const std::string &dir, const std::string &prefix, const std::string &ext, size_t nReductions)
Read in already PSF-subtracted files.
int m_deleteBack
Specify how many files from m_fileList to delete from the back of the list.
realT m_minGoodFract
The minimum fraction of good (un-masked) pixels to include in the final combination (0....
std::string m_qualityFile
File containing 2 space-delimited columns of fileVame qualityValue pairs.
eigenImageT m_mask
The mask.
int readWeights()
Read the image weights from m_weightFile.
int m_combineMethod
Determine how to combine the PSF subtracted images.
Eigen::Array< realT, Eigen::Dynamic, Eigen::Dynamic > eigenImageT
The Eigen image array type basted on realT.
int readFiles()
Read the list of files, cut to size, and preprocess.
realT m_preProcess_azUSM_radW
Radial boxcar width for azimuthal unsharp mask [pixels].
realT m_sigmaThreshold
The standard deviation threshold used if combineMethod == HCI::sigmaMeanCombine.
std::string m_finimName
The base file name of the output final image.
bool m_skipPreProcess
Don't do any of the pre-processing steps (including coadding).
int m_Ncols
Number of columns of the images in m_tgtIms.
int m_Nims
Number of images in m_tgtIms.
void readMask()
Read the mask file, resizing to imSize if needed.
int m_coaddMaxImno
Maximum number of images to coadd.
bool m_MJDisISO8601
Whether or not the date is in ISO 8601 format.
bool m_filesRead
Whether or not the m_fileList has been read.
std::string m_outputDir
The directory where to write output files.
bool m_preProcess_subradprof
If true, a radial profile is subtracted from each image.
std::vector< std::string > m_fileList
The list of files to read in.
realT m_coaddMaxTime
Maximum elapsed time over which to coadd the images.
eigenCube< realT > m_maskCube
A cube of masks, one for each input image, which may be modified versions (e.g. rotated) of mask.
virtual void makeMaskCube()
Populate the mask cube which is used for post-processing. Derived classes can do this as appropriate,...
void outputRDIPreProcessed()
Output the pre-processed reference images.
virtual int postCoadd()
Perform post-coadd actions for the target images, for use by derived classes.
void outputPSFSub(fits::fitsHeader *addHead=0)
Write the PSF subtracted images to disk.
std::vector< eigenCube< realT > > m_psfsub
The PSF subtracted images.
std::string m_PSFSubPrefix
Prefix of the FITS file names used to write individual PSF subtracted images to disk if m_doOutputPSF...
bool m_preProcess_beforeCoadd
controls whether pre-processing takes place before or after coadding
void load_fileList(const std::string &dir, const std::string &prefix, const std::string &ext)
Load the file list.
int m_Npix
Pixels per image, that is Nrows*Ncols.
int threshold(std::vector< std::string > &fileList, const std::string &qualityFile, realT qualityThreshold)
Read the image qualities from a qualityFile and apply the threshold to a fileList.
std::string m_MJDKeyword
Name of the keyword to use for the image date.
eigenCube< realT > m_refIms
The optional reference image cube.
std::vector< std::string > m_keywords
Vector of FITS header keywords to read from the files in m_fileList.
bool m_doOutputPSFSub
Controls whether or not the individual PSF subtracted images are written to disk.
realT m_RDIqualityThreshold
Threshold to apply to qualityValues read from qualityFile.
int m_coaddCombineMethod
Determine how to coadd the raw images.
realT m_qualityThreshold
Threshold to apply to qualityValues read from qualityFile.
virtual int postRDIReadFiles()
Perform post-read actions for the RDI images, for use by derived classes.
int m_deleteFront
Specify how many files from m_fileList to delete from the front of the list.
realT m_preProcess_gaussUSM_fwhm
Kernel FWHM for symmetric Gaussian unsharp mask (USM)
virtual int postReadFiles()
Perform post-read actions for the target images, for use by derived classes.
realT m_preProcess_azUSM_azW
Azimuthal boxcar width for azimuthal unsharp mask [pixels].
void coaddImages(int coaddCombineMethod, int coaddMaxImno, int coaddMaxTime, std::vector< std::string > &coaddKeywords, std::vector< double > &imageMJD, std::vector< fits::fitsHeader > &heads, eigenCube< realT > &ims)
Coadd the images.
std::vector< realT > m_comboWeights
Vector to hold the image weights read from the m_weightFile.
std::vector< fits::fitsHeader > m_heads
Vector of FITS headers, one per file, populated with the values for the keywords.
std::string m_maskFile
Specify a mask file to apply.
int m_doWriteFinim
Set whether the final combined image is written to disk.
virtual int postRDICoadd()
Perform post-coadd actions, for use by derived classes.
bool m_filesDeleted
Whether or not the specified files have been deleted from m_fileList.
void combineFinim()
Combine the images into a single final image.
realT m_preProcess_azUSM_maxAz
Mazimum azimuthal boxcar width for azimuthal unsharp mask [degrees].
void preProcess(eigenCube< realT > &ims)
Do the pre-processing.
int m_RDIdeleteFront
Specify how many files from m_RDIfileList to delete from the front of the list.
std::vector< double > m_imageMJD
Vector of target image times, in MJD.
void outputPreProcessed()
Output the pre-processed target images.
eigenCube< realT > m_finim
The final combined images, one for each cube in psfsub.
bool m_RDIfilesDeleted
Whether or not the specified files have been deleted from m_RDIfileList.
Azimuthally variable boxcare kernel.
Symetric Gaussian smoothing kernel.