mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
KLIPreduction.hpp
Go to the documentation of this file.
1 /** \file KLIPreduction.hpp
2  * \author Jared R. Males
3  * \brief Declarations and definitions for an implementation of the Karhunen-Loeve Image Processing (KLIP) algorithm.
4  * \ingroup hc_imaging_files
5  * \ingroup image_processing_files
6  *
7  */
8 
9 
10 
11 #ifndef __KLIPreduction_hpp__
12 #define __KLIPreduction_hpp__
13 
14 
15 #include <vector>
16 #include <map>
17 
18 #include <omp.h>
19 
20 #include "../ipc/ompLoopWatcher.hpp"
21 #include "../math/geo.hpp"
22 #include "../math/eigenLapack.hpp"
23 
24 #include "ADIobservation.hpp"
25 
26 namespace mx
27 {
28 namespace improc
29 {
30 
31 //double t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, tf;
32 //double dcut, dscv, dklims, dgemm, dsyevr, dcfs, drot, dcombo, dread;
33 
34 
35 
36 
37 
38 namespace HCI
39 {
40 
41  ///Mean subtraction methods
42  /** These control how the data in each search region is centered to meet the PCA requirement.
43  * \ingroup hc_imaging_enums
44  */
45  enum meansubMethods{ imageMean, ///< The mean of each image (within the search region) is subtracted from itself
46  imageMedian, ///< The median of each image (within the search region) is subtracted from itself
47  imageMode, ///< The mode of each image (within the search region) is subtracted from itself
48  meanImage, ///< The mean image of the data is subtracted from each image
49  medianImage ///< The median image of the data is subtracted from each image
50  };
51 
52  std::string meansubMethodStr( int method );
53 
54  int meansubMethodFmStr( const std::string & method );
55 
56  ///Image exclusion methods
57  /** \ingroup hc_imaging_enums
58  */
59  enum excludeMethods{ excludeNone, ///< Exclude no images
60  excludePixel, ///< Exclude by pixels of rotation
61  excludeAngle, ///< Exclude by angle of roration
62  excludeImno ///< Exclude by number of images
63  };
64 
65  std::string excludeMethodStr(int method);
66 
67  int excludeMethodFmStr(const std::string & method);
68 
69  ///Image inclusion methods
70  /** \ingroup hc_imaging_enums
71  */
72  enum includeMethods{ includeAll, ///< include all images
73  includeCorr, ///< include images which are most correlated with the target
74  includeTime, ///< include images which are closest in time to the target
75  includeAngle, ///< include images which are closest in angle to the target
76  includeImno ///< include images which are closest in imno to the target
77  };
78 
79  std::string includeMethodStr( int method );
80 
81  int includeMethodFmStr( const std::string & method );
82 }
83 
84 /// An implementation of the Karhunen-Loeve Image Processing (KLIP) algorithm.
85 /** KLIP\cite soummer_2012 is a principle components analysis (PCA) based technique for PSF estimation.
86  *
87  *
88  * \tparam _realT is the floating point type in which to do calculations
89  * \tparam _derotFunctObj the ADIobservation derotator class.
90  * \tparam _evCalcT the real type in which to do eigen-decomposition. Should generally be double for stable results.
91  * \ingroup hc_imaging
92  */
93 template<typename _realT, class _derotFunctObj, typename _evCalcT = double>
94 struct KLIPreduction : public ADIobservation<_realT, _derotFunctObj>
95 {
96  typedef _realT realT;
97 
98  typedef Eigen::Array<realT, Eigen::Dynamic, Eigen::Dynamic> eigenImageT;
99 
100  typedef _evCalcT evCalcT;
101 
102  /// Default c'tor
103  KLIPreduction();
104 
105  /// Construct and load the target file list.
106  /** Populates the \ref m_fileList vector by searching on disk for files which match
107  * "dir/prefix*.ext". See \ref load_fileList
108  *
109  */
110  KLIPreduction( const std::string & dir, ///< [in] the directory to search for files.
111  const std::string & prefix, ///< [in] the prefix of the files
112  const std::string & ext ///< [in] the extension of the files
113  );
114 
115  /// Construct using a file containing the target file list
116  /** Populates the \ref m_fileList vector by reading the file, which should be a single
117  * column of new-line delimited file names.
118  */
119  explicit KLIPreduction( const std::string & fileListFile /**< [in] the full path to a file containing a list of files */ );
120 
121  //Construct and load the target file list and the RDI file list
122  /** Populates the \ref m_fileList vector by searching on disk for files which match
123  * "dir/prefix*.ext". See \ref load_fileList
124  *
125  * Populates the \ref m_RDIfileList vector by searching on disk for files which match
126  * "RDIdir/RDIprefix*.RDIext". See \ref load_RDIfileList
127  */
128  KLIPreduction( const std::string & dir, ///< [in] the directory to search for files.
129  const std::string & prefix, ///< [in] the prefix of the files
130  const std::string & ext, ///< [in] the extension of the files, default is .fits
131  const std::string & RDIdir, ///< [in] the directory to search for the reference files.
132  const std::string & RDIprefix, ///< [in] the initial part of the file name for the reference files. Can be empty "".
133  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.
134  );
135 
136  /// Construct using a file containing the target file list and a file containing the RDI target file list
137  /** Populates the \ref m_fileList vector by reading the file, which should be a single
138  * column of new-line delimited file names.
139  *
140  * Populates the \ref m_RDIfileList vector by reading the file, which should be a single
141  * column of new-line delimited file names.
142  */
143  explicit KLIPreduction( const std::string & fileListFile, ///< [in] a file name path to read for the target file names.
144  const std::string & RDIfileListFile ///< [in] a file name path to read for the reference file names.
145  );
146 
147 
148  virtual ~KLIPreduction();
149 
150 
151 
152 
153 
154 
155 
156  /// Specify how the data are centered for PCA within each search region
157  /** Can have the following values:
158  * - <b>HCI::imageMean</b> = the mean of each image (within the search region) is subtracted from itself
159  * - <b>HCI::imageMedian</b> = the median of each image (within the search region) is subtracted from itself
160  * - <b>HCI::imageMode</b> = the mode of each image (within the search region) is subtracted from itself
161  * - <b>HCI::meanImage</b> = the mean image of the data is subtracted from each image
162  * - <b>HCI::medianImage</b> = the median image of the data is subtracted from each image
163  */
165 
166 
167  int m_padSize {4};
168 
169  /// Specifies the number of modes to include in the PSF.
170  /** The output image is a cube with a plane for each entry in m_Nmodes.
171  * Only the number of eigenvalues required for the maximum value of m_Nmodes
172  * are calculated, so this can have an important impact on speed.
173  *
174  * Can be initialized as:
175  * \code
176  * red.m_Nmodes={5,10,15,20};
177  * \endcode
178  *
179  */
180  std::vector<int> m_Nmodes;
181 
182  int m_maxNmodes {0};
183 
184  /// Specify the minimum pixel difference at the inner edge of the search region
185  realT m_minDPx {0};
186 
187  /// Specify the maximum pixel difference at the inner edge of the search region
188  realT m_maxDPx {0};
189 
190  /// Controls how reference images are excluded, if at all, from the covariance matrix for each target image based on a minimum criterion.
191  /** Can have the following values:
192  * - <b>HCI::excludeNone</b> = no exclusion, all images included [default]
193  * - <b>HCI::excludePixel</b> = exclude based on pixels of rotation at the inner edge of the region
194  * - <b>HCI::excludeAngle</b> = exclude based on degrees of rotation at the inner edge of the region
195  * - <b>HCI::excludeImno</b> = exclude based on number of images
196  */
198 
199  /// Controls how reference images are excluded, if at all, from the covariance matrix for each target image based on a maximum criterion.
200  /** Can have the following values:
201  * - <b>HCI::excludeNone</b> = no exclusion, all images included [default]
202  * - <b>HCI::excludePixel</b> = exclude based on pixels of rotation at the inner edge of the region
203  * - <b>HCI::excludeAngle</b> = exclude based on degrees of rotation at the inner edge of the region
204  * - <b>HCI::excludeImno</b> = exclude based on number of images
205  */
207 
208  ///Number of reference images to include in the covariance matrix
209  /** If > 0, then at most this many images, determined by highest cross-correlation, are included.
210  * This is determined after rotational/image-number exclusion.
211  * If == 0, then all reference images are included.
212  */
213  int m_includeRefNum {0};
214 
215  /// Controls how number of included images is calculated.
216  /** The number of included images is calculated after exclusion is complete.
217  * Can have the following values:
218  * - <b>HCI::includeAll</b> = all remaining images are included [default]
219  * - <b>HCI::includeCorr</b> = the m_includeRefNum of the remaining images which are most correlated with the target are included
220  * - <b>HCI::includeTime</b> = the m_includeRefNum of the remaining images which are closest in time to the target are included
221  * - <b>HCI::includeAngle</b> = the m_includeRefNum of the remaining images which are closest in angle to the target are included
222  * - <b>HCI::includeImno</b> = the m_includeRefNum of the remaining images which are closest in image number to the target are included
223  */
225 
226  eigenImage<int> m_imsIncluded;
227 
228 
229  /// Subtract the basis mean from each of the images
230  /** The mean is subtracted according to m_meanSubMethod.
231  */
232  void meanSubtract( eigenCube<realT> & rims, ///< [in.out] The reference images. These are mean subtracted on output.
233  eigenCube<realT> & tims, ///< [in.out] The target images, which can be the same cube as rims (tested by pointer comparison), in which case they will be ignored. Mean subtractedon output.
234  std::vector<realT> & sds ///< [out] The standard deviation of the mean subtracted refernce images.
235  );
236 
237  std::vector<_realT> m_minr;
238  std::vector<_realT> m_maxr;
239  std::vector<_realT> m_minq;
240  std::vector<_realT> m_maxq;
241 
242  /// Run KLIP in a set of geometric search regions.
243  /** The arguments are 4 vectors, where each entry defines one component of the search region.
244  *
245  * \returns 0 on success
246  * \returns -1 on error
247  *
248  */
249  int regions( std::vector<realT> minr, ///< [in]
250  std::vector<realT> maxr, ///< [in]
251  std::vector<realT> minq, ///< [in]
252  std::vector<realT> maxq ///< [in]
253  );
254 
255  /// Run KLIP in a geometric search region.
256  /** \overload
257  *
258  * \returns 0 on success
259  * \returns -1 on error
260  *
261  */
262  int regions( realT minr, ///< [in]
263  realT maxr, ///< [in]
264  realT minq, ///< [in]
265  realT maxq ///< [in]
266  )
267  {
268  std::vector<realT> vminr(1, minr);
269  std::vector<realT> vmaxr(1, maxr);
270  std::vector<realT> vminq(1, minq);
271  std::vector<realT> vmaxq(1, maxq);
272 
273  return regions(vminr, vmaxr, vminq, vmaxq);
274  }
275 
276  void worker( eigenCube<realT> & rims,
277  eigenCube<realT> & tims,
278  std::vector<size_t> & idx,
279  realT dang,
280  realT dangMax
281  );
282 
283  int finalProcess();
284 
285  int processPSFSub( const std::string & dir,
286  const std::string & prefix,
287  const std::string & ext
288  );
289 
290  double t_worker_begin {0};
291  double t_worker_end {0};
292 
293  double t_eigenv {0};
294  double t_klim {0};
295  double t_psf {0};
296 
297  void dump_times()
298  {
299  printf("KLIP reduction times: \n");
300  printf(" Total time: %f sec\n", this->t_end-this->t_begin);
301  printf(" Loading: %f sec\n", this->t_load_end-this->t_load_begin);
302  printf(" Fake Injection: %f sec\n", this->t_fake_end-this->t_fake_begin);
303  printf(" Coadding: %f sec\n", this->t_coadd_end-this->t_coadd_begin);
304  printf(" Preprocessing: %f sec\n", this->t_preproc_end - this->t_preproc_begin);
305  printf(" Az USM: %f sec\n", this->t_azusm_end - this->t_azusm_begin);
306  printf(" Gauss USM: %f sec\n", this->t_gaussusm_end - this->t_gaussusm_begin);
307  printf(" KLIP algorithm: %f elapsed real sec\n", this->t_worker_end - this->t_worker_begin);
308  double klip_cpu = this->t_eigenv + this->t_klim + this->t_psf;
309  printf(" EigenDecomposition %f cpu sec (%f%%)\n", this->t_eigenv, this->t_eigenv/klip_cpu*100);
310  printf(" KL image calc %f cpu sec (%f%%)\n", this->t_klim, this->t_klim/klip_cpu*100);
311  printf(" PSF calc/sub %f cpu sec (%f%%)\n", this->t_psf, this->t_psf/klip_cpu*100);
312  printf(" Derotation: %f sec\n", this->t_derotate_end-this->t_derotate_begin);
313  printf(" Combination: %f sec\n", this->t_combo_end-this->t_combo_begin);
314  }
315 
316 
317 
318 };
319 
320 template<typename _realT, class _derotFunctObj, typename _evCalcT>
322 {
323 }
324 
325 template<typename _realT, class _derotFunctObj, typename _evCalcT>
327  const std::string & prefix,
328  const std::string & ext
329  ) : ADIobservation<_realT, _derotFunctObj>(dir, prefix, ext)
330 {
331 }
332 
333 template<typename _realT, class _derotFunctObj, typename _evCalcT>
335  ) : ADIobservation<_realT, _derotFunctObj>(fileListFile)
336 {
337 }
338 
339 template<typename _realT, class _derotFunctObj, typename _evCalcT>
341  const std::string & prefix,
342  const std::string & ext,
343  const std::string & RDIdir,
344  const std::string & RDIprefix,
345  const std::string & RDIext
346  ) : ADIobservation<_realT, _derotFunctObj>(dir, prefix, ext, RDIdir, RDIprefix, RDIext)
347 {
348  std::cerr << "KLIP 6\n";
349 }
350 
351 template<typename _realT, class _derotFunctObj, typename _evCalcT>
353  const std::string & RDIfileListFile
354  ) : ADIobservation<_realT, _derotFunctObj>(fileListFile, RDIfileListFile)
355 {
356 }
357 
358 template<typename _realT, class _derotFunctObj, typename _evCalcT>
360 {
361 }
362 
363 template<typename _realT, class _derotFunctObj, typename _evCalcT>
365  eigenCube<realT> & tims,
366  std::vector<_realT> & norms
367  )
368 {
369 
370  norms.resize(ims.planes());
371 
372  if(m_meanSubMethod == HCI::meanImage || m_meanSubMethod == HCI::medianImage)
373  {
374  eigenImageT mean;
375 
376  if(m_meanSubMethod == HCI::meanImage)
377  {
378  ims.mean(mean);
379  }
380  else if(m_meanSubMethod == HCI::medianImage)
381  {
382  ims.median(mean);
383  }
384 
385  for(int n=0;n<ims.planes(); ++n)
386  {
387  ims.image(n) -= mean;
388 
389  realT immean = ims.image(n).mean();
390  norms[n] = (ims.image(n)-immean).matrix().norm();
391  }
392 
393  if(&tims != &ims)
394  {
395  for(int n=0;n<tims.planes(); ++n)
396  {
397  tims.image(n) -= mean;
398  }
399  }
400  }
401  else
402  {
403  realT mean;
404  std::vector<realT> work; //Working memmory for median calc
405 
406  for(int n=0;n<ims.planes(); ++n)
407  {
408  if( m_meanSubMethod == HCI::imageMean )
409  {
410  mean = ims.image(n).mean();
411  }
412  else if(m_meanSubMethod == HCI::imageMedian)
413  {
414  mean = imageMedian(ims.image(n), &work);
415  }
416 
417  ims.image(n) -= mean;
418 
419  //Because we might not have used the mean, we need to re-mean to make this the standard deviation
420  realT immean = ims.image(n).mean();
421  norms[n] = (ims.image(n)-immean).matrix().norm();
422 
423  }
424 
425  if(&tims != &ims)
426  {
427  for(int n=0;n<tims.planes(); ++n)
428  {
429  if( m_meanSubMethod == HCI::imageMean )
430  {
431  mean = tims.image(n).mean();
432  }
433  else if(m_meanSubMethod == HCI::imageMedian)
434  {
435  mean = imageMedian(tims.image(n), &work);
436  }
437 
438  tims.image(n) -= mean;
439  }
440  }
441  }
442 }
443 
444 
445 
446 template<typename _realT, class _derotFunctObj, typename _evCalcT>
448  std::vector<_realT> maxr,
449  std::vector<_realT> minq,
450  std::vector<_realT> maxq
451  )
452 {
453  this->t_begin = sys::get_curr_time();
454 
455  m_minr = minr;
456  m_maxr = maxr;
457  m_minq = minq;
458  m_maxq = maxq;
459 
460 
461  m_maxNmodes = m_Nmodes[0];
462  for(size_t i = 1; i < m_Nmodes.size(); ++i)
463  {
464  if( m_Nmodes[i] > m_maxNmodes) m_maxNmodes = m_Nmodes[i];
465  }
466 
467  std::cerr << "Beginning\n";
468 
469  if(this->m_imSize == 0)
470  {
471  this->m_imSize = 2*(*std::max_element(maxr.begin(),maxr.end()) + m_padSize);
472  }
473 
474  if(!this->m_filesRead)
475  {
476  if( this->readFiles() < 0) return -1;
477  }
478 
479  //CHECK IF RDI HERE
480  if(!this->m_RDIfilesRead && this->m_RDIfileList.size() != 0 )
481  {
482  if( this->readRDIFiles() < 0) return -1;
483  }
484 
485  if(this->m_preProcess_only && !this->m_skipPreProcess)
486  {
487  std::cerr << "Pre-processing complete, stopping.\n";
488  return 0;
489  }
490 
491  std::cerr << "allocating psf subtracted cubes\n";
492  this->m_psfsub.resize(m_Nmodes.size());
493  for(size_t n=0;n<m_Nmodes.size(); ++n)
494  {
495  this->m_psfsub[n].resize(this->m_Nrows, this->m_Ncols, this->m_Nims);
496  this->m_psfsub[n].cube().setZero();
497  }
498 
499  //Make radius and angle images
500  eigenImageT rIm(this->m_Nrows,this->m_Ncols);
501  eigenImageT qIm(this->m_Nrows,this->m_Ncols);
502 
503  radAngImage<math::degreesT<realT>>(rIm, qIm, .5*(this->m_Nrows-1), .5*(this->m_Ncols-1));
504 
505  m_imsIncluded.resize(this->m_Nims,this->m_Nims);
506  m_imsIncluded.setConstant(1);
507 
508  std::cerr << "starting regions " << minr.size() << "\n";
509 
510  //******** For each region do this:
511  for(size_t regno = 0; regno < minr.size(); ++regno)
512  {
513  eigenImageT * maskPtr = 0;
514 
515  if( this->m_mask.rows() == this->m_Nrows && this->m_mask.cols() == this->m_Ncols) maskPtr = &this->m_mask;
516 
517  std::vector<size_t> idx = annulusIndices<math::degreesT<realT>>(rIm, qIm, .5*(this->m_Nrows-1), .5*(this->m_Ncols-1),
518  minr[regno], maxr[regno], minq[regno], maxq[regno], maskPtr);
519 
520  //Create storage for the R-ims and psf-subbed Ims
521  eigenCube<realT> tims(idx.size(), 1, this->m_Nims);
522 
523  //------If doing RDI, create bims
524  eigenCube<realT> rims;
525 
526  if(this->m_refIms.planes() > 0)
527  {
528  rims.resize(idx.size(), 1, this->m_Nims);
529  }
530 
531  //#pragma omp parallel for schedule(static, 1)
532  for(int i=0;i< this->m_Nims; ++i)
533  {
534  auto tim = tims.image(i);
535  cutImageRegion(tim, this->m_tgtIms.image(i), idx, false);
536  }
537 
538  for(int p=0;p<this->m_refIms.planes();++p)
539  {
540  auto rim = rims.image(p);
541  cutImageRegion(rim, this->m_refIms.image(p), idx, false);
542  }
543 
544  realT dang = 0;
545  realT dangMax = 0;
546 
547  if(m_minDPx < 0) m_excludeMethod = HCI::excludeNone;
548  if(m_maxDPx < 0) m_excludeMethodMax = HCI::excludeNone;
549 
550  //------- If doing RDI, excludeMethod and excludeMethodMax must be none!
551  if(this->m_refIms.planes() > 0)
552  {
553  m_excludeMethod = HCI::excludeNone;
554  m_excludeMethodMax = HCI::excludeNone;
555  }
556 
557  if(m_excludeMethod == HCI::excludePixel)
558  {
559  dang = fabs(atan(m_minDPx/minr[regno]));
560  }
561  else if(m_excludeMethod == HCI::excludeAngle)
562  {
563  dang = math::dtor(m_minDPx);
564  }
565  else if(m_excludeMethod == HCI::excludeImno)
566  {
567  dang = m_minDPx;
568  }
569 
570  if(m_excludeMethodMax == HCI::excludePixel)
571  {
572  dangMax = fabs(atan(m_maxDPx/minr[regno]));
573  }
574  else if(m_excludeMethodMax == HCI::excludeAngle)
575  {
576  dangMax = math::dtor(m_maxDPx);
577  }
578  else if(m_excludeMethodMax == HCI::excludeImno)
579  {
580  dangMax = m_maxDPx;
581  }
582 
583  //------- If doing RDI, call this with rims, bims
584  //*** Dispatch the work
585  if(this->m_refIms.planes() > 0) //RDI
586  {
587  std::cerr << "\n\n******* RDI MODE **********\n\n";
588  worker(rims, tims, idx, dang, dangMax);
589  }
590  else //ADI
591  {
592  std::cerr << "\n\n******* ADI MODE **********\n\n";
593  worker(tims, tims, idx, dang, dangMax);
594  }
595  std::cerr << "worker done\n";
596 
597  }
598 
599  fits::fitsFile<int> ffii;
600  ffii.write("imsIncluded.fits", m_imsIncluded);
601 
602 
603  if(finalProcess() < 0)
604  {
605  std::cerr << "Error in final processing\n";
606  }
607 
608  this->t_end = sys::get_curr_time();
609 
610  dump_times();
611 
612  return 0;
613 }
614 
615 struct cvEntry
616 {
617  int index;
618  double cvVal;
619  double angle;
620  bool included {true};
621 };
622 
623 
624 template<typename eigenT, typename eigenTin>
625 void extractRowsAndCols(eigenT & out, const eigenTin & in, const std::vector<size_t> & idx)
626 {
627 
628  out.resize(idx.size(), idx.size());
629 
630  for(size_t i=0; i< idx.size(); ++i)
631  {
632  for(size_t j=0; j < idx.size(); ++j)
633  {
634  out(i,j) = in(idx[i], idx[j]);
635  }
636  }
637 
638 }
639 
640 template<typename eigenT, typename eigenTin>
641 void extractCols(eigenT & out, const eigenTin & in, const std::vector<size_t> & idx)
642 {
643 
644  out.resize(in.rows(), idx.size());
645 
646  for(size_t i=0; i< idx.size(); ++i)
647  {
648  out.col(i) = in.col(idx[i]); //it1->index);
649  }
650 
651 }
652 
653 template<typename realT, typename eigenT, typename eigenTv, class derotFunctObj>
654 void collapseCovar( eigenT & cutCV,
655  const eigenT & CV,
656  const std::vector<realT> & sds,
657  eigenT & rimsCut,
658  const eigenTv & rims,
659  int imno,
660  double dang,
661  double dangMax,
662  int Nims,
663  int excludeMethod,
664  int excludeMethodMax,
665  int includeRefNum,
666  const derotFunctObj & derotF,
667  eigenImage<int> & imsIncluded
668  )
669 {
670  std::vector<cvEntry> allidx(Nims);
671 
672  //std::cerr << "dangs: " << dang << " " << dangMax << "\n";
673 
674 
675  //Initialize the vector of cvEntries
676  for(int i=0; i < Nims; ++i)
677  {
678  allidx[i].index = i;
679  allidx[i].angle = derotF.derotAngle(i);
680 
681  //CV is lower-triangular
682  if(i <= imno)
683  {
684  allidx[i].cvVal = CV(imno,i)/(sds[i]*sds[imno]);
685  }
686  else
687  {
688  allidx[i].cvVal = CV(i,imno)/(sds[i]*sds[imno]);
689  }
690  }
691 
692  if(excludeMethod == HCI::excludePixel || excludeMethod == HCI::excludeAngle )
693  {
694  for(size_t j=0; j < Nims; ++j)
695  {
696  if( fabs(math::angleDiff<math::radiansT<realT>>( derotF.derotAngle(j), derotF.derotAngle(imno))) <= dang ) allidx[j].included = false;
697  }
698  }
699  else if(excludeMethod == HCI::excludeImno)
700  {
701  for(size_t j=0; j < Nims; ++j)
702  {
703  if( fabs( (long) j - imno) <= dang ) allidx[j].included = false;
704  }
705  }
706 
707  if(excludeMethodMax == HCI::excludePixel || excludeMethodMax == HCI::excludeAngle )
708  {
709  for(size_t j=0; j < Nims; ++j)
710  {
711  if( fabs(math::angleDiff<math::radiansT<realT>>( derotF.derotAngle(j), derotF.derotAngle(imno))) > dangMax ) allidx[j].included = false;
712  }
713  }
714  else if(excludeMethodMax == HCI::excludeImno)
715  {
716  for(size_t j=0; j < Nims; ++j)
717  {
718  if( fabs( (long) j - imno) > dangMax ) allidx[j].included = false;
719  }
720  }
721 
722 
723  if( includeRefNum > 0 && (size_t) includeRefNum < allidx.size())
724  {
725  long kept = 0;
726  for(size_t j=0; j < Nims; ++j)
727  {
728  if(allidx[j].included == true) ++kept;
729  }
730 
731  //Get a vector for sorting
732  std::vector<realT> cvVal;
733  cvVal.resize(kept);
734  size_t k = 0;
735  for(size_t j=0; j < Nims; ++j)
736  {
737  if(allidx[j].included == true)
738  {
739  cvVal[k] = allidx[j].cvVal;
740  ++k;
741  }
742  }
743 
744  //Partially sort the correlation values
745  std::nth_element(cvVal.begin(), cvVal.begin()+ (kept-includeRefNum), cvVal.end());
746 
747  realT mincorr = cvVal[kept-includeRefNum];
748  std::cerr << " Minimum correlation: " << mincorr << "\n";
749 
750 
751  for(size_t j=0; j < Nims; ++j)
752  {
753  if( allidx[j].cvVal < mincorr ) allidx[j].included = false;
754  }
755 
756  }
757 
758  std::vector<size_t> keepidx;
759  for(size_t j=0;j<Nims;++j)
760  {
761  imsIncluded(imno,j) = allidx[j].included;
762 
763  if(allidx[j].included) keepidx.push_back(j);
764  }
765 
766  //std::cerr << " Keeping " << keepidx.size() << " reference images out of " << Nims << " (" << Nims-keepidx.size() << " rejected)\n";
767 
768  if(keepidx.size() == 0)
769  {
770  std::cerr << "\n\n" << imno << "\n\n";
771  }
772 
773  extractRowsAndCols(cutCV, CV, keepidx);
774  extractCols(rimsCut, rims, keepidx);
775 
776 }
777 
778 
779 template<typename _realT, class _derotFunctObj, typename _evCalcT>
781  eigenCube<_realT> & tims,
782  std::vector<size_t> & idx,
783  realT dang,
784  realT dangMax
785  )
786 {
787  std::cerr << "beginning worker\n";
788 
789  t_worker_begin = sys::get_curr_time();
790 
791  std::vector<realT> sds;
792 
793  eigenImageT meanim;
794 
795  //*** First mean subtract ***//
796  meanSubtract(rims, tims, sds);
797 
798  //*** Form lower-triangle covariance matrix
799  eigenImageT cv;
800 
801  math::eigenSYRK(cv, rims.cube());
802 
804  ff.write("cv.fits", cv);
805  ipc::ompLoopWatcher<> status( this->m_Nims, std::cerr);
806 
807  //Pre-calculate KL images once if we are exclude none OR IF RDI
808  eigenImageT master_klims;
809  if( m_excludeMethod == HCI::excludeNone && m_excludeMethodMax == HCI::excludeNone && m_includeRefNum == 0)
810  {
811  double teigenv;
812  double tklim;
813 
814  std::cerr << cv.rows() << " " << cv.cols() << " " << rims.rows() << " " << rims.cols() << " " << rims.planes() << " " << m_maxNmodes << "\n";
815  math::calcKLModes<double>(master_klims, cv, rims.cube(), m_maxNmodes, nullptr, &teigenv, &tklim);
816 
817  t_eigenv += teigenv;
818  t_klim += tklim;
819  }
820 
821 
822  //int nTh = 0;
823  #pragma omp parallel //num_threads(20)
824  {
825  //We need local copies for each thread. Only way this works, for whatever reason.
826  eigenImageT cfs; //The coefficients
827  eigenImageT psf;
828  eigenImageT rims_cut;
829  eigenImageT cv_cut;
830  eigenImageT klims;
831 
833 
834  if( m_excludeMethod == HCI::excludeNone && m_excludeMethodMax == HCI::excludeNone && m_includeRefNum == 0 ) //OR RDI
835  {
836  klims = master_klims;
837  }
838 
839  #pragma omp for
840  for(int imno = 0; imno < this->m_Nims; ++imno)
841  {
842 
843  if( m_excludeMethod != HCI::excludeNone || m_excludeMethodMax != HCI::excludeNone || m_includeRefNum != 0 )
844  {
845  collapseCovar<realT>( cv_cut, cv, sds, rims_cut, rims.asVectors(), imno, dang, dangMax, this->m_Nims, this->m_excludeMethod, this->m_excludeMethodMax, this->m_includeRefNum, this->m_derotF, m_imsIncluded);
846 
847  /**** Now calculate the K-L Images ****/
848  double teigenv, tklim;
849  math::calcKLModes(klims, cv_cut, rims_cut, m_maxNmodes, &mem, &teigenv, &tklim);
850  t_eigenv += teigenv;
851  t_klim += tklim;
852  }
853  cfs.resize(1, klims.rows());
854 
855 
856  double t0 = sys::get_curr_time();
857 
858  for(int j=0; j<cfs.size(); ++j)
859  {
860  cfs(j) = klims.row(j).matrix().dot(tims.cube().col(imno).matrix());
861  }
862 
863  for(size_t mode_i =0; mode_i < m_Nmodes.size(); ++mode_i)
864  {
865  psf = cfs(cfs.size()-1)*klims.row(cfs.size()-1);
866 
867  //Count down, since eigenvalues are returned in increasing order
868  // handle case where cfs.size() < m_Nmodes[mode_i], i.e. when more modes than images.
869  for(int j=cfs.size()-2; j>=cfs.size()-m_Nmodes[mode_i] && j >= 0; --j)
870  {
871  psf += cfs(j)*klims.row(j);
872  }
873 
874  //#pragma omp critical
875  insertImageRegion( this->m_psfsub[mode_i].cube().col(imno), tims.cube().col(imno) - psf.transpose(), idx);
876  }
877 
878 
879  t_psf += (sys::get_curr_time() - t0) ;/// omp_get_num_threads();
880 
881  status.incrementAndOutputStatus();
882 
883  } //for imno
884  }//openmp parrallel
885 
886  t_worker_end = sys::get_curr_time();
887 }
888 
889 template<typename _realT, class _derotFunctObj, typename _evCalcT>
891 {
892  if(this->m_postMedSub)
893  {
894  std::cerr << "Subtracting medians in post\n";
895 
896  for(size_t n=0; n<this->m_psfsub.size(); ++n)
897  {
898  #pragma omp parallel
899  {
900  eigenImage<realT> medim;
901 
902  this->m_psfsub[n].median(medim);
903 
904  #pragma omp for
905  for(int i=0; i<this->m_psfsub[n].planes();++i)
906  {
907  this->m_psfsub[n].image(i) -= medim;
908  }
909  }
910  }
911  }
912 
913  if(this->m_doDerotate)
914  {
915  std::cerr << "derotating\n";
916  this->derotate();
917  }
918 
919 
920  if(this->m_combineMethod > 0)
921  {
922  std::cerr << "combining\n";
923  this->combineFinim();
924 
925  }
926 
927  if(this->m_doWriteFinim == true || this->m_doOutputPSFSub == true)
928  {
929  std::cerr << "writing\n";
930 
931  fits::fitsHeader head;
932 
933  this->ADIobservation<_realT, _derotFunctObj>::stdFitsHeader(&head);
934 
935  head.append("", fits::fitsCommentType(), "----------------------------------------");
936  head.append("", fits::fitsCommentType(), "mx::KLIPreduction parameters:");
937  head.append("", fits::fitsCommentType(), "----------------------------------------");
938 
939 
940  head.append("MEANSUBM", HCI::meansubMethodStr(m_meanSubMethod), "PCA mean subtraction method");
941 
942 
943  std::stringstream str;
944 
945  if(m_Nmodes.size() > 0)
946  {
947  for(size_t nm=0;nm < m_Nmodes.size()-1; ++nm) str << m_Nmodes[nm] << ",";
948  str << m_Nmodes[m_Nmodes.size()-1];
949  head.append<char *>("NMODES", (char *)str.str().c_str(), "number of modes");
950  }
951 
952  if(m_minr.size() > 0)
953  {
954  str.str("");
955  for(size_t nm=0;nm < m_minr.size()-1; ++nm) str << m_minr[nm] << ",";
956  str << m_minr[m_minr.size()-1];
957  head.append<char *>("REGMINR", (char *)str.str().c_str(), "region inner edge(s)");
958  }
959 
960  if(m_maxr.size() > 0)
961  {
962  str.str("");
963  for(size_t nm=0;nm < m_maxr.size()-1; ++nm) str << m_maxr[nm] << ",";
964  str << m_maxr[m_maxr.size()-1];
965  head.append<char *>("REGMAXR", (char *)str.str().c_str(), "region outer edge(s)");
966  }
967 
968  if(m_minq.size() > 0)
969  {
970  str.str("");
971  for(size_t nm=0;nm < m_minq.size()-1; ++nm) str << m_minq[nm] << ",";
972  str << m_minq[m_minq.size()-1];
973  head.append<char *>("REGMINQ", (char *)str.str().c_str(), "region minimum angle(s)");
974  }
975 
976  if(m_maxq.size() > 0)
977  {
978  str.str("");
979  for(size_t nm=0;nm < m_maxq.size()-1; ++nm) str << m_maxq[nm] << ",";
980  str << m_maxq[m_maxq.size()-1];
981  head.append<char *>("REGMAXQ", (char *)str.str().c_str(), "region maximum angle(s)");
982  }
983 
984  head.append<std::string>("EXMTHDMN", HCI::excludeMethodStr(m_excludeMethod), "exclusion method (min)");
985  head.append<realT>("MINDPX", m_minDPx, "minimum delta (units based on EXMTHDMN)");
986 
987  head.append<std::string>("EXMTHDMX", HCI::excludeMethodStr(m_excludeMethodMax), "exclusion method (max)");
988  head.append<realT>("MAXDPX", m_maxDPx, "maximum delta (units based on EXMTHDMX)");
989 
990  head.append<std::string>("INMTHDMX", HCI::includeMethodStr(m_includeMethod), "inclusion method");
991  head.append<int>("INCLREFN", m_includeRefNum, "number of images included by INMTHDMX");
992 
993  if(this->m_doWriteFinim == true && this->m_combineMethod > 0)
994  {
995  this->writeFinim(&head);
996  }
997 
998  if(this->m_doOutputPSFSub)
999  {
1000  this->outputPSFSub(&head);
1001  }
1002  }
1003 
1004  return 0;
1005 }
1006 
1007 template<typename _realT, class _derotFunctObj, typename _evCalcT>
1008 int KLIPreduction<_realT, _derotFunctObj, _evCalcT>::processPSFSub( const std::string & dir,
1009  const std::string & prefix,
1010  const std::string & ext
1011  )
1012 
1013 {
1014  std::cerr << "Beginning PSF Subtracted Image Processing\n";
1015 
1016  //Load first file to condigure based on its header.
1017  std::vector<std::string> flist = ioutils::getFileNames(dir, prefix, "000", ext);
1018 
1019  fits::fitsHeader fh;
1020  eigenImage<realT> im;
1021  fits::fitsFile<realT> ff;
1022 
1023  ff.read(im, fh, flist[0]);
1024 
1025  if(fh.count("MEANSUBM") == 0)
1026  {
1027  mxError("KLIPReduction", MXE_PARAMNOTSET, "MEANSUBM not found in FITS header.");
1028  return -1;
1029  }
1030  m_meanSubMethod = HCI::meansubMethodFmStr(fh["MEANSUBM"].String());
1031  std::cerr << "meanSubMethod: " << HCI::meansubMethodStr(m_meanSubMethod) << "\n";
1032 
1033  if(fh.count("NMODES") == 0)
1034  {
1035  mxError("KLIPReduction", MXE_PARAMNOTSET, "NMODES not found in FITS header.");
1036  return -1;
1037  }
1038  ioutils::parseStringVector(m_Nmodes, fh["NMODES"].String(), ",");
1039  if(m_Nmodes.size() == 0)
1040  {
1041  mxError("KLIPReduction", MXE_PARSEERR, "NMODES vector did not parse correctly.");
1042  return -1;
1043  }
1044  std::cerr << "nModes: " << fh["NMODES"].String() << "\n";
1045 
1046  /* -- REGMINR -- */
1047  if(fh.count("REGMINR") == 0)
1048  {
1049  mxError("KLIPReduction", MXE_PARAMNOTSET, "REGMINR not found in FITS header.");
1050  return -1;
1051  }
1052  ioutils::parseStringVector(m_minr, fh["REGMINR"].String(), ",");
1053  if(m_minr.size() == 0)
1054  {
1055  mxError("KLIPReduction", MXE_PARSEERR, "REGMINR vector did not parse correctly.");
1056  return -1;
1057  }
1058  std::cerr << "minr: " << fh["REGMINR"].String() << "\n";
1059 
1060  /* -- REGMAXR -- */
1061  if(fh.count("REGMAXR") == 0)
1062  {
1063  mxError("KLIPReduction", MXE_PARAMNOTSET, "REGMAXR not found in FITS header.");
1064  return -1;
1065  }
1066  ioutils::parseStringVector(m_maxr, fh["REGMAXR"].String(), ",");
1067  if(m_maxr.size() == 0)
1068  {
1069  mxError("KLIPReduction", MXE_PARSEERR, "REGMAXR vector did not parse correctly.");
1070  return -1;
1071  }
1072  std::cerr << "minr: " << fh["REGMAXR"].String() << "\n";
1073 
1074 
1075  /* -- REGMINQ -- */
1076  if(fh.count("REGMINQ") == 0)
1077  {
1078  mxError("KLIPReduction", MXE_PARAMNOTSET, "REGMINQ not found in FITS header.");
1079  return -1;
1080  }
1081  ioutils::parseStringVector(m_minq, fh["REGMINQ"].String(), ",");
1082  if(m_minq.size() == 0)
1083  {
1084  mxError("KLIPReduction", MXE_PARSEERR, "REGMINQ vector did not parse correctly.");
1085  return -1;
1086  }
1087  std::cerr << "minq: " << fh["REGMINQ"].String() << "\n";
1088 
1089  /* -- REGMAXR -- */
1090  if(fh.count("REGMAXR") == 0)
1091  {
1092  mxError("KLIPReduction", MXE_PARAMNOTSET, "REGMAXR not found in FITS header.");
1093  return -1;
1094  }
1095  ioutils::parseStringVector(m_maxq, fh["REGMAXR"].String(), ",");
1096  if(m_maxq.size() == 0)
1097  {
1098  mxError("KLIPReduction", MXE_PARSEERR, "REGMAXR vector did not parse correctly.");
1099  return -1;
1100  }
1101  std::cerr << "minr: " << fh["REGMAXR"].String() << "\n";
1102 
1103  if(fh.count("EXMTHDMN") == 0)
1104  {
1105  mxError("KLIPReduction", MXE_PARAMNOTSET, "EXMTHDMN not found in FITS header.");
1106  return -1;
1107  }
1108  m_excludeMethod = HCI::excludeMethodFmStr(fh["EXMTHDMN"].String());
1109  std::cerr << "excludeMethod: " << HCI::excludeMethodStr(m_excludeMethod) << "\n";
1110 
1111  if(fh.count("MINDPX") == 0)
1112  {
1113  mxError("KLIPReduction", MXE_PARAMNOTSET, "MINDPX not found in FITS header.");
1114  return -1;
1115  }
1116  m_minDPx = fh["MINDPX"].value<realT>();
1117  std::cerr << "minDPx: " << m_minDPx << "\n";
1118 
1119  if(fh.count("EXMTHDMX") == 0)
1120  {
1121  mxError("KLIPReduction", MXE_PARAMNOTSET, "EXMTHDMX not found in FITS header.");
1122  return -1;
1123  }
1124  m_excludeMethodMax = HCI::excludeMethodFmStr(fh["EXMTHDMX"].String());
1125  std::cerr << "excludeMethodMax: " << HCI::excludeMethodStr(m_excludeMethodMax) << "\n";
1126 
1127  if(fh.count("MAXDPX") == 0)
1128  {
1129  mxError("KLIPReduction", MXE_PARAMNOTSET, "MAXDPX not found in FITS header.");
1130  return -1;
1131  }
1132  m_maxDPx = fh["MAXDPX"].value<realT>();
1133  std::cerr << "maxDPx: " << m_maxDPx << "\n";
1134 
1135  if(fh.count("INMTHDMX") == 0)
1136  {
1137  mxError("KLIPReduction", MXE_PARAMNOTSET, "INMTHDMX not found in FITS header.");
1138  return -1;
1139  }
1140  m_includeMethod = HCI::includeMethodFmStr(fh["INMTHDMX"].String());
1141  std::cerr << "includeMethod: " << HCI::includeMethodStr(m_includeMethod) << "\n";
1142 
1143  if(fh.count("INCLREFN") == 0)
1144  {
1145  mxError("KLIPReduction", MXE_PARAMNOTSET, "INCLREFN not found in FITS header.");
1146  return -1;
1147  }
1148  m_includeRefNum = fh["INCLREFN"].value<int>();
1149  std::cerr << "includedRefNum: " << m_includeRefNum << "\n";
1150 
1151 
1152 
1153  this->m_skipPreProcess = true;
1154 
1155  this->m_keywords.clear();
1156 
1157 
1158  this->readPSFSub(dir, prefix, ext, m_Nmodes.size());
1159 
1160 
1161  finalProcess();
1162 
1163  return 0;
1164 }
1165 
1166 ///@}
1167 
1168 
1169 template<typename realT> class ADIDerotator;
1170 
1171 extern template struct KLIPreduction<float, ADIDerotator<float>, float>;
1172 extern template struct KLIPreduction<float, ADIDerotator<float>, double>;
1173 extern template struct KLIPreduction<double, ADIDerotator<double>, double>;
1174 
1175 } //namespace improc
1176 } //namespace mx
1177 
1178 #endif //__KLIPreduction_hpp__
Defines the ADI high contrast imaging data type.
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 median(eigenT &mim)
Calculate the median image of the cube.
Definition: eigenCube.hpp:548
Eigen::Map< Eigen::Array< dataT, Eigen::Dynamic, Eigen::Dynamic > > cube()
Returns a 2D Eigen::Eigen::Map pointed at the entire cube.
Definition: eigenCube.hpp:370
void mean(eigenT &mim)
Calculate the mean image of the cube.
Definition: eigenCube.hpp:423
Eigen::Map< Eigen::Array< dataT, Eigen::Dynamic, Eigen::Dynamic > > asVectors()
Return an Eigen::Eigen::Map of the cube where each image is a vector.
Definition: eigenCube.hpp:394
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.
constexpr units::realT k()
Boltzmann Constant.
Definition: constants.hpp:71
Eigen::Array< scalarT, -1, -1 > eigenImage
Definition of the eigenImage type, which is an alias for Eigen::Array.
Definition: eigenImage.hpp:44
MXLAPACK_INT calcKLModes(eigenT &klModes, eigenT &cv, const eigenT1 &Rims, int n_modes=0, syevrMem< _evCalcT > *mem=0, double *t_eigenv=nullptr, double *t_klim=nullptr)
Calculate the K-L modes, or principle components, given a covariance matrix.
void eigenSYRK(eigenT1 &cv, const eigenT2 &ims)
Calculates the lower triangular part of the covariance matrix of ims.
Definition: eigenLapack.hpp:65
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
angleT::realT angleDiff(typename angleT::realT q1, typename angleT::realT q2)
Calculate the difference between two angles, correctly across 0/360.
Definition: geo.hpp:191
realT dtor(realT q)
Convert from degrees to radians.
Definition: geo.hpp:132
includeMethods
Image inclusion methods.
meansubMethods
Mean subtraction methods.
excludeMethods
Image exclusion methods.
@ includeImno
include images which are closest in imno to the target
@ includeTime
include images which are closest in time to the target
@ includeAngle
include images which are closest in angle to the target
@ includeAll
include all images
@ includeCorr
include images which are most correlated with the target
@ imageMode
The mode of each image (within the search region) is subtracted from itself.
@ imageMean
The mean of each image (within the search region) is subtracted from itself.
@ imageMedian
The median of each image (within the search region) is subtracted from itself.
@ meanImage
The mean image of the data is subtracted from each image.
@ medianImage
The median image of the data is subtracted from each image.
@ excludePixel
Exclude by pixels of rotation.
@ excludeAngle
Exclude by angle of roration.
@ excludeImno
Exclude by number of images.
@ excludeNone
Exclude no images.
void cutImageRegion(imageTout &imout, const imageTin &imin, const std::vector< size_t > &idx, bool resize=true)
Cut out a region of an image specified by an index-mask.
Definition: imageMasks.hpp:777
void insertImageRegion(imageTout imout, const imageTin &imin, const std::vector< size_t > &idx)
Insert a region of an image specified by an index-mask.
Definition: imageMasks.hpp:805
void parseStringVector(std::vector< typeT > &v, const std::string &s, char delim=',')
Parses a string into a vector of tokens delimited by a character.
typeT get_curr_time(timespec &tsp)
Get the current system time in seconds.
Definition: timeUtils.hpp:63
The mxlib c++ namespace.
Definition: mxError.hpp:107
Process an angular differential imaging (ADI) observation.
An implementation of the Karhunen-Loeve Image Processing (KLIP) algorithm.
int m_meanSubMethod
Specify how the data are centered for PCA within each search region.
realT m_minDPx
Specify the minimum pixel difference at the inner edge of the search region.
realT m_maxDPx
Specify the maximum pixel difference at the inner edge of the search region.
int regions(std::vector< realT > minr, std::vector< realT > maxr, std::vector< realT > minq, std::vector< realT > maxq)
Run KLIP in a set of geometric search regions.
void meanSubtract(eigenCube< realT > &rims, eigenCube< realT > &tims, std::vector< realT > &sds)
Subtract the basis mean from each of the images.
int m_includeRefNum
Number of reference images to include in the covariance matrix.
void worker(eigenCube< realT > &rims, eigenCube< realT > &tims, std::vector< size_t > &idx, realT dang, realT dangMax)
int m_excludeMethodMax
Controls how reference images are excluded, if at all, from the covariance matrix for each target ima...
std::vector< int > m_Nmodes
Specifies the number of modes to include in the PSF.
int regions(realT minr, realT maxr, realT minq, realT maxq)
Run KLIP in a geometric search region.
KLIPreduction()
Default c'tor.
int m_includeMethod
Controls how number of included images is calculated.
int m_excludeMethod
Controls how reference images are excluded, if at all, from the covariance matrix for each target ima...
A struct to hold the working memory for eigenSYEVR and maintain it between calls if desired.
Definition: eigenLapack.hpp:85