8#ifndef mx_AO_sim_pyramidSensor_hpp
9#define mx_AO_sim_pyramidSensor_hpp
13#include "../../mxlib.hpp"
15#include "../../wfp/imagingUtils.hpp"
16#include "../../wfp/fraunhoferPropagator.hpp"
17#include "../../sys/timeUtils.hpp"
19#include "../../improc/eigenImage.hpp"
20#include "../../improc/milkImage.hpp"
21#include "../../improc/imageMasks.hpp"
23#include "../../math/constants.hpp"
24#include "../../math/geo.hpp"
27#include "../../math/cuda/cublasHandle.hpp"
30#include "wavefront.hpp"
33#define BREAD_CRUMB std::cout << "DEBUG: " << __FILE__ << " " << __LINE__ << "\n";
45template <
typename _realT>
54 typedef improc::milkImage<realT> imageT;
68template <
typename _realT,
typename _detectorT,
int _cudaGPU = 0>
72 static constexpr int cudaGPU = _cudaGPU;
89 typedef typename wfp::fraunhoferPropagatorArrayT<realImageT, cudaGPU>::arrayT
realArrayT;
92 typedef typename wfp::fraunhoferPropagatorArrayT<complexFieldT, cudaGPU>::arrayT
complexArrayT;
142 void wfSz(
const uint32_t &sz );
159 void detSize(
const uint32_t &nrows,
160 const uint32_t &ncols
172 void lambda(
const realT &l );
178 void iTime(
const uint32_t &it );
184 void roTime(
const uint32_t &rt );
190 void simStep(
const realT &st );
193 template <
typename AOSysT>
290 void nSides(
const uint32_t &ns );
302 void perStep(
const realT &prStp );
338 void D(
const realT &d );
353 void pupilSz(
const uint32_t &sz );
396 void imageSz(
const uint32_t &is );
414 bool m_opdMaskMade{
false };
417 bool m_tiltsMade{
false };
418 std::vector<complexArrayT> m_tilts;
420 bool m_preAllocated{
false };
438 int m_iTime_counter{ 0 };
442 int m_roTime_counter{ 0 };
444 std::vector<wavefrontT> _wavefronts;
446 int m_lastWavefront{ 0 };
458 template <
int ccudaGPU = cudaGPU>
461 template <
int ccudaGPU = cudaGPU>
466 void allocThreadMem();
474 template <
int ccudaGPU = cudaGPU>
476 typename std::enable_if<ccudaGPU == 0>::type * = 0 );
482 template <
int ccudaGPU = cudaGPU>
484 typename std::enable_if<ccudaGPU == 1>::type * = 0 );
490 template <
int ccudaGPU = cudaGPU>
494 typename std::enable_if<ccudaGPU == 0>::type * = 0 );
500 template <
int ccudaGPU = cudaGPU>
504 typename std::enable_if<ccudaGPU == 1>::type * = 0 );
510 template <
int ccudaGPU = cudaGPU>
514 typename std::enable_if<ccudaGPU == 0>::type * = 0 );
520 template <
int ccudaGPU = cudaGPU>
524 typename std::enable_if<ccudaGPU == 1>::type * = 0 );
526 void doSenseWavefront();
530 bool m_firstRun{
true };
535 std::vector<mx::cuda::cublasHandle *> m_cublasHandle;
540template <
typename realT,
typename detectorT,
int cudaGPU>
545 m_frProp.wholePixel( 0 );
548template <
typename realT,
typename detectorT,
int cudaGPU>
555 for(
size_t nTh = 0; nTh < m_cublasHandle.size(); ++nTh)
557 delete m_cublasHandle[nTh];
563template <
typename realT,
typename detectorT,
int cudaGPU>
569template <
typename realT,
typename detectorT,
int cudaGPU>
580 m_opdMaskMade =
false;
581 m_preAllocated =
false;
584template <
typename realT,
typename detectorT,
int cudaGPU>
590template <
typename realT,
typename detectorT,
int cudaGPU>
596template <
typename realT,
typename detectorT,
int cudaGPU>
599 if( m_detRows == nrows && m_detCols == ncols )
607 detector.setSize( m_detRows, m_detCols );
609 detectorImage.image.create(
"camwfs", m_detRows, m_detCols );
610 detectorImage.tipImage.create(
"camtip", m_wfSz, m_wfSz);
612 m_opdMaskMade =
false;
615template <
typename realT,
typename detectorT,
int cudaGPU>
621template <
typename realT,
typename detectorT,
int cudaGPU>
629 if( m_wavelengths.size() == 0 )
631 m_wavelengths.resize( 1, m_lambda );
632 _wavelengthWeights.resize( 1, 1.0 );
636template <
typename realT,
typename detectorT,
int cudaGPU>
642template <
typename realT,
typename detectorT,
int cudaGPU>
652 _wavefronts.resize( m_iTime + 2 );
653 m_lastWavefront = -1;
655 detector.expTime( m_simStep * m_iTime );
658template <
typename realT,
typename detectorT,
int cudaGPU>
664template <
typename realT,
typename detectorT,
int cudaGPU>
675template <
typename realT,
typename detectorT,
int cudaGPU>
681template <
typename realT,
typename detectorT,
int cudaGPU>
687 detector.expTime( m_simStep * m_iTime );
690template <
typename realT,
typename detectorT,
int cudaGPU>
691template <
typename AOSysT>
694 AOSys.wfs.wfPS( AOSys.m_wfPS );
695 AOSys.wfs.D( AOSys.m_D );
698template <
typename realT,
typename detectorT,
int cudaGPU>
703 if( m_lastWavefront >= _wavefronts.size() )
705 _wavefronts[m_lastWavefront].amplitude = pupilPlane.
amplitude;
706 _wavefronts[m_lastWavefront].phase = pupilPlane.
phase;
707 _wavefronts[m_lastWavefront].iterNo = pupilPlane.
iterNo;
724 if( m_roTime_counter >= m_roTime )
726 detector.exposeImage( detectorImage.image(), m_wfsImage.image() );
727 detectorImage.image.post();
729 detectorImage.tipImage() = m_wfsImage.tipImage();
730 detectorImage.tipImage.post();
732 detectorImage.iterNo = m_wfsImage.iterNo;
734 m_roTime_counter = 0;
740 if( m_iTime_counter >= m_iTime )
746 m_roTime_counter = 0;
752template <
typename realT,
typename detectorT,
int cudaGPU>
758 doSenseWavefront( pupilPlane );
762 detector.exposeImage( detectorImage.image(), m_wfsImage.image() );
763 detectorImage.image.post();
767 detectorImage.tipImage() = m_wfsImage.tipImage();
768 detectorImage.tipImage.post();
777template <
typename realT,
typename detectorT,
int cudaGPU>
783template <
typename realT,
typename detectorT,
int cudaGPU>
787 m_opdMaskMade =
false;
790template <
typename realT,
typename detectorT,
int cudaGPU>
796template <
typename realT,
typename detectorT,
int cudaGPU>
802template <
typename realT,
typename detectorT,
int cudaGPU>
810 m_wfPS = m_D / m_pupilSz;
818 m_opdMaskMade =
false;
819 m_preAllocated =
false;
820 m_opdMaskMade =
false;
821 m_preAllocated =
false;
824template <
typename realT,
typename detectorT,
int cudaGPU>
830template <
typename realT,
typename detectorT,
int cudaGPU>
835 if( m_modRadius <= 0 )
841 realT radPerStep = m_perStep / m_modRadius;
855template <
typename realT,
typename detectorT,
int cudaGPU>
861template <
typename realT,
typename detectorT,
int cudaGPU>
867template <
typename realT,
typename detectorT,
int cudaGPU>
871 perStep( m_perStep );
876template <
typename realT,
typename detectorT,
int cudaGPU>
882template <
typename realT,
typename detectorT,
int cudaGPU>
885 if( m_pupilSz == sz )
895 m_wfPS = m_D / m_pupilSz;
905 m_wfPS = m_D / m_pupilSz;
913 m_opdMaskMade =
false;
914 m_preAllocated =
false;
917template <
typename realT,
typename detectorT,
int cudaGPU>
923template <
typename realT,
typename detectorT,
int cudaGPU>
926 if( m_pupilSep == sz )
933 m_opdMaskMade =
false;
934 m_preAllocated =
false;
937template <
typename realT,
typename detectorT,
int cudaGPU>
940 return m_angleOffset;
943template <
typename realT,
typename detectorT,
int cudaGPU>
946 if( m_angleOffset == ao )
953 m_opdMaskMade =
false;
954 m_preAllocated =
false;
957template <
typename realT,
typename detectorT,
int cudaGPU>
968template <
typename realT,
typename detectorT,
int cudaGPU>
971 if( m_imageSz == sz )
980 m_imageSzAuto =
true;
984 m_imageSzAuto =
false;
987 m_opdMaskMade =
false;
988 m_preAllocated =
false;
991template <
typename realT,
typename detectorT,
int cudaGPU>
994 return m_imageSzAuto;
997template <
typename realT,
typename detectorT,
int cudaGPU>
1002 m_opdMaskMade =
false;
1004 m_preAllocated =
false;
1007template <
typename realT,
typename detectorT,
int cudaGPU>
1014 "wavefront platescale (m_wfPS) is 0. Must set pupilSz and D first." );
1017 if( !std::isfinite( m_wfPS ) || !std::isnormal( m_wfPS ) )
1020 "wavefront platescale (m_wfPS) is infinite. Must set pupilSz and D first." );
1023 std::cerr << m_wfPS <<
" " << m_D <<
"\n";
1031 m_frProp.setWavefrontSizePixels( m_wfSz );
1033 m_opdMask.resize( m_wfSz, m_wfSz );
1035 complexFieldT opdMask;
1036 opdMask.resize( m_wfSz, m_wfSz );
1038 complexFieldT opdMaskQ;
1039 opdMaskQ.resize( m_wfSz, m_wfSz );
1043 mask.resize( m_opdMask.rows(), m_opdMask.cols() );
1051 realT pupilRad = m_pupilSep * m_pupilSz / ( 2 * sin( dang / 2.0 ) );
1053 for(
int n = 0; n < m_nSides; ++n )
1055 realT ang = m_angleOffset * math::degreesT<realT>::radians + 0.5 * dang + n * dang;
1057 realT dx = pupilRad * cos( ang );
1064 realT dy = pupilRad * sin( ang );
1071 opdMaskQ.setConstant( std::complex<realT>( 0, 1 ) );
1075 0.5 * ( mask.rows() - 1 ),
1076 0.5 * ( mask.cols() - 1 ),
1080 wfp::extractMaskedPixels( opdMask, opdMaskQ, mask );
1083 uploadTilt( m_opdMask, opdMask );
1086 2 * std::max( { fabs( maxx ), fabs( minx ) } ) + 2 * std::max( { ( pupilRad / 2 ), ( (realT)m_pupilSz / 2 ) } );
1089 2 * std::max( { fabs( maxy ), fabs( miny ) } ) + 2 * std::max( { ( pupilRad / 2 ), ( (realT)m_pupilSz / 2 ) } );
1093 m_imageSz = std::max( xsz, ysz );
1095 if( m_pupilSep > 1 )
1097 m_imageSz += ( m_pupilSep - 1.0 ) * m_pupilSz;
1101 if( m_imageSz > m_wfSz )
1103 std::string msg =
"image size (m_imageSz = " + std::to_string( m_imageSz ) +
") ";
1104 msg +=
"> wavefront size (m_wfSz = " + std::to_string( m_wfSz ) +
"). ";
1105 msg +=
"Decrease number of sides (m_nSides = " + std::to_string( m_nSides ) +
") or increase wavefront size. ";
1109 m_wfsImage.image.create(
"camwfs_raw", m_imageSz, m_imageSz );
1110 m_wfsImage.tipImage.create(
"camtip_raw", m_wfSz, m_wfSz );
1112 if( m_detRows == 0 || m_detCols == 0 )
1114 detSize( m_imageSz, m_imageSz );
1117 else if( m_detRows > m_imageSz || m_detCols > m_imageSz )
1119 std::string msg =
"image size (m_imageSz = " + std::to_string( m_imageSz ) +
") ";
1120 msg +=
"< detector size size (m_detRows = " + std::to_string( m_detRows );
1121 msg +=
" m_detCols = " + std::to_string( m_detCols ) +
"). ";
1125 m_opdMaskMade =
true;
1128template <
typename realT,
typename detectorT,
int cudaGPU>
1129template <
int ccudaGPU>
1130error_t pyramidSensor<realT, detectorT, cudaGPU>::uploadTilt( complexArrayT &tilt,
1131 complexFieldT <ilt,
1132 typename std::enable_if<ccudaGPU == 0>::type * )
1138template <
typename realT,
typename detectorT,
int cudaGPU>
1139template <
int ccudaGPU>
1140error_t pyramidSensor<realT, detectorT, cudaGPU>::uploadTilt( complexArrayT &tilt,
1141 complexFieldT <ilt,
1142 typename std::enable_if<ccudaGPU == 1>::type * )
1144 return tilt.upload( ltilt.data(), ltilt.size() );
1147template <
typename realT,
typename detectorT,
int cudaGPU>
1148void pyramidSensor<realT, detectorT, cudaGPU>::makeTilts()
1152 if( m_modSteps == 0 )
1160 "wavefront platescale (m_wfPS) is 0. "
1161 "Must set pupilSz and D first." );
1164 if( !std::isfinite( m_wfPS ) )
1167 "wavefront platescale (m_wfPS) is infinite. "
1168 "Must set pupilSz and D first." );
1176 realT dang = 2 *
pi / ( m_modSteps );
1179 m_tilts.resize( m_modSteps );
1181 std::cout <<
"WF Size: " << m_wfSz <<
"\n";
1182 std::cout <<
"WF PS: " << m_wfPS <<
"\n";
1183 std::cout <<
"Lambda: " << m_lambda <<
"\n";
1184 std::cout <<
"Pyr. PS: " << wfp::fftPlateScale<realT>( m_wfSz, m_wfPS, m_lambda ) * 206265.*1000 <<
" (mas/pix)\n";
1185 std::cout <<
"Mod. steps: " << m_modSteps <<
"\n";
1186 std::cout <<
"Mod rad: " << m_modRadius * ( m_lambda / m_D ) / wfp::fftPlateScale<realT>( m_wfSz, m_wfPS, m_lambda )
1189 for(
int i = 0; i < m_modSteps; ++i )
1191 dx = m_modRadius * ( m_lambda / m_D ) / wfp::fftPlateScale<realT>( m_wfSz, m_wfPS, m_lambda ) *
1192 cos( 0.0 * dang + dang * i );
1193 dy = m_modRadius * ( m_lambda / m_D ) / wfp::fftPlateScale<realT>( m_wfSz, m_wfPS, m_lambda ) *
1194 sin( 0.0 * dang + dang * i );
1197 tilt.resize( m_wfSz, m_wfSz );
1198 tilt.setConstant( std::complex<realT>( 0, 1 ) );
1202 uploadTilt( m_tilts[i], tilt );
1208template <
typename realT,
typename detectorT,
int cudaGPU>
1209void pyramidSensor<realT, detectorT, cudaGPU>::allocThreadMem()
1211 if( !m_opdMaskMade )
1216 m_pupilPlaneCF.resize( m_wfSz, m_wfSz );
1220 m_pupilPlaneCF_gpu.resize( m_wfSz, m_wfSz );
1223 int maxTh = omp_get_max_threads();
1224 m_th_tiltedPlane.resize( maxTh );
1226 m_th_focalPlane.resize( maxTh );
1228 m_th_focalImage.resize( maxTh );
1230 m_th_sensorPlane.resize( maxTh );
1232 m_th_sensorImage.resize( maxTh );
1238 m_cublasHandle.resize(maxTh);
1242 for(
int nTh = 0; nTh < maxTh; ++nTh )
1244 m_th_tiltedPlane[nTh].resize( m_wfSz, m_wfSz );
1246 m_th_focalPlane[nTh].resize( m_wfSz, m_wfSz );
1248 m_th_focalImage[nTh].resize( m_wfSz, m_wfSz );
1250 m_th_sensorPlane[nTh].resize( m_wfSz, m_wfSz );
1252 m_th_sensorImage[nTh].resize( m_imageSz, m_imageSz );
1258 m_cublasHandle[nTh] =
new mx::cuda::cublasHandle(
true);
1263 m_wfsTipImageAccum.resize( m_wfSz, m_wfSz );
1264 m_wfsImageAccum.resize( m_imageSz, m_imageSz );
1266 m_preAllocated =
true;
1269template <
typename realT,
typename detectorT,
int cudaGPU>
1270void pyramidSensor<realT, detectorT, cudaGPU>::preAllocate()
1277 if( !m_opdMaskMade )
1282 if( !m_preAllocated )
1288template <
typename realT,
typename detectorT,
int cudaGPU>
1289void pyramidSensor<realT, detectorT, cudaGPU>::doSenseWavefront()
1293 wavefrontT pupilPlane;
1296 int _firstWavefront = m_lastWavefront - m_iTime;
1297 if( _firstWavefront < 0 )
1298 _firstWavefront += _wavefronts.size();
1300 pupilPlane.amplitude = _wavefronts[_firstWavefront].amplitude;
1301 pupilPlane.phase = _wavefronts[_firstWavefront].phase;
1303 realT avgIt = _wavefronts[_firstWavefront].iterNo;
1307 for(
int i = 0; i < m_iTime; ++i )
1310 if( (
size_t)_firstWavefront >= _wavefronts.size() )
1311 _firstWavefront = 0;
1313 pupilPlane.amplitude += _wavefronts[_firstWavefront].amplitude;
1314 pupilPlane.phase += _wavefronts[_firstWavefront].phase;
1315 avgIt += _wavefronts[_firstWavefront].iterNo;
1320 pupilPlane.amplitude /= ( m_iTime + 1 );
1321 pupilPlane.phase /= ( m_iTime + 1 );
1323 avgIt /= ( m_iTime + 1.0 );
1326 doSenseWavefront( pupilPlane );
1328 m_wfsImage.iterNo = avgIt;
1331template <
typename complexT>
1332void elWiseProduct_cpu( complexT *out, complexT *in1, complexT *in2,
size_t nelem )
1334 for(
int ii = 0; ii < nelem; ++ii )
1336 out[ii] = in1[ii] * in2[ii];
1340template <
typename complexT>
1341void elWiseProduct_gpu( complexT *out, complexT *in1, complexT *in2,
size_t nelem )
1344 cuda::elementwiseXxY( out, in1, in2, nelem );
1347 cudaError_t ce = cudaDeviceSynchronize();
1349 if( ce != cudaSuccess )
1351 std::cerr <<
"cudaError " << cudaGetErrorName( ce ) <<
": " << cudaGetErrorString( ce ) <<
'\n';
1357template <
typename complexT,
int cudaGPU>
1358void elWiseProduct( complexT *out, complexT *in1, complexT *in2,
size_t nelem );
1361void elWiseProduct<std::complex<float>, 0>( std::complex<float> *out,
1362 std::complex<float> *in1,
1363 std::complex<float> *in2,
1366 elWiseProduct_cpu( out, in1, in2, nelem );
1370void elWiseProduct<std::complex<double>, 0>( std::complex<double> *out,
1371 std::complex<double> *in1,
1372 std::complex<double> *in2,
1375 elWiseProduct_cpu( out, in1, in2, nelem );
1379void elWiseProduct<std::complex<float>, 1>( std::complex<float> *out,
1380 std::complex<float> *in1,
1381 std::complex<float> *in2,
1385 elWiseProduct_gpu(
reinterpret_cast<cuComplex *
>( out ),
1386 reinterpret_cast<cuComplex *
>( in1 ),
1387 reinterpret_cast<cuComplex *
>( in2 ),
1390 cudaError_t ce = cudaDeviceSynchronize();
1392 if( ce != cudaSuccess )
1394 std::cerr <<
"cudaError " << cudaGetErrorName( ce ) <<
": " << cudaGetErrorString( ce ) <<
'\n';
1401void elWiseProduct<std::complex<double>, 1>( std::complex<double> *out,
1402 std::complex<double> *in1,
1403 std::complex<double> *in2,
1406 elWiseProduct_gpu(
reinterpret_cast<cuDoubleComplex *
>( out ),
1407 reinterpret_cast<cuDoubleComplex *
>( in1 ),
1408 reinterpret_cast<cuDoubleComplex *
>( in2 ),
1412template <
typename realT,
typename detectorT,
int cudaGPU>
1413template <
int ccudaGPU>
1416 typename std::enable_if<ccudaGPU == 0>::type * )
1421template <
typename realT,
typename detectorT,
int cudaGPU>
1422template <
int ccudaGPU>
1425 typename std::enable_if<ccudaGPU == 1>::type * )
1427 m_pupilPlaneCF_gpu.upload( cf.data() );
1428 return &m_pupilPlaneCF_gpu;
1431template <
typename realT,
typename detectorT,
int cudaGPU>
1432template <
int ccudaGPU>
1436 typename std::enable_if<ccudaGPU == 0>::type * )
1441template <
typename realT,
typename detectorT,
int cudaGPU>
1442template <
int ccudaGPU>
1446 typename std::enable_if<ccudaGPU == 1>::type * )
1452 mx::cuda::cublasTaxpy<realT>( *m_cublasHandle[omp_get_thread_num()], aim.size(), &w, im.data(), 1, aim.data(), 1 );
1458template <
typename realT,
typename detectorT,
int cudaGPU>
1459template <
int ccudaGPU>
1463 typename std::enable_if<ccudaGPU == 0>::type * )
1468template <
typename realT,
typename detectorT,
int cudaGPU>
1469template <
int ccudaGPU>
1473 typename std::enable_if<ccudaGPU == 1>::type * )
1475 aim.download( im.data() );
1479template <
typename realT,
typename detectorT,
int cudaGPU>
1482 if( m_modRadius == 0 )
1484 return doSenseWavefrontNoMod( pupilPlane );
1487 if( !m_preAllocated )
1496 m_wfsTipImageAccum.setZero();
1497 m_wfsImageAccum.setZero();
1501 for(
size_t l = 0; l < m_wavelengths.size(); ++l )
1503 pupilPlane.lambda = m_lambda;
1504 pupilPlane.getWavefront( m_pupilPlaneCF, m_wavelengths[l], m_wfSz );
1506 complexArrayT *pupilPlaneCF = uploadPupilPlaneCF( m_pupilPlaneCF );
1509 #pragma omp parallel
1511 int nTh = omp_get_thread_num();
1514 m_th_sensorImage[nTh].setZero();
1515 m_th_focalImage[nTh].setZero();
1522 complexT *opdm_Data;
1525 ppm_Data =
reinterpret_cast<complexT *
>( pupilPlaneCF->data() );
1526 tpm_Data =
reinterpret_cast<complexT *
>( m_th_tiltedPlane[nTh].data() );
1527 fpm_Data =
reinterpret_cast<complexT *
>( m_th_focalPlane[nTh].data() );
1528 opdm_Data =
reinterpret_cast<complexT *
>( m_opdMask.data() );
1530 int nelem = m_wfSz * m_wfSz;
1534 for(
int i = 0; i < m_modSteps; ++i )
1537 tim_Data =
reinterpret_cast<complexT*
>(m_tilts[i].data());
1544 elWiseProduct<complexT, cudaGPU>( tpm_Data, ppm_Data, tim_Data, nelem );
1551 m_frProp.propagatePupilToFocal( m_th_focalPlane[nTh], m_th_tiltedPlane[nTh],
true );
1558 wfp::extractIntensityImageAccum<realArrayT, complexArrayT, cudaGPU>( m_th_focalImage[nTh],
1563 m_th_focalPlane[nTh],
1572 elWiseProduct<complexT, cudaGPU>( fpm_Data, fpm_Data, opdm_Data, nelem );
1579 m_frProp.propagateFocalToPupil( m_th_sensorPlane[nTh], m_th_focalPlane[nTh],
true );
1587 wfp::extractIntensityImageAccum<realArrayT, complexArrayT, cudaGPU>( m_th_sensorImage[nTh],
1592 m_th_sensorPlane[nTh],
1593 0.5 * m_wfSz - m_imageSz / 2,
1594 0.5 * m_wfSz - m_imageSz / 2 );
1603 #pragma omp critical
1605 accumWeightedImage( m_wfsTipImageAccum, m_th_focalImage[nTh], _wavelengthWeights[l] );
1607 accumWeightedImage( m_wfsImageAccum, m_th_sensorImage[nTh], _wavelengthWeights[l] );
1616 downloadAccumImage( m_wfsImage.tipImage(), m_wfsTipImageAccum, m_modSteps );
1617 m_wfsImage.tipImage.post();
1619 downloadAccumImage( m_wfsImage.image(), m_wfsImageAccum, m_modSteps );
1620 m_wfsImage.image.post();
1626template <
typename T>
1627void memCopy_cpu( T *out, T *in,
size_t nelem )
1629 memcpy( out, in, nelem *
sizeof( T ) );
1632template <
typename T>
1633void memCopy_gpu( T *out, T *in,
size_t nelem )
1635 cudaMemcpy( out, in, nelem *
sizeof( T ), cudaMemcpyDeviceToDevice );
1638template <
typename T,
int cudaGPU>
1639void memCopy( T *out, T *in,
size_t nelem );
1642void memCopy<std::complex<float>, 0>( std::complex<float> *out, std::complex<float> *in,
size_t nelem )
1644 memCopy_cpu( out, in, nelem );
1648void memCopy<std::complex<double>, 0>( std::complex<double> *out, std::complex<double> *in,
size_t nelem )
1650 memCopy_cpu( out, in, nelem );
1654void memCopy<std::complex<float>, 1>( std::complex<float> *out, std::complex<float> *in,
size_t nelem )
1656 memCopy_gpu( out, in, nelem );
1660void memCopy<std::complex<double>, 1>( std::complex<double> *out, std::complex<double> *in,
size_t nelem )
1662 memCopy_gpu( out, in, nelem );
1665template <
typename realT,
typename detectorT,
int cudaGPU>
1666void pyramidSensor<realT, detectorT, cudaGPU>::doSenseWavefrontNoMod( wavefrontT &pupilPlane )
1671 if( !m_opdMaskMade )
1676 m_wfsImage.image.create(
"camwfs", m_imageSz, m_imageSz );
1677 m_wfsImage.image().setZero();
1678 m_wfsImage.image.post();
1680 m_wfsImage.tipImage.create(
"camtip", m_wfSz, m_wfSz );
1681 m_wfsImage.tipImage().setZero();
1682 m_wfsImage.tipImage.post();
1684 pupilPlane.getWavefront( m_pupilPlaneCF, m_wfSz );
1686 complexArrayT *pupilPlaneCF = uploadPupilPlaneCF( m_pupilPlaneCF );
1688 complexFieldT tiltedPlane;
1689 complexFieldT focalPlane;
1690 complexFieldT sensorPlane;
1692 tiltedPlane.resize( m_wfSz, m_wfSz );
1693 focalPlane.resize( m_wfSz, m_wfSz );
1694 sensorPlane.resize( m_wfSz, m_wfSz );
1696 int nelem = m_wfSz * m_wfSz;
1698 complexT *tpm_Data =
reinterpret_cast<complexT *
>( tiltedPlane.data() );
1699 complexT *ppm_Data =
reinterpret_cast<complexT *
>( pupilPlaneCF->data() );
1700 complexT *opdm_Data =
reinterpret_cast<complexT *
>( m_opdMask.data() );
1701 complexT *fpm_Data =
reinterpret_cast<complexT *
>( focalPlane.data() );
1708 memCopy<complexT, cudaGPU>( tpm_Data, ppm_Data, nelem );
1719 m_frProp.propagatePupilToFocal( focalPlane, tiltedPlane,
true );
1726 wfp::extractIntensityImageAccum<realArrayT, complexArrayT, cudaGPU>( m_wfsImage.tipImage(),
1740 elWiseProduct<complexT, cudaGPU>( fpm_Data, fpm_Data, opdm_Data, nelem );
1751 m_frProp.propagateFocalToPupil( sensorPlane, focalPlane,
true );
1758 wfp::extractIntensityImageAccum<realArrayT, complexArrayT, cudaGPU>( m_wfsImage.image(),
1764 0.5 * m_wfSz - m_imageSz / 2,
1765 0.5 * m_wfSz - m_imageSz / 2 );
A Pyramid Sensor Simulation.
std::vector< complexArrayT > m_th_sensorPlane
Thread-local sensor-pupil-plane wavefront.
realT perStep()
Get the minimum number of modulation steps.
uint32_t m_wfSz
Size of the wavefront in pixels.
std::vector< realT > m_wavelengths
Vector of wavelengths in the WFS bandpass.
std::vector< realArrayT > m_th_focalImage
Thread-local tip image.
realT lambda()
Get the PyWFS central wavelength.
pyramidSensor()
Default constructor.
wfp::fraunhoferPropagatorArrayT< complexFieldT, cudaGPU >::arrayT complexArrayT
The complex array data type.
realT angleOffset()
Get the angle offset.
int wfSz()
Get the wavefront size in pixels.
void detSize(const uint32_t &nrows, const uint32_t &ncols)
Set the detector columns in pixels.
uint32_t m_nSides
Number of sides in the pyramid.
realT simStep()
Get the simulation step-size, in seconds.
wavefront< realT > wavefrontT
The wavefront data type.
int iTime()
Get the PyWFS integration time, in time steps.
wfsImageT< realT > detectorImage
The image on the detector, resized from m_wfsImage.
Eigen::Array< floatT, Eigen::Dynamic, Eigen::Dynamic > wfsImageT
The wavefront sensor detector image type.
improc::eigenImage< std::complex< realT > > complexFieldT
The wavefront complex field type.
void accumWeightedImage(realArrayT &aim, realArrayT &im, realT w, typename std::enable_if< ccudaGPU==0 >::type *=0)
Accumulate an image with a weight applied on the CPU.
bool m_imageSzAuto
Flag to track if m_imageSz should be set to 0.
void linkSystem(AOSysT &AOSys)
Link this WFS to an AO system simulation.
realT m_D
Telescope diameter, in meters.
std::vector< complexArrayT > m_th_focalPlane
Thread-local tip wavefront, used for FFT tilting.
realT wfPS()
Get the wavefront pixel scale in meters per pixel.
uint32_t detCols()
Get the detector columns in pixels.
int modSteps()
Get the number of modulation steps.
realT m_pupilSep
The separation of the pupil images in fraction of a pupil. 0 <= m_pupilSep, default 1.
realT m_angleOffset
The angle by which to offset the pupils, in degrees. Default is 0.
_detectorT detectorT
The wavefront sensor detector image type.
void downloadAccumImage(improc::eigenMap< realT > &im, realArrayT &aim, uint32_t naccums, typename std::enable_if< ccudaGPU==0 >::type *=0)
Scale the accumulated image by number of accumulations and assign it to the output image....
wfsImageT< realT > m_wfsImage
The image formed by the WFS.
int roTime()
Get the PyWFS detector readout time, in time steps.
_realT realT
The real floating point type used for calculations.
uint32_t imageSz()
Get the image size in wavefront pixels.
detectorT detector
The WFS detector.
std::vector< realT > _wavelengthWeights
The relative weights of the wavelengths.
~pyramidSensor()
Destructor.
int m_iTime
Integration time in loop steps.
wfp::fraunhoferPropagatorArrayT< realImageT, cudaGPU >::arrayT realArrayT
The real array data type.
std::complex< realT > complexT
The complex floating point type used for calculations.
uint32_t detRows()
Get the detector rows in pixels.
complexArrayT * uploadPupilPlaneCF(complexFieldT &cf, typename std::enable_if< ccudaGPU==0 >::type *=0)
Convert a cpu complex field to a pointer to its CPU memory.
std::vector< complexArrayT > m_th_tiltedPlane
Thread-local modulated wavefront.
realT modRadius()
Get the radius of modulation.
realT m_lambda
Central wavelength, in meters.
uint32_t m_pupilSz
The size of the pupil in wavefront pixels.
bool senseWavefrontCal(wavefrontT &pupilPlane)
Sense the wavefront aberrations in calibration mode.
int m_roTime
Readout time in loop steps.
bool senseWavefront(wavefrontT &pupilPlane)
Sense the wavefront aberrations.
uint32_t pupilSz()
Get the pupil size in pixels.
int nSides()
Get the number of pyramid sides.
bool imageSzAuto()
Get the value of the image size auto flag.
realT D()
Get the telescope diameter.
std::vector< realArrayT > m_th_sensorImage
uint32_t m_imageSz
The size of the resulting PyWFS image in wavefront pixels.
realT m_wfPS
Wavefront pixel scale, in meters/pixel.
realT m_simStep
The simulation stepsize in seconds.
realT m_modRadius
Radius of the modulation in pixels.
Augments an exception with the source file and line.
Class to perform Fraunhofer propagation between pupil and focal planes.
Eigen::Array< scalarT, -1, -1 > eigenImage
Definition of the eigenImage type, which is an alias for Eigen::Array.
Eigen::Map< Eigen::Array< scalarT, -1, -1 > > eigenMap
Definition of the eigenMap type, which is an alias for Eigen::Map<Array>.
error_t
The mxlib error codes.
@ noerror
No error has occurred.
@ invalidconfig
A config setting was invalid.
constexpr T pi()
Get the value of pi.
constexpr floatT six_fifths()
Return 6/5 in the specified precision.
realT rtod(realT q)
Convert from radians to degrees.
void maskWedge(arrayT &m, typename arrayT::Scalar xcen, typename arrayT::Scalar ycen, typename arrayT::Scalar angCen, typename arrayT::Scalar angHW, typename arrayT::Scalar val=0)
Mask a wedge in an image.
void tiltWavefront(wavefrontT &complexWavefront, typename wavefrontT::Scalar::value_type xTilt, typename wavefrontT::Scalar::value_type yTilt)
Apply a tilt to a wavefront.
Structure containing the phase and amplitude of a wavefront.
realImageT amplitude
The wavefront amplitude.
realT iterNo
The iteration number of this wavefront.
realImageT phase
The wavefront phase.