/* \fcnfh Set hard coded values */ void sethcdef(struct transit *tr, struct atm_data *at, prop_samp *rads) { //Hard coded values. //'hc\_t' temperature. //'hc\_meanmass' is both the mean mass and the mass of the only //isotope. //'hc\_abund' is the abundance of the first isotope, the rest are //just set at zero in the hardcode modality. PREC_ZREC hc_t=1350; PREC_ATM hc_pres=1.0e3; PREC_ATM hc_abund=6.5e-4; PREC_ATM hc_meanmass=2.3; int nrad=rads->n; rads->v=(PREC_ATM *)calloc(nrad,sizeof(PREC_ATM)); at->atm.tfct=1; at->atm.pfct=1; at->atm.t= (PREC_ATM *)calloc(nrad,sizeof(PREC_ATM)); at->atm.p= (PREC_ATM *)calloc(nrad,sizeof(PREC_ATM)); at->mm= (PREC_ATM *)calloc(nrad,sizeof(PREC_ATM)); rads->v[0]=1.0; at->n_niso=0; struct isotopes *iso=tr->ds.iso; int nmb=iso->n_e=iso->n_i+at->n_niso; at->isov=(prop_isov *)calloc(nmb,sizeof(prop_isov)); at->atm.t[0]=hc_t; at->atm.p[0]=hc_pres; at->mm[0]=hc_meanmass; for(int i=0; i<nmb; i++) { at->isov[i].d=(PREC_ATM *)calloc(1,sizeof(PREC_ATM)); at->isov[i].d[0]=stateeqnford(at->mass,hc_abund,hc_meanmass, hc_meanmass,hc_pres,hc_t); hc_abund=0; } telldefaults(iso,at); }
/* FUNCTION: Calculate opacities for the grid of wavenumber, radius, and temperature arrays for each molecule. */ int calcopacity(struct transit *tr, FILE *fp){ struct opacity *op=tr->ds.op; /* Opacity struct */ struct isotopes *iso=tr->ds.iso; /* Isotopes struct */ struct molecules *mol=tr->ds.mol; /* Molecules struct */ struct lineinfo *li=tr->ds.li; /* Lineinfo struct */ long Nmol, Ntemp, Nlayer, Nwave; /* Opacity-grid dimension sizes */ int i, j, t, r, /* for-loop indices */ rn, iso1db; double *z; int k; PREC_ATM *density = (PREC_ATM *)calloc(mol->nmol, sizeof(PREC_ATM)); double *Z = (double *)calloc(iso->n_i, sizeof(double)); /* Make temperature array from hinted values: */ maketempsample(tr); Ntemp = op->Ntemp = tr->temp.n; op->temp = (PREC_RES *)calloc(Ntemp, sizeof(PREC_RES)); for (i=0; i<Ntemp; i++) op->temp[i] = tr->temp.v[i]; /* Temperature boundaries check: */ if (op->temp[0] < li->tmin) { tr_output(TOUT_ERROR, "The opacity file attempted to sample a " "temperature (%.1f K) below the lowest allowed " "TLI temperature (%.1f K).\n", op->temp[0], li->tmin); exit(EXIT_FAILURE); } if (op->temp[Ntemp-1] > li->tmax) { tr_output(TOUT_ERROR, "The opacity file attempted to sample a " "temperature (%.1f K) beyond the highest allowed " "TLI temperature (%.1f K).\n", op->temp[Ntemp-1], li->tmax); exit(EXIT_FAILURE); } tr_output(TOUT_RESULT, "There are %li temperature samples.\n", Ntemp); /* Evaluate the partition at these temperatures: */ op->ziso = (PREC_ATM **)calloc(iso->n_i, sizeof(PREC_ATM *)); op->ziso[0] = (PREC_ATM *)calloc(iso->n_i*Ntemp, sizeof(PREC_ATM)); for(i=1; i<iso->n_i; i++) op->ziso[i] = op->ziso[0] + i*Ntemp; /* Interpolate the partition function: */ for(i=0; i<iso->n_db; i++){ /* For each database separately: */ iso1db = iso->db[i].s; /* Index of first isotope in current DB */ for(j=0; j < iso->db[i].i; j++){ transitASSERT(iso1db + j > iso->n_i-1, "Trying to reference an isotope " "(%i) outside the extended limit (%i).\n", iso1db+j, iso->n_i-1); z = calloc(li->db[i].t, sizeof(double)); spline_init(z, li->db[i].T, li->isov[iso1db+j].z, li->db[i].t); for(k=0;k<Ntemp;k++) op->ziso[iso1db+j][k] = splinterp_pt(z, li->db[i].t, li->db[i].T, li->isov[iso1db+j].z, op->temp[k]); free(z); } } /* Get pressure array from transit (save in CGS units): */ Nlayer = op->Nlayer = tr->rads.n; op->press = (PREC_RES *)calloc(Nlayer, sizeof(PREC_RES)); for (i=0; i<Nlayer; i++) op->press[i] = tr->atm.p[i]*tr->atm.pfct; tr_output(TOUT_RESULT, "There are %li radius samples.\n", Nlayer); /* Make molecules array from transit: */ Nmol = op->Nmol = tr->ds.iso->nmol; op->molID = (int *)calloc(Nmol, sizeof(int)); tr_output(TOUT_RESULT, "There are %li molecules with line " "transitions.\n", Nmol); for (i=0, j=0; i<iso->n_i; i++){ /* If this molecule is not yet in molID array, add it's universal ID: */ if (valueinarray(op->molID, mol->ID[iso->imol[i]], j) < 0){ op->molID[j++] = mol->ID[iso->imol[i]]; tr_output(TOUT_DEBUG, "Isotope's (%d) molecule ID: %d (%s) " "added at position %d.\n", i, op->molID[j-1], mol->name[iso->imol[i]], j-1); } } /* Get wavenumber array from transit: */ Nwave = op->Nwave = tr->wns.n; op->wns = (PREC_RES *)calloc(Nwave, sizeof(PREC_RES)); for (i=0; i<Nwave; i++) op->wns[i] = tr->wns.v[i]; tr_output(TOUT_RESULT, "There are %li wavenumber samples.\n", Nwave); /* Allocate opacity array: */ if (fp != NULL){ op->o = (PREC_RES ****) calloc(Nlayer, sizeof(PREC_RES ***)); for (r=0; r<Nlayer; r++){ op->o[r] = (PREC_RES ***) calloc(Ntemp, sizeof(PREC_RES **)); for (t=0; t<Ntemp; t++){ op->o[r][t] = (PREC_RES **) calloc(Nmol, sizeof(PREC_RES *)); for (i=0; i<Nmol; i++){ op->o[r][t][i] = (PREC_RES *)calloc(Nwave, sizeof(PREC_RES)); } } } if (!op->o[0][0][0]) tr_output(TOUT_ERROR, "Allocation fail.\n"); /* Compute extinction: */ for (r=0; r<Nlayer; r++){ /* For each layer: */ tr_output(TOUT_DEBUG, "\nOpacity Grid at layer %03d/%03ld.\n", r+1, Nlayer); for (t=0; t<Ntemp; t++){ /* For each temperature: */ /* Get density and partition-function arrays: */ for (j=0; j < mol->nmol; j++) density[j] = stateeqnford(tr->ds.at->mass, mol->molec[j].q[r], tr->atm.mm[r], mol->mass[j], op->press[r], op->temp[t]); for (j=0; j < iso->n_i; j++) Z[j] = op->ziso[j][t]; if((rn=computemolext(tr, op->o[r][t], op->temp[t], density, Z, 1)) != 0) { tr_output(TOUT_ERROR, "extinction() returned error code %i.\n", rn); exit(EXIT_FAILURE); } } } /* Save dimension sizes: */ fwrite(&Nmol, sizeof(long), 1, fp); fwrite(&Ntemp, sizeof(long), 1, fp); fwrite(&Nlayer, sizeof(long), 1, fp); fwrite(&Nwave, sizeof(long), 1, fp); /* Save arrays: */ fwrite(&op->molID[0], sizeof(int), Nmol, fp); fwrite(&op->temp[0], sizeof(PREC_RES), Ntemp, fp); fwrite(&op->press[0], sizeof(PREC_RES), Nlayer, fp); fwrite(&op->wns[0], sizeof(PREC_RES), Nwave, fp); /* Save opacity: */ for (r=0; r<Nlayer; r++) for (t=0; t<Ntemp; t++) for (i=0; i<Nmol; i++) fwrite(op->o[r][t][i], sizeof(PREC_RES), Nwave, fp); fclose(fp); } tr_output(TOUT_RESULT, "Done.\n"); 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 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; }