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