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.hpp"
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>
225int zernikeVarVec(
const std::string & fname,
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);
246 zernikeCovariance<realT, aosysT> Pp;
255#pragma omp for schedule( dynamic, 5 )
256 for(
int i=0; i< N; ++i)
266 result = Pp.getVariance(
error);
270 watcher.incrementAndOutputStatus();
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>
314int zernikePSDMap( improc::eigenImage<realT> & var,
315 improc::eigenImage<realT> & psd,
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>
370int zernikeCovarMap(
const std::string & fname,
381 std::vector<mx::sigproc::zernikeModeDef> ml;
382 mx::sigproc::makezernikeModeFreqs_Rect(ml, N);
385 aoSystem<realT, vonKarmanSpectrum<realT>> aosys;
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);
404 ipc::ompLoopWatcher<> watcher(psz, std::cout);
406 std::cerr <<
"Starting . . .\n";
409 zernikeCovariance<realT, aoSystem<realT, vonKarmanSpectrum<realT> > > Pp;
414 if(!modified) Pp.useBasic =
true;
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);
435 watcher.incrementAndOutputStatus();
439 fits::fitsHeader head;
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", mxlib_comp_current_sha1(), mxlib_comp_repo_modified() );
450 fits::fitsFile<realT> ff;
451 ff.write(fname +
".fits", covar, head);
459template<
typename realT,
typename aosysT>
460int zernikeCovarMapSeparated(
const std::string & fname,
467 std::vector<mx::sigproc::zernikeModeDef> ml;
468 mx::sigproc::makezernikeModeFreqs_Rect(ml, N);
470 int psz = 0.5*ml.size();
472 Eigen::Array<realT,-1,-1> covar_pp( (
int) (0.5*psz), (
int)(.5*psz)), covar_ppp( (
int) (0.5*psz), (
int)(0.5*psz));
477 if( aosys.d_min() > 0)
479 mnCon = floor( aosys.D()/aosys.d_min()/2.0);
482 ipc::ompLoopWatcher<> watcher((psz+1)*0.125*(psz+1)*2, std::cout);
487 zernikeCovariance<realT, aosysT > Pp;
492 if(!modified) Pp.useBasic =
true;
498#pragma omp for schedule( dynamic, 5 )
499 for(
int i=0; i< psz; i+=2)
501 for(
int j=0; j<= 0.5*i; ++j)
503 for(
int k=0;
k< 2; ++
k)
509 Pp.pp = ml[2*j +
k].p;
510 Pp.mp = ml[2*j +
k].m;
511 Pp.np = ml[2*j +
k].n;
512 result = Pp.getVariance(
error);
516 covar_pp(i/2, j) = result;
520 covar_ppp(i/2, j) = result;
522 watcher.incrementAndOutputStatus();
528 fits::fitsHeader head;
529 head.append(
"DIAMETER", aosys.D(),
"Diameter in meters");
530 head.append(
"L0", aosys.atm.L_0(),
"Outer scale (L_0) in meters");
531 head.append(
"SUBPIST", aosys.psd.subPiston(),
"Piston subtractioon true/false flag");
532 head.append(
"SUBTILT", aosys.psd.subTipTilt(),
"Tip/Tilt subtractioon true/false flag");
533 head.append(
"ABSTOL", absTol,
"Absolute tolerance in qagiu");
534 head.append(
"RELTOL", relTol,
"Relative tolerance in qagiu");
536 fitsHeaderGitStatus( head,
"mxlib", mxlib_comp_current_sha1(), mxlib_comp_repo_modified() );
538 fits::fitsFile<realT> ff;
539 ff.write(fname +
"_pp.fits", covar_pp, head);
540 ff.write(fname +
"_ppp.fits", covar_ppp, head);
545template<
typename realT>
546void calcKLCoeffs(
const std::string & outFile,
547 const std::string & cvFile )
549 fits::fitsFile<realT> ff;
551 Eigen::Array<realT,-1,-1> cvT, cv, evecs, evals;
557 std::cerr << cvT.rows() <<
" " << cvT.cols() <<
"\n";
571 std::cerr <<
"info =" << info <<
"\n";
575 std::cerr <<
"Time = " << t1-t0 <<
" secs\n";
578 for(
int i=0;i< evecs.cols(); ++i)
580 evecs.col(i) = evecs.col(i)/sqrt(fabs(evals(i)));
583 ff.write(outFile, evecs);
586template<
typename eigenArrT1,
typename eigenArrT2,
typename eigenArrT3>
587void makeKL( eigenArrT1 & kl,
589 eigenArrT3 && rvecs )
592 int tNims = evecs.rows();
593 int tNpix = rvecs.rows();
602 tNims, 1., evecs.data(), evecs.rows(), rvecs.data(), rvecs.rows(),
603 0., kl.data(), kl.rows());
607template<
typename realT>
608void makeFKL(
const std::string & outFile,
609 const std::string & coeffs,
613 fits::fitsFile<realT> ff;
614 Eigen::Array<realT, -1, -1> evecs;
616 ff.read(evecs, coeffs);
618 improc::eigenCube<realT> Rims;
619 sigproc::makezernikeBasis_Rect(Rims, pupSize, N, MX_zernike_MODIFIED);
621 std::cout << Rims.planes() <<
" " << evecs.cols() <<
"\n";
623 Eigen::Array<realT,-1,-1> kl;
624 kl.resize( Rims.planes(), Rims.rows()*Rims.cols());
626 std::cerr << 1 <<
"\n";
627 makeKL( kl, evecs, Rims.cube());
628 std::cerr << 2 <<
"\n";
630 Eigen::Array<realT,-1,-1> klT = kl.transpose();
635 improc::eigenCube<realT> klims(klT.data(), Rims.rows(), Rims.cols(), Rims.planes());
637 improc::eigenCube<realT> klimsR;
638 klimsR.resize( klims.rows(), klims.cols(), klims.planes());
640 for(
int i=0; i< klims.planes(); ++i)
642 klimsR.image(i) = klims.image(klims.planes()-1-i);
645 ff.write(outFile, klimsR);
646 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.
mxException for parameters which aren't set
A class to track the number of iterations in an OMP parallelized loop.
constexpr units::realT k()
Boltzmann Constant.
@ error
A general error has occurred.
#define mxThrowException(extype, src, expl)
Throw an exception. This macro takes care of the file and line.
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.