mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
deformableMirror.hpp
Go to the documentation of this file.
1 /** \file
2  * \author Jared R. Males (jaredmales@gmail.com)
3  * \brief
4  * \ingroup mxAO_sim_files
5  *
6  */
7 
8 #ifndef deformableMirror_hpp
9 #define deformableMirror_hpp
10 
11 #include <cmath>
12 
13 #include "../../wfp/imagingUtils.hpp"
14 #include "../../sys/timeUtils.hpp"
15 #include "../../ioutils/fits/fitsFile.hpp"
16 
17 #include "../../ioutils/readColumns.hpp"
18 
19 #include "../../math/constants.hpp"
20 
21 #include "../../math/cuda/cudaPtr.hpp"
22 #include "../../math/cuda/templateCublas.hpp"
23 
24 #include "../aoPaths.hpp"
25 #include "wavefront.hpp"
26 
27 
28 
29 
30 #ifdef DEBUG
31 #define BREAD_CRUMB std::cout << "DEBUG: " << __FILE__ << " " << __LINE__ << "\n";
32 #else
33 #define BREAD_CRUMB
34 #endif
35 
36 namespace mx
37 {
38 
39 namespace AO
40 {
41 
42 namespace sim
43 {
44 
45 struct deformableMirrorSpec
46 {
47  std::string name;
48  std::string basisName;
49 };
50 
51 template<typename _realT>
52 class deformableMirror
53 {
54 public:
55 
56  typedef _realT realT;
57 
58  typedef std::complex<realT> complexT;
59 
60  ///The wavefront data type
61  typedef wavefront<realT> wavefrontT;
62 
63  ///The pupil image type
64  typedef Eigen::Array< realT, Eigen::Dynamic, Eigen::Dynamic> imageT;
65 
66  typedef deformableMirrorSpec specT;
67 
68 public: //<-give these accesors and make protected
69 
70  std::string _name;
71 
72  std::string _basisName;
73 
74  std::string m_pupilName;
75 
76  ///Time to move from old shape to new shape, in loop time steps
77  int _settleTime;
78 
79  int _settling;
80 
81  int _settleTime_counter;
82 
83  ///The amplitude used when measuring the response matrix of the current basis set.
84  float _calAmp;
85 
86 
87  imageT m_pupil; ///The system pupil, possibly apodized, etc.
88  realT m_pupilSum; ///The sum of the pupil mask, nominally the number of pixels.
89  std::vector<size_t> m_idx; /// The offset coordinates of non-zero pixels in the pupil
90 
91 
92 public:
93 
94  //The modes-2-command matrix for the basis
95  Eigen::Array<realT, -1, -1> m_m2c;
96 
97  //The mirror influence functions
98  improc::eigenCube<realT> m_infF;
99 
100  #ifdef MXAO_USE_GPU
101  cublasHandle_t *m_cublasHandle;
102  cuda::cudaPtr<realT> m_one;
103  cuda::cudaPtr<realT> m_alpha;
104  cuda::cudaPtr<realT> m_zero;
105 
106  cuda::cudaPtr<realT> m_devM2c;
107  cuda::cudaPtr<realT> m_devInfF;
108 
109  cuda::cudaPtr<realT> m_devModeCommands;
110  cuda::cudaPtr<realT> m_devActCommands;
111  cuda::cudaPtr<realT> m_devShape;
112  #endif
113 
114  size_t m_nActs;
115  size_t m_nRows;
116  size_t m_nCols;
117 
118 protected:
119  //The current shape of the mirror
120  imageT _shape;
121 
122  //The shape of the mirror when movement begins
123  imageT _oldShape;
124 
125  //The next shape of the mirror after movement ends.
126  imageT _nextShape;
127 
128 
129 public:
130 
131  ///Default c'tor.
132  deformableMirror();
133 
134  ~deformableMirror()
135  {
136  if(_commandFileOpen)
137  {
138  _commandFout.close();
139  }
140  }
141 
142  template<typename AOSysT>
143  void initialize( AOSysT & AOSys,
144  specT & spec,
145  const std::string & pupil
146  );
147 
148  std::string name()
149  {
150  return _name;
151  }
152 
153  std::string basisName()
154  {
155  return _basisName;
156  }
157 
158 
159  ///Get the settling time of the DM
160  int settleTime();
161 
162  ///Set the settling time of the DM
163  void settleTime(int st);
164 
165  ///Get the calibration amplitude.
166  /** The modal commands are relative to this value.
167  */
168  realT calAmp();
169 
170  ///Set the calibration amplitude.
171  void calAmp(realT ca);
172 
173  ///Get the number of modes in the M2C.
174  int nModes();
175 
176  ///Apply a single mode.
177  void applyMode(wavefrontT & wf, int modeNo, realT amp, realT lambda);
178 
179  realT _settlingIter;
180  realT _settledIter;
181 
182  template<typename commandT>
183  void setShape(commandT & commandV);
184 
185  void applyShape( wavefrontT & wf,
186  realT lambda
187  );
188 
189  double t0, t1, t_mm, t_sum;
190 
191  bool _writeCommands;
192  bool _commandFileOpen;
193  std::string _commandFile;
194  std::ofstream _commandFout;
195 
196  realT _commandLimit;
197 
198  Eigen::Array<double,-1,-1> _pos, _map;
199 
200  sigproc::psdFilter<realT,2> m_filter;
201 
202  bool m_applyFilter {false};
203 
204  void setFilter( int width );
205 };
206 
207 
208 template<typename _realT>
209 deformableMirror<_realT>::deformableMirror()
210 {
211  _settleTime = 1;
212  _settling = 0;
213  _settleTime_counter = 0;
214  _calAmp = 1e-6;
215 
216  t_mm = 0;
217  t_sum = 0;
218 
219  _writeCommands = false;
220  _commandFileOpen = false;
221 
222  _commandLimit = 0;
223 
224  //readColumns("sigma.dat", sigma);
225 
226  //std::cerr << "sigma.size() = " << sigma.size() << "\n";
227 }
228 
229 template<typename _realT>
230 template<typename AOSysT>
231 void deformableMirror<_realT>::initialize( AOSysT & AOSys,
232  specT & spec,
233  const std::string & pupil )
234 {
235  _name = spec.name;
236  _basisName = spec.basisName;
237  m_pupilName = pupil;
238 
239  fits::fitsFile<_realT> ff;
240 
241  std::string pName;
242  pName = mx::AO::path::pupil::pupilFile(m_pupilName);
243  ff.read(m_pupil, pName);
244  m_pupilSum = m_pupil.sum();
245 
246  m_idx.clear();
247  int kk = 0;
248  for(int rr=0;rr<m_pupil.rows();++rr)
249  {
250  for(int cc=0;cc<m_pupil.cols();++cc)
251  {
252  if(m_pupil(rr,cc) == 1)
253  {
254  m_idx.push_back(kk);
255  }
256  ++kk;
257  }
258  }
259 
260  if(_name == "modalDM")
261  {
262  std::cerr << "modalDM\n";
263 
264  std::string ifName;
265  ifName = mx::AO::path::basis::modes(_basisName);
266 
267  ff.read(m_infF, ifName);
268 
269  m_nActs = m_infF.planes();
270  m_nRows = m_infF.rows();
271  m_nCols = m_infF.cols();
272 
273  m_m2c.resize( m_nActs, m_nActs);
274  m_m2c.setZero();
275 
276  for(int i=0;i<m_m2c.rows();++i) m_m2c(i,i) = 1.0;
277 
278  #ifdef MXAO_USE_GPU
279 
280  m_cublasHandle = &AOSys.m_cublasHandle;
281 
282  m_one.resize(1);
283  realT one = 1.0;
284  m_one.upload(&one, 1);
285 
286  m_alpha.resize(1);
287  realT alpha = -1*_calAmp;
288  m_alpha.upload(&alpha, 1);
289 
290  m_zero.resize(1);
291  m_zero.initialize();
292 
294 
295  modft.resize( m_idx.size(),m_nActs);
296 
297  for(int pp=0;pp<m_nActs;++pp)
298  {
299  for(int nn=0; nn < m_idx.size(); ++nn)
300  {
301  *(modft.data() + pp*m_idx.size() + nn) = *(m_infF.image(pp).data() + m_idx[nn]);
302  }
303  }
304 
305  m_devInfF.upload(modft.data(), modft.rows()*modft.cols());
306 
307  m_devM2c.upload(m_m2c.data(), m_m2c.rows()*m_m2c.cols());
308 
309  m_devModeCommands.resize(m_nActs);
310  m_devActCommands.resize(m_nActs);
311 
312  #endif
313 
314  }
315  else
316  {
317  std::cerr << "Non-modal DM is currently not implemented\n";
318  exit(-1);
319 #if 0
320  std::string ifName;
321  ifName = mx::AO::path::dm::influenceFunctions(_name);
322 
323 
324  improc::eigenCube<realT> infFLoad;
325  ff.read(infFLoad, ifName);
326 
327  realT c = 0.5*(infFLoad.rows()-1);
328  realT w = 0.5*(m_pupil.rows()-1);
329 
330  m_infF.resize( m_pupil.rows(), m_pupil.cols(), infFLoad.planes());
331 
332  for(int i=0;i<infFLoad.planes(); ++i)
333  {
334  m_infF.image(i) = infFLoad.image(i).block( c-w, c-w, m_pupil.rows(), m_pupil.rows());
335  }
336 
337  std::string m2cName;
338 
339  m2cName = mx::AO::path::dm::M2c( _name, _basisName );
340 
341  ff.read(m_m2c, m2cName);
342 
343 
344  std::string posName = mx::AO::path::dm::actuatorPositions(_name, true);
345 
346  ff.read(_pos, posName);
347 #endif
348 
349  }
350 
351  _shape.resize(m_nRows, m_nCols);
352 
353  _shape.setZero();
354  _nextShape = _shape;
355  _oldShape = _shape;
356 
357  return;
358 }
359 
360 
361 
362 template<typename _realT>
363 int deformableMirror<_realT>::settleTime()
364 {
365  return settleTime;
366 }
367 
368 template<typename _realT>
369 void deformableMirror<_realT>::settleTime(int st)
370 {
371  if(st < 1)
372  {
373  std::cerr << "DM: settleTime must be > 1. Correcting.\n";
374  st = 1;
375  }
376 
377  _settleTime = st;
378 }
379 
380 template<typename _realT>
381 _realT deformableMirror<_realT>::calAmp()
382 {
383  return _calAmp;
384 }
385 
386 template<typename _realT>
387 void deformableMirror<_realT>::calAmp(realT ca)
388 {
389  _calAmp = ca;
390 
391  #ifdef MXAO_USE_GPU
392  realT alpha = -1*_calAmp;
393  m_alpha.upload(&alpha, 1);
394  #endif
395 
396 }
397 
398 
399 template<typename _realT>
400 int deformableMirror<_realT>::nModes()
401 {
402  return m_m2c.cols();
403 }
404 
405 
406 template<typename _realT>
407 void deformableMirror<_realT>::applyMode(wavefrontT & wf, int modeNo, realT amp, realT lambda)
408 {
409 
410  Eigen::Array<_realT,-1,-1> commandV(1, nModes());
411  commandV.setZero();
412 
413  commandV(0, modeNo) = 1;
414 
415  Eigen::Array<_realT, -1, -1> c;
416 
417  t0 = sys::get_curr_time();
418  c = m_m2c.matrix() * commandV.matrix().transpose();
419  t1 = sys::get_curr_time();
420  t_mm += t1-t0;
421 
422  imageT shape( m_nRows, m_nCols);
423 
424 
425  shape = c(0,0)*m_infF.image(0);
426 
427 
428  t0 = sys::get_curr_time();
429  #pragma omp parallel
430  {
431  Eigen::Array<_realT, -1, -1> tmp;
432  //tmp.resize(m_nRows, m_nCols);
433  //tmp.setZero();
434  tmp.setZero(m_nRows, m_nCols);
435 
436  #pragma omp for schedule(static)
437  for(int i=1;i < m_nActs; ++i)
438  {
439  tmp += c(i,0) * m_infF.image(i);
440  }
441  #pragma omp critical
442  shape += tmp;
443  }
444 
445  t1 = sys::get_curr_time();
446  t_sum += t1-t0;
447 
448  wf.phase += 2*amp*shape*m_pupil*math::two_pi<realT>()/lambda;
449 
450 }
451 
452 template<typename realT>
453 void makeMap( Eigen::Array<realT, -1, -1> & map, Eigen::Array<realT, -1, -1> & pos, Eigen::Array<realT, -1, -1> & act)
454 {
455 
456  realT minx = pos.row(0).minCoeff();
457  realT maxx = pos.row(0).maxCoeff();
458 
459  int i=0;
460  realT dx = 0;
461  while(dx == 0)
462  {
463  dx = fabs(pos(0,i)- pos(0,0));
464  ++i;
465  }
466 
467  realT miny = pos.row(1).minCoeff();
468  realT maxy = pos.row(1).maxCoeff();
469 
470  i = 0;
471  realT dy = 0;
472 
473  while(dy == 0)
474  {
475  dy = fabs(pos(1,i)- pos(1,0));
476  ++i;
477  }
478 
479  int nx = (maxx-minx)/dx + 1;
480  int ny = (maxy-miny)/dy + 1;
481 
482 
483  map.resize(nx, ny);
484  map.setZero();
485 
486  realT x, y;
487 
488  for(int j=0;j < pos.cols(); ++j)
489  {
490  x = (pos(0,j) - minx)/dx;
491 
492  y = ( pos(1,j) - miny ) / dy;
493 
494  map( (int) x, (int) y) = act(j,0);
495  }
496 
497 
498 
499 }
500 
501 
502 template<typename _realT>
503 template<typename commandT>
504 void deformableMirror<_realT>::setShape(commandT & commandV)
505 {
506 
507  if(_settling)
508  {
509  std::cerr << "DM: new command received while still settling.\n";
510  return;
511  }
512 
513 
514  static Eigen::Array<_realT, -1, -1> c; //static to avoid re-alloc, todo: make class member
515 
516  #ifdef MXAO_USE_GPU
517  m_devModeCommands.upload(commandV.measurement.data(), commandV.measurement.size());
518  realT alpha;
519  cublasStatus_t stat = cuda::cublasTgemv<realT>(*m_cublasHandle, CUBLAS_OP_N, m_nActs, m_nActs, m_alpha(), m_devM2c(), m_devModeCommands(), m_zero(), m_devActCommands());
520 
521  if(stat != CUBLAS_STATUS_SUCCESS)
522  {
523  std::cerr << "cublas error\n";
524  }
525 
526 
527  //c.resize(m_nActs,1);
528  //m_devActCommands.download(c.data());
529 
530 
531  #else
532  Eigen::Map<Eigen::Array<realT,-1,-1>> commandV_measurement(commandV.measurement.data(), 1, commandV.measurement.size());
533  c = -1*_calAmp*m_m2c.matrix() * commandV_measurement.matrix().transpose();
534 
535  #endif
536 
537 #if 0
538 
539  if(_commandLimit > 0)
540  {
541 
542  realT r1 = sqrt( pow(_pos(0,1) - _pos(0,0),2) + pow(_pos(1,1) - _pos(1,0),2));
543 
544  realT r;
545 
546  int nLimited = 0;
547 
548  for(int i=0; i< _pos.cols(); ++i)
549  {
550  for(int j=i+1; j< _pos.cols(); ++j)
551  {
552  r = sqrt( pow(_pos(0,j) - _pos(0,i),2) + pow(_pos(1,j) - _pos(1,i),2));
553 
554  if( fabs(r1 - r) < .01 )
555  {
556  realT iact = fabs( c(i,0) - c(j,0) );
557  if( iact > _commandLimit )
558  {
559  std::cerr << "Limited Actuators " << i << " " << j << "\n";
560  ++nLimited;
561  c(i,0) *= _commandLimit/iact;
562  c(j,0) *= _commandLimit/iact;
563  }
564  }
565  }
566  }
567  if(nLimited > 0) std::cerr << nLimited << " strokes limited\n";
568 
569  }
570 
571 #if 0
572  if(_commandLimit > 0 )
573  {
574  for(int i=0; i < c.rows(); ++i)
575  {
576  if(c(i,0) > _commandLimit ) c(i,0) = _commandLimit;
577  if(c(i,0) < -1*_commandLimit ) c(i,0) = -1*_commandLimit;
578  }
579  }
580 #endif
581 
582 
583 
584  if( _writeCommands )
585  {
586  if(!_commandFileOpen)
587  {
588  _commandFout.open( _commandFile );
589  _commandFout << std::scientific;
590  _commandFileOpen = true;
591  }
592 
593  _commandFout << commandV.iterNo << "> ";
594  for(int i=0; i<c.rows(); ++i)
595  {
596  _commandFout << c(i,0) << " ";
597  }
598  _commandFout << std::endl;
599  }
600 
601 
602  bool skipFrame = 0;
603 
604  ///\todo Should check for command limits here.
605  for(int i=0; i< m_nActs; ++i)
606  {
607  if( std::isnan( c(i,0) ) || !std::isfinite(c(i,0)))
608  {
609  skipFrame = true;
610  break;
611  }
612  }
613 
614  if(skipFrame)
615  {
616  std::cerr << "SKIP FRAME\n";
617  return;
618  }
619 
620 #endif
621 
622  #ifdef MXAO_USE_GPU
623 
624  static std::vector<realT> tmp;
625  tmp.resize(m_idx.size());
626 
627  m_devShape.resize(m_idx.size()); //no-op except first time.
628  m_devShape.initialize();
629 
630  for(int i=0; i < m_nActs; ++i)
631  {
632  //realT alpha = c(i,0);
633  cuda::cublasTaxpy<realT>(*m_cublasHandle, m_idx.size(), m_devActCommands()+i, m_devInfF() + i*m_idx.size(), 1, m_devShape(), 1);
634  }
635 
636  m_devShape.download(tmp.data());
637 
638  _nextShape.setZero();
639 
640  realT * imP = _nextShape.data();
641 
642  for(size_t n=0; n<m_idx.size(); ++n) imP[m_idx[n]] = tmp[n];
643 
644  #else
645 
646  _nextShape = c(0,0)*m_infF.image(0);//*sigma[0];
647 
648  #pragma omp parallel
649  {
650  Eigen::Array<_realT, -1, -1> tmp ;
651  tmp.resize(m_nRows, m_nCols);
652  tmp.setZero();
653 
654  realT * tmpP = tmp.data();
655  #pragma omp for
656  for(int i=1;i < m_nActs; ++i)
657  {
658  realT * imP = m_infF.image(i).data();
659  for(size_t n=0; n<m_idx.size(); ++n) *(tmpP + m_idx[n]) += c(i,0) * *(imP + m_idx[n]);
660  }
661  #pragma omp critical
662  {
663  realT * imP = _nextShape.data();
664  for(size_t n=0; n<m_idx.size(); ++n) *(imP + m_idx[n]) += *(tmpP + m_idx[n]);
665  }
666  }
667  #endif
668 
669  //================ filter here!!
670 
671 
672  if(m_applyFilter)
673  {
674  std::cerr << "DM filtering\n";
675  m_filter.filter(_nextShape);
676  }
677 
678  _oldShape = _shape;
679 #if 1
680  _settling = 1;
681  _settleTime_counter = 0;
682  _settlingIter = commandV.iterNo;
683 #else
684 //Ignoring settling time.
685  _shape = _nextShape;
686 #endif
687 
688 }
689 
690 template<typename _realT>
691 void deformableMirror<_realT>::applyShape(wavefrontT & wf, realT lambda)
692 {
693 
694 #if 1
695  BREAD_CRUMB;
696 
697  if(_settling)
698  {
699  BREAD_CRUMB;
700  _shape = _oldShape + (_nextShape-_oldShape)*( (realT) _settleTime_counter+1.0)/( (realT) _settleTime);
701 
702  realT mn = (_shape*m_pupil).sum()/m_pupilSum;
703  _shape = (_shape - mn)*m_pupil;
704 
705  ++_settleTime_counter;
706 
707  if(_settleTime_counter >= _settleTime)
708  {
709  _settling = 0;
710  _settledIter = _settlingIter;
711  }
712  }
713 #endif
714 
715 
716  BREAD_CRUMB;
717 
718  wf.phase += 2*_shape*math::two_pi<realT>()/lambda;
719 
720  BREAD_CRUMB;
721 
722  #ifdef MXAO_DIAG_LOOPCOUNTS
723  std::cerr << "DM " << m_nActs << " Shape applied: " << wf.iterNo << " " << _settledIter << "\n";
724  #endif
725 }
726 
727 template<typename _realT>
728 void deformableMirror<_realT>::setFilter( int width )
729 {
730  int nr = _shape.rows();
731  int nc = _shape.cols();
732 
733  typename wfsImageT<_realT>::imageT filterMask;
734 
735  filterMask.resize( nr, nc );
736  filterMask.setZero();
737 
738  filterMask.block(0,0, width+1, width+1).setConstant(1.0);
739  filterMask.block(0, nc - width, width+1, width).setConstant(1.0);
740  filterMask.block(nr - width, 0, width, width+1).setConstant(1.0);
741  filterMask.block(nr - width, nc - width, width, width).setConstant(1.0);
742 
743 
744  m_filter.psdSqrt(filterMask, 1.0/_shape.rows(), 1.0/_shape.cols());
745 
746 
747 
748 }
749 
750 } //sim
751 } //AO
752 } //namespace mx
753 
754 #endif //deformableMirror_hpp
std::string M2c(const std::string &dmName, const std::string &basisName, bool create=false)
The path for the modes-to-commands (M2c) matrix for a deformable mirror (DM) and a basis set.
Definition: aoPaths.hpp:200
std::string pupilFile(const std::string &pupilName, bool create=false)
The path for the pupil FITS file.
Definition: aoPaths.hpp:328
std::string actuatorPositions(const std::string &dmName, bool create=false)
The path for the deformable mirror (DM) actuator positions.
Definition: aoPaths.hpp:123
std::string influenceFunctions(const std::string &dmName, bool create=false)
The path for the deformable mirror (DM) influence functions.
Definition: aoPaths.hpp:109
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
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