8 #ifndef fourierCovariance_hpp
9 #define fourierCovariance_hpp
12 #include <gsl/gsl_integration.h>
13 #include <gsl/gsl_errno.h>
15 #include "../../math/constants.hpp"
16 #include "../../math/func/jinc.hpp"
17 #include "../../sigproc/fourierModes.hpp"
18 #include "../../ioutils/fits/fitsFile.hpp"
19 #include "../../improc/eigenImage.hpp"
20 #include "../../improc/eigenCube.hpp"
21 #include "../../mxlib_uncomp_version.h"
22 #include "../../ipc/ompLoopWatcher.hpp"
23 #include "../../sys/timeUtils.hpp"
24 #include "../../math/eigenLapack.hpp"
26 #include "../../math/func/airyPattern.hpp"
54 template<
typename realT,
typename aosysT>
55 struct fourierCovariance;
67 template<
typename realT,
typename aosysT>
73 realT D = Pp->
aosys->D();
85 realT cosp = cos(phi);
86 realT sinp = sin(phi);
90 realT Ji_mn_p, Ji_mn_m;
93 kmn_p = sqrt( pow(
k*cosp + m/D, 2) + pow(
k*sinp + n/D, 2));
94 kmn_m = sqrt( pow(
k*cosp - m/D, 2) + pow(
k*sinp - n/D, 2));
100 realT N = 1./sqrt(0.5 + p*
math::func::jinc(math::two_pi<realT>()*sqrt(m*m+n*n)));
102 Q_mn = N*(Ji_mn_p + p*Ji_mn_m);
105 realT kmpnp_p, kmpnp_m;
106 realT Ji_mpnp_p, Ji_mpnp_m;
109 kmpnp_p = sqrt( pow(
k*cosp + mp/D, 2) + pow(
k*sinp + np/D, 2));
110 kmpnp_m = sqrt( pow(
k*cosp - mp/D, 2) + pow(
k*sinp - np/D, 2));
116 realT Np = 1./sqrt(0.5 + pp*
math::func::jinc(math::two_pi<realT>()*sqrt(mp*mp+np*np)));
118 Q_mpnp = Np*(Ji_mpnp_p + pp*Ji_mpnp_m);
120 realT P = Pp->
aosys->psd(Pp->
aosys->atm, 0,
k, 1.0);
122 return P*
k*(Q_mn*Q_mpnp);
133 template<
typename realT,
typename aosysT>
140 realT D = Pp->
aosys->D();
152 realT mnCon = Pp->
mnCon;
154 realT cosp = cos(phi);
155 realT sinp = sin(phi);
159 realT Ji_mn_p, Ji_mn_m;
161 kmn_p = sqrt( pow(
k*cosp + m/D, 2) + pow(
k*sinp + n/D, 2));
162 kmn_m = sqrt( pow(
k*cosp - m/D, 2) + pow(
k*sinp - n/D, 2));
169 realT kmpnp_p, kmpnp_m;
170 realT Ji_mpnp_p, Ji_mpnp_m;
172 kmpnp_p = sqrt( pow(
k*cosp + mp/D, 2) + pow(
k*sinp + np/D, 2));
173 kmpnp_m = sqrt( pow(
k*cosp - mp/D, 2) + pow(
k*sinp - np/D, 2));
183 QQ = 2.0*( Ji_mn_p*Ji_mpnp_p + Ji_mn_m*Ji_mpnp_m);
187 QQ = 2.0*( Ji_mn_p*Ji_mpnp_m + Ji_mn_m*Ji_mpnp_p);
190 realT P = Pp->
aosys->psd(Pp->
aosys->atm, 0,
k, 1.0);
214 template<
typename realT,
typename aosysT>
226 func.function = &phiInt_basic<realT, aosysT>;
230 func.function = &phiInt_mod<realT, aosysT>;
237 gsl_integration_qag(&func, 0., math::two_pi<double>(), 1e-10, 1e-4, WSZ, GSL_INTEG_GAUSS21, Pp->
phi_w, &result, &error);
248 template<
typename realT,
typename aosysT>
291 gsl_integration_workspace *
k_w;
296 phi_w = gsl_integration_workspace_alloc (WSZ);
297 k_w = gsl_integration_workspace_alloc (WSZ);
303 gsl_integration_workspace_free(
phi_w);
304 gsl_integration_workspace_free(
k_w);
316 func.function = &kInt<realT, aosysT>;
319 gsl_set_error_handler_off();
321 int ec = gsl_integration_qagiu (&func, 0,
absTol,
relTol, WSZ,
k_w, &result, &error);
330 template<
typename realT,
typename aosysT>
340 std::vector<realT> var(N,0);
345 if( aosys.d_min(0) > 0)
347 mnCon = floor( aosys.D()/aosys.d_min(0)/2.0);
361 #pragma omp for schedule(dynamic,5)
362 for(
int i=0; i< N; ++i)
384 realT r_0 = aosys.atm.r_0();
385 realT tot = 1.0299*pow(D/r_0, 5./3.);
389 std::cout << 0 <<
" " << 0 <<
" " << 0 <<
" " << tot <<
"\n";
390 for(
int i=0; i<N; ++i)
394 realT P = aosys.psd(aosys.atm, 0,
k, 1.0);
400 P *= pow(math::two_pi<realT>()*aosys.atm.v_wind()*
k * (aosys.minTauWFS(0)+aosys.deltaTau()),2);
405 fout << i+1 <<
" " << var[i] <<
" " << P/pow(D,2) <<
" " << tot-sum <<
"\n";
419 template<
typename realT,
typename aosysT>
428 psd.resize(2*N + 1, 2*N+1);
431 if( aosys.d_min() > 0)
433 mnCon = floor( aosys.D()/aosys.d_min()/2.0);
436 for(
int i=0; i<=N; ++i)
438 for(
int j=-N; j<=N; ++j)
442 realT
k = sqrt( pow(i,2) + pow(j,2))/D/overSample;
444 realT P = aosys.psd(aosys.atm,
k, aosys.lam_sci(), 0, aosys.lam_wfs(), 1.0);
450 P *= pow(math::two_pi<realT>()*aosys.atm.v_wind()*
k * (aosys.minTauWFS()+aosys.deltaTau()),2);
454 psd(N+i, N + j) = P/pow(D*overSample,2);
455 psd(N-i, N - j) = P/pow(D*overSample,2);
460 Eigen::Array<realT, -1,-1> psf;
461 psf.resize(2*N+3,2*N+3);
462 for(
int i=0;i<psf.rows();++i)
464 for(
int j=0;j<psf.cols();++j)
475 template<
typename realT>
487 std::vector<mx::sigproc::fourierModeDef> ml;
488 mx::sigproc::makeFourierModeFreqs_Rect(ml, N);
496 aosys.atm.
r_0(1.0, 0.5e-6);
499 aosys.atm.
L_0( L_0 );
500 aosys.psd.subPiston( subPist );
501 aosys.psd.subTipTilt( subTilt );
505 Eigen::Array<realT,-1,-1> covar( psz, psz);
512 std::cerr <<
"Starting . . .\n";
524 #pragma omp for schedule(static,5)
525 for(
int i=0; i< psz; ++i)
527 for(
int j=i; j< psz; ++j)
546 head.
append(
"DIAMETER", aosys.
D(),
"Diameter in meters");
547 head.
append(
"NSUBAP", N,
"Linear number of s.f. sampled");
548 head.
append(
"L0", aosys.atm.
L_0(0),
"Outer scale (L_0) in meters");
549 head.
append(
"SUBPIST", aosys.psd.subPiston(),
"Piston subtractioon true/false flag");
550 head.
append(
"SUBTILT", aosys.psd.subTipTilt(),
"Tip/Tilt subtractioon true/false flag");
551 head.
append(
"ABSTOL", absTol,
"Absolute tolerance in qagiu");
552 head.
append(
"RELTOL", relTol,
"Relative tolerance in qagiu");
554 fitsHeaderGitStatus(head,
"mxlib_uncomp", MXLIB_UNCOMP_CURRENT_SHA1, MXLIB_UNCOMP_REPO_MODIFIED);
558 ff.
write(fname +
".fits", covar, head);
566 template<
typename realT,
typename aosysT>
567 int fourierCovarMapSeparated(
const std::string & fname,
574 std::vector<mx::sigproc::fourierModeDef> ml;
575 mx::sigproc::makeFourierModeFreqs_Rect(ml, N);
577 int psz = 0.5*ml.size();
579 Eigen::Array<realT,-1,-1> covar_pp( (
int) (0.5*psz), (
int)(.5*psz)), covar_ppp( (
int) (0.5*psz), (
int)(0.5*psz));
584 if( aosys.d_min() > 0)
586 mnCon = floor( aosys.D()/aosys.d_min()/2.0);
594 fourierCovariance<realT, aosysT > Pp;
599 if(!modified) Pp.useBasic =
true;
605 #pragma omp for schedule(dynamic,5)
606 for(
int i=0; i< psz; i+=2)
608 for(
int j=0; j<= 0.5*i; ++j)
610 for(
int k=0;
k< 2; ++
k)
616 Pp.pp = ml[2*j +
k].p;
617 Pp.mp = ml[2*j +
k].m;
618 Pp.np = ml[2*j +
k].n;
619 result = Pp.getVariance(error);
623 covar_pp(i/2, j) = result;
627 covar_ppp(i/2, j) = result;
629 watcher.incrementAndOutputStatus();
635 fits::fitsHeader head;
636 head.append(
"DIAMETER", aosys.D(),
"Diameter in meters");
637 head.append(
"L0", aosys.atm.L_0(),
"Outer scale (L_0) in meters");
638 head.append(
"SUBPIST", aosys.psd.subPiston(),
"Piston subtractioon true/false flag");
639 head.append(
"SUBTILT", aosys.psd.subTipTilt(),
"Tip/Tilt subtractioon true/false flag");
640 head.append(
"ABSTOL", absTol,
"Absolute tolerance in qagiu");
641 head.append(
"RELTOL", relTol,
"Relative tolerance in qagiu");
644 fitsHeaderGitStatus(head,
"mxlib_uncomp", MXLIB_UNCOMP_CURRENT_SHA1, MXLIB_UNCOMP_REPO_MODIFIED);
646 fits::fitsFile<realT> ff;
647 ff.write(fname +
"_pp.fits", covar_pp, head);
648 ff.write(fname +
"_ppp.fits", covar_ppp, head);
653 template<
typename realT>
654 void calcKLCoeffs(
const std::string & outFile,
655 const std::string & cvFile )
657 fits::fitsFile<realT> ff;
659 Eigen::Array<realT,-1,-1> cvT, cv, evecs, evals;
665 std::cerr << cvT.rows() <<
" " << cvT.cols() <<
"\n";
667 math::syevrMem<double> mem;
671 int info = math::eigenSYEVR<double,double>(evecs, evals, cv, 0, -1,
'U', &mem);
679 std::cerr <<
"info =" << info <<
"\n";
683 std::cerr <<
"Time = " << t1-t0 <<
" secs\n";
686 for(
int i=0;i< evecs.cols(); ++i)
688 evecs.col(i) = evecs.col(i)/sqrt(fabs(evals(i)));
691 ff.write(outFile, evecs);
694 template<
typename eigenArrT1,
typename eigenArrT2,
typename eigenArrT3>
695 void makeKL( eigenArrT1 & kl,
697 eigenArrT3 && rvecs )
700 int tNims = evecs.rows();
701 int tNpix = rvecs.rows();
709 math::gemm<typename eigenArrT1::Scalar>(CblasColMajor, CblasTrans, CblasTrans, n_modes, tNpix,
710 tNims, 1., evecs.data(), evecs.rows(), rvecs.data(), rvecs.rows(),
711 0., kl.data(), kl.rows());
715 template<
typename realT>
716 void makeFKL(
const std::string & outFile,
717 const std::string & coeffs,
721 fits::fitsFile<realT> ff;
722 Eigen::Array<realT, -1, -1> evecs;
724 ff.read(evecs, coeffs);
726 improc::eigenCube<realT> Rims;
727 sigproc::makeFourierBasis_Rect(Rims, pupSize, N, MX_FOURIER_MODIFIED);
729 std::cout << Rims.planes() <<
" " << evecs.cols() <<
"\n";
731 Eigen::Array<realT,-1,-1> kl;
732 kl.resize( Rims.planes(), Rims.rows()*Rims.cols());
734 std::cerr << 1 <<
"\n";
735 makeKL( kl, evecs, Rims.cube());
736 std::cerr << 2 <<
"\n";
738 Eigen::Array<realT,-1,-1> klT = kl.transpose();
743 improc::eigenCube<realT> klims(klT.data(), Rims.rows(), Rims.cols(), Rims.planes());
745 improc::eigenCube<realT> klimsR;
746 klimsR.resize( klims.rows(), klims.cols(), klims.planes());
748 for(
int i=0; i< klims.planes(); ++i)
750 klimsR.image(i) = klims.image(klims.planes()-1-i);
753 ff.write(outFile, klimsR);
754 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.
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.
realT phiInt_mod(realT phi, void *params)
Worker for the azimuthal integral (in phi) for the modified Fourier mode covariance.
int fourierPSDMap(improc::eigenImage< realT > &var, improc::eigenImage< realT > &psd, int N, int overSample, aosysT &aosys)
Calculate a map of Fourier variances by convolution with the PSD.
int fourierCovarMap(const std::string &fname, int N, realT D, realT L_0, bool subPist, bool subTilt, realT absTol, realT relTol, bool modified=true)
int fourierVarVec(const std::string &fname, int N, aosysT &aosys, realT absTol, realT relTol, bool modifed=true)
Calculate a vector of Fourier mode variances.
realT kInt(realT k, void *params)
Worker function for the radial integral in the covariance calculation.
@ modified
The modified Fourier basis from .
constexpr units::realT k()
Boltzmann Constant.
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.
T jinc(const T &x)
The Jinc function.
realT phiInt_basic(realT phi, void *params)
Worker for the azimuthal integral (in phi) for the basic Fourier mode covariance.
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(timespec &tsp)
Get the current system time in seconds.
Structure to manage the Fourier mode covariance calculation, passed to integration functions.
realT m
The m-index of the unprimed mode, corresponding to the component of spatial frequency.
int p
p-index of the unprimed mode. +/-1 for modified modes. If basic, then +1==>cosine,...
realT n
The n-indexof the unprimed mode, corresponding to the component of spatial frequency.
realT getVariance(realT &error)
Calculate the covariance between the two modes.
fourierCovariance()
Constructor.
realT absTol
Absolute tolerance for the radial integral. Default is 1e-7.
~fourierCovariance()
Destructor.
int pp
p-index of the primed mode. +/-1 for modified modes. If basic, then +1==>cosine, -1==>sine.
bool useBasic
Flag controlling use of basic or modified Fourier modes. If true, the basic sin/cos modes are used....
aosysT * aosys
Pointer to an AO system, which contains the relevant spatial PSD of turbulence.
realT np
The n-indexof the primed mode, corresponding to the component of spatial frequency.
gsl_integration_workspace * phi_w
Working memory for the azimuthal integral.
gsl_integration_workspace * k_w
Working memory for the radial integral.
realT relTol
Relative tolerance for the radial integral. Default is 1e-7.
realT mnCon
The maximum controlled value of spatial frequency (k*D). If < 0 then not controlled.
realT mp
The m-index of the primed mode, corresponding to the component of spatial frequency.
realT k
Spatial frequency being calculated, passed for use in the integrand worker functions.
A utility to convert a wavefront variance map to an intensity image.