mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
pywfsSlopeReconstructor.hpp
1 #ifndef __pywfsSlopeReconstructor_hpp__
2 #define __pywfsSlopeReconstructor_hpp__
3 
4 #include <mx/improc/eigenCube.hpp>
5 
6 
7 namespace mx
8 {
9 namespace AO
10 {
11 namespace sim
12 {
13 
14 struct pywfsSlopeReconstructorSpec
15 {
16  std::string dmName;
17  std::string basisName;
18 
19  std::string rMatId;
20 };
21 
22 ///A Pyramid Wavefront Sensor slope reconstructor.
23 /** Calculates slopes, normalized by total flux in the image.
24  */
25 template<typename _floatT>
27 {
28 public:
29 
30  typedef _floatT floatT;
31 
32  ///The type of the measurement (i.e. the slope vector)
33  //typedef Eigen::Array<floatT,-1,-1> measurementT;
34 
35  ///The type of the WFS image
36  typedef Eigen::Array<floatT, -1, -1> imageT;
37 
38  ///The type of the response matrix
39  typedef Eigen::Array<floatT, -1, -1> rmatT;
40 
41  typedef pywfsSlopeReconstructorSpec specT;
42 
43 protected:
44  Eigen::Array<floatT,-1,-1> _recon; ///< The reconstructor matrix.
45 
46  int _maskType; ///0 is centrally obscured circle, 1 is supplied by fits files
47 
48  floatT _maskRadius; ///<The radius of the quadrant mask
49  floatT _maskObscuration; ///<The central obscuration of the quadrant mask
50 
51  std::string _maskFile; ///<The name of the quadrant mask file
52 
53  bool _maskMade; ///<Whether or not the mask has been made
54 
55  Eigen::Array<floatT, -1,-1> _quadMask; ///<The quadrant mask
56  void calcMask(); ///<Calculates the quadrant mask
57  int _measurementSize; ///<The number of slopes in the measurement
58 
59 
60  floatT _calAmp; ///<The calibration amplitude used for response matrix acquisition
61 
62  int _nModes; ///<The number of modes to be reconstructed
63 
64  int _detRows; ///<The size of the WFS image, in rows
65  int _detCols;///<The size of the WFS image, in columns
66 
67 
68  imageT _rMat; ///<The response matrix
70 
71 public:
72 
73  int _binFact; ///<The binning to apply before reconstructing.
74 
75  ///Default c'tor
77 
78  template<typename AOSysT>
79  void initialize(AOSysT & AOSys, specT & spec)
80  {
81  std::string recMatrix = mx::AO::path::sys::cal::iMat( AOSys._sysName,
82  spec.dmName,
83  AOSys._wfsName,
84  AOSys._pupilName,
85  spec.basisName,
86  spec.rMatId) ;
87  loadRecon(recMatrix);
88 
89 
90  }
91 
92 
93  ///Get the quadrant mask radius (_maskRadius)
94  floatT maskRadius();
95 
96  ///Set the quadrant mask radius (_maskRadius)
97  /** Calling this will cause the quadrant mask to be recalculated next time it is needed.
98  *
99  * \param mr [in] the new mask radius
100  */
101  void maskRadius(floatT mr);
102 
103  ///Get the quadrant mask central obscuration ratio (_maskObscuration)
104  floatT maskObscuration();
105 
106  ///Set the quadrant mask central obscuration ratio (_maskObscuration)
107  /** Calling this will cause the quadrant mask to be recalculated next time it is needed.
108  *
109  * \param mo [in] the new central obscuration ratio
110  */
111  void maskObscuration(floatT mo);
112 
113  ///Get the quadrant mask file name (_maskFile)
114  std::string maskFile();
115 
116  ///Set the quadrant mask file name (_maskFile)
117  /** Calling this will cause the quadrant mask to be reloaded next time it is needed.
118  *
119  * \param mf [in] the new mask file
120  */
121  void maskFile(const std::string & mf);
122 
123  ///Get the calibration amplitude used in response matrix acquisition (_calAmp)
124  floatT calAmp();
125 
126  ///Set the calibration amplitude used in response matrix acquisition (_calAmp)
127  /**
128  * \param ca [in] the new calibration amplitude
129  */
130  void calAmp(floatT ca);
131 
132  ///Get the number of modes (_nModes)
133  int nModes();
134 
135  ///Get the number of detector rows (_detRows)
136  int detRows();
137 
138  ///Set the number of detector rows (_detRows)
139  void detRows(int dr);
140 
141  ///Get the number of detector columns (_detCols)
142  int detCols();
143 
144  ///Set the number of detector columns (_detCols)
145  void detCols(int dc);
146 
147  ///Load the reconstrutor from the specified FITS file
148  /**
149  * \param fname is the name of the FITS file, including path
150  */
151  void loadRecon(std::string fname);
152 
153  ///Return the size of the unbinned measurement
154  int measurementSize();
155 
156  ///Calculate the slope measurement
157  /**
158  * \param slopes [out] a (_measurementSize X 2) array of slopes
159  * \param wfsImage [in] the WFS image from which to measure the slopes
160  */
161  template<typename measurementT, typename wfsImageT>
162  void calcMeasurement(measurementT & slopes, wfsImageT & wfsImage);
163 
164  ///Reconstruct the wavefront from the input image, producing the modal amplitude vector
165  template<typename measurementT, typename wfsImageT>
166  void reconstruct(measurementT & commandVect, wfsImageT & wfsImage);
167 
168  ///Initialize the response matrix for acquisition
169  /**
170  * \param nmodes the number of modes
171  * \param calamp the calibration amplitude
172  * \param detrows the number of detector rows
173  * \param detcols the number of detector columns
174  */
175  void initializeRMat(int nmodes, floatT calamp, int detrows,int detcols);
176 
177  ///Accumalte the next measurement in the response matrix
178  /**
179  * \param i the measurement index
180  * \param measureVec is the i-th measurement vector
181  */
182  template<typename measurementT>
183  void accumulateRMat(int i, measurementT &measureVec);
184 
185  template<typename measurementT, typename wfsImageT>
186  void accumulateRMat(int i, measurementT &measureVec, wfsImageT & wfsImage);
187 
188  ///Write the accumulated response matrix to disk
189  /**
190  * \param fname the name, including path, of the response matrix
191  */
192  void saveRMat(std::string fname);
193 
194  void saveRImages(std::string fname);
195 
196 
197 
198 };
199 
200 
201 template<typename floatT>
203 {
204  _maskRadius = 0;
205  _maskObscuration = 0;
206 
207  _maskMade = false;
208 
209  _binFact = 1;
210 }
211 
212 template<typename floatT>
214 {
215  return _maskRadius;
216 }
217 
218 template<typename floatT>
220 {
221  _maskRadius = mr;
222  _maskType = 0;
223  _maskMade = false;
224 
225 }
226 
227 template<typename floatT>
229 {
230  return _maskObscuration;
231 }
232 
233 template<typename floatT>
235 {
236  _maskObscuration = mo;
237  _maskType = 0;
238  _maskMade = false;
239 }
240 
241 template<typename floatT>
243 {
244  return _maskFile;
245 }
246 
247 template<typename floatT>
248 void pywfsSlopeReconstructor<floatT>::maskFile(const std::string & mf)
249 {
250  _maskFile = mf;
251  _maskType = 1;
252  _maskMade = false;
253 }
254 
255 template<typename floatT>
257 {
258  return _calAmp;
259 }
260 
261 template<typename floatT>
263 {
264  _calAmp = ca;
265 }
266 
267 template<typename floatT>
269 {
270  return _nModes;
271 }
272 
273 template<typename floatT>
275 {
276  return _detRows;
277 }
278 
279 template<typename floatT>
281 {
282  _detRows = dr;
283  _maskMade = false;
284 }
285 
286 template<typename floatT>
288 {
289  return _detCols;
290 }
291 
292 template<typename floatT>
294 {
295  _detCols = dc;
296  _maskMade = false;
297 }
298 
299 
300 
301 
302 template<typename floatT>
304 {
305  improc::fitsFile<floatT> ff;
306  improc::fitsHeader head;
307 
308  ff.read(fname, _recon, head);
309 
310  _maskRadius = head["MASKRAD"].Value<floatT>();
311  _maskObscuration = head["MASKOBS"].Value<floatT>();
312  _maskFile = head["MASKFILE"].String();
313 
314  if( _maskFile != "") _maskType = 1;
315 
316  _calAmp = head["CALAMP"].Value<floatT>();
317 
318  _nModes = head["NMODES"].Value<int>();
319 
320  _detRows = head["DETROWS"].Int();
321  _detCols = head["DETCOLS"].Int();
322 
323  _maskMade = false;
324 }
325 
326 template<typename floatT>
328 {
329  if(_maskType == 1)
330  {
331  improc::fitsFile<floatT> ff;
332 
333  std::cerr << "Loading Mask: " << _maskFile << "\n";
334  ff.read(_maskFile, _quadMask);
335 
336 
337  }
338  {
339  _quadMask.resize(0.5*_detRows/_binFact,0.5*_detCols/_binFact);
340  wfp::circularPupil( _quadMask, _maskObscuration,_maskRadius/_binFact);
341  }
342 
343  _measurementSize = 2* _quadMask.sum();// + 64*64;
344 
345  _maskMade = true;
346 
347  improc::fitsFile<floatT> ff;
348  ff.write("quadMask.fits", _quadMask);
349 }
350 
351 template<typename floatT>
353 {
354  if(!_maskMade) calcMask();
355  return _measurementSize;
356 
357 }
358 
359 template<typename floatT>
360 template<typename measurementT, typename wfsImageT>
361 void pywfsSlopeReconstructor<floatT>::calcMeasurement(measurementT & slopes, wfsImageT & wfsImage)
362 {
363  if(!_maskMade) calcMask();
364 
365  imageT _wfsImage;
366 
367  if(_binFact > 1)
368  {
369  std::cout << "rebinning" << "\n";
370  _wfsImage.resize( wfsImage.image.rows()/_binFact, wfsImage.image.cols()/_binFact);
371  imageDownSample( _wfsImage, wfsImage.image);
372  }
373  else
374  {
375  _wfsImage = wfsImage.image;
376  }
377 
378  int nsz = _wfsImage.rows();
379 
380  int nPix = _quadMask.sum();
381 
382  std::vector<int> x(nPix), y(nPix);
383 
384  int k = 0;
385  for(int i=0;i<_quadMask.rows(); ++i)
386  {
387  for(int j=0;j<_quadMask.rows(); ++j)
388  {
389  if(_quadMask(i,j) == 1)
390  {
391  x[k] = i;
392  y[k] = j;
393  ++k;
394  }
395  }
396  }
397 
398  slopes.measurement.resize(1, 2.*nPix);// + 64*64); //wfsImage.tipImage.rows()*wfsImage.tipImage.cols());
399 
400  floatT I0, I1, I2, I3;
401 
402  floatT norm = _wfsImage.sum();
403 
404  for(int i=0;i<nPix; ++i)
405  {
406  I0 = _wfsImage(x[i], y[i]);
407  I1 = _wfsImage(x[i] + 0.5*nsz, y[i]);
408  I2 = _wfsImage(x[i], y[i]+0.5*nsz);
409  I3 = _wfsImage(x[i]+0.5*nsz, y[i]+0.5*nsz);
410 
411  if(norm == 0)
412  {
413  slopes.measurement(0,i) =0;;
414  slopes.measurement(0,i+nPix) = 0;//
415  }
416  else
417  {
418  slopes.measurement(0,i) = (I0 + I1 - I2 - I3)/norm;//(I0+I1+I2+I3);
419  slopes.measurement(0,i+nPix) = (I0 + I2 - I1 - I3)/norm; //(I0+I1+I2+I3);
420  }
421  }
422 
423 
424  /*
425  for(int i=0; i< wfsImage.tipImage.rows(); ++i)
426  {
427  for(int j=0;j<wfsImage.tipImage.cols(); ++j)
428  {
429  slopes.measurement(0, 2*nPix + i*wfsImage.tipImage.cols() + j) = wfsImage.tipImage(i,j);
430  }
431  }*/
432 
433 }
434 
435 template<typename floatT>
436 template<typename measurementT, typename wfsImageT>
437 void pywfsSlopeReconstructor<floatT>::reconstruct(measurementT & commandVect, wfsImageT & wfsImage)
438 {
439  measurementT slopes;
440 
441  calcMeasurement(slopes, wfsImage);
442 
443  commandVect.measurement = slopes.measurement.matrix()*_recon.matrix();
444 
445  commandVect.iterNo = wfsImage.iterNo;
446 }
447 
448 template<typename floatT>
449 void pywfsSlopeReconstructor<floatT>::initializeRMat(int nModes, floatT calamp, int detRows, int detCols)
450 {
451 
452  _nModes = nModes;
453 
454  calAmp(calamp);
455 
456  _detRows = detRows;
457  _detCols = detCols;
458 
459  _rMat.resize(measurementSize(), nModes);
460  _rMat.setZero();
461 
462  _rImages.resize(_detRows, _detCols, _nModes);
463 
464 }
465 
466 template<typename floatT>
467 template<typename measurementT>
468 void pywfsSlopeReconstructor<floatT>::accumulateRMat(int i, measurementT &measureVec)
469 {
470  _rMat.col(i) = measureVec.measurement.row(0);
471 }
472 
473 template<typename floatT>
474 template<typename measurementT, typename wfsImageT>
475 void pywfsSlopeReconstructor<floatT>::accumulateRMat(int i, measurementT &measureVec, wfsImageT & wfsImage)
476 {
477  accumulateRMat(i, measureVec);
478 
479  _rImages.image(i) = wfsImage.image;
480 }
481 
482 template<typename floatT>
484 {
485  improc::fitsFile<floatT> ff;
486  improc::fitsHeader head;
487 
488  if(_maskType == 1)
489  {
490  head.append("MASKFILE", maskFile(), "Name of mask file");
491  }
492  else
493  {
494  head.append("MASKRAD", maskRadius(), "Mask radius, in pixels");
495  head.append("MASKOBS", maskObscuration(), "Mask fractional central obscuration");
496  }
497 
498  head.append("DETROWS", _detRows, "WFS detector rows");
499  head.append("DETCOLS", _detCols, "WFS detector cols");
500  head.append("CALAMP", _calAmp, "DM Calibration amplitude");
501  head.append("NMODES", _nModes, "Number of modes included in the response matrix.");
502 
503  //ff.write(fname, _rMat.data(), _rMat.rows(), _rMat.cols(), 1, &head);
504  ff.write(fname, _rMat, head);
505 }
506 
507 template<typename floatT>
508 void pywfsSlopeReconstructor<floatT>::saveRImages(std::string fname)
509 {
510  improc::fitsFile<floatT> ff;
511  improc::fitsHeader head;
512 
513  if(_maskType == 1)
514  {
515  head.append("MASKFILE", maskFile(), "Name of mask file");
516  }
517  else
518  {
519  head.append("MASKRAD", maskRadius(), "Mask radius, in pixels");
520  head.append("MASKOBS", maskObscuration(), "Mask fractional central obscuration");
521  }
522 
523  head.append("DETROWS", _detRows, "WFS detector rows");
524  head.append("DETCOLS", _detCols, "WFS detector cols");
525  head.append("CALAMP", _calAmp, "DM Calibration amplitude");
526  head.append("NMODES", _nModes, "Number of modes included in the response matrix.");
527 
528  //ff.write(fname, _rImages.data(), _rImages.rows(), _rImages.cols(), _rImages.planes(), &head);
529  ff.write(fname, _rImages, head);
530 }
531 
532 } //namespace sim
533 } //namespace AO
534 } //namespace mx
535 
536 #endif //__pywfsSlopeReconstructor_hpp__
537 
A Pyramid Wavefront Sensor slope reconstructor.
floatT calAmp()
Get the calibration amplitude used in response matrix acquisition (_calAmp)
int _detCols
The size of the WFS image, in columns.
void reconstruct(measurementT &commandVect, wfsImageT &wfsImage)
Reconstruct the wavefront from the input image, producing the modal amplitude vector.
int _detRows
The size of the WFS image, in rows.
int nModes()
Get the number of modes (_nModes)
floatT _maskRadius
0 is centrally obscured circle, 1 is supplied by fits files
std::string _maskFile
The name of the quadrant mask file.
void saveRMat(std::string fname)
Write the accumulated response matrix to disk.
floatT maskObscuration()
Get the quadrant mask central obscuration ratio (_maskObscuration)
Eigen::Array< floatT,-1,-1 > _recon
The reconstructor matrix.
Eigen::Array< floatT, -1,-1 > _quadMask
The quadrant mask.
int _nModes
The number of modes to be reconstructed.
int detCols()
Get the number of detector columns (_detCols)
int _measurementSize
The number of slopes in the measurement.
Eigen::Array< floatT, -1, -1 > imageT
The type of the measurement (i.e. the slope vector)
int measurementSize()
Return the size of the unbinned measurement.
bool _maskMade
Whether or not the mask has been made.
int _binFact
The binning to apply before reconstructing.
floatT _calAmp
The calibration amplitude used for response matrix acquisition.
void calcMeasurement(measurementT &slopes, wfsImageT &wfsImage)
Calculate the slope measurement.
void accumulateRMat(int i, measurementT &measureVec)
Accumalte the next measurement in the response matrix.
Eigen::Array< floatT, -1, -1 > rmatT
The type of the response matrix.
floatT _maskObscuration
The central obscuration of the quadrant mask.
int detRows()
Get the number of detector rows (_detRows)
void loadRecon(std::string fname)
Load the reconstrutor from the specified FITS file.
floatT maskRadius()
Get the quadrant mask radius (_maskRadius)
std::string maskFile()
Get the quadrant mask file name (_maskFile)
void initializeRMat(int nmodes, floatT calamp, int detrows, int detcols)
Initialize the response matrix for acquisition.
void calcMask()
Calculates the quadrant mask.
constexpr units::realT k()
Boltzmann Constant.
Definition: constants.hpp:71
void imageDownSample(imageOutT &imout, const imageInT &imin)
Down-sample an image, reducing its size while conserving the total flux.
The mxlib c++ namespace.
Definition: mxError.hpp:107