mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
lyotCoronagraph.hpp
Go to the documentation of this file.
1 /** \file lyotCoronagraph.hpp
2  * \brief Declares and defines a class to describe and optimize a Lyot Coronagraph.
3  * \ingroup imaging_files
4  * \author Jared R. Males (jaredmales@gmail.com)
5  *
6  */
7 
8 //***********************************************************************//
9 // Copyright 2015, 2016, 2017, 2018 Jared R. Males (jaredmales@gmail.com)
10 //
11 // This file is part of mxlib.
12 //
13 // mxlib is free software: you can redistribute it and/or modify
14 // it under the terms of the GNU General Public License as published by
15 // the Free Software Foundation, either version 3 of the License, or
16 // (at your option) any later version.
17 //
18 // mxlib is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 // GNU General Public License for more details.
22 //
23 // You should have received a copy of the GNU General Public License
24 // along with mxlib. If not, see <http://www.gnu.org/licenses/>.
25 //***********************************************************************//
26 
27 #ifndef __lyotCoronagraph_hpp__
28 #define __lyotCoronagraph_hpp__
29 
30 #include <iostream>
31 
32 #include "imagingArray.hpp"
33 #include "imagingUtils.hpp"
34 #include "fraunhoferPropagator.hpp"
35 
36 #include "../ioutils/fits/fitsFile.hpp"
37 #include "../ioutils/fits/fitsUtils.hpp"
38 
39 #include "../improc/eigenImage.hpp"
40 #include "../improc/eigenCube.hpp"
41 
42 namespace mx
43 {
44 
45 namespace wfp
46 {
47 
48 /// The Lyot Coronagraph
49 /** A generalized Lyot coronagraph, which can include a pupil apodization, a focal plane mask with complex transmission, and a
50  * Lyot stop. Light is propagated through the coronagraph plane-by-plane, and the complex wavefront can be accessed at any plane.
51  * Also provides functions for optimizing the pupil apodizer and focal plane mask.
52  *
53  * \ingroup coronagraphs
54  */
55 template<typename _realT, typename _fpmaskFloatT>
57 {
58 public:
59  ///The real floating point type
60  typedef _realT realT;
61 
62  ///The real floating point type for mask calculations.
63  typedef _fpmaskFloatT fpmaskFloatT;
64 
65  ///The complex floating point type
66  typedef std::complex<realT> complexT;
67 
68  ///The wavefront complex field type
69  typedef mx::wfp::imagingArray<std::complex<realT>, fftwAllocator<std::complex<realT> >, 0> complexFieldT;
70 
71  ///The focal plane mask type
72  typedef Eigen::Array< std::complex<fpmaskFloatT>, Eigen::Dynamic, Eigen::Dynamic> fpMaskT;
73 
74  ///The image type
75  typedef Eigen::Array< realT, Eigen::Dynamic, Eigen::Dynamic> imageT;
76 
77 
78 public:
79 
80  ///The directory where coronagraph files are stored
81  std::string m_fileDir {"coron"};
82 
83  ///The linear size of the wavefront in pixels
84  int m_wfSz {0};
85 
86  ///Image containing the pupil apodization.
88 
89 
90  int m_maskSource; ///< 0= read from file, 1 = constructed by makeFocalMask, 2 = trans optimized.
91  std::string m_maskFile; ///< Name of file from which mask was loaded.
92 
93  realT m_maskRad; ///<Radius of mask if it was constructed.
94  realT m_maskTrans; ///<Transmission of mask if it was constructed.
95 
96  ///The focal plane mask.
98 
99  ///Image containing the lyot stop.
101 
102 
103  complexFieldT m_focalPlane;
104 
105  bool m_savePreMaskFocalPlane {false};
106  complexFieldT m_preMaskFocalPlane;
107 
108  bool m_savePreLyotPupilPlane {false};
109  complexFieldT m_preLyotPupilPlane;
110 
111  ///Fraunhofer propagator
113 
114 public:
115 
116  /// Default c'tor
117  lyotCoronagraph();
118 
119  ///Get the wavefront size in pixels
120  /**
121  * \returns the wavefront size in pixels
122  */
123  int wfSz();
124 
125  ///Set the wavefront size in pixels.
126  /**
127  */
128  void wfSz(int sz /**< [in] is the new size */);
129 
130 
131  ///Make the focal plane mask
132  void makeFocalMask( realT rad,
133  fpmaskFloatT trans = 0.0,
134  int sz = 0.0 );
135 
136  ///Load the apodizer from a FITS file
137  /**
138  * \returns 0 on success.
139  * \returns -1 on error.
140  */
141  int loadApodizer( const std::string & apodName /**< [in] is the name of the FITS file containing the apodizer. */);
142 
143  ///Load the focal plane mask from a FITS file
144  /**
145  * \returns 0 on success.
146  * \returns -1 on error.
147  */
148  int loadFocalMask( const std::string & fpmName /**< [in] is the name of the FITS file containing the focal plane mask. */);
149 
150  ///Load the Lyot stop from a FITS file
151  /**
152  * \returns 0 on success.
153  * \returns -1 on error.
154  */
155  int loadLyotStop( const std::string & lyotName /**< [in] is the name of the FITS file containing the lyot stop. */);
156 
157  ///Load the components of the coronagraph from FITS files
158  /**
159  * \returns 0 on success.
160  * \returns -1 on error.
161  */
162  int loadCoronagraph( const std::string & apodName, ///< [in] is the name of the FITS file containing the apodizer.
163  const std::string & fpmName, ///< [in] is the name of the FITS file containing the focal plane mask.
164  const std::string & lyotName ///< [in] is the name of the FITS file containing the lyot stop.
165  );
166 
167  ///Load the components of the coronagraph based in its base name
168  /** Looks in _filDir for the files.
169  *
170  * \returns 0 on success.
171  * \returns -1 on error.
172  */
173  int loadCoronagraph( const std::string & cName /**< [in] is the base name of the coronagraph without directory or file extension. */);
174 
175  void applyApodizer( complexFieldT &pupilPlane );
176  void applyFocalMask( complexFieldT & focalPlane );
177  void applyLyotStop( complexFieldT &lyotPlane );
178 
179  ///Propagate the given pupil-plane wavefront through the coronagraph.
180  int propagate( complexFieldT & pupilPlane /**< [in.out] The wavefront at the input pupil plane. It is modified by the coronagraph. */);
181 
182  int propagate( imageT & fpIntensity, ///< [out] The intensity image in the focal plane. This should be pre-allocated.
183  complexFieldT & pupilPlane ///< [in.out] The wavefront at the input pupil plane. It is modified by the coronagraph.
184  );
185 
186  /// Propagate the given pupil-plane wavefront without the coronagraph.
187  /** For a Lyot coronagraph, this applies the pupil apodization and Lyot stop, but not the FPM, to the given pupil-plane wavefront such
188  * that the result will produce the non-coronagraphic (off-axis) PSF.
189  */
190  int propagateNC( complexFieldT & pupilPlane /**< [in.out] The wavefront at the input pupil plane. It is modified by the coronagraph. */);
191 
192  int propagateNC( imageT & fpIntensity, ///< [out] The intensity image in the focal plane. This should be pre-allocated.
193  complexFieldT & pupilPlane ///< [in.out] The wavefront at the input pupil plane. It is modified by the coronagraph.
194  );
195 
196  ///Optimize the pupil amplitude apodization and focal-plane mask complex transmission.
197  /** Uses the algorithm in Guyon (2014) \cite guyon_2014 for optimizing an Apodized-Pupil Lyot Complex Mask Coronagraph (APLCMC).
198  *
199  */
200  void optimizeAPLCMC( imageT & geomPupil, ///< The geometric pupil mask, binary 1/0 transmission.
201  realT fpmRadPix, ///< The radius in pixels of the FPM.
202  realT relTol, ///< Relative tolerance for convergence.
203  realT absTol, ///< Absolute tolerance for convergence.
204  int maxIter, ///< Maximum number of iterations to allow.
205  const std::string & cname ///< Name of coronagraph, used as base-name for output files in m_fileDir.
206  );
207 
208  void optimizeAPLCMC( imageT & geomPupil, ///< The geometric pupil mask, binary 1/0 transmission.
209  realT fpmRadPix, ///< The radius in pixels of the FPM.
210  imageT & fpmPhase,
211  realT relTol, ///< Relative tolerance for convergence.
212  realT absTol, ///< Absolute tolerance for convergence.
213  int maxIter, ///< Maximum number of iterations to allow.
214  const std::string & cname ///< Name of coronagraph, used as base-name for output files in m_fileDir.
215  );
216 
217 };
218 
219 template<typename _realT, typename _fpmaskFloatT>
221 {
222 }
223 
224 template<typename _realT, typename _fpmaskFloatT>
226 {
227  return m_wfSz;
228 }
229 
230 template<typename _realT, typename _fpmaskFloatT>
232 {
233  m_wfSz = sz;
234 
235  m_fp.setWavefrontSizePixels(sz);
236  m_focalPlane.resize(sz, sz);
237 
238 }
239 
240 template<typename _realT, typename _fpmaskFloatT>
242  _fpmaskFloatT trans,
243  int sz )
244 {
245  if(sz == 0)
246  {
247  sz = 2*rad+1;
248  if(sz % 2 == 1) ++sz;
249  }
250 
251  //Make a real circular mask
253  mx::wfp::circularPupil( fpm, 0., rad);
254 
255  //Convert to complex amplitude
256  m_focalMask.resize(sz,sz);
257  for(int i=0; i<sz; ++i)
258  {
259  for(int j=0; j<sz; ++j)
260  {
261  if(fpm(i,j) == 1) m_focalMask(i,j) = std::complex<fpmaskFloatT>(trans,0);
262  else m_focalMask(i,j) = std::complex<fpmaskFloatT>(1,0);
263  }
264  }
265 
266  m_maskSource = 1;
267  m_maskFile = "";
268  m_maskRad = rad;
269  m_maskTrans = 0.0;
270 
271 }
272 
273 template<typename _realT, typename _fpmaskFloatT>
275 {
277 
278  return ff.read(m_pupilApodizer, apodName);
279 
280 }
281 
282 template<typename _realT, typename _fpmaskFloatT>
284 {
287 
288  if(ff.read(fpm, fpmName) < 0) return -1;
289 
290  if(fpm.planes()==1)
291  {
292  m_focalMask = fpm.image(0);
293  }
294  else if(fpm.planes()==2)
295  {
296  m_focalMask.resize( fpm.rows(), fpm.cols());
297 
298  for( int r = 0; r < fpm.rows(); ++r)
299  {
300  for( int c = 0; c < fpm.cols(); ++c)
301  {
302  m_focalMask(r,c) = fpm.image(0)(r,c)*exp( std::complex<fpmaskFloatT>(0, fpm.image(1)(r,c)));
303  }
304  }
305  }
306  else
307  {
308  std::cerr << "too many planes in focal mask file\n";
309  return -1;
310  }
311 
312  m_maskSource = 0;
313  m_maskFile = fpmName;
314  m_maskRad = 0.0;
315  m_maskTrans = 0.0;
316 
317  return 0;
318 }
319 
320 template<typename _realT, typename _fpmaskFloatT>
322 {
324 
325  return ff.read(m_lyotStop, lyotName);
326 
327 }
328 
329 template<typename _realT, typename _fpmaskFloatT>
331  const std::string & fpmName,
332  const std::string & lyotName)
333 {
334  if(loadApodizer(apodName) < 0) return -1;
335  if(loadFocalMask(fpmName) < 0) return -1;
336  if(loadLyotStop(lyotName) < 0) return -1;
337 
338  return 0;
339 }
340 
341 template<typename _realT, typename _fpmaskFloatT>
343 {
344  if( m_fileDir == "")
345  {
346  mxError("lyotCoronagraph", MXE_PARAMNOTSET, "file directory (fileDir) not set.");
347  return -1;
348  }
349 
350  std::string apodName= m_fileDir + "/" + cName + "_apod.fits";
351  std::string fpmName = m_fileDir + "/" + cName + "_fpm.fits";
352  std::string lyotName = m_fileDir + "/" + cName + "_lyot.fits";
353 
354  return loadCoronagraph(apodName, fpmName, lyotName);
355 }
356 
357 template<typename _realT, typename _fpmaskFloatT>
358 void lyotCoronagraph<_realT, _fpmaskFloatT>::applyApodizer( complexFieldT &pupilPlane )
359 {
360  int sz = m_pupilApodizer.rows();
361 
362  realT w = 0.5*(sz - 1.0);
363 
364  realT xc = 0.5*(pupilPlane.rows() - 1);
365  realT yc = 0.5*(pupilPlane.cols() - 1);
366 
367  for(int i=0; i<pupilPlane.rows(); ++i)
368  {
369  for(int j=0; j<pupilPlane.cols(); ++j)
370  {
371  if(i >= xc-w && i <= xc+w && j >= yc-w && j <= yc+w) pupilPlane( i, j) *= m_pupilApodizer((int)(i-(xc-w)),(int)(j-(yc-w)));
372  else pupilPlane(i,j) *= 0;
373  }
374  }
375 
376 }
377 
378 template<typename _realT, typename _fpmaskFloatT>
379 void lyotCoronagraph<_realT, _fpmaskFloatT>::applyFocalMask( complexFieldT &focalPlane )
380 {
381  int sz = m_focalMask.rows();
382 
383  realT w = 0.5*(sz - 1.0);
384 
385  realT xc = 0.5*(focalPlane.rows() - 1);
386  realT yc = 0.5*(focalPlane.cols() - 1);
387 
388  for(int i=0; i<sz; ++i)
389  {
390  for(int j=0; j<sz; ++j)
391  {
392  focalPlane( xc - w + i, yc - w + j ) *= m_focalMask(i,j);
393  }
394  }
395 
396 }
397 
398 template<typename _realT, typename _fpmaskFloatT>
399 void lyotCoronagraph<_realT, _fpmaskFloatT>::applyLyotStop( complexFieldT & lyotPlane )
400 {
401  int sz = m_lyotStop.rows();
402 
403  realT w = 0.5*(sz - 1.0);
404 
405  realT xc = 0.5*(lyotPlane.rows() - 1);
406  realT yc = 0.5*(lyotPlane.cols() - 1);
407 
408  for(int i=0; i< lyotPlane.rows(); ++i)
409  {
410  for(int j=0; j< lyotPlane.cols(); ++j)
411  {
412  if(i >= xc-w && i <= xc+w && j >= yc-w && j <= yc+w) lyotPlane( i, j) *= m_lyotStop((int)(i - (xc-w)),(int)(j - (yc-w)));
413  else lyotPlane(i,j) = 0;
414  }
415  }
416 
417 }
418 
419 template<typename _realT, typename _fpmaskFloatT>
421 {
422  applyApodizer( pupilPlane);
423 
424  m_fp.propagatePupilToFocal(m_focalPlane, pupilPlane);
425 
426  if(m_savePreMaskFocalPlane)
427  {
428  m_preMaskFocalPlane = m_focalPlane;
429  }
430 
431  applyFocalMask( m_focalPlane);
432 
433  m_fp.propagateFocalToPupil(pupilPlane, m_focalPlane);
434 
435  if(m_savePreLyotPupilPlane)
436  {
437  m_preLyotPupilPlane = pupilPlane;
438  }
439 
440  applyLyotStop( pupilPlane);
441 
442  return 0;
443 }
444 
445 template<typename _realT, typename _fpmaskFloatT>
447  complexFieldT & pupilPlane
448  )
449 {
450  propagate(pupilPlane);
451 
452  m_fp.propagatePupilToFocal(m_focalPlane, pupilPlane);
453 
454  int x0 = 0.5*(m_wfSz-1) - 0.5*(fpIntensity.rows()-1);
455  int y0 = 0.5*(m_wfSz-1) - 0.5*(fpIntensity.cols()-1);
456 
457  extractIntensityImage(fpIntensity,0, fpIntensity.rows(),0,fpIntensity.cols(), m_focalPlane, x0,y0);
458 
459  return 0;
460 }
461 template<typename _realT, typename _fpmaskFloatT>
463 {
464  applyApodizer( pupilPlane);
465 
466  m_fp.propagatePupilToFocal(m_focalPlane, pupilPlane);
467 
468  m_fp.propagateFocalToPupil(pupilPlane, m_focalPlane);
469 
470  applyLyotStop( pupilPlane);
471 
472  return 0;
473 }
474 
475 template<typename _realT, typename _fpmaskFloatT>
477  complexFieldT & pupilPlane
478  )
479 {
480  propagateNC(pupilPlane);
481 
482  m_fp.propagatePupilToFocal(m_focalPlane, pupilPlane);
483 
484  int x0 = 0.5*(m_wfSz-1) - 0.5*(fpIntensity.rows()-1);
485  int y0 = 0.5*(m_wfSz-1) - 0.5*(fpIntensity.cols()-1);
486 
487  extractIntensityImage(fpIntensity,0, fpIntensity.rows(),0,fpIntensity.cols(), m_focalPlane, x0,y0);
488 
489  return 0;
490 }
491 
492 
493 template<typename _realT, typename _fpmaskFloatT>
495  realT fpmRadPix,
496  realT relTol,
497  realT absTol,
498  int maxIter,
499  const std::string & cname )
500 {
501  complexFieldT focalPlane, pupilPlane;
502 
503  pupilPlane.resize(m_wfSz, m_wfSz);
504  focalPlane.resize(m_wfSz, m_wfSz);
505 
506  mx::wfp::imagingArray<realT,fftwAllocator<realT>, 0> mask(m_wfSz, m_wfSz);
507  mx::wfp::circularPupil( mask, 0., fpmRadPix);
508  /*for(int c=0; c< mask.cols()*0.5; ++c)
509  {
510  for(int r=0; r < mask.rows(); ++r) mask(r,c) = 0;
511  }*/
512 
513  //Initialize pupilImage
514  mx::wfp::imagingArray<realT,fftwAllocator<realT>, 0> pupilImage(m_wfSz, m_wfSz);
515  pupilImage.setZero();
516 
517  int gpLLi = 0.5*(m_wfSz-1) - 0.5*(geomPupil.rows()-1);
518  int gpLLj = 0.5*(m_wfSz-1) - 0.5*(geomPupil.cols()-1);
519 
520  int gpURi = gpLLi + geomPupil.rows();
521  int gpURj = gpLLj + geomPupil.cols();
522 
523  for(int i=0;i<geomPupil.rows();++i)
524  {
525  for(int j=0;j< geomPupil.cols();++j)
526  {
527  pupilImage(gpLLi + i, gpLLj + j) = geomPupil(i,j);
528  }
529  }
530 
531  realT lastLambdaA, LambdaA;
532 
533  lastLambdaA = 1;
534  int n;
535  std::string reason;
536  for(n=0; n< maxIter; ++n)
537  {
538  mx::wfp::makeComplexPupil(pupilPlane, pupilImage, m_wfSz);
539 
540  m_fp.propagatePupilToFocal(focalPlane, pupilPlane);
541 
542  for(int i=0; i < m_wfSz; ++i)
543  {
544  for(int j=0;j < m_wfSz; ++j)
545  {
546  focalPlane(i,j) *= mask(i,j);
547  }
548  }
549 
550  m_fp.propagateFocalToPupil(pupilPlane, focalPlane);
551 
552  for(int i=0; i< m_wfSz; ++i) for(int j=0;j< m_wfSz; ++j) pupilImage(i,j) = abs(pupilPlane(i,j));
553 
554 
555  LambdaA = 0;
556  for(int i=0; i< m_wfSz; ++i)
557  {
558  for(int j=0;j< m_wfSz; ++j)
559  {
560  if( i >= gpLLi && i < gpURi && j >= gpLLj && j < gpURj)
561  {
562  pupilImage(i,j) *= geomPupil(i-gpLLi,j-gpLLj);
563  if(pupilImage(i,j) > LambdaA) LambdaA = pupilImage(i,j);
564  }
565  else
566  {
567  pupilImage(i,j) = 0;
568  }
569  }
570  }
571  //LambdaA = 1.0/LambdaA;
572  for(int i=0; i< m_wfSz; ++i) for(int j=0;j<m_wfSz; ++j) pupilImage(i,j) /= LambdaA;
573 
574  std::cout << n << " " << LambdaA << "\n";
575  if( fabs(LambdaA - lastLambdaA) < absTol)
576  {
577  std::cout << "Converged on absTol.\n";
578  reason = "absTol";
579  break;
580  }
581  if( fabs((LambdaA - lastLambdaA)/lastLambdaA) < relTol)
582  {
583  std::cout << "Converged on relTol.\n";
584  reason = "relTol";
585  break;
586  }
587 
588  if(n == maxIter - 1)
589  {
590  std::cout << "maxIter reached.\n";
591  reason = "maxIter";
592  }
593 
594  lastLambdaA = LambdaA;
595  }
596  if(LambdaA > 1) LambdaA = 1;
597 
598  std::cout << "LambdaA: = " << LambdaA << "\n";
599 
600  realT trans = 1.0 - 1.0/LambdaA;
601 
602  int pupSize = geomPupil.rows();
603 
604  m_pupilApodizer.resize(pupSize, pupSize);
605 
606  extractBlock(m_pupilApodizer, 0, pupSize, 0, pupSize, pupilImage, 0.5*( (pupilImage.rows()-1) - (pupSize-1)), 0.5*( (pupilImage.rows()-1) - (pupSize-1)));
607 
608  makeFocalMask(fpmRadPix, trans, pupSize);
609 
610  /*for(int c=0; c< m_focalMask.cols()*0.5; ++c)
611  {
612  for(int r=0; r < m_focalMask.rows(); ++r)
613  {
614  if(m_focalMask(r,c).real()==1) m_focalMask(r,c) = 0;
615  }
616  }*/
617 
618  m_maskSource = 2;
619 
620  m_lyotStop = geomPupil;
621 
622 
623  fits::fitsHeader head;
624 
625  head.append("", fits::fitsCommentType(), "----------------------------------------");
626  head.append("", fits::fitsCommentType(), "lyotCoronagraph optimization Parameters:");
627  head.append("", fits::fitsCommentType(), "----------------------------------------");
628  head.append<int>("WFSZ", m_wfSz, "Size of wavefront used for FFTs (pixels)");
629  head.append<realT>("FPMRADPX", fpmRadPix, "input radius of focal plane mask (pixels)");
630  head.append<realT>("ABSTOL", absTol , "input absolute tolerance");
631  head.append<realT>("RELTOL", relTol , "input relative tolerance");
632  head.append<int>("MAXITER", maxIter , "input maximum iterations");
633  head.append<int>("NITER", n , "actual number of iterations");
634  head.append<std::string>("XREASON", reason , "reason for convergence");
635  head.append<realT>("FPMTRANS", trans, "transmission of FPM");
636 
637 
639 
640  std::string fname = "coron/" + cname + "_apod.fits";
641 
642  ff.write(fname, m_pupilApodizer, head);
643 
644  fname = "coron/" + cname + "_fpm.fits";
645  improc::eigenImage<fpmaskFloatT> fpm(m_focalMask.rows(), m_focalMask.cols());
646  for(int r=0;r<m_focalMask.rows(); ++r)
647  {
648  for(int c=0; c< m_focalMask.cols(); ++c)
649  {
650  fpm(r,c) = m_focalMask(r,c).real();
651  }
652  }
653 
654  ff.write(fname, fpm,head);
655 
656  fname = "coron/" + cname + "_lyot.fits";
657  ff.write(fname, m_lyotStop, head);
658 }
659 
660 template<typename _realT, typename _fpmaskFloatT>
662  realT fpmRadPix,
663  imageT & fpmPhase,
664  realT relTol,
665  realT absTol,
666  int maxIter,
667  const std::string & cname )
668 {
669  complexFieldT focalPlane, pupilPlane;
670 
671  pupilPlane.resize(m_wfSz, m_wfSz);
672  focalPlane.resize(m_wfSz, m_wfSz);
673 
674  mx::wfp::imagingArray<realT,fftwAllocator<realT>, 0> mask(m_wfSz, m_wfSz);
675  mx::wfp::circularPupil( mask, 0., fpmRadPix);
676 
677  //Initialize pupilImage
678  mx::wfp::imagingArray<realT,fftwAllocator<realT>, 0> pupilImage(m_wfSz, m_wfSz);
679  pupilImage.setZero();
680 
681  int gpLLi = 0.5*(m_wfSz-1) - 0.5*(geomPupil.rows()-1);
682  int gpLLj = 0.5*(m_wfSz-1) - 0.5*(geomPupil.cols()-1);
683 
684  int gpURi = gpLLi + geomPupil.rows();
685  int gpURj = gpLLj + geomPupil.cols();
686 
687  for(int i=0;i<geomPupil.rows();++i)
688  {
689  for(int j=0;j< geomPupil.cols();++j)
690  {
691  pupilImage(gpLLi + i, gpLLj + j) = geomPupil(i,j);
692  }
693  }
694 
695  realT lastLambdaA, LambdaA;
696 
697  lastLambdaA = 1;
698  int n;
699  std::string reason;
700  for(n=0; n< maxIter; ++n)
701  {
702  mx::wfp::makeComplexPupil(pupilPlane, pupilImage, m_wfSz);
703 
704  m_fp.propagatePupilToFocal(focalPlane, pupilPlane);
705 
706  for(int i=0; i < m_wfSz; ++i)
707  {
708  for(int j=0;j < m_wfSz; ++j)
709  {
710  focalPlane(i,j) *= mask(i,j)*exp( std::complex<realT>(0, fpmPhase(i,j)));;
711  }
712  }
713 
714  m_fp.propagateFocalToPupil(pupilPlane, focalPlane);
715 
716  for(int i=0; i< m_wfSz; ++i) for(int j=0;j< m_wfSz; ++j) pupilImage(i,j) = abs(pupilPlane(i,j));
717 
718 
719  LambdaA = 0;
720  for(int i=0; i< m_wfSz; ++i)
721  {
722  for(int j=0;j< m_wfSz; ++j)
723  {
724  if( i >= gpLLi && i < gpURi && j >= gpLLj && j < gpURj)
725  {
726  pupilImage(i,j) *= geomPupil(i-gpLLi,j-gpLLj);
727  if(pupilImage(i,j) > LambdaA) LambdaA = pupilImage(i,j);
728  }
729  else
730  {
731  pupilImage(i,j) = 0;
732  }
733  }
734  }
735  //LambdaA = 1.0/LambdaA;
736  for(int i=0; i< m_wfSz; ++i) for(int j=0;j<m_wfSz; ++j) pupilImage(i,j) /= LambdaA;
737 
738  std::cout << n << " " << LambdaA << "\n";
739  if( fabs(LambdaA - lastLambdaA) < absTol)
740  {
741  std::cout << "Converged on absTol.\n";
742  reason = "absTol";
743  break;
744  }
745  if( fabs((LambdaA - lastLambdaA)/lastLambdaA) < relTol)
746  {
747  std::cout << "Converged on relTol.\n";
748  reason = "relTol";
749  break;
750  }
751 
752  if(n == maxIter - 1)
753  {
754  std::cout << "maxIter reached.\n";
755  reason = "maxIter";
756  }
757 
758  lastLambdaA = LambdaA;
759  }
760  if(LambdaA > 1) LambdaA = 1;
761 
762  std::cout << "LambdaA: = " << LambdaA << "\n";
763 
764  realT trans = 1.0 - 1.0/LambdaA;
765 
766  int pupSize = geomPupil.rows();
767 
768  m_pupilApodizer.resize(pupSize, pupSize);
769 
770  extractBlock(m_pupilApodizer, 0, pupSize, 0, pupSize, pupilImage, 0.5*( (pupilImage.rows()-1) - (pupSize-1)), 0.5*( (pupilImage.rows()-1) - (pupSize-1)));
771 
772  makeFocalMask(fpmRadPix, trans, pupSize);
773  m_maskSource = 2;
774 
775  m_lyotStop = geomPupil;
776 
777 
778  fits::fitsHeader head;
779 
780  head.append("", fits::fitsCommentType(), "----------------------------------------");
781  head.append("", fits::fitsCommentType(), "lyotCoronagraph optimization Parameters:");
782  head.append("", fits::fitsCommentType(), "----------------------------------------");
783  head.append<int>("WFSZ", m_wfSz, "Size of wavefront used for FFTs (pixels)");
784  head.append<realT>("FPMRADPX", fpmRadPix, "input radius of focal plane mask (pixels)");
785  head.append<realT>("ABSTOL", absTol , "input absolute tolerance");
786  head.append<realT>("RELTOL", relTol , "input relative tolerance");
787  head.append<int>("MAXITER", maxIter , "input maximum iterations");
788  head.append<int>("NITER", n , "actual number of iterations");
789  head.append<std::string>("XREASON", reason , "reason for convergence");
790  head.append<realT>("FPMTRANS", trans, "transmission of FPM");
791 
792 
794 
795  std::string fname = "coron/" + cname + "_apod.fits";
796 
797  ff.write(fname, m_pupilApodizer, head);
798 
799  fname = "coron/" + cname + "_fpm.fits";
800  improc::eigenImage<fpmaskFloatT> fpm(m_focalMask.rows(), m_focalMask.cols());
801  for(int r=0;r<m_focalMask.rows(); ++r)
802  {
803  for(int c=0; c< m_focalMask.cols(); ++c)
804  {
805  fpm(r,c) = m_focalMask(r,c).real();
806  }
807  }
808 
809  ff.write(fname, fpm,head);
810 
811  fname = "coron/" + cname + "_lyot.fits";
812  ff.write(fname, m_lyotStop, head);
813 }
814 
815 } //namespace wfp
816 } //namespace mx
817 
818 #endif //__lyotCoronagraph_hpp__
819 
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
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
void append(fitsHeaderCard card)
Append a fitsHeaderCard to the end of the header.
Definition: fitsHeader.cpp:156
An image cube with an Eigen-like API.
Definition: eigenCube.hpp:31
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
Declares and defines a class for Fraunhofer propagation of optical wavefronts.
constexpr units::realT c()
The speed of light.
Definition: constants.hpp:60
Eigen::Array< scalarT, -1, -1 > eigenImage
Definition of the eigenImage type, which is an alias for Eigen::Array.
Definition: eigenImage.hpp:44
void makeComplexPupil(arrayOutT &complexPupil, const arrayInT &realPupil, int wavefrontSizePixels)
Create a complex pupil plane wavefront from a real amplitude mask.
int circularPupil(arrayT &m, typename arrayT::Scalar eps=0, typename arrayT::Scalar rad=0, typename arrayT::Scalar overscan=0)
Fill in an Eigen-like array with a circular pupil mask.
Declares and defines a class for managing images.
Utilities for modeling image formation.
The mxlib c++ namespace.
Definition: mxError.hpp:107
The Lyot Coronagraph.
std::string m_maskFile
Name of file from which mask was loaded.
Eigen::Array< realT, Eigen::Dynamic, Eigen::Dynamic > imageT
The image type.
int loadCoronagraph(const std::string &apodName, const std::string &fpmName, const std::string &lyotName)
Load the components of the coronagraph from FITS files.
lyotCoronagraph()
Default c'tor.
int m_maskSource
0= read from file, 1 = constructed by makeFocalMask, 2 = trans optimized.
int m_wfSz
The linear size of the wavefront in pixels.
int loadApodizer(const std::string &apodName)
Load the apodizer from a FITS file.
Eigen::Array< std::complex< fpmaskFloatT >, Eigen::Dynamic, Eigen::Dynamic > fpMaskT
The focal plane mask type.
int propagate(complexFieldT &pupilPlane)
Propagate the given pupil-plane wavefront through the coronagraph.
mx::wfp::imagingArray< std::complex< realT >, fftwAllocator< std::complex< realT > >, 0 > complexFieldT
The wavefront complex field type.
imageT m_lyotStop
Image containing the lyot stop.
void makeFocalMask(realT rad, fpmaskFloatT trans=0.0, int sz=0.0)
Make the focal plane mask.
int propagateNC(complexFieldT &pupilPlane)
Propagate the given pupil-plane wavefront without the coronagraph.
fpMaskT m_focalMask
The focal plane mask.
fraunhoferPropagator< complexFieldT > m_fp
Fraunhofer propagator.
std::complex< realT > complexT
The complex floating point type.
void optimizeAPLCMC(imageT &geomPupil, realT fpmRadPix, realT relTol, realT absTol, int maxIter, const std::string &cname)
Optimize the pupil amplitude apodization and focal-plane mask complex transmission.
_realT realT
The real floating point type.
realT m_maskTrans
Transmission of mask if it was constructed.
imageT m_pupilApodizer
Image containing the pupil apodization.
int loadFocalMask(const std::string &fpmName)
Load the focal plane mask from a FITS file.
int loadLyotStop(const std::string &lyotName)
Load the Lyot stop from a FITS file.
realT m_maskRad
Radius of mask if it was constructed.
_fpmaskFloatT fpmaskFloatT
The real floating point type for mask calculations.
int wfSz()
Get the wavefront size in pixels.
std::string m_fileDir
The directory where coronagraph files are stored.