/* \fcnfh Add all the abundance from different isotopes except those that are going to split the remainder. @returns total abundance that is going to be always between 0 and 1 inclusive */ static inline double addq(prop_isov *isov, /* Variable isotope info (abundance among other) */ enum isodo *isodo, /* Just add those that are ignored */ _Bool *other, /* Don't add those that are going to take care of the remainder to unity */ int n, /* Number of isotopes */ PREC_NREC r) /* Radius at which to compute everything */ { double res=0; while(--n) if(isodo[n]!=ignore && !other[n]) res+=isov[n].q[r]; if(*isodo!=ignore && !*other) res+=isov->q[r]; if(res>1.001||res<0) transiterror(TERR_SERIOUS, "Without processing 'other' molecules, abundance\n" "addition(%g) is either bigger than 1 or negative!\n" ,res); return res; }
/* \fcnfh Finds the abundance of the molecule called 'iso' among the arrays given by 'isov' and 'isof' for the radius at level 'r' @returns abundance of reference level */ static inline double findfactq(char *iso, /* reference isotope looked for */ prop_isof *isof, /* fixed isotope info (name among others) */ prop_isov *isov, /* variable isotope info like abundance */ int n, /* Number of isotopes */ PREC_NREC r) /* Radius index from which get the abundance */ { while (--n) if(strcasecmp(iso,isof[n].n)==0) return isov[n].q[r]; if(strcasecmp(iso,isof->n)==0) return isov->q[r]; for(n=0 ; n<nfonly ; n++) if(strcasecmp(iso,fonly[n].n)==0) return fonly[n].q; transiterror(TERR_SERIOUS, "Isotope you want to reference(%s) was not found among\n" "those whose abundance was given.\n" ,iso); return -1; }
/* \fcnfh Find the isotope in 'isof' with name 'iso' and get its abundance at radius given by index 'r' Return: abundance at requested radius */ static inline double findfactq(char *iso, /* Name of isotope searched */ prop_isof *isof, /* Fixed isotope info */ prop_isov *isov, /* Variable isotope info */ int n, /* Number of isotopes */ PREC_NREC r){ /* Radius index */ /* Search molecule: */ while (--n) if(strcasecmp(iso, isof[n].n)==0) //return isov[n].q[r]; return 0; /* n == 1 case: */ if(strcasecmp(iso, isof->n)==0) //return isov->q[r]; return 0; /* If it wasn't in isof, then search in fonly: */ for(n=0; n<nfonly; n++) if(strcasecmp(iso, fonly[n].n)==0) return fonly[n].q; transiterror(TERR_SERIOUS, "Isotope you want to reference(%s) was not found among " "those whose abundance was given.\n", iso); return -1; }
/* \fcnfh Print error message when a line of 'file' is longer than 'max' characters */ static void atmerr(int max, /* Maximum length of an accepted line */ char *file, /* File from which we were reading */ int line){ /* Line being read */ transiterror(TERR_SERIOUS|TERR_ALLOWCONT, "Line %i of file '%s' has more than %i characters, " "that is not allowed\n", file, max); exit(EXIT_FAILURE); }
/* \fcnfh Error printing function for lines longer than maxline in the CIA file */ void ciaerr(int max, /* Max line length */ char *name, /* CIA file name */ int line){ /* Line number */ transiterror(TERR_SERIOUS, "Line %i of CIA file '%s' is longer than %i characters ...\n" " hard coded values in file '%s' need to be changed.\n", line, name, max, __FILE__); }
/* \fcnfh Print error message when a field with transition info is invalid */ static void invalidfield(char *line, /* Contents of the line */ int nmb, /* File number */ int fld, /* Field with the error */ char *fldn){ /* Name of the field */ transiterror(TERR_SERIOUS|TERR_ALLOWCONT, "Line %i of file '%s': Field %i (%s) does not have a valid " "value:\n%s.\n", nmb, atmfilename, fld, fldn, line); exit(EXIT_FAILURE); }
/* \fcnfh Check whether isotope 'name' found in atmosphere file do correspond to an isotope in the lineinfofile for which extinction is going to be calculated */ static void isisoline(char *name, /* Isotope's name */ PREC_ATM mass, /* Isotope's mass */ int *isoeq, /* Isotope's lineinfo position to be stored */ enum isodo atisodo, /* Action for current isotope */ prop_isof *isof, /* Info from lineinfo file */ enum isodo *isodo, /* Action to be taken storage */ PREC_NREC nliso) /* Number of isotopes in the lineinfo */ { PREC_NREC i; //Note that here, even though the isotope might be ignored, it will //stilll have an equivalent lineiso associated if one is found. //\refline{isodbassoc} for(i=0;i<nliso;i++){ if(strcasecmp(name,isof[i].n)==0){ *isoeq=i; if(isolineinatm[i]) transiterror(TERR_SERIOUS, "Isotope %s has been defined more than once in the\n" "atmosphere file.\n" ,name); isolineinatm[i]=1; if(isodo[i]!=ignore) isodo[i]=atisodo; if(isodo[i]==ignore) transitprint(2,verblevel, "Ignoring isotope %s (%g AMU)\n" ,isof[i].n,isof[i].m); else if(isof[i].m!=mass&&mass!=0) transiterror(TERR_WARNING, "Mass of isotope %s, is not the same\n" "in the atmosphere file %s(%g) than in\n" "the transition info file(%g)\n" ,name,atmfilename,mass, isof[i].m); break; } } if(*isoeq==-1&&atisodo==ignore) nfonly++; }
/* \fcnfh Check that val is positive */ static inline void checkposvalue(PREC_RES val, /* value to check */ int field, /* field where it was read */ long line) /* line from which it was read */ { if(val<0) transiterror(TERR_SERIOUS, "While reading the %ith field in line %li of atmosphere\n" "file %s, a negative value was found (%g)\n" ,field,line-1,atmfilename,val); }
/* \fcnfh observable information as it would be seen before any telescope interaction. Calculates ratio in-transit over out-transit for the simplest expression of modulation. @returns modulation obtained */ static PREC_RES modulationperwn (PREC_RES *tau, long last, double toomuch, prop_samp *ip, struct geometry *sg, int exprlevel) { switch(exprlevel){ case 1: return modulation1(tau,last,toomuch,ip,sg); break; case -1: return modulationm1(tau,last,toomuch,ip,sg); break; default: transiterror(TERR_CRITICAL, "slantpath:: modulationperwn:: Level %i of detail\n" "has not been implemented to compute modulation\n" ,exprlevel); return 0; } }
/* \fcnfh Computes optical depth at a given impact parameter, note that b needs to be given in units of 'rad' and the result needs to be multiplied by the units 'rad' to be real. @returns $\frac{tau}{units_{rad}}$ returns optical depth divided by units of 'rad' */ static inline PREC_RES totaltau(PREC_RES b, /* differential impact parameter with respect to maximum value */ PREC_RES *rad, /* radius array */ PREC_RES *refr, /* refractivity index */ PREC_RES *ex, /* extinction[rad] */ long nrad, /* number of radii elements */ int exprlevel) /* Expression level of detail */ { switch(exprlevel){ case 1: return totaltau1(b,rad,*refr,ex,nrad); break; case 2: return totaltau2(b,rad,refr,ex,nrad); break; default: transiterror(TERR_CRITICAL, "slantpath:: totaltau:: Level %i of detail\n" "has not been implemented to compute optical depth\n" ,exprlevel); return 0; } }
/* \fcnfh Computes optical depth at a given impact parameter, note that b needs to be given in units of 'rad' and the result needs to be multiplied by the units 'rad' to be real. There is no ray bending, refr=constant. It can take nrad values of 1 or bigger. However, if 2 is given then 'ex' and 'rad' need to have a referenceable element at position -1; i.e. rad[-1] and ex[-1] need to exist. @returns $\frac{tau}{units_{rad}}$ returns optical depth divided by units of 'rad' */ static PREC_RES totaltau1(PREC_RES b, /* impact parameter */ PREC_RES *rad, /* Equispaced radius array */ PREC_RES refr, /* refractivity index */ PREC_RES *ex, /* extinction[rad] */ long nrad) /* number of radii elements */ { int rs; int i; PREC_RES res; PREC_RES x3[3],r3[3]; //Look for closest approach radius PREC_RES r0=b/refr; //get bin value 'rs' such that r0 is between rad[rs] inclusive //and rad[rs+1] exclusive. //If we are looking at the outmost layer, then return if((rs=binsearch(rad,0,nrad-1,r0))==-5) return 0; //If some other error occurred else if(rs<0) transiterror(TERR_CRITICAL, "Closest approach value(%g) is outside sampled radius\n" "range(%g - %g)\n" ,r0,rad[0],rad[nrad-1]); //advance the extinction and radius arrays such that the zeroeth //element now is the closest sample to the minimum approach from below //it. rad+=rs; ex+=rs; nrad-=rs; //By parabolic fitting, interpolate the value of extinction at the //radius of minimum approach and store it in the sample that //corresponded to the closest from below. Store such value and radius, //which are to be replaced before returning (\lin{tmpex}) const PREC_RES tmpex=*ex; const PREC_RES tmprad=*rad; if(nrad==2) *ex=interp_parab(rad-1,ex-1,r0); else *ex=interp_parab(rad,ex,r0); *rad=r0; if(nrad==2){ x3[0]=ex[0]; x3[2]=ex[1]; x3[1]=(ex[1]+ex[0])/2.0; r3[0]=rad[0]; r3[2]=rad[1]; r3[1]=(rad[0]+rad[1])/2.0; *rad=tmprad; *ex=tmpex; rad=r3; ex=x3; nrad++; } const PREC_RES dr=rad[1]-rad[0]; //Now convert to s spacing, i.e. distance along the path. Radius needs //to be equispaced. PREC_RES s[nrad]; const PREC_RES Dr=rad[2]-rad[1]; const PREC_RES cte=dr*(dr + 2*r0); s[0]=0; for(i=1 ; i<nrad ; i++) s[i]=sqrt(cte + (i-1)*Dr*(2.0*(r0+dr) + (i-1)*Dr) ); //Integrate!\par //Use spline if GSL is available along with at least 3 points #ifdef _USE_GSL gsl_interp_accel *acc = gsl_interp_accel_alloc (); gsl_interp *spl=gsl_interp_alloc(gsl_interp_cspline,nrad); gsl_interp_init(spl,s,ex,nrad); res=gsl_interp_eval_integ(spl,s,ex,0,s[nrad-1],acc); gsl_interp_free(spl); gsl_interp_accel_free (acc); #else #error non equispaced integration is not implemented without GSL #endif /* _USE_GSL */ //replace original value of extinction //\linelabel{tmpex} *ex=tmpex; *rad=tmprad; //return return 2*(res); }
/* \fcnfh Computes most basic modulation scheme, obtained when there is no limb darkening or emitted flux. @returns modulation obtained */ static PREC_RES modulation1 (PREC_RES *tau, long last, /* Index of the last poisition it has to be at least 1 */ double toomuch, prop_samp *ip, /* Order is descending */ struct geometry *sg) { //general variables PREC_RES res; double srad=sg->starrad*sg->starradfct; //Impact parameter variables long ipn=ip->n; long ipn1=ipn-1; long i; const PREC_RES maxtau=tau[last]>toomuch?tau[last]:toomuch; PREC_RES rinteg[ipn],ipv[ipn]; //this function calculates 1 minus the ratio of in-transit over out-of-transit //expresion for the simplest case, which is given by (INVALID //EXPRESSION FOLLOWING!!) //\[ //M_{\lambda}^{(0)}= //\frac{1}{\pi R_M^2}\int_{R<R_M}\ee^{-\tau( b,\xi)} R \dd R\dd\phi //\]\par //Let's integrate; for each of the planet's layer starting from the //outermost until the closest layer for(i=0;i<=last;i++){ ipv[ipn1-i] = ip->v[i] * ip->fct; rinteg[ipn1-i] = exp(-tau[i]) * ipv[ipn1-i]; } //fill one more lower part bin with 0. Only two to have a nice ending //spline and not unnecessary values. last+=1; if(last>ipn1) last=ipn1; for(;i<=last;i++){ ipv[ipn1-i] = ip->v[i] * ip->fct; rinteg[ipn1-i] = 0; } //increment last to represent number of elements now, check that we //have enough. last++; if(last<3) transiterror(TERR_CRITICAL, "Condition failed, less than 3 items (only %i) for radial\n" "integration.\n" ,last); //integrate in radii #ifdef _USE_GSL gsl_interp_accel *acc = gsl_interp_accel_alloc (); gsl_interp *spl=gsl_interp_alloc( gsl_interp_cspline, last ); gsl_interp_init( spl, ipv+ipn-last, rinteg+ipn-last, last ); res = gsl_interp_eval_integ( spl, ipv+ipn-last, rinteg+ipn-last, ipv[ipn-last], ipv[ipn1], acc ); gsl_interp_free(spl); gsl_interp_accel_free (acc); //or err without GSL #else # error computation of modulation() without GSL is not implemented #endif /* TD: Add real unblocked area of the star, considering geometry */ //substract the total area blocked by the planet. This is from the //following //\begin{align} //1-M=&1-\frac{\int_0^{r_p}\int\ee^{-\tau}\dd \theta r\dd r // +\int_{r_p}^{R_s}\dd A} // {\pi R_s^2}\\% // =&-\frac{\int_0^{r_p}\int\ee^{-\tau}\dd \theta r\dd r // +Area_{planet}} // {\pi R_s^2} // =&-\frac{2\int_0^{r_p}\ee^{-\tau}r\dd r // +r_p^2} // {\pi R_s^2} //\end{align} res = ipv[ipn1] * ipv[ipn1] - 2.0 * res ; //If the planet is going to be transparent with its maximum optical //depth given by toomuch then if(sg->transpplanet) res -= exp(-maxtau) * ipv[ipn-last] * ipv[ipn-last]; //normalize by the planet res *= 1.0 / srad / srad; return res; }
/* \fcnfh Computes optical depth at a given impact parameter, note that b needs to be given in units of 'rad' and the result needs to be multiplied by the units 'rad' to be real. This uses a bent path ray solution. @returns $\frac{tau}{units_{rad}}$ returns optical depth divided by units of 'rad' */ static PREC_RES totaltau2(PREC_RES b, /* differential impact parameter with respect to maximum value */ PREC_RES *rad, /* radius array */ PREC_RES *refr, /* refractivity index */ PREC_RES *ex, /* extinction[rad] */ long nrad) /* number of radii elements */ { PREC_RES dt[nrad]; PREC_RES r0a=b; PREC_RES r0=0; int i; const int maxiterations=50; int rs; transiterror(TERR_CRITICAL|TERR_ALLOWCONT, "Tau 2??? I'm afraid that this has not been" " successfully tested yet. I'll continue but" " be critical of the result\n"); //Look for closest approach radius i=0; while(1){ r0=b/lineinterp(r0a,rad,refr,nrad); if(r0==r0a) break; if(i++>maxiterations) transiterror(TERR_CRITICAL, "Maximum iterations(%i) reached while looking for\n" "r0. Convergence not reached (%.6g!=%.6g)\n" ,maxiterations,r0,r0a); r0a=r0; } //get bin value 'rs' such that r0 is between rad[rs-1] inclusive //and rad[rs] exclusive. //If we are looking at the outmost layer, then return if((rs=binsearch(rad,0,nrad-1,r0))==-5) return 0; //If some other error occurred else if(rs<0) transiterror(TERR_CRITICAL, "Closest approach value(%g) is outside sampled radius\n" "range(%g - %g)\n" ,r0,rad[0],rad[nrad-1]); //advance the index to point as desired. Now nrad-rs indicates the //number of points available for integration. rs++; //A fraction 'analiticfrac' of the integration near the closest //appraoach is calcualated analitically, otherwise, I get a division //by zero. In formula\par //\[ //\tau_{\wn}(\rho)= //\underbrace{ //\frac{2\extc_{\wn}\rho}{n}\left( // \sqrt{\left(\frac{nr_1}{\rho}\right)^2-1} // -\sqrt{\left(\frac{nr_0}{\rho}\right)^2-1}\right) //}_{\mathrm{analitic}} + //\underbrace{ //2\int_{r_1=r_0+\delta r}^{\infty} //\frac{\extc_{\wn}~n~r}{\sqrt{n^2r^2-\rho^2}}\dd r //}_{\mathrm{numerical}} //\]\par //First for the analitical part of the integral PREC_RES res; if(ex[rs-1]==ex[rs]) res= ex[rs] * r0 * ( sqrt( rad[rs] * rad[rs] / r0 / r0 - 1) ); else{ PREC_RES alpha = ( ex[rs] - ex[rs-1] ) / ( rad[rs] - rad[rs-1] ); PREC_RES rm = rad[rs]; if(alpha<0) res= - alpha * (rm * sqrt( rm * rm - r0 * r0) - r0 * r0 * log( sqrt( rm * rm / r0 / r0 - 1) + rm / r0 ) ) / 2.0; else res= alpha * (rm * sqrt( rm * rm - r0 * r0) + r0 * r0 * log( sqrt( rm * rm / r0 / r0 - 1) + rm / r0 ) ) / 2.0; } //And now for the numerical integration. Set the variables for(i=rs;i<nrad;i++){ r0a=b/refr[i]/rad[i]; transitASSERT(r0a>1, "Oops! condition could not be asserted, b/(nr)=%g > 1\n" ,r0a); dt[i]=ex[i]/sqrt(1-r0a*r0a); } //Integrate!\par //Use spline if GSL is available along with at least 3 points #ifdef _USE_GSL if(nrad-rs>2){ gsl_interp_accel *acc = gsl_interp_accel_alloc (); gsl_spline *spl=gsl_spline_alloc(gsl_interp_cspline,nrad-rs); gsl_spline_init(spl,rad+rs,dt+rs,nrad-rs); res+=gsl_spline_eval_integ(spl,rad[rs],rad[nrad-1],acc); gsl_spline_free(spl); gsl_interp_accel_free (acc); } //Only integrate Trapezium if there are only two points available. else #endif /* _USE_GSL */ //Integrate Simpson-Trapezium if enough(w/o GSL) or not enough(w/ GSL) //elements. if(nrad-rs>1) res+=integ_trasim(rad[1]-rad[0],dt+rs,nrad-rs); return 2*(res); }
/* DEF */ static PREC_RES eclipse_intens(struct transit *tr, /* Transit structure */ PREC_RES *tau, /* Optical depth array */ PREC_RES w, /* Current wavenumber value */ long last, /* Index where tau == toomuch */ double toomuch, /* Maximum optical depth calculated */ prop_samp *rad){ /* Radius array */ /* FINDME: toomuch is not needed as a parameter */ /* General variables: */ PREC_RES res; /* Result */ PREC_ATM *temp = tr->atm.t; /* Temperatures */ PREC_RES angle = tr->angles[tr->angleIndex] * DEGREES; /* Takes sampling properties for wavenumber from tr: */ prop_samp *wn = &tr->wns; /* Wavenumber units factor to cgs: */ double wfct = wn->fct; /* Radius parameter variables: */ long rnn = rad->n; long i; /* Blackbody function at each layer: */ PREC_RES B[rnn]; /* Integration parts: */ PREC_RES tauInteg[rnn], /* Integrand function */ tauIV[rnn]; /* Tau integration variable */ /* Integrate for each of the planet's layer starting from the outermost until the closest layer. The order is opposite since tau starts from the top and radius array starts from the bottom. */ /* Planck function (erg/s/sr/cm) for wavenumbers: B_\nu = 2 h {\bar\nu}^3 c^2 \frac{1} {\exp(\frac{h \bar \nu c}{k_B T})-1} */ for(i=0; i <= last; i++){ tauIV[i] = tau[i]; B[i] = (2.0 * H * w * w * w * wfct * wfct * wfct * LS * LS) / (exp(H * w * wfct * LS / (KB * temp[rnn-1-i])) - 1.0); tauInteg[i] = B[i] * exp(-tau[i]/ cos(angle)); } /* Added 0 at the end when tau reach toomuch, so the spline looks nice */ /* Add all other layers to be 0. */ for(; i<rnn; i++){ tauInteg[i] = 0; /* Geometric progression is used to provide enough elements for integral to work. It does not change the final outcome/result. */ tauIV[i] = tauIV[i-1] + 1; } /* Adding additional 0 layer, plus the last represent number of elements is -1, so we need to add one more. 2 in total. */ last += 2; /* If atmosphere is transparent, and at last level tau has not reached tau.toomuch, last is set to max number of layers (rnn, instead of rnn-1 because we added 2 on the previous step). The code requests never to go over it. */ if(last > rnn) last = rnn; /* Checks if we have enough radii to do spline, at least 3: */ if(last < 3) transiterror(TERR_CRITICAL, "Less than 3 items (%i given) for radial " "integration.\n", last); /* Integrate along tau up to tau = toomuch: */ #ifdef _USE_GSL gsl_interp_accel *acc = gsl_interp_accel_alloc(); gsl_interp *spl = gsl_interp_alloc(gsl_interp_cspline, last); gsl_interp_init(spl, tauIV, tauInteg, last); res = gsl_interp_eval_integ(spl, tauIV, tauInteg, tauIV[0], tauIV[last-1], acc); gsl_interp_free(spl); gsl_interp_accel_free (acc); #else # error computation of modulation() without GSL is not implemented #endif /* GSL is stupid. I will use a trapezoidal rule for integration instead (when I want to run the code in safety mode): */ //res = integ_trapz(tauIV, tauInteg, last); //if (fabs(w-2877.00) <= 0.5){ // transitprint(1, 2, "\nI(w=%.10g) = %.10g\n", w, res); // for (i=0; i<last; i++) // transitprint(1, 2, " tau: %.10e int:%.10e\n", tauIV[i], tauInteg[i]); // double res2 = integ_trapz(tauIV, tauInteg, last-1); // transitprint(1,2, "Trapezoidal integration: %.10e\n", res2); //} //if (res < 0){ //if (fabs(w-1844.59) <= 0.005){ // double res2 = integ_trapz(tauIV, tauInteg, last-1); // transitprint(1,2, "Trapezoidal integration: %.10e\n", res2); // transitprint(1, 2, "\nI(w=%.10g) = %.10g\n", w, res); // for (i=0; i<last; i++) // transitprint(1, 2, " tau: %.10e int:%.10g\n", tauIV[i], tauInteg[i]); //} return res/cos(angle); }
/* \fcnfh Calculate the transit modulation at each wavenumber Return: 0 on success, else -1 if impact parameter sampling is not equispaced */ int modulation(struct transit *tr){ struct optdepth *tau = tr->ds.tau; struct geometry *sg = tr->ds.sg; static struct outputray st_out; tr->ds.out = &st_out; long w; prop_samp *ip = &tr->ips; prop_samp *wn = &tr->wns; ray_solution *sol = tr->sol; /* Check that impact parameter and wavenumber samples exist: */ transitcheckcalled(tr->pi, "modulation", 3, "tau", TRPI_TAU, "makeipsample", TRPI_MAKEIP, "makewnsample", TRPI_MAKEWN); /* Allocate the modulation array: */ PREC_RES *out = st_out.o = (PREC_RES *)calloc(wn->n, sizeof(PREC_RES)); /* Set time to the user hinted default, and other user hints: */ setgeom(sg, HUGE_VAL, &tr->pi); /* Integrate for each wavelength: */ transitprint(1, verblevel, "Integrating over wavelength.\n"); int nextw = wn->n/10; /* Calculate the modulation spectrum at each wavenumber: */ for(w=0; w < wn->n; w++){ out[w] = sol->spectrum(tr, tau->t[w], wn->v[w], tau->last[w], tau->toomuch, ip); if (out[w] < 0){ switch(-(int)out[w]){ case 1: if(tr->modlevel == -1) transiterror(TERR_SERIOUS, "Optical depth didn't reach limiting " "%g at wavenumber %g cm-1 (only reached %g). Cannot " "use critical radius technique (-1).\n", tau->toomuch, tau->t[w][tau->last[w]], wn->v[w]*wn->fct); default: transiterror(TERR_SERIOUS, "There was a problem while calculating " "modulation at wavenumber %g cm-1. Error code %i.\n", wn->v[w]*wn->fct, (int)out[w]); break; } exit(EXIT_FAILURE); } /* Print to screen the progress status: */ if(w==nextw){ nextw += wn->n/10; transitprint(2, verblevel, "%i%% ", (10*(int)(10*w/wn->n+0.9999999999))); } } transitprint(1, verblevel, "\nDone.\n"); /* Set progress indicator, and print output: */ tr->pi |= TRPI_MODULATION; printmod(tr); return 0; }
/* \fcnfh Read abundances and pressure for each isotope and radius @returns number of radius point */ int readatmfile(FILE *fp, /* File */ struct transit *tr, /* transit info */ struct atm_data *at, /* atmosphere info */ prop_samp *rads, /* radius sampling */ int nrad) /* number of allocated radii, note that is not returned updated */ { //find abundance related quantities for each radius int lines=at->begline; PREC_NREC r=0; PREC_RES tmp; char rc; float allowq=1-tr->allowrq; double sumq; char line[maxline],*lp,*lp2; prop_isov *isov=at->isov; int *isoeq=at->isoeq; struct isotopes *iso=tr->ds.iso; enum isodo *isodo=at->isodo; int i,neiso=iso->n_e; fseek(fp,at->begpos,SEEK_SET); while(1){ //reallocate if necessary if(r==nrad){ nrad<<=1; rads->v=(PREC_ATM *)realloc(rads->v,nrad*sizeof(PREC_ATM)); at->atm.t= (PREC_ATM *)realloc(at->atm.t,nrad*sizeof(PREC_ATM)); at->atm.p= (PREC_ATM *)realloc(at->atm.p,nrad*sizeof(PREC_ATM)); at->mm=(double *)realloc(at->mm,nrad*sizeof(double)); for(i=0;i<neiso;i++){ isov[i].d=(PREC_ATM *)realloc(isov[i].d, nrad*sizeof(PREC_ATM)); isov[i].q=(PREC_ATM *)realloc(isov[i].q, nrad*sizeof(PREC_ATM)); isov[i].n=nrad; } } //Skip comments and read next line while((rc=fgetupto_err(lp=line,maxline,fp,&atmerr,atmfilename,lines++)) =='#'||rc=='\n'); //if it is end of file, stop loop if(!rc) break; tmp=rads->v[r]=strtod(lp,&lp2)+zerorad; checkposvalue(tmp,1,lines); if(lp==lp2) invalidfield(line, lines, 1, "radius"); tmp=at->atm.p[r]=strtod(lp2,&lp); checkposvalue(tmp,2,lines); if(lp==lp2) invalidfield(line, lines, 2, "pressure"); tmp=at->atm.t[r]=strtod(lp,&lp2); checkposvalue(tmp,3,lines); if(lp==lp2) invalidfield(line, lines, 3, "temperature"); //variables to be used by factor (except ieq which is general) int ieq, feq; double ref; _Bool otherfct[neiso]; memset(otherfct,0,sizeof(otherfct)); //now read abundances for every isotope, but don't process //factorized elements. Because they might be proportional to a fixed //element which is set below. for(i=0;i<at->n_aiso;i++){ ieq=isoeq[i]; switch(isodo[i]){ case fixed: if(!r){ isov[ieq].q[0]=askforposd(" %s abundance for isotope %s: " ,at->mass?"Mass":"Number" ,iso->isof[ieq].n); if(isov[ieq].q[0]>=1){ fprintf(stderr," Abundance for any single isotope has to be" " less than one\n Try Again!\n"); i--; } } else isov[ieq].q[r]=isov[ieq].q[0]; break; case factor: //don't process yet those that will use whatever abundance is left //to complete unity feq=ieq; ieq=isoprop[feq].eq; if(strcasecmp(isoprop[feq].t,"other")==0){ otherfct[ieq]=1; continue; } //find the reference value ref=findfactq(isoprop[feq].t,iso->isof,isov,neiso,r); isov[ieq].q[r]=isoprop[feq].f*ref; break; default: transiterror(TERR_CRITICAL, "Trying to read isotope in readatmfile() which is\n" "not 'fixed', 'atmfile', 'ignored', nor 'factor'.\n" ); exit(EXIT_FAILURE); break; case atmfile: case ignore: transitASSERT(ieq<0 || (isodo[i]==ignore&&ieq>=nfonly) || (isodo[i]!=ignore&&ieq>=iso->n_e), "Assertion failed in file %s, line %i: %i!=[0,%i].\n" " Fonly: %i\n" ,__FILE__, __LINE__, isoeq[i], isodo[i]==ignore?nfonly:iso->n_e-1, isodo[i]==ignore); //Read the abundance of the new element. There are two ways: //If processing one of the factor only elements if(isodo[i]==ignore) tmp=fonly[ieq].q=strtod(lp2,&lp); //otherwise if this element is going to be considered else tmp=isov[ieq].q[r]=strtod(lp2,&lp); checkposvalue(tmp, i+4, lines); if(lp==lp2) invalidfield(line, lines, 4+i, "isotope abundance"); lp2=lp; break; } } //process factorized elements that will take care of the rest of the //atmosphere ref=1-addq(isov,iso->isodo,otherfct,neiso,r); for(i=0;i<at->n_aiso;i++) if(isodo[i]==factor){ feq=isoeq[i]; ieq=isoprop[feq].eq; if(otherfct[ieq]) isov[ieq].q[r]=isoprop[feq].f*ref; } //calculate mean molecular mass and check whether abundances add up //correctly, up to round off error of course sumq=checkaddmm(at->mm+r,r,isov,iso->isof,neiso,at->mass,iso->isodo); if((int)(sumq*ROUNDOFF+0.5)<(int)(allowq*ROUNDOFF+0.5)) transiterror(TERR_WARNING, "In radius %g(%i: %g in file), abundances\n" "don't add up to 1: %.9g\n" ,at->rads.v[r],r,at->rads.v[r]-zerorad,sumq); //Calculate densities for(i=0;i<neiso;i++) isov[i].d[r]=stateeqnford(at->mass, isov[i].q[r], at->mm[r], iso->isof[i].m, at->atm.p[r]*at->atm.pfct, at->atm.t[r]*at->atm.tfct); r++; } //reduce array to the right number of radii rads->n=nrad=r; rads->v=(PREC_ATM *)realloc(rads->v,nrad*sizeof(PREC_ATM)); at->atm.t= (PREC_ATM *)realloc(at->atm.t,nrad*sizeof(PREC_ATM)); at->atm.p= (PREC_ATM *)realloc(at->atm.p,nrad*sizeof(PREC_ATM)); at->mm=(double *)realloc(at->mm,nrad*sizeof(double)); for(i=0;i<neiso;i++){ isov[i].d=(PREC_ATM *)realloc(isov[i].d, nrad*sizeof(PREC_ATM)); isov[i].q=(PREC_ATM *)realloc(isov[i].q, nrad*sizeof(PREC_ATM)); isov[i].n=nrad; } //free arrays that were used only to get the factorizing elements free(fonly); return nrad; }
/* \fcnfh Get keyword variables from atmosphere file (mass/number abundance bool; zero-radius offset; radius, temperature, and pressure units factor; atmfile name/info; list isotopes; list of proportional-abundance isotopes). Store molecules and proportional isotopes in atm_data struct. Determine which linedb isotope corresponds to such atm_data isotope. Solve non-matched linedb isotope cases. Put all non-ignore isotopes in transit.ds.iso structure. Return: Number of lines read */ int getmnfromfile(FILE *fp, /* Pointer to atmospheric file */ struct atm_data *at, /* atmosphere structure */ struct transit *tr, /* transit structure */ PREC_ZREC *f_remainder){ /* Remainder molecules' factor */ struct molecules *mol=tr->ds.mol; char line[maxline], *lp; int nimol=0, /* Number of molecules with abundance profile */ nmol=0, /* Total number of molecules */ i; /* Auxiliary for-loop index */ double cumulother = 0; /* Cumulative remainder-molecules' factor */ int ipi = 0; /* Number of remainder molecules */ /* Is the isotope defined in the atm file?: */ //isoprop = (struct atm_isoprop *)calloc(ipa, sizeof(struct atm_isoprop)); at->begline = 0; /* Line where the info begins */ /* Read and store the keyword atmospheric variables: */ while(1){ switch(fgetupto_err(line, maxline, fp, &atmerr, atmfilename, at->begline++)){ /* Ignore comments and blank lines: */ case '\n': case '#': continue; case 0: /* Throw error if EOF */ transiterror(TERR_SERIOUS|TERR_ALLOWCONT, "readatm :: EOF unexpectedly found at line %i " "of file %s while no t,p data points have been read.\n", at->begline, atmfilename); exit(EXIT_FAILURE); continue; /* Determine whether abundance is by mass or number: */ case 'q': lp = line + 1; while(*lp++ == ' '); /* Skip blank spaces */ lp--; switch(*lp|0x20){ case 'n': at->mass = 0; /* Number abundance (mixing ratio) */ break; case 'm': at->mass = 1; /* Mass abundance (mass mixing ratio) */ break; default: transiterror(TERR_SERIOUS, "'q' option in the atmosphere file can only be followed " "by 'm' (for abundances by mass) or 'n' (for abundances " "by number). '%s' is invalid.\n", line); break; } continue; /* Zero radius value: */ case 'z': zerorad = atof(line+1); continue; /* Radius, temperature, or pressure units factor: */ case 'u': switch(line[1]){ case 'r': at->rads.fct = atof(line+2); break; case 'p': at->atm.pfct = atof(line+2); break; case 't': at->atm.tfct = atof(line+2); break; default: transiterror(TERR_SERIOUS, "Invalid unit factor indication in " "atmosphere file.\n"); exit(EXIT_FAILURE); } continue; case 'n': /* Name or identifier for file data */ storename(at, line+1); continue; case 'i': /* Molecule names with an abundance profile: */ /* Count the number of wrds (molecules) in line: */ nimol = countfields(line+1, ' '); transitprint(15, verblevel, "The number of molecules is %d.\n", nimol); /* Allocate Molecules names: */ mol->name = (char **)calloc(nimol, sizeof(char *)); mol->name[0] = (char *)calloc(nimol*maxeisoname, sizeof(char)); for(i=1; i<nimol; i++) mol->name[i] = mol->name[0] + i*maxeisoname; transitprint(1, verblevel, "Molecules with abundance profile:\n "); lp = line; lp = nextfield(lp); /* Skip keyword */ /* Read and store names: */ for (i=0; i<nimol; i++){ getname(lp, mol->name[i]); lp = nextfield(lp); transitprint(1, verblevel, "%s, ", mol->name[i]); } transitprint(1, verblevel, "\b\b.\n"); continue; /* Molecules with abundance proportional to the remainder: */ case 'f': lp = line; lp = nextfield(lp); /* Skip keyword */ /* Current total number of molecules: */ nmol = ++ipi + nimol; /* Re-allocate to add the new molecule: */ mol->name = (char **)realloc(mol->name, nmol*sizeof(char *)); mol->name[0] = (char *)realloc(mol->name[0], nmol*maxeisoname*sizeof(char)); for (i=1; i<nmol; i++) mol->name[i] = mol->name[0] + i*maxeisoname; /* Re-allocate remainder factors: */ f_remainder = (PREC_ZREC *)realloc(f_remainder, ipi*sizeof(PREC_ZREC)); /* Read and store the molecule's name: */ getname(lp, mol->name[nmol-1]); lp = nextfield(lp); /* Move pointer to next field */ if(*lp == '=') /* Skip an optional equal '=' sign */ lp++; /* Read and store factor: */ f_remainder[ipi-1] = strtod(lp, NULL); transitprint(30, verblevel, "%s remainder factor: %.3f\n", mol->name[nmol-1], f_remainder[ipi-1]); if(f_remainder[ipi-1] < 0) transiterror(TERR_CRITICAL, "Abundance ratio has to be positive in atmosphere " "file '%s' in line: '%s'.\n", atmfilename, line); continue; /* End of keyword variables: */ default: break; } break; } transitprint(1, verblevel, "Molecules with abundance proportional to " "remainder:\n "); for(i=nimol; i<nmol; i++) transitprint(1, verblevel, "%s, ", mol->name[i]); transitprint(1, verblevel, "\b\b.\n"); transitprint(3, verblevel, "Read all keywords in atmosphere file without " "problems.\n"); /* Set total number of molecules in atmosphere: */ mol->nmol = at->n_aiso = nmol; /* Check that there was at least one isotope defined and re-allocate array sizes to their final size: */ if(!nimol) transiterror(TERR_SERIOUS, "No isotopes were found in atmosphere file, " "make sure to specify them in a line starting " "with the letter 'i'. First non-comment line " "read:\n%s\n", line); /* Set position of beginning of data: */ at->begpos = ftell(fp) - strlen(line) - 1; /* Calculate cumulative fraction of remainder molecules: */ for(i=0; i < nmol-nimol; i++) cumulother += f_remainder[i]; transitprint(30, verblevel, "Cumulative remainder fraction: %.4f.\n", cumulother); /* Check that cumulother sums to 1.0 (within allowed errors): */ if(nmol>nimol && abs(1.0 - cumulother) > ROUNDTHRESH) transiterror(TERR_SERIOUS, "Sum of remainder-molecules fractional " "abundance (%g) must add to 1.0 +/- %g.\n", cumulother, ROUNDTHRESH); /* Resolve what to do with those isotopes that appear in the line transition database, but not in the atmosphere file. Get the number of non-ignored isotopes in atm_data without linelist: */ //at->n_niso = checknonmatch(tr, at, isodo); /* FINDME: This will be a task in readline (if actually needed). */ return at->begline; }
/* \fcnfh get number of isotopes from file and set index @returns number of lines read */ int getmnfromfile(FILE *fp, struct atm_data *at, struct transit *tr, int nmb) { char line[maxline],*lp; int ison=0,i; struct isotopes *iso=tr->ds.iso; enum isodo *isodo=iso->isodo; //Set variable to handle proportional to isotopes int ipi=0,ipa=at->ipa=4; isolineinatm=(_Bool *)calloc(iso->n_i,sizeof(_Bool)); isoprop=(struct atm_isoprop *)calloc(ipa,sizeof(struct atm_isoprop)); at->begline=0; enum isodo atisodo; at->isodo = (enum isodo *)calloc(nmb,sizeof(enum isodo)); at->isoeq = (int *) calloc(nmb,sizeof(int)); at->m = (PREC_ZREC *) calloc(nmb,sizeof(PREC_ZREC)); at->n = (char **) calloc(nmb,sizeof(char *)); at->n[0] = (char *) calloc(nmb*maxeisoname,sizeof(char)); at->isoeq[0]=-1; for(i=1;i<nmb;i++){ at->n[i]=at->n[0]+i*maxeisoname; at->isoeq[i]=-1; } //while t,p data doesn't start, check for the various modifiers while(1){ switch(fgetupto_err(line,maxline,fp,&atmerr,atmfilename, at->begline++)){ case '\n': //Ignore comments and case '#': // blank lines continue; case 0: //Error if EOF transiterror(TERR_SERIOUS|TERR_ALLOWCONT, "readatminfo:: EOF unexpectedly found at line %i\n" "of file %s while no t,p data points have been read\n" ,at->begline,atmfilename); exit(EXIT_FAILURE); continue; case 'q': //Whether is mass or number abundance lp=line+1; while(*lp++==' '); lp--; switch(*lp|0x20){ case 'n': at->mass=0; break; case 'm': at->mass=1; break; default: transiterror(TERR_SERIOUS, "'q' option in the atmosphere file can only be followed\n" "by 'm' (for abundances by mass) or 'n' (for abundances by\n" "number). '%s' is invalid.\n" ,line); break; } continue; case 'z': //Zero radius value zerorad=atof(line+1); continue; case 'f': //An isotope is to be taken as //proportional to other. lp=line+1; while(*lp==' '||*lp=='\t') lp++; if(ipi==ipa) isoprop=(struct atm_isoprop *)realloc(isoprop,(ipa<<=1)* sizeof(struct atm_isoprop)); isoprop[ipi].m=getds(lp,0,isoprop[ipi].n,maxeisoname-1); //skip over recently read field, and go to next field. lp=nextfield(lp); //skip an optional equal '=' sign if(*lp=='=' && lp[1]==' ') lp=nextfield(lp); //get factor, which has to be between 0 and 1 isoprop[ipi].f=strtod(lp,NULL); if(isoprop[ipi].f<0 ) transiterror(TERR_CRITICAL, "Abundance ratio has to be positive in atmosphere\n" "file '%s' in line: %s" ,atmfilename,line); lp=nextfield(lp); //get name of reference and increase index i=0; while(*lp) isoprop[ipi].t[i++]=*lp++; isoprop[ipi].t[i]='\0'; //now check if that isotope is one of the given in the lineinfo //file isoprop[ipi].eq=-1; isisoline(isoprop[ipi].n,isoprop[ipi].m,&isoprop[ipi].eq,factor, iso->isof,isodo,iso->n_i); //advance index and go for the next line ipi++; continue; case 'u': //Change factorization of radius, temp, //or press switch(line[1]){ case 'r': at->rads.fct=atof(line+2); break; case 'p': at->atm.pfct=atof(line+2); break; case 't': at->atm.tfct=atof(line+2); break; default: transiterror(TERR_SERIOUS, "Invalid unit factor indication in atmosphere file\n"); exit(EXIT_FAILURE); } continue; case 'n': //Name or identifier for file data storename(at,line+1); continue; case 'i': //Isotope information lp=line+1; while(*lp==' '||*lp=='\t') lp++; //'i' has to come before 'f' if(ipi) transiterror(TERR_CRITICAL, "In line '%s'.\n" " 'f' lines have to come after all the 'i' lines in\n" " atmosphere file '%s'" ,line,atmfilename); //for each field while(*lp){ atisodo=atmfile; //Allocate if necessary if(ison==nmb){ nmb<<=1; at->isodo = (enum isodo *)realloc(at->isodo,nmb*sizeof(enum isodo)); at->isoeq = (int *) realloc(at->isoeq,nmb*sizeof(int)); at->m = (PREC_ZREC *) realloc(at->m, nmb*sizeof(PREC_ZREC)); at->n = (char **) realloc(at->n, nmb*sizeof(char *)); at->n[0] = (char *) realloc(at->n[0], nmb*maxeisoname*sizeof(char)); for(i=1;i<nmb;i++) at->n[i]=at->n[0]+i*maxeisoname; for(i=nmb/2;i<nmb;i++) at->isoeq[i]=-1; } //get mass and name, checking that is correct. First see if this //isotope wants to be ignored. if(*lp=='!'){ lp++; atisodo=ignore; } at->m[ison]=getds(lp,0,at->n[ison],maxeisoname-1); if(at->m[ison]<0||at->n[ison]=='\0'){ transiterror(TERR_SERIOUS, "Invalid field in file %s, line %i while reading isotope" " info at:\n%s\n" ,atmfilename,at->begline,lp); } //now check if that isotope is one of the given in the lineinfo //file isisoline(at->n[ison],at->m[ison],at->isoeq+ison,atisodo, iso->isof,isodo,iso->n_i); at->isodo[ison++]=atisodo; //skip over recently read field, and go to next field. while(*lp!=' '&&*lp!='\0') lp++; while(*lp==' '||*lp=='\t') lp++; } continue; default: //T,P seems to be starting break; } break; } transitprint(3,verblevel, "Read all keywords in atmosphere file without problems\n"); //Check if there was at least an isotope identification and allocate new //arrays if(!ison) transiterror(TERR_SERIOUS, "No isotopes were found in atmosphere file, make sure to\n" "specify them in a line starting with the letter 'i'.\n" "First non-comment line read:\n%s\n" ,line); at->begpos=ftell(fp)-strlen(line)-1; //shorten extra length of arrays fonly=(struct fonly *)calloc(nfonly,sizeof(struct fonly)); at->ipa=ipa=ipi; isoprop=(struct atm_isoprop *)realloc(isoprop,ipa* sizeof(struct atm_isoprop)); //Makes at arrays bigger, so that they can hold the factorized values. nmb = at->n_aiso = ison + ipa; at->isodo = (enum isodo *)realloc(at->isodo,nmb*sizeof(enum isodo) ); at->isoeq = (int *) realloc(at->isoeq,nmb*sizeof(int) ); at->m = (PREC_ZREC *) realloc(at->m, nmb*sizeof(PREC_ZREC) ); at->n = (char **) realloc(at->n, nmb*sizeof(char *) ); at->n[0] = (char *) realloc(at->n[0], nmb*maxeisoname*sizeof(char)); for(i=1;i<nmb;i++) at->n[i] = at->n[0] + i * maxeisoname; //initialize values for the factorized elements for(i=ison;i<nmb;i++){ strncpy(at->n[i],isoprop[i-ison].n,maxeisoname-1); at->n[i][maxeisoname-1] = '\0'; at->isoeq[i] = i-ison; at->m[i] = isoprop[i-ison].m; at->isodo[i] = factor; } //Resolve what to do with those isotopes that appear in the transition //database, but not in the atmosphere file. at->n_niso = checknonmatch(tr,at,isodo); //Set full isotope info in the transit structure nmb = iso->n_i + at->n_niso; iso->isodo = (enum isodo *)realloc(iso->isodo, nmb*sizeof(enum isodo)); iso->isof = (prop_isof *)realloc(iso->isof, nmb*sizeof(prop_isof)); iso->isof[iso->n_i].n = (char *)realloc(iso->isof[iso->n_i].n, (nmb-iso->n_i)*maxeisoname* sizeof(char)); for(i=1;i<nmb-iso->n_i;i++) iso->isof[iso->n_i+i].n = iso->isof[iso->n_i].n + i * maxeisoname; //Look for isotopes who have not been associated and see whether they //are supposed to be ignored. nmb = iso->n_i; ipi = 0; int lineignore=0; for(i=0 ; i<ison+ipa ; i++) //If the isotope is not associated to the linedb isotopes, then //associate it. Note that isotopes in linedb that are ignored will //be associated (see comments for Line \label{isodbassoc}). Hence //they won't be detected in this IF. Factor isotopes will also be //associated, and will be handled below if(at->isoeq[i] == -1){ //If they are not going to be ignored then associate them with the //following index available of post linedb isotopes. if(at->isodo[i] != ignore){ at->isoeq[i] = nmb; iso->isodo[nmb] = at->isodo[i]; iso->isof[nmb].m = at->m[i]; strcpy(iso->isof[nmb++].n, at->n[i]); } //otherwise, they might only be used as a reference to factor. else{ at->isoeq[i] = ipi; strcpy(fonly[ipi++].n, at->n[i]); } } //Just count the number of ignored isotopes that belonged to the line //isotopes. else if(at->isodo[i] == ignore) lineignore++; //If there is factor isotopes else if(at->isodo[i] == factor && isoprop[at->isoeq[i]].eq == -1){ if(at->isodo[i]==ignore) transiterror(TERR_CRITICAL, "Trying to ignore an factor isotope, that is not\n" "posible.\n"); isoprop[at->isoeq[i]].eq = nmb; iso->isodo[nmb] = at->isodo[i]; iso->isof[nmb].m = at->m[i]; strcpy(iso->isof[nmb++].n, at->n[i]); } //Reduce the array to get rid of nonline-ignored isotopes. (isov has //not even been allocated yet) iso->n_e = nmb; iso->isodo = (enum isodo *)realloc(iso->isodo, nmb*sizeof(enum isodo)); iso->isof = (prop_isof *)realloc(iso->isof, nmb*sizeof(prop_isof)); iso->isof[iso->n_i].n = (char *)realloc(iso->isof[iso->n_i].n, nmb*maxeisoname*sizeof(char)); for(i=1;i<nmb-iso->n_i;i++) iso->isof[iso->n_i+i].n = iso->isof[iso->n_i].n + i * maxeisoname; //Check that everything makes sense double cumulother=0; for(i=0 ; i<at->n_aiso ; i++) if(at->isodo[i]==factor){ int feq=at->isoeq[i]; if(strcasecmp(isoprop[feq].n,"other")==0) cumulother+=isoprop[feq].f; } //It doesn't make sense for cumulother to be anything different from //unity (except round-off error): you want to associate the //remainder of the atmosphere to some isotopic properties. if( cumulother!=0 && (int)(cumulother*ROUNDOFF+0.5)!=(int)(ROUNDOFF+0.5) ) transiterror(TERR_SERIOUS, "If you are specifying isotopes proportional to 'other'\n" "you have to complete unity (%g). It doesn't make sense\n" "otherwise\n" ,cumulother); transitASSERT(nmb+nfonly!=ison+ipa, "Oooops, number of ignored-nonline elements (%i), plus the\n" "number of ignored-line elements(%i), plus the number of\n" "nonignored (%i), doesn't match the number of elements\n" "found in fields 'i'(%i) and 'f'(%i) of the atmosphere\n" "file '%s'\n" ,nfonly,lineignore,nmb-lineignore,ison,ipa,atmfilename); transitASSERT(nmb!=iso->n_e, "Uyuyuyuyu! Problem in file %s, line %i,\n" "assertion failed: %i != %i!!\n" ,__FILE__,__LINE__,nmb,iso->n_e); //free unused array, store factor info in at structure and return line //where T,P start free(isolineinatm); at->isoprop=isoprop; return at->begline; }
/* \fcnfh Read CIA info from tabulated files. Return: 0 on success */ int readcia(struct transit *tr){ FILE *fp; /* Pointer to CIA file */ char *file, /* CIA file name */ *colname; /* CIA isotope names */ PREC_CIA **a, /* CIA cross sections sample */ *wn; /* CIA sampled wavenumber array */ static struct cia st_cia; /* CIA structure */ tr->ds.cia = &st_cia; int npairs = tr->ds.cia->nfiles = tr->ds.th->ncia; /* Number of CIA files */ int p; /* Auxiliary wavenumber index */ long nt, wa; /* Number of temperature, wn samples in CIA file */ char rc; char *lp, *lpa; /* Pointers in file */ int maxline=300, n; /* Max length of line. Counter */ long lines; /* Lines read counter */ long i; /* Auxiliary for indices */ char line[maxline+1]; /* Array to hold line being read */ struct molecules *mol=tr->ds.mol; /* Make sure that radius and wavenumber samples exist: */ transitcheckcalled(tr->pi, "interpolatecia", 2, "makewnsample", TRPI_MAKEWN, "makeradsample", TRPI_MAKERAD); /* Allocate (output) transit extinction array (in cm-1): */ st_cia.e = (PREC_CIA **)calloc(tr->wns.n, sizeof(PREC_CIA *)); st_cia.e[0] = (PREC_CIA *)calloc(tr->wns.n*tr->rads.n, sizeof(PREC_CIA)); for(p=1; p < tr->wns.n; p++) st_cia.e[p] = st_cia.e[0] + p*tr->rads.n; memset(st_cia.e[0], 0, tr->wns.n*tr->rads.n*sizeof(double)); /* If there are no files, allocate tr.ds.cia.e (extinction) and return: */ if(!npairs){ return 0; } transitprint(1, verblevel, "Computing CIA opacities for %i database%s:\n", npairs, npairs>1 ? "s":""); /* Allocate string for molecule names: */ colname = (char *)calloc(maxline, sizeof(char)); /* Allocate molecules' ID: */ st_cia.mol1 = (int *)calloc(npairs, sizeof(int)); st_cia.mol2 = (int *)calloc(npairs, sizeof(int)); /* Number of temperature and wavenumber samples per file: */ st_cia.ntemp = (int *)calloc(npairs, sizeof(int)); st_cia.nwave = (int *)calloc(npairs, sizeof(int)); /* CIA, temperature and wavenumber samples: */ st_cia.cia = (PREC_CIA ***)calloc(npairs, sizeof(PREC_CIA **)); st_cia.temp = (PREC_CIA **)calloc(npairs, sizeof(PREC_CIA *)); st_cia.wn = (PREC_CIA **)calloc(npairs, sizeof(PREC_CIA *)); for(p=0; p < npairs; p++){ /* Copy file names from hint: */ file = xstrdup(tr->ds.th->ciafile[p]); /* Attempt to open the files: */ if((fp=fopen(file, "r")) == NULL) transiterror(TERR_SERIOUS, "Cannot read CIA file '%s'.\n", file); transitprint(10, verblevel, " CIA file (%d/%d): '%s'\n", p+1, npairs, file); lines = 0; /* lines read counter */ lpa = 0; /* Read the file headers: */ while(1){ /* Skip comments, blanks and read next line: */ while((rc=fgetupto_err(lp=line, maxline, fp, &ciaerr, file, lines++)) =='#' || rc=='\n'); /* If it is end of file, stop loop: */ if(!rc) transiterror(TERR_SERIOUS, "File '%s' finished before opacity info.\n", file); switch(rc){ case 'i': /* Read the name of the isotopes: */ while(isblank(*++lp)); /* Check that there are exactly two isotopes: */ if(countfields(lp, ' ') != 2) transiterror(TERR_SERIOUS, "Wrong line %i in CIA file '%s', if it begins with a " "'i', it should have the species separated by blank " "spaces. Rest of line:\n'%s'\n", lines, file, lp); st_cia.mol1[p] = st_cia.mol2[p] = -1; /* Allocate and copy the name of the first moleculee: */ getname(lp, colname); /* Find the ID of the first molecule: */ for(i=0; i<mol->nmol; i++) if(strcmp(mol->name[i], colname)==0) st_cia.mol1[p] = i; /* If the molecule is not in the atmosphere file: */ if(st_cia.mol1[p] == -1) transiterror(TERR_SERIOUS, "CIA molecule '%s' from file '%s' does " "not match any in the atmsopheric file.\n", colname, file); /* Allocate and store the name of the second isotope: */ lp = nextfield(lp); getname(lp, colname); for(i=0; i < mol->nmol; i++) if(strcmp(mol->name[i], colname)==0) st_cia.mol2[p] = i; if(st_cia.mol2[p] == -1) transiterror(TERR_SERIOUS, "CIA molecule '%s' from file '%s' does " "not match any in the atmsopheric file.\n", colname, file); transitprint(10, verblevel, " CIA molecules: [%s, %s]\n", mol->name[st_cia.mol1[p]], mol->name[st_cia.mol2[p]]); continue; case 't': /* Read the sampling temperatures array: */ while(isblank(*++lp)); nt = st_cia.ntemp[p] = countfields(lp, ' '); /* Number of temps. */ transitprint(10, verblevel, " Number of temperature samples: %ld\n", nt); if(!nt) transiterror(TERR_SERIOUS, "Wrong line %i in CIA file '%s', if it " "begins with a 't' then it should have the " "blank-separated fields with the temperatures. Rest " "of line: %s.\n", lines, file, lp); /* Allocate and store the temperatures array: */ st_cia.temp[p] = (PREC_CIA *)calloc(nt, sizeof(PREC_CIA)); n = 0; /* Count temperatures per line */ lpa = lp; /* Pointer in line */ transitprint(20, verblevel, " Temperatures (K) = ["); while(n < nt){ while(isblank(*lpa++)); st_cia.temp[p][n] = strtod(--lpa, &lp); /* Get value */ transitprint(20, verblevel, "%d, ", (int)st_cia.temp[p][n]); if(lp==lpa) transiterror(TERR_CRITICAL, "Less fields (%i) than expected (%i) " "were read for temperature in the CIA file '%s'.\n", n, nt, file); if((lp[0]|0x20) == 'k') lp++; /* Remove trailing K if exists */ lpa = lp; n++; } transitprint(20, verblevel, "\b\b]\n"); continue; default: break; } break; } /* Set an initial value for allocated wavenumber fields: */ wa = 32; /* Allocate wavenumber array: */ wn = (PREC_CIA *)calloc(wa, sizeof(PREC_CIA)); /* Allocate input extinction array (in cm-1 amagat-2): */ a = (PREC_CIA **)calloc(wa, sizeof(PREC_CIA *)); a[0] = (PREC_CIA *)calloc(wa*nt, sizeof(PREC_CIA)); for(i=1; i<wa; i++) a[i] = a[0] + i*nt; n=0; /* Read information for each wavenumber sample: */ while(1){ /* Skip comments and blanks; read next line: */ if (n) while((rc=fgetupto_err(lp=line, maxline, fp, &ciaerr, file, lines++)) =='#'||rc=='\n'); /* Stop, if it is end of file: */ if(!rc) break; /* Re-allocate (double the size) if necessary: */ if(n==wa){ wn = (PREC_CIA *)realloc(wn, (wa<<=1) * sizeof(PREC_CIA)); a = (PREC_CIA **)realloc(a, wa * sizeof(PREC_CIA *)); a[0] = (PREC_CIA *)realloc(a[0], wa * nt * sizeof(PREC_CIA)); for(i=1; i<wa; i++) a[i] = a[0] + i*nt; } /* Store new line: wavenumber first, then loop over cross sections: */ while(isblank(*lp++)); wn[n] = strtod(lp-1, &lpa); /* Store wavenumber */ if(lp==lpa+1) transiterror(TERR_CRITICAL, "Invalid fields for the %ith wavenumber " "in the CIA file '%s'.\n", n+1, file); i = 0; while(i<nt){ a[n][i] = strtod(lpa, &lp); /* Store cross section */ if(lp==lpa) transiterror(TERR_CRITICAL, "Less fields (%i) than expected (%i) " "were read for the %ith wavenumber in the CIA " "file '%s'.\n", i, nt, n+1, file); lpa = lp; i++; } n++; } /* Re-allocate arrays to their final sizes: */ if(n<wa){ st_cia.wn[p] = (PREC_CIA *)realloc(wn, n* sizeof(PREC_CIA)); a = (PREC_CIA **)realloc(a, n* sizeof(PREC_CIA *)); a[0] = (PREC_CIA *)realloc(a[0], n*nt*sizeof(PREC_CIA)); for(i=1; i<n; i++) a[i] = a[0] + i*nt; } transitprint(10, verblevel, " Number of wavenumber samples: %d\n", n); transitprint(20, verblevel, " Wavenumber array (cm-1) = [%.1f, %.1f, " "%.1f, ..., %.1f, %.1f, %.1f]\n", st_cia.wn[p][0], st_cia.wn[p][1], st_cia.wn[p][2], st_cia.wn[p][n-3], st_cia.wn[p][n-2], st_cia.wn[p][n-1]); st_cia.cia[p] = a; st_cia.nwave[p] = n; fclose(fp); } /* FINDME: The program breaks when I free colname, it makes no sense */ free(colname); transitprint(1, verblevel, "Done.\n"); tr->pi |= TRPI_CIA; return 0; }
/* \fcnfh Obtains the quantity that is observable, but before being convolved to telescope resolution @returns 0 on success -1 if impact parameter sampling is not equispaced */ int modulation(struct transit *tr) /* Main structure */ { static struct outputray st_out; tr->ds.out=&st_out; transitcheckcalled(tr->pi,"modulation",3, "tau",TRPI_TAU, "makeipsample",TRPI_MAKEIP, "makewnsample",TRPI_MAKEWN ); //initial variables and check that impact parameters was a monospaced //array. Stop otherwise. long w; prop_samp *ip=&tr->ips; prop_samp *wn=&tr->wns; transit_ray_solution *sol=tr->sol; if(ip->d==0&&sol->monoip) { transiterror(TERR_SERIOUS|TERR_ALLOWCONT, "To compute %s modulation, the impact parameter has to\n" "be an equispaced array\n" ,sol->name); return -1; } //output and geometry variables. PREC_RES *out=st_out.o=(PREC_RES *)calloc(wn->n,sizeof(PREC_RES)); struct geometry *sg=tr->ds.sg; struct optdepth *tau=tr->ds.tau; //set time to the user hinted default, and other user hints setgeom(sg,HUGE_VAL,&tr->pi); const int modlevel=tr->modlevel=tr->ds.th->modlevel; //integrate for each wavelength transitprint(1,verblevel, "\nIntegrating for each wavelength...\n"); int nextw=wn->n/10; for(w=0; w<wn->n; w++) { out[w]=sol->obsperwn(tau->t[w],tau->last[w],tau->toomuch, ip,sg,modlevel); if(out[w]<0) { switch(-(int)out[w]) { case 1: if(modlevel==-1) transiterror(TERR_SERIOUS, "Optical depth didn't reach limiting %g at wavenumber %g[cm-1]\n" " (Only reached %g)." " Cannot use critical radius technique (-1)\n" ,tau->toomuch,tau->t[w][tau->last[w]],wn->v[w]*wn->fct); default: transiterror(TERR_SERIOUS, "There was a problem while calculating modulation\n" " at wavenumber %g[cm-1]. Error code %i\n" ,wn->v[w]*wn->fct,(int)out[w]); break; } exit(EXIT_FAILURE); } if(w==nextw) { nextw+=wn->n/10; transitprint(2,verblevel, "%i%%\r" ,(10*(int)(10*w/wn->n+0.9999999999))); } } transitprint(1,verblevel," done\n"); //frees no longer needed memory. freemem_idexrefrac(tr->ds.ir,&tr->pi); freemem_extinction(tr->ds.ex,&tr->pi); freemem_tau(tr->ds.tau,&tr->pi); //set progress indicator, and print output tr->pi&=TRPI_MODULATION; printmod(tr); return 0; }
/* \fcnfh Read radius, pressure, temperature, and abundances and store it into at_data of transit. Calculate mean molecular mass and densities. Detailed: Read and store radius, pressure, and temperature from file. Read abundances for each (non other-factor) isotope. Sum fractional abundances. Calculate ramaining (other-factor) abundances. Calculate mean molecular mass per radius. Calculate densities per isotope at each radius. Returns: number of sample radius */ int readatmfile(FILE *fp, /* Atmospheric file */ struct transit *tr, /* transit struct */ struct atm_data *at, /* Atmosphere struct */ prop_samp *rads, /* Radius sampling */ int nrad, /* Size of allocated radius array */ PREC_ZREC *f_remainder){ /* Remainder molecules' factor */ transitprint(1, verblevel, "Start reading abundances.\n"); /* Find abundance related quantities for each radius */ int lines = at->begline; PREC_NREC r = 0; /* Radius index (number of radii being read) */ char rc; /* File reading output */ float allowq = 1 - tr->allowrq; int nabundances; /* Number of abundances in list */ double sumq; /* Sum of abundances per line */ char line[maxline], *lp, *lp2; prop_mol *molec = at->molec; struct molecules *mol = tr->ds.mol; int i, j; /* Auxiliary for-loop indices */ /* Variables to be used by factor (except ieq which is general): */ /* Count the number of abundances in each line: */ fseek(fp, at->begpos, SEEK_SET); /* Go to position where data begins */ /* Skip comments: */ while((rc=fgetupto_err(lp=line, maxline, fp, &atmerr, atmfilename, lines++)) =='#' || rc=='\n'); /* Count values per line: */ nabundances = countfields(lp, ' ') - 3; /* Subtract rad, p, and T columns */ fseek(fp, at->begpos, SEEK_SET); /* Go to position where data begins */ while(1){ /* Reallocate if necessary: */ if(r==nrad){ nrad <<= 1; rads->v = (PREC_ATM *)realloc(rads->v, nrad*sizeof(PREC_ATM)); at->atm.t = (PREC_ATM *)realloc(at->atm.t, nrad*sizeof(PREC_ATM)); at->atm.p = (PREC_ATM *)realloc(at->atm.p, nrad*sizeof(PREC_ATM)); at->mm = (double *)realloc(at->mm, nrad*sizeof(double)); for(i=0; i<at->n_aiso; i++){ molec[i].d = (PREC_ATM *)realloc(molec[i].d, nrad*sizeof(PREC_ATM)); molec[i].q = (PREC_ATM *)realloc(molec[i].q, nrad*sizeof(PREC_ATM)); molec[i].n = nrad; } } /* Skip comments and read next line: */ while((rc=fgetupto_err(lp=line, maxline, fp, &atmerr, atmfilename, lines++)) =='#' || rc=='\n'); /* If it is end of file, stop loop: */ if(!rc) break; /* Read and store radius, pressure, and temperature from file: */ rads->v[r] = strtod(lp, &lp2) + zerorad; /* Radius */ checkposvalue(rads->v[r], 1, lines); /* Check value is positive */ if(lp==lp2) invalidfield(line, lines, 1, "radius"); at->atm.p[r] = strtod(lp2, &lp); /* Pressure */ checkposvalue(at->atm.p[r], 2, lines); if(lp==lp2) invalidfield(line, lines, 2, "pressure"); at->atm.t[r] = strtod(lp, &lp2); /* Temperature */ checkposvalue(at->atm.t[r], 3, lines); if(lp==lp2) invalidfield(line, lines, 3, "temperature"); /* Read abundances for each isotope. Keep reading-in values while there are numbers in line: */ for(i=0, sumq=0; i<nabundances; i++){ lp = lp2; /* Read the abundance of the isotope: */ molec[i].q[r] = strtod(lp, &lp2); if (r==0) transitprint(30, verblevel, "density[%d, %li]: %.9f.\n", i, r, molec[i].q[r]); sumq += molec[i].q[r]; /* Add the abundances */ checkposvalue(molec[i].q[r], i+4, lines); /* Check that tmp is positive */ if(lp==lp2) invalidfield(line, lines, 4+i, "isotope abundance"); } /* Remainder of the sum of abundances: */ /* Set abundance of remainder molecules: */ for(j=0; i < at->n_aiso; i++, j++) molec[i].q[r] = f_remainder[j]*(1-sumq); transitASSERT(i!=at->n_aiso, "The line %s of file %s contains %d abundance " "values, when there were %d expected.\n", __LINE__, __FILE__, i, at->n_aiso); /* Calculate mean molecular mass and check whether abundances add up to one (within roundoff error): */ sumq = checkaddmm(at->mm+r, r, molec, mol, at->n_aiso, at->mass); if((int)(sumq*ROUNDOFF+0.5)<(int)(allowq*ROUNDOFF+0.5)) transiterror(TERR_WARNING, "In radius %g (%i: %g in file), abundances " "don't add up to 1: %.9g\n", at->rads.v[r], r, at->rads.v[r]-zerorad, sumq); /* Calculate densities using ideal gas law: */ if (r>=0){ transitprint(30, verblevel, "Abund: %.9f, mmm: %.3f, mass: %.3f, " "p: %.3f, T: %.3f.\n", molec[2].q[r], at->mm[r], mol->mass[2], at->atm.p[r]*at->atm.pfct, at->atm.t[r]*at->atm.tfct); } for(i=0; i<at->n_aiso; i++) molec[i].d[r] = stateeqnford(at->mass, molec[i].q[r], at->mm[r], mol->mass[i], at->atm.p[r]*at->atm.pfct, at->atm.t[r]*at->atm.tfct); transitprint(30, verblevel, "dens[%2li]: %.14f, ", r, molec[2].d[r]); r++; } /* Re-allocate arrays to final size (nrad): */ rads->n = nrad = r; rads->v = (PREC_ATM *)realloc(rads->v, nrad*sizeof(PREC_ATM)); at->atm.t = (PREC_ATM *)realloc(at->atm.t, nrad*sizeof(PREC_ATM)); at->atm.p = (PREC_ATM *)realloc(at->atm.p, nrad*sizeof(PREC_ATM)); at->mm = (double *)realloc(at->mm, nrad*sizeof(double)); for(i=0; i<at->n_aiso; i++){ molec[i].d = (PREC_ATM *)realloc(molec[i].d, nrad*sizeof(PREC_ATM)); molec[i].q = (PREC_ATM *)realloc(molec[i].q, nrad*sizeof(PREC_ATM)); molec[i].n = nrad; } /* Free arrays that were used only to get the factorizing elements: */ free(fonly); nfonly = 0; return nrad; }