8#ifndef zernikeCovariance_hpp
9#define zernikeCovariance_hpp
11#include <gsl/gsl_integration.h>
12#include <gsl/gsl_errno.h>
14#include "../../math/constants.hpp"
15#include "../../math/func/jinc.hpp"
16#include "../../sigproc/zernike.hpp"
17#include "../../ioutils/fits/fitsFile.hpp"
18#include "../../improc/eigenImage.hpp"
19#include "../../improc/eigenCube.hpp"
20#include "../../mxlib_uncomp_version.h"
21#include "../../ipc/ompLoopWatcher.hpp"
22#include "../../sys/timeUtils.hpp"
23#include "../../math/eigenLapack.hpp"
25#include "../../math/func/airyPattern.hpp"
44template <
typename realT,
typename aosysT>
78 size_t m_workspaceSize{ 1000000 };
90 m_workspacePhi = gsl_integration_workspace_alloc( m_workspaceSize );
91 m_workspaceK = gsl_integration_workspace_alloc( m_workspaceSize );
101 void workspaceSize(
size_t wsz )
106 m_workspacePhi = gsl_integration_workspace_alloc( m_workspaceSize );
107 m_workspaceK = gsl_integration_workspace_alloc( m_workspaceSize );
110 size_t workspaceSize()
112 return m_workspaceSize;
115 gsl_integration_workspace *workspacePhi()
131 err::paramnotset,
"zernikeCovariance::getCovariance",
"AO system not setup (aosys is nullptr)" );
135 func.function = &
kInt;
138 gsl_set_error_handler_off();
140 int ec = gsl_integration_qagiu(
150 static realT
kInt( realT k,
158 static realT
phiInt( realT phi,
163template <
typename realT,
typename aosysT>
172 func.function = &phiInt;
178 gsl_integration_qag( &func,
180 math::two_pi<double>(),
192template <
typename realT,
typename aosysT>
205 std::complex<realT> Q_mn = zernikeQ( k * D / 2.0, phi, n, m );
211 std::complex<realT> Q_mpnp = zernikeQ( k * D / 2.0, phi, np, mp );
214 realT QQ = real( conj( Q_mn ) * Q_mpnp );
224template<
typename realT,
typename aosysT>
234 std::vector<realT> var(N,0);
239 if( aosys.d_min(0) > 0)
241 mnCon = floor( aosys.D()/aosys.d_min(0)/2.0);
255#pragma omp for schedule( dynamic, 5 )
256 for(
int i=0; i< N; ++i)
266 result = Pp.getVariance(error);
278 realT r_0 = aosys.atm.r_0();
279 realT tot = 1.0299*pow(D/r_0, 5./3.);
283 std::cout << 0 <<
" " << 0 <<
" " << 0 <<
" " << tot <<
"\n";
284 for(
int i=0; i<N; ++i)
288 realT P = aosys.psd(aosys.atm, 0, k, 1.0);
294 P *= pow(
math::two_pi<realT>()*aosys.atm.v_wind()* k * (aosys.minTauWFS(0)+aosys.deltaTau()),2);
299 fout << i+1 <<
" " << var[i] <<
" " << P/pow(D,2) <<
" " << tot-sum <<
"\n";
313template<
typename realT,
typename aosysT>
322 psd.resize(2*N + 1, 2*N+1);
325 if( aosys.d_min() > 0)
327 mnCon = floor( aosys.D()/aosys.d_min()/2.0);
330 for(
int i=0; i<=N; ++i)
332 for(
int j=-N; j<=N; ++j)
336 realT k = sqrt( pow(i,2) + pow(j,2))/D/overSample;
338 realT P = aosys.psd(aosys.atm, k, aosys.lam_sci(), 0, aosys.lam_wfs(), 1.0);
344 P *= pow(
math::two_pi<realT>()*aosys.atm.v_wind()* k * (aosys.minTauWFS()+aosys.deltaTau()),2);
348 psd(N+i, N + j) = P/pow(D*overSample,2);
349 psd(N-i, N - j) = P/pow(D*overSample,2);
354 Eigen::Array<realT, -1,-1> psf;
355 psf.resize(2*N+3,2*N+3);
356 for(
int i=0;i<psf.rows();++i)
358 for(
int j=0;j<psf.cols();++j)
369template<
typename realT>
381 std::vector<mx::sigproc::zernikeModeDef> ml;
382 mx::sigproc::makezernikeModeFreqs_Rect(ml, N);
390 aosys.atm.
r_0(1.0, 0.5e-6);
393 aosys.atm.
L_0( L_0 );
394 aosys.psd.subPiston( subPist );
395 aosys.psd.subTipTilt( subTilt );
399 Eigen::Array<realT,-1,-1> covar( psz, psz);
406 std::cerr <<
"Starting . . .\n";
418#pragma omp for schedule( static, 5 )
419 for(
int i=0; i< psz; ++i)
421 for(
int j=i; j< psz; ++j)
430 result = Pp.getVariance(error);
440 head.
append(
"DIAMETER", aosys.
D(),
"Diameter in meters");
441 head.
append(
"NSUBAP", N,
"Linear number of s.f. sampled");
442 head.
append(
"L0", aosys.atm.
L_0(0),
"Outer scale (L_0) in meters");
443 head.
append(
"SUBPIST", aosys.psd.subPiston(),
"Piston subtractioon true/false flag");
444 head.
append(
"SUBTILT", aosys.psd.subTipTilt(),
"Tip/Tilt subtractioon true/false flag");
445 head.
append(
"ABSTOL", absTol,
"Absolute tolerance in qagiu");
446 head.
append(
"RELTOL", relTol,
"Relative tolerance in qagiu");
448 fitsHeaderGitStatus(head,
"mxlib_uncomp", MXLIB_UNCOMP_CURRENT_SHA1, MXLIB_UNCOMP_REPO_MODIFIED);
452 ff.
write(fname +
".fits", covar, head);
460template<
typename realT,
typename aosysT>
461int zernikeCovarMapSeparated(
const std::string & fname,
468 std::vector<mx::sigproc::zernikeModeDef> ml;
469 mx::sigproc::makezernikeModeFreqs_Rect(ml, N);
471 int psz = 0.5*ml.size();
473 Eigen::Array<realT,-1,-1> covar_pp( (
int) (0.5*psz), (
int)(.5*psz)), covar_ppp( (
int) (0.5*psz), (
int)(0.5*psz));
478 if( aosys.d_min() > 0)
480 mnCon = floor( aosys.D()/aosys.d_min()/2.0);
488 zernikeCovariance<realT, aosysT > Pp;
493 if(!modified) Pp.useBasic =
true;
499#pragma omp for schedule( dynamic, 5 )
500 for(
int i=0; i< psz; i+=2)
502 for(
int j=0; j<= 0.5*i; ++j)
504 for(
int k=0; k< 2; ++k)
510 Pp.pp = ml[2*j + k].p;
511 Pp.mp = ml[2*j + k].m;
512 Pp.np = ml[2*j + k].n;
513 result = Pp.getVariance(error);
517 covar_pp(i/2, j) = result;
521 covar_ppp(i/2, j) = result;
523 watcher.incrementAndOutputStatus();
529 fits::fitsHeader head;
530 head.append(
"DIAMETER", aosys.D(),
"Diameter in meters");
531 head.append(
"L0", aosys.atm.L_0(),
"Outer scale (L_0) in meters");
532 head.append(
"SUBPIST", aosys.psd.subPiston(),
"Piston subtractioon true/false flag");
533 head.append(
"SUBTILT", aosys.psd.subTipTilt(),
"Tip/Tilt subtractioon true/false flag");
534 head.append(
"ABSTOL", absTol,
"Absolute tolerance in qagiu");
535 head.append(
"RELTOL", relTol,
"Relative tolerance in qagiu");
538 fitsHeaderGitStatus(head,
"mxlib_uncomp", MXLIB_UNCOMP_CURRENT_SHA1, MXLIB_UNCOMP_REPO_MODIFIED);
540 fits::fitsFile<realT> ff;
541 ff.write(fname +
"_pp.fits", covar_pp, head);
542 ff.write(fname +
"_ppp.fits", covar_ppp, head);
547template<
typename realT>
548void calcKLCoeffs(
const std::string & outFile,
549 const std::string & cvFile )
551 fits::fitsFile<realT> ff;
553 Eigen::Array<realT,-1,-1> cvT, cv, evecs, evals;
559 std::cerr << cvT.rows() <<
" " << cvT.cols() <<
"\n";
573 std::cerr <<
"info =" << info <<
"\n";
577 std::cerr <<
"Time = " << t1-t0 <<
" secs\n";
580 for(
int i=0;i< evecs.cols(); ++i)
582 evecs.col(i) = evecs.col(i)/sqrt(fabs(evals(i)));
585 ff.write(outFile, evecs);
588template<
typename eigenArrT1,
typename eigenArrT2,
typename eigenArrT3>
589void makeKL( eigenArrT1 & kl,
591 eigenArrT3 && rvecs )
594 int tNims = evecs.rows();
595 int tNpix = rvecs.rows();
604 tNims, 1., evecs.data(), evecs.rows(), rvecs.data(), rvecs.rows(),
605 0., kl.data(), kl.rows());
609template<
typename realT>
610void makeFKL(
const std::string & outFile,
611 const std::string & coeffs,
615 fits::fitsFile<realT> ff;
616 Eigen::Array<realT, -1, -1> evecs;
618 ff.read(evecs, coeffs);
620 improc::eigenCube<realT> Rims;
621 sigproc::makezernikeBasis_Rect(Rims, pupSize, N, MX_zernike_MODIFIED);
623 std::cout << Rims.planes() <<
" " << evecs.cols() <<
"\n";
625 Eigen::Array<realT,-1,-1> kl;
626 kl.resize( Rims.planes(), Rims.rows()*Rims.cols());
628 std::cerr << 1 <<
"\n";
629 makeKL( kl, evecs, Rims.cube());
630 std::cerr << 2 <<
"\n";
632 Eigen::Array<realT,-1,-1> klT = kl.transpose();
637 improc::eigenCube<realT> klims(klT.data(), Rims.rows(), Rims.cols(), Rims.planes());
639 improc::eigenCube<realT> klimsR;
640 klimsR.resize( klims.rows(), klims.cols(), klims.planes());
642 for(
int i=0; i< klims.planes(); ++i)
644 klimsR.image(i) = klims.image(klims.planes()-1-i);
647 ff.write(outFile, klimsR);
648 std::cerr << 3 <<
"\n";
Provides a class to specify atmosphere parameters.
Spatial power spectra used in adaptive optics.
Declares and defines an analytical AO system.
realT L_0(const size_t &n)
Get the value of the outer scale for a single layer.
realT r_0()
Get the value of Fried's parameter r_0 at the reference wavelength lam_0.
Describes an analytic adaptive optics (AO) system.
void loadMagAOX()
Load parameters corresponding to the MagAO-X system.
void D(realT nD)
Set the value of the primary mirror diameter.
mxException for parameters which aren't set
Class to manage interactions with a FITS file.
int write(const dataT *im, int d1, int d2, int d3, fitsHeader *head)
Write the contents of a raw array to the FITS file.
A class to track the number of iterations in an OMP parallelized loop.
void incrementAndOutputStatus()
Increment and output status.
@ modified
The modified Fourier basis from .
Eigen::Array< scalarT, -1, -1 > eigenImage
Definition of the eigenImage type, which is an alias for Eigen::Array.
void fitsHeaderGitStatus(fitsHeader &head, const std::string &repoName, const char *sha1, int modified)
Write the status of a Git repository to HISTORY in a FITS header.
realT airyPattern(realT x)
The classical Airy pattern.
constexpr floatT six_fifths()
Return 6/5 in the specified precision.
void varmapToImage(imageT &im, imageT &varmap, imageT &psf)
Convert a wavefront variance map to an intensity image by convolving with the PSF.
typeT get_curr_time()
Get the current system time in seconds.
Structure to manage the zernike mode covariance calculation, passed to integration functions.
zernikeCovariance()
Constructor.
realT m_kIntEpsAbs
Absolute tolerance for the radial integral. Default is 1e-10.
aosysT * m_aosys
Pointer to an AO system, which contains the relevant spatial PSD of turbulence.
realT m_k
Spatial frequency being calculated, passed for use in the integrand worker functions.
realT m_m
The m-index of the unprimed mode.
realT m_mp
The m-index of the primed mode, corresponding to the component of spatial frequency.
realT m_np
The n-indexof the primed mode, corresponding to the component of spatial frequency.
gsl_integration_workspace * m_workspacePhi
Working memory for the azimuthal integral.
realT m_phiIntEpsRel
Relative tolerance for the azimuthal integral. Default is 0, meaning absolute is used.
static realT phiInt(realT phi, void *params)
Worker for the azimuthal integral (in phi) for the zernike mode covariance.
realT getCovariance(realT &error)
Calculate the covariance between the two modes.
realT m_n
The n-index of the unprimed mode.
realT m_phiIntEpsAbs
Absolute tolerance for the azimuthal integral. Default is 1e-10.
~zernikeCovariance()
Destructor.
gsl_integration_workspace * m_workspaceK
Working memory for the radial integral.
realT m_kIntEpsRel
Relative tolerance for the radial integral. Default is 0, meaning absolute is used.
static realT kInt(realT k, void *params)
Worker function for the radial integral in the covariance calculation.
A utility to convert a wavefront variance map to an intensity image.
int zernikeCovarMap(const std::string &fname, int N, realT D, realT L_0, bool subPist, bool subTilt, realT absTol, realT relTol, bool modified=true)
int zernikeVarVec(const std::string &fname, int N, aosysT &aosys, realT absTol, realT relTol, bool modifed=true)
Calculate a vector of zernike mode variances.
int zernikePSDMap(improc::eigenImage< realT > &var, improc::eigenImage< realT > &psd, int N, int overSample, aosysT &aosys)
Calculate a map of zernike variances by convolution with the PSD.