/** Free the ASTER_S array. */ void free_aster(ASTER_S *aster, int naster, const PARMS_S *parms){ (void) parms; for(int iaster=0; iaster<naster; iaster++){ int ndtrat=parms->skyc.ndtrat; if(aster[iaster].kalman){ if(parms->skyc.multirate){ kalman_free(aster[iaster].kalman[0]); dcellfreearr(aster[iaster].neam, 1); }else{ for(int i=0; i<ndtrat; i++){ kalman_free(aster[iaster].kalman[i]); } dcellfreearr(aster[iaster].neam, ndtrat); } free(aster[iaster].kalman); aster[iaster].kalman=0; } dcellfree(aster[iaster].gain); dcellfree(aster[iaster].pgm); dcellfree(aster[iaster].sigman); dfree(aster[iaster].res_ws); dfree(aster[iaster].res_ngs); free(aster[iaster].wfs); dcellfree(aster[iaster].g); dfree(aster[iaster].gm); dfree(aster[iaster].dtrats); dfree(aster[iaster].idtrats); free(aster[iaster].ngs); } free(aster); }
void TomoL(dcell **xout, const void *A, const dcell *xin, const double alpha){ const RECON_T *recon=(const RECON_T *)A; dcell *gg=NULL; dspcellmulmat_thread(&gg, recon->G0tomo, xin, 1.,recon->nthread); TTFR(gg, recon->TTF, recon->PTTF); dcell *gg2=NULL; dspcellmulmat_thread(&gg2, recon->saneai, gg,1,recon->nthread); sptcellmulmat_thread(xout,recon->G0tomo,gg2,alpha,recon->nthread); dcellfree(gg); dcellfree(gg2); if(recon->L2){ apply_L2(xout, recon->L2, xin, alpha, recon->nthread); }else{ apply_invpsd(xout, recon->xloc_embed, recon->invpsd, recon->fftxopd, xin, alpha); } if(recon->ZZT){/*single point piston constraint */ sptcellmulmat_thread(xout, recon->ZZT, xin, alpha, recon->nthread); } /*Tikhonov regularization is not added because it is not necessary in CG mode.*/ }
/** Free SERVO_T struct */ void servo_free(SERVO_T *st){ if(!st) return; dcellfree(st->mlead); dcellfree(st->merrlast); dcellfree(st->mpreint); cellfree(st->merrhist); cellfree(st->mint); dfree(st->ap); dfree(st->ep); free(st); }
void TomoR(dcell **xout, const void *A, const dcell *xin, const double alpha){ const RECON_T *recon=(const RECON_T *)A; dcell *x2=NULL; dcellcp(&x2, xin); TTFR(x2, recon->TTF, recon->PTTF); dcell *x3=NULL; dspcellmulmat_thread(&x3,recon->saneai, x2, 1,recon->nthread); sptcellmulmat_thread(xout,recon->G0tomo,x3,alpha,recon->nthread); dcellfree(x2); dcellfree(x3); }
static int test_fit(){ info("Fit\n"); dcell *opdr=dcellread("opdr.bin"); MUV_T FR; FR.M=dspcellread("FRM.bin"); FR.U=dcellread("FRU.bin"); FR.V=dcellread("FRV.bin"); MUV_T FL; FL.M=dspcellread("FLM.bin"); FL.U=dcellread("FLU.bin"); FL.V=dcellread("FLV.bin"); dcell *rhs=NULL; tic; for(int i=0; i<10; i++) MUV(&rhs, &FR, opdr, 1); toc(""); dcell *MUV_f=NULL; tic; for(int i=0; i<10; i++) MUV(&MUV_f, &FL, rhs, 1); toc(""); writebin(rhs,"fit_rhs1.bin"); writebin(MUV_f,"MUV_f.bin"); RECON_T *recon=mycalloc(1,RECON_T); recon->HX=dspcellread("HX.bin"); recon->HA=dspcellread("HA.bin"); recon->W1=dread("W1.bin"); recon->W0=dspread("W0.bin"); recon->NW=dcellread("NW.bin"); recon->fitwt=dread("fitwt.bin"); dcell *rhs2=NULL; tic; for(int i=0; i<10; i++) FitR(&rhs2, recon, opdr, 1); toc(""); writebin(rhs2,"fit_rhs2.bin"); tic; dcell *FitL_f=NULL; for(int i=0; i<10; i++) FitL(&FitL_f, recon, rhs2, 1); toc(""); writebin(FitL_f,"FitL_f.bin"); info("Diff between rhs is %g\n", dcelldiff(rhs, rhs2)); info("Diff between lhs is %g\n", dcelldiff(MUV_f, FitL_f)); dcellfree(rhs); dcellfree(MUV_f); dcellfree(rhs2); dcellfree(FitL_f); return 0; }
/** test type I/II filter with ideal measurement to make sure it is implemented correctly. */ dmat* servo_test(dmat *input, double dt, int dtrat, dmat *sigma2n, dmat *gain){ if(input->ny==1){/*single mode. each column is for a mode.*/ input->ny=input->nx; input->nx=1; } int nmod=input->nx; PDMAT(input,pinput); dmat *merr=dnew(nmod,1); dcell *mreal=cellnew(1,1); dmat *mres=dnew(nmod,input->ny); dmat *sigman=NULL; if(dnorm(sigma2n)>0){ sigman=dchol(sigma2n); } dcell *meas=cellnew(1,1); dmat *noise=dnew(nmod, 1); SERVO_T *st2t=servo_new(NULL, NULL, 0, dt*dtrat, gain); rand_t rstat; seed_rand(&rstat, 1); PDMAT(mres,pmres); /*two step delay is ensured with the order of using, copy, acc*/ for(int istep=0; istep<input->ny; istep++){ memcpy(merr->p, pinput[istep], nmod*sizeof(double)); dadd(&merr, 1, mreal->p[0], -1); memcpy(pmres[istep],merr->p,sizeof(double)*nmod); if(istep % dtrat == 0){ dzero(meas->p[0]); } dadd(&meas->p[0], 1, merr, 1);/*average the error. */ dcellcp(&mreal, st2t->mint->p[0]); if((istep+1) % dtrat == 0){ if(dtrat!=1) dscale(meas->p[0], 1./dtrat); if(sigman){ drandn(noise, 1, &rstat); if(sigman->nx>0){ dmm(&meas->p[0], 1, sigman, noise, "nn", 1); }else{ dadd(&meas->p[0], 1, noise, sigman->p[0]); } } servo_filter(st2t, meas); } } dfree(sigman); dfree(merr); dcellfree(mreal); dcellfree(meas); servo_free(st2t); return mres; }
void setup_aster_lsr(ASTER_S *aster, STAR_S *star, const PARMS_S *parms){ int ndtrat=parms->skyc.ndtrat; if(aster->pgm){ dcellfree(aster->pgm); dcellfree(aster->sigman); } aster->pgm=cellnew(ndtrat,1); aster->sigman=cellnew(ndtrat,1); dmat *gm=ddup(aster->gm); if(aster->nwfs==1 && parms->maos.nmod==6 && gm->nx==8){ info2("set 3rd column of gm to zero\n"); memset(gm->p+gm->nx*2, 0, sizeof(double)*gm->nx); } for(int idtrat=0; idtrat<ndtrat; idtrat++){ dcell *nea=cellnew(aster->nwfs, 1); for(int iwfs=0; iwfs<aster->nwfs; iwfs++){ nea->p[iwfs]=ddup(aster->wfs[iwfs].pistat->sanea->p[idtrat]); dcwpow(nea->p[iwfs], 2); } dmat *neam=dcell2m(nea);//measurement error covariance dcellfree(nea); dcwpow(neam, -1);//inverse /*Reconstructor */ aster->pgm->p[idtrat]=dpinv(gm, neam); /*sigman is error due to noise. */ dcwpow(neam, -1);//inverse again aster->sigman->p[idtrat]=calc_recon_error(aster->pgm->p[idtrat],neam,parms->maos.mcc); dfree(neam); } if(parms->skyc.dbg){ writebin(gm,"%s/aster%d_gm",dirsetup,aster->iaster); writebin(aster->pgm, "%s/aster%d_pgm", dirsetup,aster->iaster); writebin(aster->sigman, "%s/aster%d_sigman", dirsetup,aster->iaster); } dfree(gm); }
/*A FIFO queue to add delay*/ static const dcell*servo_shift_al(SERVO_T *st, const dcell *merr){ if(!st->al){ return merr; }else{ long nhist=st->merrhist->nx; dcell *cycle=st->merrhist->p[0]; for(int i=0; i<nhist-1; i++){ st->merrhist->p[i]=st->merrhist->p[i+1]; } st->merrhist->p[nhist-1]=cycle; if(!merr){ dcellfree(st->merrhist->p[nhist-1]); }else{ dcelladd(&st->merrhist->p[nhist-1], 0, merr, 1); } return st->merrhist->p[0]; } }
void MUV(dcell **xout, const void *A, const dcell *xin, const double alpha){ /** Apply the sparse plug low rand compuation to xin without scaling of alpha: xout=(muv.M-muv.U*muv.V')*xin*alpha; U,V are low rank. */ const MUV_T *muv=(const MUV_T *)A; dspcellmulmat(xout, muv->M, xin, alpha); dcell *tmp=NULL; dcellmm(&tmp,muv->V, xin, "tn", -1.); dcellmm(xout,muv->U, tmp, "nn", alpha); dcellfree(tmp); if(muv->invpsd){ apply_invpsd(xout, muv->xembed, muv->invpsd, muv->fftxopd, xin, alpha); } }
/** Assemble the DM fitting matrix The fitting is done by minimizing \f$||H_X x - H_A a||^2_W\f$ where \f$H_X, H_A\f$ are ray tracing operator from tomography grid xloc, and deformable mirror grid aloc to pupil grid ploc. The norm is weighted using bilinear influence functions within the telescope aperture. We have \f$a=\left[H_A^T(W_0-W_1 W_1^T)H_A\right]^{-1} H_A^T (W_0-W_1) H_X x\f$ For details see www.opticsinfobase.org/abstract.cfm?URI=josaa-19-9-1803 */ static void setup_recon_fit_matrix(RECON_T *recon, const PARMS_T *parms){ const int nfit=parms->fit.nfit; const int ndm=parms->ndm; if(ndm==0) return; dspcell *HATc=dspcelltrans(recon->HA); PDSPCELL(HATc, HAT); PDSPCELL(recon->HA,HA); info2("Before assembling fit matrix:\t%.2f MiB\n",get_job_mem()/1024.); /*Assemble Fit matrix. */ int npsr=recon->npsr; if(parms->load.fit){ if(!(zfexist("FRM") && zfexist("FRU") && zfexist("FRV"))){ error("FRM, FRU, FRV (.bin) not all exist\n"); } warning("Loading saved recon->FR\n"); recon->FR.M=readbin("FRM"); recon->FR.U=dcellread("FRU"); recon->FR.V=dcellread("FRV"); }else{ if(recon->HXF){ info2("Building recon->FR\n"); recon->FR.M=cellnew(ndm, npsr); PDSPCELL(recon->FR.M, FRM); PDSPCELL(recon->HXF, HXF); for(int ips=0; ips<npsr; ips++){ for(int ifit=0; ifit<nfit; ifit++){ if(fabs(recon->fitwt->p[ifit])<1.e-12) continue; dsp *tmp=dspmulsp(recon->W0, HXF[ips][ifit],"nn"); for(int idm=0; idm<ndm; idm++){ dspmulsp2(&FRM[ips][idm],HAT[ifit][idm], tmp, "nn", recon->fitwt->p[ifit]); } dspfree(tmp); } } recon->FR.V=cellnew(npsr, 1); dmat **FRV=recon->FR.V->p; for(int ips=0; ips<npsr; ips++){ int nloc=recon->xloc->p[ips]->nloc; FRV[ips]=dnew(nloc,nfit); for(int ifit=0; ifit<nfit; ifit++){ /*notice the sqrt. */ if(fabs(recon->fitwt->p[ifit])<1.e-12) continue; dspmulvec(FRV[ips]->p+ifit*nloc, HXF[ips][ifit], recon->W1->p, 't', sqrt(recon->fitwt->p[ifit])); } } if(parms->save.recon){ writebin(recon->FR.M,"FRM"); writebin(recon->FR.V,"FRV"); } }else{ info("Avoid building recon->FR.M\n"); recon->FR.M=NULL; recon->FR.V=NULL; } /*Always need FR.U as it is used to do FL.U, FL.V */ recon->FR.U=cellnew(ndm, 1); dmat **FRU=recon->FR.U->p; for(int idm=0; idm<ndm; idm++){ int nloc=recon->aloc->p[idm]->nloc; FRU[idm]=dnew(nloc, nfit); for(int ifit=0; ifit<nfit; ifit++){ /*notice the sart. */ if(fabs(recon->fitwt->p[ifit])<1.e-12) continue; dspmulvec(FRU[idm]->p+ifit*nloc, HA[idm][ifit], recon->W1->p,'t', sqrt(recon->fitwt->p[ifit])); } } if(parms->save.recon){ writebin(recon->FR.U,"FRU"); } } if(parms->load.fit){ if(!(zfexist("FLM") && zfexist("FLU") && zfexist("FLV"))){ error("FLM, FLU, FLV (.bin) not all exist\n"); } warning("Loading saved recon->FL\n"); recon->FL.M=readbin("FLM"); recon->FL.U=dcellread("FLU"); recon->FL.V=dcellread("FLV"); }else{ info2("Building recon->FL\n"); recon->FL.M=cellnew(ndm, ndm); dsp *(*FLM)[ndm]=(dsp*(*)[ndm])recon->FL.M->p; for(int idm=0; idm<ndm; idm++){ for(int ifit=0; ifit<nfit; ifit++){ if(fabs(recon->fitwt->p[ifit])<1.e-12) continue; dsp *tmp=dspmulsp(recon->W0, HA[idm][ifit],"nn"); for(int jdm=0; jdm<ndm; jdm++){ dspmulsp2(&FLM[idm][jdm],HAT[ifit][jdm], tmp,"nn", recon->fitwt->p[ifit]); } dspfree(tmp); } } dspcellfree(HATc); if(fabs(parms->fit.tikcr)>1.e-15){ double tikcr=parms->fit.tikcr; /*Estimated from the formula. 1/nloc is due to W0, the other scaling is due to ray tracing between different sampling freq.*/ int nact=0; for(int idm=0; idm<parms->ndm; idm++){ nact+=recon->aloc->p[idm]->nloc; } double maxeig=4./nact; info2("Adding tikhonov constraint of %g to FLM\n", tikcr); info2("The maximum eigen value is estimated to be around %e\n", maxeig); dcelladdI(recon->FL.M,tikcr*maxeig); } {/*Low rank terms. */ recon->FL.U=dcellcat_each(recon->FR.U, recon->fitNW, 2); dcell *tmp=NULL;/*negative NW. */ dcelladd(&tmp, 1, recon->fitNW, -1); recon->FL.V=dcellcat_each(recon->FR.U, tmp, 2); dcellfree(tmp); } if(recon->actslave){ dcelladd(&recon->FL.M, 1, recon->actslave, 1); } /*dspcellsym(recon->FL.M); */ info2("DM Fit number of Low rank terms: %ld in RHS, %ld in LHS\n", recon->FR.U->p[0]->ny, recon->FL.U->p[0]->ny); if(parms->save.recon){ writebin(recon->FL.M,"FLM.bin"); writebin(recon->FL.U,"FLU"); writebin(recon->FL.V,"FLV"); } } if((parms->fit.alg==0 || parms->fit.alg==2) && parms->fit.bgs){ muv_direct_diag_prep(&(recon->FL),(parms->fit.alg==2)*parms->fit.svdthres); } if((parms->fit.alg==0 || parms->fit.alg==2) && !parms->fit.bgs){ if(fabs(parms->fit.tikcr)<1.e-14){ warning("tickcr=%g is too small, chol may fail.\n", parms->fit.tikcr); } muv_direct_prep(&(recon->FL),(parms->fit.alg==2)*parms->fit.svdthres); info2("After cholesky/svd on matrix:\t%.2f MiB\n",get_job_mem()/1024.); } if(parms->save.recon){ if(recon->FL.C){ chol_convert(recon->FL.C, 1); chol_save(recon->FL.C,"FLC.bin"); } if(recon->FL.MI) writebin(recon->FL.MI,"FLMI"); if(recon->FL.Up) writebin(recon->FL.Up, "FLUp"); if(recon->FL.Vp) writebin(recon->FL.Vp, "FLVp"); if(recon->FL.CB){ for(int ib=0; ib<recon->FL.nb; ib++){ chol_save(recon->FL.CB[ib],"FLCB_%d.bin", ib); } } if(recon->FL.MIB){ writebin(recon->FL.MIB,"FLMIB"); } } info2("After assemble fit matrix:\t%.2f MiB\n",get_job_mem()/1024.); }
/** Optimize type II servo gains beased on measurement noise and signal PSD. We try to minimize \f[ \sigma^2=\int \textrm{PSD}_{ngs,ws}H_{rej}\textrm{d}\nu + \int_0^{\nu_{nyquist}} \textrm{PSF}\textrm{d}\nu \f] */ static void setup_aster_servo(SIM_S *simu, ASTER_S *aster, const PARMS_S *parms){ int ndtrat=parms->skyc.ndtrat; if(aster->gain){ dcellfree(aster->gain); dfree(aster->res_ws); dfree(aster->res_ngs); } aster->gain=cellnew(ndtrat,1); aster->res_ws=dnew(ndtrat,1); aster->res_ngs=dnew(ndtrat,3); PDMAT(aster->res_ngs, pres_ngs); for(int idtrat=0; idtrat<ndtrat; idtrat++){ int dtrat=parms->skyc.dtrats->p[idtrat]; double sigma_ngs= aster->sigman->p[idtrat]->p[0]; double sigma_tt = aster->sigman->p[idtrat]->p[1]; double sigma_ps = sigma_ngs-sigma_tt; double sigma_focus = aster->sigman->p[idtrat]->p[2]; long nmod=parms->maos.nmod; /*gsplit: 0: All modes use the same gain. 1: PS, TT, focus (if nmod>5) use different gains. 2: PS, TT use different gains. focus mode (if nmod>5) use PS gains. */ double res_ngs;/*residual error due to signal after servo rejection. */ double res_ngsn;/*residual error due to noise. */ const int servotype=parms->skyc.servo; const int ng=parms->skyc.ngain; aster->gain->p[idtrat]=dnew(ng,nmod); PDMAT(aster->gain->p[idtrat], pgain); if(parms->skyc.gsplit){ double pg_tt[ng+2]; double pg_ps[ng+2]; double pg_focus[ng+2]; if(parms->skyc.interpg){ interp_gain(pg_tt, simu->gain_tt[idtrat], simu->gain_x, sigma_tt); interp_gain(pg_ps, simu->gain_ps[idtrat], simu->gain_x, sigma_ps); interp_gain(pg_focus, simu->gain_focus[idtrat], simu->gain_x, sigma_focus); }else{ dmat *sigma2=dnew(1,1); dcell *tmp; sigma2->p[0]=sigma_tt; tmp=servo_optim(simu->psd_tt, parms->maos.dt, dtrat, parms->skyc.pmargin, sigma2, servotype); memcpy(pg_tt, tmp->p[0]->p, (ng+2)*sizeof(double)); dcellfree(tmp); sigma2->p[0]=sigma_ps; tmp=servo_optim(simu->psd_ps, parms->maos.dt, dtrat, parms->skyc.pmargin, sigma2, servotype); memcpy(pg_ps, tmp->p[0]->p, (ng+2)*sizeof(double)); dcellfree(tmp); if(nmod>5){ sigma2->p[0]=sigma_focus; tmp=servo_optim(simu->psd_focus, parms->maos.dt, dtrat, parms->skyc.pmargin, sigma2, servotype); memcpy(pg_focus, tmp->p[0]->p, (ng+2)*sizeof(double)); dcellfree(tmp); } dfree(sigma2); } res_ngs = pg_tt[ng] + pg_ps[ng] + pg_focus[ng];//residual mode res_ngsn = pg_tt[ng+1] + pg_ps[ng+1] + pg_focus[ng+1];//error due to noise for(int imod=0; imod<MIN(nmod,5); imod++){ memcpy(pgain[imod], imod<2?pg_tt:pg_ps, sizeof(double)*ng); } if(nmod>5){ memcpy(pgain[5], pg_focus, sizeof(double)*ng); } }else{ double pg_ngs[ng+2]; if(parms->skyc.interpg){ interp_gain(pg_ngs, simu->gain_ngs[idtrat], simu->gain_x, sigma_ngs); }else{ dmat *sigma2=dnew(1,1); sigma2->p[0]=sigma_ngs; dcell *tmp; tmp=servo_optim(simu->psd_ngs, parms->maos.dt, dtrat, parms->skyc.pmargin, sigma2, servotype); memcpy(pg_ngs, tmp->p[0]->p, (ng+2)*sizeof(double)); dcellfree(tmp); } res_ngs=pg_ngs[ng]; res_ngsn=pg_ngs[ng+1]; for(int imod=0; imod<nmod; imod++){ memcpy(pgain[imod], pg_ngs, sizeof(double)*ng); } } pres_ngs[0][idtrat]=res_ngs+res_ngsn;/*error due to signal and noise */ pres_ngs[1][idtrat]=res_ngs;/*error due to signal */ pres_ngs[2][idtrat]=res_ngsn;/*error due to noise propagation. */ /*if(parms->skyc.reest){//estiamte error in time domain dmat *sigma2=dnew(nmod,nmod);PDMAT(sigma2, psigma2); PDMAT(parms->maos.mcc, pmcc); //convert noise into mode space from WFE space. psigma2[0][0]=psigma2[1][1]=sigma_tt/(2*pmcc[0][0]); psigma2[2][2]=psigma2[3][3]=psigma2[4][4]=sigma_ps/(3*pmcc[2][2]); if(nmod>5){ psigma2[5][5]=sigma_focus/pmcc[5][5]; } dmat *res=servo_test(simu->mideal, parms->maos.dt, dtrat, sigma2, aster->gain->p[idtrat]); double rms=calc_rms(res,parms->maos.mcc, parms->skyc.evlstart); pres_ngs[0][idtrat]=rms; dfree(sigma2); dfree(res); }*/ dmat *g_tt=dnew_ref(ng,1,pgain[0]); double gain_n; aster->res_ws->p[idtrat]=servo_residual(&gain_n, parms->skyc.psd_ws, parms->maos.dt, dtrat, g_tt, 2); dfree(g_tt); }//for dtrat if(parms->skyc.dbg){ writebin(aster->gain,"%s/aster%d_gain",dirsetup,aster->iaster); writebin(aster->res_ws,"%s/aster%d_res_ws",dirsetup,aster->iaster); writebin(aster->res_ngs,"%s/aster%d_res_ngs",dirsetup,aster->iaster); } }
/** Closed loop simulation main loop. It calls init_simu() to initialize the simulation struct. Then calls genatm() to generate atmospheric turbulence screens. Then for every time step, it calls perfevl() to evaluate performance, wfsgrad() to do wfs measurement, reconstruct() to do tomography and DM fit, filter() to do DM command filtering. In MOAO mode, it call calls moao_recon() for MOAO DM fitting. \callgraph */ void maos_sim(){ const PARMS_T *parms=global->parms; POWFS_T *powfs=global->powfs; RECON_T *recon=global->recon; APER_T *aper=global->aper; int simend=parms->sim.end; int simstart=parms->sim.start; if(parms->sim.skysim){ save_skyc(powfs,recon,parms); } if(parms->evl.psfmean || parms->evl.psfhist){ /*compute diffraction limited PSF. Save to output directory.*/ dmat *iopdevl=dnew(aper->locs->nloc,1); ccell *psf2s=0; locfft_psf(&psf2s, aper->embed, iopdevl, parms->evl.psfsize, 0); const int nwvl=parms->evl.nwvl; dcell *evlpsfdl=dcellnew(nwvl,1); for(int iwvl=0; iwvl<nwvl; iwvl++){ cabs22d(&evlpsfdl->p[iwvl], 1, psf2s->p[iwvl], 1); evlpsfdl->p[iwvl]->header=evl_header(parms, aper, -1, iwvl); } ccellfree(psf2s); writebin(evlpsfdl, "evlpsfdl.fits"); dcellfree(evlpsfdl); dfree(iopdevl); } info2("PARALLEL=%d\n", PARALLEL); if(simstart>=simend) return; double restot=0; long rescount=0; for(int iseed=0; iseed<parms->sim.nseed; iseed++){ SIM_T *simu=0; while(!(simu=maos_iseed(iseed))){ iseed++; } #ifdef HAVE_NUMA_H numa_set_localalloc(); #endif for(int isim=simstart; isim<simend; isim++){ maos_isim(isim); if(parms->sim.pause){ mypause(); } }/*isim */ { /*Compute average performance*/ int isim0; if(parms->sim.closeloop){ if(parms->sim.end>100){ isim0=MAX(50,parms->sim.end/10); }else{ isim0=MIN(20, parms->sim.end/2); } }else{ isim0=0; } double sum=0; for(int i=isim0; i<parms->sim.end; i++){ sum+=simu->cle->p[i*parms->evl.nmod]; } restot+=sum/(parms->sim.end-isim0); rescount++; } free_simu(simu); global->simu=0; }/*seed */ printf("%g\n", sqrt(restot/rescount)*1e9); }
/** Setup the least square reconstruct by directly inverting GA matrix. The reconstructor is simply the pseudo inverse of GA matrix: \f[\hat{x}=(G_a^TC_g^{-1}G_a)^{-1}G_a^TC_g^{-1}\f] This is very close to RR except replacing GX with GA. We use the tomograhy parameters for lsr, since lsr is simply "tomography" onto DM directly. */ void setup_recon_lsr(RECON_T *recon, const PARMS_T *parms){ const int ndm=parms->ndm; const int nwfs=parms->nwfsr; cell *GAlsr; cell *GAM=parms->recon.modal?(cell*)recon->GM:(cell*)recon->GA; if(parms->recon.split){ //high order wfs only in split mode. GAlsr=parms->recon.modal?(cell*)recon->GMhi:(cell*)recon->GAhi; }else{ //all wfs in integrated mode. GAlsr=GAM; } int free_GAlsr=0; if(GAlsr->p[0]->id!=M_DBL){ dsp *tmp=dsp_cast(GAlsr->p[0]); if(tmp->nzmax>tmp->nx*tmp->ny*0.2){//not very sparse dcell *tmp2=0; free_GAlsr=1; dcelladd(&tmp2, 1, (dspcell*)GAlsr, 1); GAlsr=(cell*)tmp2; } } info2("Building recon->LR\n"); recon->LR.M=dcellmm2(GAlsr, recon->saneai, "tn"); // Tip/tilt and diff focus removal low rand terms for LGS WFS. if(recon->TTF){ dcellmm(&recon->LR.U, recon->LR.M, recon->TTF, "nn", 1); recon->LR.V=dcelltrans(recon->PTTF); } info2("Building recon->LL\n"); recon->LL.M=dcellmm2(recon->LR.M, GAlsr, "nn"); if(free_GAlsr){ cellfree(GAlsr); } double maxeig=pow(recon->neamhi * recon->aloc->p[0]->dx, -2); if(parms->recon.modal){ double strength=1; for(int idm=0; idm<ndm; idm++){ strength*=dnorm(recon->amod->p[idm]); } strength=pow(strength, 2./ndm); maxeig*=strength; } if(fabs(parms->lsr.tikcr)>EPS){ info2("Adding tikhonov constraint of %g to LLM\n", parms->lsr.tikcr); info2("The maximum eigen value is estimated to be around %g\n", maxeig); dcelladdI(recon->LL.M, parms->lsr.tikcr*maxeig); } dcell *NW=NULL; if(!parms->recon.modal){ if(parms->lsr.alg!=2){ /* Not SVD, need low rank terms for piston/waffle mode constraint. */ NW=dcellnew(ndm,1); int nmod=2;/*two modes. */ for(int idm=0; idm<ndm; idm++){ loc_create_map(recon->aloc->p[idm]); const long nloc=recon->aloc->p[idm]->nloc; NW->p[idm]=dnew(nloc, ndm*nmod); double *p=NW->p[idm]->p+nmod*idm*nloc; const double *cpl=recon->actcpl->p[idm]->p; for(long iloc=0; iloc<nloc; iloc++){ if(cpl[iloc]>0.1){ p[iloc]=1;/*piston mode */ } } /*notice offset of 1 because map start count at 1 */ p=NW->p[idm]->p+(1+nmod*idm)*nloc-1; map_t *map=recon->aloc->p[idm]->map; for(long iy=0; iy<map->ny; iy++){ for(long ix=0; ix<map->nx; ix++){ if(IND(map,ix,iy)){ p[(long)IND(map,ix,iy)]=(double)2*((iy+ix)&1)-1; } } } } /*scale it to match the magnitude of LL.M */ dcellscale(NW, sqrt(maxeig)); if(parms->save.setup){ writebin(NW, "lsrNW"); } } if(parms->lsr.actslave){ /*actuator slaving. important. change from 0.5 to 0.1 on 2011-07-14. */ dspcell *actslave=slaving(recon->aloc, recon->actcpl, NW, recon->actstuck, recon->actfloat, parms->lsr.actthres, maxeig); if(parms->save.setup){ if(NW){ writebin(NW, "lsrNW2"); } writebin(actslave,"actslave"); } dcelladd(&recon->LL.M, 1, actslave, 1); cellfree(actslave); } } /*Low rank terms for low order wfs. Only in Integrated tomography. */ dcell *ULo=dcellnew(ndm,nwfs); dcell *VLo=dcellnew(ndm,nwfs); dcell* pULo=ULo/*PDELL*/; dcell* pVLo=VLo/*PDELL*/; for(int iwfs=0; iwfs<nwfs; iwfs++){ int ipowfs=parms->wfsr[iwfs].powfs; if(parms->powfs[ipowfs].skip || !parms->powfs[ipowfs].lo){ continue; } for(int idm=0; idm<ndm; idm++){ dspfull(PIND(pULo,idm,iwfs), (dsp*)IND(recon->LR.M, idm, iwfs),'n',-1); dspfull(PIND(pVLo,idm,iwfs), (dsp*)IND(GAM, iwfs, idm),'t',1); } } recon->LL.U=dcellcat(recon->LR.U, ULo, 2); dcell *GPTTDF=NULL; dcellmm(&GPTTDF, GAM, recon->LR.V, "tn", 1); recon->LL.V=dcellcat(GPTTDF, VLo, 2); dcellfree(GPTTDF); dcellfree(ULo); dcellfree(VLo); if(!parms->recon.modal && NW){ info2("Create piston and check board modes that are in NULL space of GA.\n"); /*add to low rank terms. */ dcell *tmp=recon->LL.U; recon->LL.U=dcellcat(tmp, NW, 2); dcellfree(tmp); dcellscale(NW, -1); tmp=recon->LL.V; recon->LL.V=dcellcat(tmp, NW, 2); dcellfree(tmp); dcellfree(NW); } if(parms->lsr.fnreg){ warning("Loading LSR regularization from file %s.\n", parms->lsr.fnreg); dspcell *tmp=dspcellread("%s", parms->lsr.fnreg); dcelladd(&recon->LL.M, 1, tmp, 1); dspcellfree(tmp); } recon->LL.alg = parms->lsr.alg; recon->LL.bgs = parms->lsr.bgs; recon->LL.warm = parms->recon.warm_restart; recon->LL.maxit = parms->lsr.maxit; /*Remove empty cells. */ dcelldropempty(&recon->LR.U,2); dcelldropempty(&recon->LR.V,2); dcelldropempty(&recon->LL.U,2); dcelldropempty(&recon->LL.V,2); if(parms->save.recon){ writebin(recon->LR.M,"LRM"); writebin(recon->LR.U,"LRU"); writebin(recon->LR.V,"LRV"); writebin(recon->LL.M,"LLM.bin");/*disable compression */ writebin(recon->LL.U,"LLU"); writebin(recon->LL.V,"LLV"); } if(parms->lsr.alg==0 || parms->lsr.alg==2){ if(!parms->lsr.bgs){ muv_direct_prep(&recon->LL, (parms->lsr.alg==2)*parms->lsr.svdthres); if(parms->save.recon){ if(recon->LL.C) chol_save(recon->LL.C, "LLC.bin"); else writebin(recon->LL.MI, "LLMI.bin"); } cellfree(recon->LL.M); dcellfree(recon->LL.U); dcellfree(recon->LL.V); }else{ muv_direct_diag_prep(&(recon->LL), (parms->lsr.alg==2)*parms->lsr.svdthres); if(parms->save.recon){ for(int ib=0; ib<recon->LL.nb; ib++){ if(recon->LL.CB) chol_save(recon->LL.CB[ib],"LLCB_%d.bin", ib); else writebin(recon->LL.MI,"LLMIB_%d.bin", ib); } } /*Don't free M, U, V */ } } }
/** Setup the detector transfer functions. See maos/setup_powfs.c */ static void setup_powfs_dtf(POWFS_S *powfs, const PARMS_S* parms){ const int npowfs=parms->maos.npowfs; for(int ipowfs=0; ipowfs<npowfs; ipowfs++){ const int ncomp=parms->maos.ncomp[ipowfs]; const int ncomp2=ncomp>>1; const int embfac=parms->maos.embfac[ipowfs]; const int pixpsa=parms->skyc.pixpsa[ipowfs]; const double pixtheta=parms->skyc.pixtheta[ipowfs]; const double blur=parms->skyc.pixblur[ipowfs]*pixtheta; const double e0=exp(-2*M_PI*M_PI*blur*blur); const double dxsa=parms->maos.dxsa[ipowfs]; const double pixoffx=parms->skyc.pixoffx[ipowfs]; const double pixoffy=parms->skyc.pixoffy[ipowfs]; const double pxo=-(pixpsa/2-0.5+pixoffx)*pixtheta; const double pyo=-(pixpsa/2-0.5+pixoffy)*pixtheta; loc_t *loc_ccd=mksqloc(pixpsa, pixpsa, pixtheta, pixtheta, pxo, pyo); powfs[ipowfs].dtf=mycalloc(parms->maos.nwvl,DTF_S); for(int iwvl=0; iwvl<parms->maos.nwvl; iwvl++){ const double wvl=parms->maos.wvl[iwvl]; const double dtheta=wvl/(dxsa*embfac); const double pdtheta=pixtheta*pixtheta/(dtheta*dtheta); const double du=1./(dtheta*ncomp); const double du2=du*du; const double dupth=du*pixtheta; cmat *nominal=cnew(ncomp,ncomp); //cfft2plan(nominal,-1); //cfft2plan(nominal,1); cmat* pn=nominal; const double theta=0; const double ct=cos(theta); const double st=sin(theta); for(int iy=0; iy<ncomp; iy++){ int jy=iy-ncomp2; for(int ix=0; ix<ncomp; ix++){ int jx=ix-ncomp2; double ir=ct*jx+st*jy; double ia=-st*jx+ct*jy; IND(pn,ix,iy)=sinc(ir*dupth)*sinc(ia*dupth) *pow(e0,ir*ir*du2)*pow(e0,ia*ia*du2) *pdtheta; } } if(parms->skyc.fnpsf1[ipowfs]){ warning("powfs %d has additional otf to be multiplied\n", ipowfs); dcell *psf1c=dcellread("%s", parms->skyc.fnpsf1[ipowfs]); dmat *psf1=NULL; if(psf1c->nx == 1){ psf1=dref(psf1c->p[0]); }else if(psf1c->nx==parms->maos.nwvl){ psf1=dref(psf1c->p[iwvl]); }else{ error("skyc.fnpsf1 has wrong dimension\n"); } dcellfree(psf1c); if(psf1->ny!=2){ error("skyc.fnpsf1 has wrong dimension\n"); } dmat *psf1x=dnew_ref(psf1->nx, 1, psf1->p); dmat *psf1y=dnew_ref(psf1->nx, 1, psf1->p+psf1->nx); dmat *psf2x=dnew(ncomp*ncomp, 1); for(int iy=0; iy<ncomp; iy++){ int jy=iy-ncomp2; for(int ix=0; ix<ncomp; ix++){ int jx=ix-ncomp2; psf2x->p[ix+iy*ncomp]=sqrt(jx*jx+jy*jy)*dtheta; } } info("powfs %d, iwvl=%d, dtheta=%g\n", ipowfs, iwvl, dtheta*206265000); writebin(psf2x, "powfs%d_psf2x_%d", ipowfs,iwvl); dmat *psf2=dinterp1(psf1x, psf1y, psf2x, 0); normalize_sum(psf2->p, psf2->nx*psf2->ny, 1); psf2->nx=ncomp; psf2->ny=ncomp; writebin(psf2, "powfs%d_psf2_%d", ipowfs,iwvl); cmat *otf2=cnew(ncomp, ncomp); //cfft2plan(otf2, -1); ccpd(&otf2, psf2);//peak in center cfftshift(otf2);//peak in corner cfft2(otf2, -1); cfftshift(otf2);//peak in center writebin(otf2, "powfs%d_otf2_%d", ipowfs, iwvl); writebin(nominal, "powfs%d_dtf%d_nominal_0",ipowfs,iwvl); for(int i=0; i<ncomp*ncomp; i++){ nominal->p[i]*=otf2->p[i]; } writebin(nominal, "powfs%d_dtf%d_nominal_1",ipowfs,iwvl); dfree(psf1x); dfree(psf1y); dfree(psf2x); dfree(psf1); cfree(otf2); dfree(psf2); } cfftshift(nominal);//peak in corner cfft2(nominal,-1); cfftshift(nominal);//peak in center cfft2i(nominal,1); warning_once("double check nominal for off centered skyc.fnpsf1\n"); /*This nominal will multiply to OTF with peak in corner. But after inverse fft, peak will be in center*/ ccp(&powfs[ipowfs].dtf[iwvl].nominal, nominal); cfree(nominal); loc_t *loc_psf=mksqloc(ncomp, ncomp, dtheta, dtheta, -ncomp2*dtheta, -ncomp2*dtheta); powfs[ipowfs].dtf[iwvl].si=mkh(loc_psf,loc_ccd,0,0,1); locfree(loc_psf); if(parms->skyc.dbg){ writebin(powfs[ipowfs].dtf[iwvl].nominal, "%s/powfs%d_dtf%d_nominal",dirsetup,ipowfs,iwvl); writebin(powfs[ipowfs].dtf[iwvl].si, "%s/powfs%d_dtf%d_si",dirsetup,ipowfs,iwvl); } powfs[ipowfs].dtf[iwvl].U=cnew(ncomp,1); dcomplex *U=powfs[ipowfs].dtf[iwvl].U->p; for(int ix=0; ix<ncomp; ix++){ int jx=ix<ncomp2?ix:(ix-ncomp); U[ix]=COMPLEX(0, -2.*M_PI*jx*du); } }/*iwvl */ locfree(loc_ccd); }/*ipowfs */ }
/** Update DM command for next cycle using info from last cycle (two cycle delay) in closed loop mode */ static void filter_cl(SIM_T *simu){ /* 2009-11-02: Moved to the end of isim loop to update for next step. only need to cache a single dmerrlast now. 2009-12-23: Updated low fs to do lead filter/type II 2010-01-07: Create an option to merge the last integrator in the hi/lo loop to simulation the actual block diagram. removed dmreal_hi, Mreal_lo; 2010-01-08: Changed the filtering scheme by computing dm command for next cycle instead of maintianing last step error information. 2010-01-13: Implemented apdm. a(n)=a(n-1)+ep*e(n-2) or a(n)=0.5*(a(n-1)+a(n-2))+ep*e(n-2); */ const PARMS_T *parms=simu->parms; RECON_T *recon=simu->recon; assert(parms->sim.closeloop); /*copy dm computed in last cycle. This is used in next cycle (already after perfevl) */ const SIM_CFG_T *simcfg=&(parms->sim); const int isim=simu->isim; {/*Auto adjusting epdm for testing different epdm*/ static int epdm_is_auto=0; if(simcfg->epdm->p[0]<0){ epdm_is_auto=1; simcfg->epdm->p[0]=0.5; } if(epdm_is_auto){ if((isim*10)<parms->sim.end){//initial steps simcfg->epdm->p[0]=0.5; }else if((isim*10)%parms->sim.end==0){ simcfg->epdm->p[0]=(double)isim/(double)parms->sim.end; info("epdm is set to %.1f at step %d\n", simcfg->epdm->p[0], isim); } } } /*Do the servo filtering. First simulate a drop frame*/ int drop=0; if(simu->dmerr && parms->sim.dtrat_skip){ if(parms->sim.dtrat_skip>0){ if((isim+1)%parms->sim.dtrat_skip==0){//evenly drop=1; } }else if(parms->sim.dtrat_skip<0){//use random draws double tmp=randu(simu->misc_rand); if(tmp*(-parms->sim.dtrat_skip)<1.){ drop=1; } } } dcell *dmerr=0; if(drop){ warning("Drop a frame at step %d\n", isim); }else if(simu->dmerr){ dmerr=simu->dmerr; } //always run servo_filter even if dmerr is NULL. int hiout=servo_filter(simu->dmint, dmerr); if(parms->recon.split){ /*Low order in split tomography only. fused integrator*/ if(servo_filter(simu->Mint_lo, simu->Merr_lo) && parms->sim.fuseint){ /*accumulate to the main integrator.*/ addlow2dm(&simu->dmint->mint->p[0], simu, simu->Mint_lo->mpreint, 1); } } /*The following are moved from the beginning to the end because the gradients are now from last step.*/ dcellcp(&simu->dmcmd0,simu->dmint->mint->p[0]); if(!parms->sim.fuseint){ addlow2dm(&simu->dmcmd0,simu,simu->Mint_lo->mint->p[0], 1); } for(int ipowfs=0; ipowfs<parms->npowfs; ipowfs++){ //Record dmpsol for this time step for each powfs before updating it (z^-1). //Do not reference the data, even for dtrat==1 if(!parms->powfs[ipowfs].psol || !parms->powfs[ipowfs].dtrat) continue; double alpha=(isim % parms->powfs[ipowfs].dtrat == 0)?0:1; dcelladd(&simu->wfspsol->p[ipowfs], alpha, simu->dmpsol, 1./parms->powfs[ipowfs].dtrat); } dcellcp(&simu->dmpsol, simu->dmcmd0); if(parms->recon.modal){ dcellzero(simu->dmcmd); dcellmm(&simu->dmcmd, simu->recon->amod, simu->dmcmd0, "nn", 1); //convert DM command from modal to zonal spae }else if(simu->recon->actinterp && !parms->recon.psol){ //Extrapolate to edge actuators dcellzero(simu->dmcmd); dcellmm(&simu->dmcmd, simu->recon->actinterp, simu->dmcmd0, "nn", 1); }else{ dcellcp(&simu->dmcmd, simu->dmcmd0); } //The DM commands are always on zonal modes from this moment if(simu->ttmreal){ ttsplit_do(recon, simu->dmcmd, simu->ttmreal, parms->sim.lpttm); } if(parms->sim.focus2tel && hiout){ dcellcp(&simu->telfocusreal, simu->telfocusint); dcellmm(&simu->telfocusint, recon->RFdm, simu->dmcmd, "nn", parms->sim.epfocus2tel); } if(recon->dither_m){ //Change phase in calc_dither_amp if phase of dithering is changed //this is for step isim+1 double anglei=((isim+1)/recon->dither_dtrat)*(2*M_PI/recon->dither_npoint); dcelladd(&simu->dmcmd, 1, recon->dither_m, sin(anglei)); } if(!parms->dbg.ncpa_preload && recon->dm_ncpa){ info_once("Add NCPA after integrator\n"); dcelladd(&simu->dmcmd, 1, recon->dm_ncpa, 1); } if(parms->sim.dmclip || parms->sim.dmclipia || recon->actstuck){ dcell *tmp=dcelldup(simu->dmcmd); if(recon->actstuck){//zero stuck actuators act_stuck_cmd(recon->aloc, simu->dmerr, recon->actstuck); } clipdm(simu, simu->dmcmd); dcelladd(&tmp, 1, simu->dmcmd, -1); //find what is clipped dcelladd(&simu->dmint->mint->p[0], 1, tmp, -1);//remove from integrator (anti wind up) dcelladd(&simu->dmpsol, 1, tmp, -1);//also feed to PSOL (is this really necessary?) dcellfree(tmp); } /*This is after the integrator output and clipping*/ if(simu->dmhist){ for(int idm=0; idm<parms->ndm; idm++){ if(simu->dmhist->p[idm]){ dhistfill(&simu->dmhist->p[idm], simu->dmcmd->p[idm],0, parms->dm[idm].histbin, parms->dm[idm].histn); } } } /*hysteresis. */ if(simu->hyst){ hyst_dcell(simu->hyst, simu->dmreal, simu->dmcmd); } if(recon->moao && !parms->gpu.moao){ warning_once("moao filter implemented with LPF\n"); if(simu->dm_wfs){ const int nwfs=parms->nwfs; for(int iwfs=0; iwfs<nwfs; iwfs++){ int ipowfs=parms->wfs[iwfs].powfs; int imoao=parms->powfs[ipowfs].moao; if(imoao<0) continue; double g=parms->moao[imoao].gdm; dadd(&simu->dm_wfs->p[iwfs], 1-g, simu->dm_wfs->p[iwfs+nwfs], g); } } if(simu->dm_evl){ const int nevl=parms->evl.nevl; int imoao=parms->evl.moao; double g=parms->moao[imoao].gdm; for(int ievl=0; ievl<nevl; ievl++){ dadd(&simu->dm_evl->p[ievl], 1-g, simu->dm_evl->p[ievl+nevl], g); } } } if(simu->fsmint){ /*fsmerr is from gradients from this time step. so copy before update for correct delay*/ dcellcp(&simu->fsmreal, simu->fsmint->mint->p[0]); servo_filter(simu->fsmint, simu->fsmerr); /*Inject dithering command, for step isim+1*/ for(int iwfs=0; iwfs<parms->nwfs; iwfs++){ const int ipowfs=parms->wfs[iwfs].powfs; if(parms->powfs[ipowfs].dither==1){//T/T dithering. //adjust delay due to propagation, and computation delay. const int adjust=parms->sim.alfsm+1-parms->powfs[ipowfs].dtrat; //Use isim+1 because the command is for next time step. //minus adjust for delay double anglei=(2*M_PI/parms->powfs[ipowfs].dither_npoint); double angle=((isim+1-adjust)/parms->powfs[ipowfs].dtrat)*anglei; simu->fsmreal->p[iwfs]->p[0]-=parms->powfs[ipowfs].dither_amp*cos(angle); simu->fsmreal->p[iwfs]->p[1]-=parms->powfs[ipowfs].dither_amp*sin(angle); } } } }
/** Time domain physical simulation. noisy: - 0: no noise at all; - 1: poisson and read out noise. - 2: only poisson noise. */ dmat *skysim_sim(dmat **mresout, const dmat *mideal, const dmat *mideal_oa, double ngsol, ASTER_S *aster, const POWFS_S *powfs, const PARMS_S *parms, int idtratc, int noisy, int phystart){ int dtratc=0; if(!parms->skyc.multirate){ dtratc=parms->skyc.dtrats->p[idtratc]; } int hasphy; if(phystart>-1 && phystart<aster->nstep){ hasphy=1; }else{ hasphy=0; } const int nmod=mideal->nx; dmat *res=dnew(6,1);/*Results. 1-2: NGS and TT modes., 3-4:On axis NGS and TT modes, 4-6: On axis NGS and TT wihtout considering un-orthogonality.*/ dmat *mreal=NULL;/*modal correction at this step. */ dmat *merr=dnew(nmod,1);/*modal error */ dcell *merrm=dcellnew(1,1);dcell *pmerrm=NULL; const int nstep=aster->nstep?aster->nstep:parms->maos.nstep; dmat *mres=dnew(nmod,nstep); dmat* rnefs=parms->skyc.rnefs; dcell *zgradc=dcellnew3(aster->nwfs, 1, aster->ngs, 0); dcell *gradout=dcellnew3(aster->nwfs, 1, aster->ngs, 0); dmat *gradsave=0; if(parms->skyc.dbg){ gradsave=dnew(aster->tsa*2,nstep); } SERVO_T *st2t=0; kalman_t *kalman=0; dcell *mpsol=0; dmat *pgm=0; dmat *dtrats=0; int multirate=parms->skyc.multirate; if(multirate){ kalman=aster->kalman[0]; dtrats=aster->dtrats; }else{ if(parms->skyc.servo>0){ const double dtngs=parms->maos.dt*dtratc; st2t=servo_new(merrm, NULL, 0, dtngs, aster->gain->p[idtratc]); pgm=aster->pgm->p[idtratc]; }else{ kalman=aster->kalman[idtratc]; } } if(kalman){ kalman_init(kalman); mpsol=dcellnew(aster->nwfs, 1); //for psol grad. } const long nwvl=parms->maos.nwvl; dcell **psf=0, **mtche=0, **ints=0; ccell *wvf=0,*wvfc=0, *otf=0; if(hasphy){ psf=mycalloc(aster->nwfs,dcell*); wvf=ccellnew(aster->nwfs,1); wvfc=ccellnew(aster->nwfs,1); mtche=mycalloc(aster->nwfs,dcell*); ints=mycalloc(aster->nwfs,dcell*); otf=ccellnew(aster->nwfs,1); for(long iwfs=0; iwfs<aster->nwfs; iwfs++){ const int ipowfs=aster->wfs[iwfs].ipowfs; const long ncomp=parms->maos.ncomp[ipowfs]; const long nsa=parms->maos.nsa[ipowfs]; wvf->p[iwfs]=cnew(ncomp,ncomp); wvfc->p[iwfs]=NULL; psf[iwfs]=dcellnew(nsa,nwvl); //cfft2plan(wvf->p[iwfs], -1); if(parms->skyc.multirate){ mtche[iwfs]=aster->wfs[iwfs].pistat->mtche[(int)aster->idtrats->p[iwfs]]; }else{ mtche[iwfs]=aster->wfs[iwfs].pistat->mtche[idtratc]; } otf->p[iwfs]=cnew(ncomp,ncomp); //cfft2plan(otf->p[iwfs],-1); //cfft2plan(otf->p[iwfs],1); ints[iwfs]=dcellnew(nsa,1); int pixpsa=parms->skyc.pixpsa[ipowfs]; for(long isa=0; isa<nsa; isa++){ ints[iwfs]->p[isa]=dnew(pixpsa,pixpsa); } } } for(int irep=0; irep<parms->skyc.navg; irep++){ if(kalman){ kalman_init(kalman); }else{ servo_reset(st2t); } dcellzero(zgradc); dcellzero(gradout); if(ints){ for(int iwfs=0; iwfs<aster->nwfs; iwfs++){ dcellzero(ints[iwfs]); } } for(int istep=0; istep<nstep; istep++){ memcpy(merr->p, PCOL(mideal,istep), nmod*sizeof(double)); dadd(&merr, 1, mreal, -1);/*form NGS mode error; */ memcpy(PCOL(mres,istep),merr->p,sizeof(double)*nmod); if(mpsol){//collect averaged modes for PSOL. for(long iwfs=0; iwfs<aster->nwfs; iwfs++){ dadd(&mpsol->p[iwfs], 1, mreal, 1); } } pmerrm=0; if(istep>=parms->skyc.evlstart){/*performance evaluation*/ double res_ngs=dwdot(merr->p,parms->maos.mcc,merr->p); if(res_ngs>ngsol*100){ dfree(res); res=NULL; break; } { res->p[0]+=res_ngs; res->p[1]+=dwdot2(merr->p,parms->maos.mcc_tt,merr->p); double dot_oa=dwdot(merr->p, parms->maos.mcc_oa, merr->p); double dot_res_ideal=dwdot(merr->p, parms->maos.mcc_oa, PCOL(mideal,istep)); double dot_res_oa=0; for(int imod=0; imod<nmod; imod++){ dot_res_oa+=merr->p[imod]*IND(mideal_oa,imod,istep); } res->p[2]+=dot_oa-2*dot_res_ideal+2*dot_res_oa; res->p[4]+=dot_oa; } { double dot_oa_tt=dwdot2(merr->p, parms->maos.mcc_oa_tt, merr->p); /*Notice that mcc_oa_tt2 is 2x5 marix. */ double dot_res_ideal_tt=dwdot(merr->p, parms->maos.mcc_oa_tt2, PCOL(mideal,istep)); double dot_res_oa_tt=0; for(int imod=0; imod<2; imod++){ dot_res_oa_tt+=merr->p[imod]*IND(mideal_oa,imod,istep); } res->p[3]+=dot_oa_tt-2*dot_res_ideal_tt+2*dot_res_oa_tt; res->p[5]+=dot_oa_tt; } }//if evl if(istep<phystart || phystart<0){ /*Ztilt, noise free simulation for acquisition. */ dmm(&zgradc->m, 1, aster->gm, merr, "nn", 1);/*grad due to residual NGS mode. */ for(int iwfs=0; iwfs<aster->nwfs; iwfs++){ const int ipowfs=aster->wfs[iwfs].ipowfs; const long ng=parms->maos.nsa[ipowfs]*2; for(long ig=0; ig<ng; ig++){ zgradc->p[iwfs]->p[ig]+=aster->wfs[iwfs].ztiltout->p[istep*ng+ig]; } } for(int iwfs=0; iwfs<aster->nwfs; iwfs++){ int dtrati=(multirate?(int)dtrats->p[iwfs]:dtratc); if((istep+1) % dtrati==0){ dadd(&gradout->p[iwfs], 0, zgradc->p[iwfs], 1./dtrati); dzero(zgradc->p[iwfs]); if(noisy){ int idtrati=(multirate?(int)aster->idtrats->p[iwfs]:idtratc); dmat *nea=aster->wfs[iwfs].pistat->sanea->p[idtrati]; for(int i=0; i<nea->nx; i++){ gradout->p[iwfs]->p[i]+=nea->p[i]*randn(&aster->rand); } } pmerrm=merrm;//record output. } } }else{ /*Accumulate PSF intensities*/ for(long iwfs=0; iwfs<aster->nwfs; iwfs++){ const double thetax=aster->wfs[iwfs].thetax; const double thetay=aster->wfs[iwfs].thetay; const int ipowfs=aster->wfs[iwfs].ipowfs; const long nsa=parms->maos.nsa[ipowfs]; ccell* wvfout=aster->wfs[iwfs].wvfout[istep]; for(long iwvl=0; iwvl<nwvl; iwvl++){ double wvl=parms->maos.wvl[iwvl]; for(long isa=0; isa<nsa; isa++){ ccp(&wvfc->p[iwfs], IND(wvfout,isa,iwvl)); /*Apply NGS mode error to PSF. */ ngsmod2wvf(wvfc->p[iwfs], wvl, merr, powfs+ipowfs, isa, thetax, thetay, parms); cembedc(wvf->p[iwfs],wvfc->p[iwfs],0,C_FULL); cfft2(wvf->p[iwfs],-1); /*peak in corner. */ cabs22d(&psf[iwfs]->p[isa+nsa*iwvl], 1., wvf->p[iwfs], 1.); }/*isa */ }/*iwvl */ }/*iwfs */ /*Form detector image from accumulated PSFs*/ double igrad[2]; for(long iwfs=0; iwfs<aster->nwfs; iwfs++){ int dtrati=dtratc, idtrat=idtratc; if(multirate){//multirate idtrat=aster->idtrats->p[iwfs]; dtrati=dtrats->p[iwfs]; } if((istep+1) % dtrati == 0){/*has output */ dcellzero(ints[iwfs]); const int ipowfs=aster->wfs[iwfs].ipowfs; const long nsa=parms->maos.nsa[ipowfs]; for(long isa=0; isa<nsa; isa++){ for(long iwvl=0; iwvl<nwvl; iwvl++){ double siglev=aster->wfs[iwfs].siglev->p[iwvl]; ccpd(&otf->p[iwfs],psf[iwfs]->p[isa+nsa*iwvl]); cfft2i(otf->p[iwfs], 1); /*turn to OTF, peak in corner */ ccwm(otf->p[iwfs], powfs[ipowfs].dtf[iwvl].nominal); cfft2(otf->p[iwfs], -1); dspmulcreal(ints[iwfs]->p[isa]->p, powfs[ipowfs].dtf[iwvl].si, otf->p[iwfs]->p, siglev); } /*Add noise and apply matched filter. */ #if _OPENMP >= 200805 #pragma omp critical #endif switch(noisy){ case 0:/*no noise at all. */ break; case 1:/*both poisson and read out noise. */ { double bkgrnd=aster->wfs[iwfs].bkgrnd*dtrati; addnoise(ints[iwfs]->p[isa], &aster->rand, bkgrnd, bkgrnd, 0,0,IND(rnefs,idtrat,ipowfs)); } break; case 2:/*there is still poisson noise. */ addnoise(ints[iwfs]->p[isa], &aster->rand, 0, 0, 0,0,0); break; default: error("Invalid noisy\n"); } igrad[0]=0; igrad[1]=0; double pixtheta=parms->skyc.pixtheta[ipowfs]; if(parms->skyc.mtch){ dmulvec(igrad, mtche[iwfs]->p[isa], ints[iwfs]->p[isa]->p, 1); } if(!parms->skyc.mtch || fabs(igrad[0])>pixtheta || fabs(igrad[1])>pixtheta){ if(!parms->skyc.mtch){ warning2("fall back to cog\n"); }else{ warning_once("mtch is out of range\n"); } dcog(igrad, ints[iwfs]->p[isa], 0, 0, 0, 3*IND(rnefs,idtrat,ipowfs), 0); igrad[0]*=pixtheta; igrad[1]*=pixtheta; } gradout->p[iwfs]->p[isa]=igrad[0]; gradout->p[iwfs]->p[isa+nsa]=igrad[1]; }/*isa */ pmerrm=merrm; dcellzero(psf[iwfs]);/*reset accumulation.*/ }/*if iwfs has output*/ }/*for wfs*/ }/*if phystart */ //output to mreal after using it to ensure two cycle delay. if(st2t){//Type I or II control. if(st2t->mint->p[0]){//has output. dcp(&mreal, st2t->mint->p[0]->p[0]); } }else{//LQG control kalman_output(kalman, &mreal, 0, 1); } if(kalman){//LQG control int indk=0; //Form PSOL grads and obtain index to LQG M for(int iwfs=0; iwfs<aster->nwfs; iwfs++){ int dtrati=(multirate?(int)dtrats->p[iwfs]:dtratc); if((istep+1) % dtrati==0){ indk|=1<<iwfs; dmm(&gradout->p[iwfs], 1, aster->g->p[iwfs], mpsol->p[iwfs], "nn", 1./dtrati); dzero(mpsol->p[iwfs]); } } if(indk){ kalman_update(kalman, gradout->m, indk-1); } }else if(st2t){ if(pmerrm){ dmm(&merrm->p[0], 0, pgm, gradout->m, "nn", 1); } servo_filter(st2t, pmerrm);//do even if merrm is zero. to simulate additional latency } if(parms->skyc.dbg){ memcpy(PCOL(gradsave, istep), gradout->m->p, sizeof(double)*gradsave->nx); } }/*istep; */ } if(parms->skyc.dbg){ int dtrati=(multirate?(int)dtrats->p[0]:dtratc); writebin(gradsave,"%s/skysim_grads_aster%d_dtrat%d",dirsetup, aster->iaster,dtrati); writebin(mres,"%s/skysim_sim_mres_aster%d_dtrat%d",dirsetup,aster->iaster,dtrati); } dfree(mreal); dcellfree(mpsol); dfree(merr); dcellfree(merrm); dcellfree(zgradc); dcellfree(gradout); dfree(gradsave); if(hasphy){ dcellfreearr(psf, aster->nwfs); dcellfreearr(ints, aster->nwfs); ccellfree(wvf); ccellfree(wvfc); ccellfree(otf); free(mtche); } servo_free(st2t); /*dfree(mres); */ if(mresout) { *mresout=mres; }else{ dfree(mres); } dscale(res, 1./((nstep-parms->skyc.evlstart)*parms->skyc.navg)); return res; }
/** Setup matched filter for stars. */ static void setup_star_mtch(const PARMS_S *parms, POWFS_S *powfs, STAR_S *star, int nstar, dcell**nonlin){ const long nwvl=parms->maos.nwvl; const long npowfs=parms->maos.npowfs; dmat* rnefs=parms->skyc.rnefs; for(int istar=0; istar<nstar; istar++){ if(!star[istar].idtrat){ star[istar].idtrat=dnew(npowfs, 1); } double radius=sqrt(pow(star[istar].thetax,2)+pow(star[istar].thetay,2)); int igg=round(radius*206265/parms->maos.ngsgrid); //info("radius=%g as, igg=%d\n", radius*206265, igg); for(int ipowfs=0; ipowfs<npowfs; ipowfs++){ const long nsa=parms->maos.nsa[ipowfs]; const long pixpsa=parms->skyc.pixpsa[ipowfs]; //size of PSF const double sigma_theta=parms->skyc.wvlmean/parms->maos.dxsa[ipowfs]; PISTAT_S *pistat=&star[istar].pistat[ipowfs]; pistat->i0=dcellnew(nsa,nwvl); pistat->gx=dcellnew(nsa,nwvl); pistat->gy=dcellnew(nsa,nwvl); pistat->i0s=dcellnew(nsa,1); pistat->gxs=dcellnew(nsa,1); pistat->gys=dcellnew(nsa,1); dcell* psf=pistat->psf; dcell* i0=pistat->i0; dcell* gx=pistat->gx; dcell* gy=pistat->gy; for(long iwvl=0; iwvl<nwvl; iwvl++){ for(long isa=0; isa<nsa; isa++){ double siglev=star[istar].siglev->p[ipowfs]->p[iwvl]; IND(i0,isa,iwvl)=dnew(pixpsa,pixpsa); IND(gx,isa,iwvl)=dnew(pixpsa,pixpsa); IND(gy,isa,iwvl)=dnew(pixpsa,pixpsa); psf2i0gxgy(IND(i0,isa,iwvl),IND(gx,isa,iwvl),IND(gy,isa,iwvl), IND(psf,isa,iwvl),powfs[ipowfs].dtf+iwvl); dadd(&pistat->i0s->p[isa], 1, IND(i0,isa,iwvl), siglev); dadd(&pistat->gxs->p[isa], 1, IND(gx,isa,iwvl), siglev); dadd(&pistat->gys->p[isa], 1, IND(gy,isa,iwvl), siglev); } } if(parms->skyc.dbg){ writebin(pistat->i0s, "%s/star%d_ipowfs%d_i0s", dirsetup,istar,ipowfs); } const double pixtheta=parms->skyc.pixtheta[ipowfs]; int ndtrat=parms->skyc.ndtrat; pistat->mtche=mycalloc(ndtrat,dcell*); pistat->sanea=dcellnew(ndtrat,1); pistat->sanea0=dcellnew(ndtrat,1); pistat->snr=dnew(ndtrat,1); dcell *i0s=NULL; dcell *gxs=NULL; dcell *gys=NULL; for(int idtrat=0; idtrat<ndtrat; idtrat++){ int dtrat=parms->skyc.dtrats->p[idtrat]; dcelladd(&i0s, 0, pistat->i0s, dtrat); dcelladd(&gxs, 0, pistat->gxs, dtrat); dcelladd(&gys, 0, pistat->gys, dtrat); genmtch(&pistat->mtche[idtrat], &pistat->sanea->p[idtrat], i0s, gxs, gys, pixtheta, IND(rnefs,idtrat,ipowfs), star[istar].bkgrnd->p[ipowfs]*dtrat, parms->skyc.mtchcr); /*Add nolinearity*/ if(nonlin){ //add linearly not quadratically since the errors are related. dmat *nea_nonlin=dinterp1(nonlin[ipowfs]->p[igg], NULL, pistat->sanea->p[idtrat], 0); for(int i=0; i<nsa*2; i++){ //info2("%g mas", pistat->sanea->p[idtrat]->p[i]*206265000); pistat->sanea->p[idtrat]->p[i]=sqrt(pow(pistat->sanea->p[idtrat]->p[i],2) +pow(nea_nonlin->p[i],2)); //info2("-->%g mas\n", pistat->sanea->p[idtrat]->p[i]*206265000); } dfree(nea_nonlin); } dcp(&pistat->sanea0->p[idtrat], pistat->sanea->p[idtrat]); if(parms->skyc.neaaniso){ for(int i=0; i<nsa*2; i++){ pistat->sanea->p[idtrat]->p[i]=sqrt(pow(pistat->sanea->p[idtrat]->p[i],2) +pow(star[istar].pistat[ipowfs].neaspec->p[i]->p[idtrat], 2)); } } if(parms->skyc.dbg){ writebin(pistat->mtche[idtrat], "%s/star%d_ipowfs%d_mtche_dtrat%d", dirsetup,istar,ipowfs,dtrat); } #if 1 double nea=sqrt(dsumsq(pistat->sanea->p[idtrat])/(nsa*2)); #else double nea=dmax(pistat->sanea->p[idtrat]); #endif double snr=sigma_theta/nea; pistat->snr->p[idtrat]=snr; if(parms->skyc.verbose) info2("dtrat=%3d, nea=%4.1f, snr=%4.1f\n", (int)parms->skyc.dtrats->p[idtrat], nea*206265000, snr); if(snr>parms->skyc.snrmin->p[parms->skyc.snrmin->nx==1?0:idtrat]){ star[istar].idtrat->p[ipowfs]=idtrat; } }//for idtrat if(parms->skyc.dbg){ info2("star %2d optim: powfs %1d: dtrat=%3d\n", istar, ipowfs, (int)parms->skyc.dtrats->p[(int)star[istar].idtrat->p[ipowfs]]); writebin(pistat->sanea, "%s/star%d_ipowfs%d_sanea", dirsetup,istar,ipowfs); }/*idtrat */ dcellfree(i0s); dcellfree(gxs); dcellfree(gys); }/*for istar */ }/*for ipowfs */ }
/** Save NGS WFS and other information for later use in MAOS simulations.*/ void skysim_save(const SIM_S *simu, const ASTER_S *aster, const double *ipres, int selaster, int seldtrat, int isky){ const PARMS_S* parms=simu->parms; const int nwvl=parms->maos.nwvl; char path[PATH_MAX]; snprintf(path,PATH_MAX,"Res%d_%d_maos/sky%d",simu->seed_maos,parms->skyc.seed,isky); mymkdir("%s",path); for(int iwfs=0; iwfs<aster[selaster].nwfs; iwfs++){ dcell *sepsf=dcelldup(aster[selaster].wfs[iwfs].pistat->psf); for(int ic=0; ic<sepsf->nx*sepsf->ny; ic++){ dfftshift(sepsf->p[ic]);/*put peak in center. required by MAOS. */ } writebin(sepsf, "%s/pistat_wfs%d",path,iwfs+6); dcellfree(sepsf); writebin(aster->wfs[iwfs].pistat->sanea->p[seldtrat], "%s/nea_tot_wfs%d",path,iwfs+6); writebin(aster[selaster].wfs[iwfs].pistat->sanea->p[seldtrat], "%s/nea_wfs%d",path,iwfs+6); writebin(aster[selaster].wfs[iwfs].pistat->sanea, "%s/neafull_wfs%d",path,iwfs+6); } writebin(aster[selaster].gain->p[seldtrat], "%s/gain",path); writebin(simu->mres->p[isky], "%s/mres",path); writebin(simu->psd_tt,"%s/psd_tt",path); writebin(simu->psd_ps,"%s/psd_ps",path); char fnconf[PATH_MAX]; snprintf(fnconf,PATH_MAX,"%s/base.conf",path); FILE *fp=fopen(fnconf,"w"); fprintf(fp,"sim.seeds=[%d]\n",simu->seed_maos); fprintf(fp,"sim.end=%d\n", parms->maos.nstep); fprintf(fp,"sim.dt=%g\n", parms->maos.dt); fprintf(fp,"sim.zadeg=%g\n", parms->maos.zadeg); fprintf(fp,"sim.mffocus=%d\n", parms->maos.mffocus); fprintf(fp,"sim.ahstfocus=%d\n", parms->maos.ahstfocus); fprintf(fp,"tomo.ahst_wt=3\n"); fprintf(fp,"sim.servotype_lo=2\n");/*type II */ fprintf(fp,"sim.eplo='gain.bin'\n"); fprintf(fp,"powfs0_llt.fnrange='%s'\n", parms->maos.fnrange); fprintf(fp,"atm.r0z=%.4f\n", parms->maos.r0z); fprintf(fp,"atm.size=[128 128]\n"); if(parms->maos.wddeg){ fprintf(fp, "atm.wddeg=["); for(int ips=0; ips<parms->maos.nwddeg; ips++){ fprintf(fp, "%.2f ", parms->maos.wddeg[ips]); } fprintf(fp, "]\n"); } fprintf(fp,"wfs.thetax=[0 0 -33.287 -20.5725 20.5725 33.287"); for(int iwfs=0; iwfs<aster[selaster].nwfs; iwfs++){ fprintf(fp," %.4f", aster[selaster].wfs[iwfs].thetax*206265); } fprintf(fp,"]\n"); fprintf(fp,"wfs.thetay=[0 35 10.8156 -28.3156 -28.3156 10.8156"); for(int iwfs=0; iwfs<aster[selaster].nwfs; iwfs++){ fprintf(fp," %.4f", aster[selaster].wfs[iwfs].thetay*206265); } fprintf(fp,"]\n"); fprintf(fp,"wfs.siglev=[900 900 900 900 900 900"); for(int iwfs=0; iwfs<aster[selaster].nwfs; iwfs++){ fprintf(fp, " %.2f", aster[selaster].wfs[iwfs].siglevtot); } fprintf(fp,"]\n"); fprintf(fp,"wfs.wvlwts=[1 1 1 1 1 1"); for(int iwfs=0; iwfs<aster[selaster].nwfs; iwfs++){ for(int iwvl=0; iwvl<nwvl; iwvl++){ fprintf(fp," %.2f ", aster[selaster].wfs[iwfs].siglev->p[iwvl] /aster[selaster].wfs[iwfs].siglevtot); } } fprintf(fp,"]\n"); fprintf(fp,"wfs.powfs=[0 0 0 0 0 0"); for(int iwfs=0; iwfs<aster[selaster].nwfs; iwfs++){ fprintf(fp, " %d", aster[selaster].wfs[iwfs].ipowfs+1); } fprintf(fp,"]\n"); dmat* rnefs=parms->skyc.rnefs; double rne=IND(rnefs,seldtrat,0); double bkgrnd=aster[selaster].wfs[0].bkgrnd; if(parms->maos.npowfs==1){ fprintf(fp, "powfs.piinfile=[\"\" \"pistat\" ]\n"); fprintf(fp, "powfs.neareconfile=[\"\" \"nea_tot\"]\n"); fprintf(fp, "powfs.phyusenea=[0 1]\n"); fprintf(fp, "powfs.dtrat=[1 %d]\n", (int)parms->skyc.dtrats->p[seldtrat]); fprintf(fp, "powfs.bkgrnd=[0 %.2f]\n", bkgrnd); fprintf(fp, "powfs.rne=[3 %.2f]\n", rne); fprintf(fp, "powfs.phystep=[0 %ld]\n", 50+(long)parms->skyc.dtrats->p[seldtrat]*20); fprintf(fp, "powfs.noisy=[1 1 ]\n"); fprintf(fp, "powfs.pixtheta=[0.5/206265 %g/206265000]\n", parms->skyc.pixtheta[1]*206265000); fprintf(fp, "powfs.pixpsa=[6 %d]\n", parms->skyc.pixpsa[0]); fprintf(fp, "powfs.ncomp=[64 %d]\n", parms->maos.ncomp[0]); fprintf(fp, "powfs.nwvl=[1 %d]\n",nwvl); fprintf(fp, "powfs.wvl=[0.589e-6"); for(int ip=0; ip<1; ip++){ for(int iwvl=0; iwvl<nwvl; iwvl++){ fprintf(fp, " %.4g", parms->maos.wvl[iwvl]); } } fprintf(fp,"]\n"); }else if(parms->maos.npowfs==2){ fprintf(fp, "powfs.piinfile=[\"\" \"pistat\" \"pistat\"]\n"); fprintf(fp, "powfs.neareconfile=[\"\" \"nea_tot\" \"nea_tot\"]\n"); fprintf(fp, "powfs.phyusenea=[0 1 1]\n"); fprintf(fp, "powfs.dtrat=[1 %d %d]\n", (int)parms->skyc.dtrats->p[seldtrat], (int)parms->skyc.dtrats->p[seldtrat]); fprintf(fp, "powfs.bkgrnd=[0 %.2f %.2f]\n", bkgrnd, bkgrnd); fprintf(fp, "powfs.rne=[3 %.2f %.2f]\n", rne,rne); fprintf(fp, "powfs.phystep=[0 %ld %ld]\n", 50+(long)parms->skyc.dtrats->p[seldtrat]*20, 50+(long)parms->skyc.dtrats->p[seldtrat]*20); fprintf(fp, "powfs.noisy=[1 1 1]\n"); fprintf(fp, "powfs.pixtheta=[0.5/206265 %g/206265000 %g/206265000]\n", parms->skyc.pixtheta[0]*206265000, parms->skyc.pixtheta[1]*206265000); fprintf(fp, "powfs.pixpsa=[6 %d %d]\n", parms->skyc.pixpsa[0], parms->skyc.pixpsa[1]); fprintf(fp, "powfs.ncomp=[64 %d %d]\n", parms->maos.ncomp[0], parms->maos.ncomp[1]); fprintf(fp, "powfs.nwvl=[1 %d %d]\n",nwvl,nwvl); fprintf(fp, "powfs.wvl=[0.589e-6"); for(int ip=0; ip<2; ip++){ for(int iwvl=0; iwvl<nwvl; iwvl++){ fprintf(fp, " %.4g", parms->maos.wvl[iwvl]); } } fprintf(fp,"]\n"); fprintf(fp, "powfs.wvlwts=[]\n"); }else{ error("Fill this out please\n"); } fclose(fp); snprintf(fnconf,PATH_MAX,"%s/skyres.txt",path); fp=fopen(fnconf,"w"); fprintf(fp, "TotAll\tNGS\tTT\n"); fprintf(fp, "%g\t%g\t%g\n", sqrt(ipres[0])*1e9, sqrt(ipres[1])*1e9, sqrt(ipres[2])*1e9); fclose(fp); }
void save_recon(SIM_T *simu) { const PARMS_T *parms=simu->parms; const RECON_T *recon=simu->recon; if(parms->plot.run) { if(parms->recon.alg==0) { for(int i=0; simu->opdr && i<simu->opdr->nx; i++) { if(simu->opdr->p[i]) { drawopd("opdr", recon->xloc->p[i], simu->opdr->p[i]->p, NULL, "Reconstructed Atmosphere","x (m)","y (m)","opdr %d",i); } } for(int i=0; simu->dmfit && i<simu->dmfit->nx; i++) { if(simu->dmfit->p[i]) { drawopd("DM", recon->aloc->p[i], simu->dmfit->p[i]->p,NULL, "DM Fitting Output","x (m)", "y (m)","Fit %d",i); } } } if(!parms->recon.modal) { for(int idm=0; simu->dmerr && idm<parms->ndm; idm++) { if(simu->dmerr->p[idm]) { drawopd("DM",recon->aloc->p[idm], simu->dmerr->p[idm]->p,NULL, "DM Error Signal (Hi)","x (m)","y (m)", "Err Hi %d",idm); } } } for(int idm=0; simu->dmerr && idm<parms->ndm; idm++) { if(simu->dmint->mint->p[0]->p[idm]) { drawopd("DM",recon->aloc->p[idm], simu->dmint->mint->p[0]->p[idm]->p,NULL, "DM Integrator (Hi)","x (m)","y (m)", "Int Hi %d",idm); } } if(simu->dm_wfs) { for(int iwfs=0; iwfs<parms->nwfs; iwfs++) { int ipowfs=parms->wfs[iwfs].powfs; int imoao=parms->powfs[ipowfs].moao; if(imoao<0) continue; drawopd("moao", recon->moao[imoao].aloc->p[0], simu->dm_wfs->p[iwfs]->p, NULL, "MOAO", "x(m)", "y(m)", "WFS %d", iwfs); } } if(simu->dm_evl) { int imoao=parms->evl.moao; for(int ievl=0; ievl<parms->evl.nevl && imoao>=0; ievl++) { drawopd("moao", recon->moao[imoao].aloc->p[0], simu->dm_evl->p[ievl]->p, NULL, "MOAO", "x(m)", "y(m)", "Evl %d", ievl); } } } if(parms->plot.run && simu->Merr_lo) { dcell *dmlo=NULL; switch(simu->parms->recon.split) { case 1: ngsmod2dm(&dmlo, recon, simu->Merr_lo, 1); break; case 2: dcellmm(&dmlo, simu->recon->MVModes, simu->Merr_lo, "nn", 1); break; } for(int idm=0; dmlo && idm<parms->ndm; idm++) { drawopd("DM",recon->aloc->p[idm], dmlo->p[idm]->p,NULL, "DM Error Signal (Lo)","x (m)","y (m)", "Err Lo %d",idm); } dcellfree(dmlo); } if(parms->plot.run && simu->Mint_lo && simu->Mint_lo->mint->p[0]) { dcell *dmlo=NULL; switch(simu->parms->recon.split) { case 1: ngsmod2dm(&dmlo, recon, simu->Mint_lo->mint->p[0], 1); break; case 2: dcellmm(&dmlo, simu->recon->MVModes, simu->Mint_lo->mint->p[0], "nn", 1); break; } for(int idm=0; dmlo && idm<parms->ndm; idm++) { drawopd("DM",recon->aloc->p[idm], dmlo->p[idm]->p,NULL, "DM Integrator (Lo)","x (m)","y (m)", "Int Lo %d",idm); } dcellfree(dmlo); } if(parms->recon.alg==0) { /*minimum variance tomo/fit reconstructor */ if(parms->save.opdr) { cellarr_dcell(simu->save->opdr, simu->reconisim, simu->opdr); } if(parms->save.opdx || parms->plot.opdx) { dcell *opdx=simu->opdx; if(!opdx) { atm2xloc(&opdx, simu); } if(parms->save.opdx) { cellarr_dcell(simu->save->opdx, simu->isim, opdx); } if(parms->plot.opdx) { /*draw opdx */ for(int i=0; i<opdx->nx; i++) { if(opdx->p[i]) { drawopd("opdx", recon->xloc->p[i], opdx->p[i]->p, NULL, "Atmosphere Projected to XLOC","x (m)","y (m)","opdx %d",i); } } } if(!parms->sim.idealfit) { dcellfree(opdx); } } } if(parms->save.dm && (!parms->sim.closeloop || simu->isim>0)) { if(simu->dmfit) { cellarr_dcell(simu->save->dmfit, simu->reconisim, simu->dmfit); } if(simu->dmerr) { cellarr_dcell(simu->save->dmerr, simu->reconisim, simu->dmerr); } if(simu->dmint->mint->p[0]) { cellarr_dcell(simu->save->dmint, simu->reconisim, simu->dmint->mint->p[0]); } if(simu->Merr_lo) { cellarr_dcell(simu->save->Merr_lo, simu->reconisim, simu->Merr_lo); if(!parms->sim.fuseint && simu->Mint_lo->mint->p[0]) { cellarr_dcell(simu->save->Mint_lo, simu->reconisim, simu->Mint_lo->mint->p[0]); } } } const int seed=simu->seed; if(parms->save.ngcov>0 && CHECK_SAVE(parms->sim.start, parms->sim.end-(parms->sim.closeloop?1:0), simu->reconisim, parms->save.gcovp)) { double scale=1./(double)(simu->reconisim-parms->sim.start+1); dcellscale(simu->gcov, scale); for(int igcov=0; igcov<parms->save.ngcov; igcov++) { writebin(simu->gcov->p[igcov], "gcov_%d_wfs%ld_%ld_%d.bin", seed, parms->save.gcov->p[igcov*2], parms->save.gcov->p[igcov*2+1], simu->reconisim+1); } dcellscale(simu->gcov, 1./scale); } if(parms->sim.psfr && CHECK_SAVE(parms->evl.psfisim, parms->sim.end-(parms->sim.closeloop?1:0), simu->reconisim, parms->sim.psfr)) { info2("Output PSF Recon Telemetry\n"); long nstep=simu->reconisim+1-parms->evl.psfisim; double scale=1./nstep; dcellscale(simu->ecov, scale); if(!parms->dbg.useopdr || parms->sim.idealfit) { writebin(simu->ecov, "ecov_%d_%ld", seed, nstep); } else { /*deprecated */ char strht[24]; for(int ievl=0; ievl<parms->evl.nevl; ievl++) { if(!simu->ecov->p[ievl]) continue; if(isfinite(parms->evl.hs->p[ievl])) { snprintf(strht, 24, "_%g", parms->evl.hs->p[ievl]); } else { strht[0]='\0'; } writebin(simu->ecov->p[ievl], "ecov_%d_x%g_y%g%s_%ld.bin", seed, parms->evl.thetax->p[ievl]*206265, parms->evl.thetay->p[ievl]*206265, strht, nstep); } } dcellscale(simu->ecov, 1./scale);//scale back to continuous accumulation } }
/** Read in pistat information, used to compute matched filter, and SANEA. */ static void setup_star_read_pistat(SIM_S *simu, STAR_S *star, int nstar, int seed){ const PARMS_S *parms=simu->parms; const int npowfs=parms->maos.npowfs; const int nwvl=parms->maos.nwvl; const double ngsgrid=parms->maos.ngsgrid; for(int istar=0; istar<nstar; istar++){ STAR_S *stari=&star[istar]; stari->pistat=mycalloc(npowfs,PISTAT_S); const double thetax=stari->thetax*206265;/*in as */ const double thetay=stari->thetay*206265; double thxnorm=thetax/ngsgrid; double thynorm=thetay/ngsgrid; long thxl=(long)floor(thxnorm); long thyl=(long)floor(thynorm); double wtx=thxnorm-thxl; double wty=thynorm-thyl; for(int ipowfs=0; ipowfs<npowfs; ipowfs++){ const int msa=parms->maos.msa[ipowfs]; const int nsa=parms->maos.nsa[ipowfs]; dcell *avgpsf=NULL; dcell *neaspec=NULL; double wtsum=0; for(int ix=0; ix<2; ix++){ double thx=(thxl+ix)*ngsgrid; for(int iy=0; iy<2; iy++){ double thy=(thyl+iy)*ngsgrid; double wtxi=fabs(((1-ix)-wtx)*((1-iy)-wty)); if(wtxi<0.01){ /*info("skipping ix=%d,iy=%d because wt=%g\n",ix,iy,wtxi); */ continue; } char fn[PATH_MAX]; snprintf(fn,PATH_MAX,"%s/pistat/pistat_seed%d_sa%d_x%g_y%g", dirstart, seed,msa,thx,thy); if(!zfexist(fn)){ /*warning("%s doesn't exist\n",fn); */ }else{ dcell *avgpsfi=dcellread("%s",fn); dcelladd(&avgpsf, 1, avgpsfi, wtxi); dcellfree(avgpsfi); wtsum+=wtxi; snprintf(fn,PATH_MAX,"%s/neaspec/neaspec_seed%d_sa%d_x%g_y%g", dirstart, seed, msa, thx, thy); dcell *neaspeci=dcellread("%s",fn); dcelladd(&neaspec, 1, neaspeci, wtxi); dcellfree(neaspeci); } } } if(wtsum<0.01){ warning("PISTAT is not available for (%g,%g) msa=%d\n",thetax,thetay,msa); } dcellscale(neaspec, 1./wtsum); dcellscale(avgpsf, 1./wtsum); dmat *scale=NULL; if(parms->skyc.bspstrehl){ scale=dnew(nsa,nwvl); dmat *gx=dnew(1,1); gx->p[0]=thxnorm; dmat *gy=dnew(1,1); gy->p[0]=thynorm; if(nsa!=avgpsf->nx || nwvl!=avgpsf->ny){ error("Mismatch: nsa=%d, nwvl=%d, avgpsf->nx=%ld, avgpsf->ny=%ld\n", nsa, nwvl, avgpsf->nx, avgpsf->ny); } for(int ic=0; ic<nsa*nwvl; ic++){ dmat *val=dbspline_eval(simu->bspstrehl[ipowfs][ic], simu->bspstrehlxy,simu->bspstrehlxy, gx, gy); double ratio=val->p[0]/avgpsf->p[ic]->p[0]; /*info("strehl: bilinear: %g, cubic: %g\n", avgpsf->p[ic]->p[0],val->p[0]); */ if(ratio<0){ warning("Ratio=%g is less than zero.\n", ratio); scale->p[ic]=1; }else{ dscale(avgpsf->p[ic], ratio); scale->p[ic]=ratio; } dfree(val); } dfree(gx); dfree(gy); } stari->pistat[ipowfs].psf=avgpsf;/*PSF is in corner. */ stari->pistat[ipowfs].neaspec=dcellnew(nsa*2, 1); for(int ig=0; ig<nsa*2; ig++){ dmat *tmp=0; for(int iwvl=0; iwvl<nwvl; iwvl++){ dadd(&tmp, 0, neaspec->p[ig+nsa*2*iwvl], parms->skyc.wvlwt->p[iwvl]); } stari->pistat[ipowfs].neaspec->p[ig]=dinterp1(simu->neaspec_dtrats, tmp, parms->skyc.dtrats, 0); dfree(tmp); } dcellfree(neaspec); stari->pistat[ipowfs].scale=scale; {/* skip stars with large PSF.*/ int size=INT_MAX; for(int ic=0; ic<avgpsf->nx*avgpsf->ny; ic++){ int size0=dfwhm(avgpsf->p[ic]); if(size0<size) size=size0; } if(size>6){ stari->use[ipowfs]=-1; } } if(parms->skyc.dbg){ writebin(avgpsf, "%s/avgpsf_star%d_ipowfs%d_psf",dirsetup,istar,ipowfs); writebin(stari->pistat[ipowfs].neaspec, "%s/pistat_star%d_ipowfs%d_neaspec",dirsetup,istar,ipowfs); } } } }