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