/* \fcnfh Set geometry variables @returns 0 on success */ int setgeom(struct geometry *sg, /* geometry structure */ double time, /* time for which to set planet position, use HUGE_VAL for use the default value stored in the geometry structure */ long *flags) /* Progress indicator flag */ { transitcheckcalled(*flags,"setgeom",1, "setgeomhint",TRPI_GEOMETRYHINT ); /* TD: include argument of pericenter and longitud of the node in the computations, right now both values are used as zero. */ //Auxiliary variables in cgs double smaxis=sg->smaxis*sg->smaxisfct; double ecc=sg->ecc*sg->eccfct; double incl=sg->incl*sg->inclfct; // double aper=sg->aper*sg->aperfct; // double lnode=sg->lnode*sg->lnodefct; double t=(time<HUGE_VAL?time:sg->time)*sg->timefct; double mass=sg->starmass*sg->starmassfct; //set mean angular velocity, mean true anomaly, and others variables double prec2=1e-12; double n=sqrt(GGRAV*mass/smaxis/smaxis/smaxis); double Ea=HUGE_VAL,E=n*time; while((E-Ea)*(E-Ea)>prec2){ Ea=E; E=n*t+ecc*sin(E); } double M=smaxis*(1-ecc*ecc); double Delta=smaxis*(1-ecc*cos(E)); double cosv=(M-Delta)/ecc/Delta; double sini=sin(incl); double cosi=cos(incl); //set X and Y. sg->x=Delta*sqrt(cosi*cosi-cosv*cosv); sg->y=Delta*sini; //set progress indicator and return. *flags|=TRPI_GEOMETRY; return 0; }
/* \fcnfh Set X and Y geometry variables Return: 0 on success */ int setgeom(struct geometry *sg, /* geometry structure */ double time, /* Time for which to set planet position. If HUGE_VAL, use the default geometry value */ long *flags){ /* Progress indicator flag */ transitcheckcalled(*flags, "setgeom", 1, "setgeomhint", TRPI_GEOMETRYHINT); /* TBD: include argument of pericenter and longitud of the node in the computations, right now both values are used as zero. */ /* Auxiliary variables in cgs */ double smaxis = sg->smaxis*sg->smaxisfct; /* semi-major axis */ double ecc = sg->ecc*sg->eccfct; /* eccentricity */ double incl = sg->incl*sg->inclfct; /* inclination */ // double aper = sg->aper*sg->aperfct; // double lnode = sg->lnode*sg->lnodefct; double t = (time<HUGE_VAL ? time:sg->time)*sg->timefct; /* observation time */ double mass = sg->starmass*sg->starmassfct; /* Stellar mass */ double prec2 = 1e-12; /* Square eccentric anomaly precision limit */ double n = sqrt(GGRAV*mass/(smaxis*smaxis*smaxis)); /* Mean motion */ double Ea = HUGE_VAL, /* Approximation to eccentric anomaly */ E = n*time; /* Eccentric anomaly */ /* Solve Kepler equation to get the eccentric anomaly at time t: */ while((E-Ea)*(E-Ea) > prec2){ Ea = E; E = n*t + ecc*sin(E); } double M = smaxis*(1-ecc*ecc); double Delta = smaxis*(1-ecc*cos(E)); double cosv = (M-Delta)/(ecc*Delta); /* a * cosine of true anomaly */ double sini = sin(incl); double cosi = cos(incl); /* Set X and Y: */ sg->x = Delta*sqrt(cosi*cosi-cosv*cosv); sg->y = Delta*sini; /* Set progress indicator and return: */ *flags |= TRPI_GEOMETRY; return 0; }
/* FUNCTION: Calculate the opacity due to molecular transitions. Return: 0 on success */ int opacity(struct transit *tr){ struct transithint *th = tr->ds.th; /* transithint struct */ static struct opacity op; /* The opacity struct */ /* Set the opacity struct's mem to 0: */ memset(&op, 0, sizeof(struct opacity)); tr->ds.op = &op; /* Check that the radius array has been sampled: */ transitcheckcalled(tr->pi, "opacity", 1, "makeradsample", TRPI_MAKERAD); /* Check if the opacity file exists: */ int file_exists = fileexistopen(th->f_opa, NULL); tr_output(TOUT_INFO, "Opacity-file exist status = %d\n", file_exists); /* Set the file name in the transit struct: */ tr->f_opa = th->f_opa; /* Opacity file has some error that makes it unusable, or not specified: */ if (file_exists < -1 || file_exists == 0) { /* Calculate Voigt profiles: */ tr_output(TOUT_INFO, "Calculating grid of Voigt profiles.\n"); calcprofiles(tr); /* Set progress indicator and return success: */ tr->pi |= TRPI_OPACITY; return 0; } /* Opacity file specified, but it just doesn't exist yet: */ if (file_exists == -1) { /* Open file for writing: */ tr->fp_opa = fopen(tr->f_opa, "wb"); /* Immediately return if the file could not be opened: */ if (tr->fp_opa == NULL){ tr_output(TOUT_WARN, "Opacity filename '%s' cannot be opened " "for writing.\n", tr->f_opa); return -1; } /* Calculate Voigt profiles: */ tr_output(TOUT_INFO, "Calculating grid of Voigt profiles.\n"); calcprofiles(tr); /* Calculate the grid of opacities: */ tr_output(TOUT_INFO, "Calculating new grid of opacities: '%s'.\n", tr->f_opa); calcopacity(tr, tr->fp_opa); /* Free the line-transition memory: */ freemem_linetransition(&tr->ds.li->lt, &tr->pi); tr->pi |= TRPI_READDATA; tr->pi |= TRPI_READINFO; /* Set progress indicator and return success: */ tr->pi |= TRPI_OPACITY; return 0; } /* Implied: The opacity file exists: */ file_exists = fileexistopen(th->f_opa, &tr->fp_opa); tr->f_opa = th->f_opa; tr_output(TOUT_INFO, "Opacity-file exist status = %d\n", file_exists); if (file_exists != 1) { tr_output(TOUT_WARN, "Opening opacity file failed.\n"); /* Calculate Voigt profiles: */ tr_output(TOUT_INFO, "Calculating grid of Voigt profiles.\n"); calcprofiles(tr); /* Set progress indicator and return success: */ tr->pi |= TRPI_OPACITY; return 0; } /* Should attempt to use shared memory: */ if (tr->opashare) { /* Get ID or create shared opacityhint struct: */ key_t hintkey = ftok(tr->f_opa, 'a'); op.hintID = shmget(hintkey, sizeof(struct opacityhint), 0644 | IPC_CREAT); /* If reserving the hint segment was unsuccessful, give up: */ if (op.hintID == -1) { tr_output(TOUT_WARN, "Could not get hint shared memory ID.\n"); /* Read the grid of opacities from file: */ tr_output(TOUT_INFO, "Reading opacity file: '%s'.\n", tr->f_opa); readopacity(tr, tr->fp_opa); /* Set progress indicator and return success: */ tr->pi |= TRPI_OPACITY; return 0; } /* Attach to the hint shared memory segment: */ op.hint = shmat(op.hintID, (void *) 0, 0); /* If attaching was unsuccessful, give up. */ if (op.hint == (struct opacityhint *) -1) { tr_output(TOUT_WARN, "Could not attach to hint shared memory.\n"); /* Read the grid of opacities from file: */ tr_output(TOUT_INFO, "Reading opacity file: '%s'.\n", tr->f_opa); readopacity(tr, tr->fp_opa); /* Set progress indicator and return success: */ tr->pi |= TRPI_OPACITY; return 0; } /* If no process has claimed to be the master, claim it: */ if (op.hint->master_PID == 0) op.hint->master_PID = getpid(); /* Wait a few cycles in case multiple processes claimed it at once: */ int i; for (i = 0; i < 10; i++); /* Check again to see if this process claimed the memory: */ if (op.hint->master_PID == getpid()) { /* Share the grid of opacities from file: */ tr_output(TOUT_INFO, "Sharing opacity file: '%s'.\n", tr->f_opa); if (shareopacity(tr, tr->fp_opa) || mountopacity(tr)) { tr_output(TOUT_WARN, "Shared memory sh/mt error. Aborting.\n"); op.hint->status |= TSHM_ERROR; /* Read the grid of opacities from file: */ tr_output(TOUT_INFO, "Reading opacity file: '%s'.\n", tr->f_opa); readopacity(tr, tr->fp_opa); } /* Assuming that all processes have attached to the two shared memory segments, mark them for destruction as soon as all of the processes have detached. */ struct shmid_ds buf1, buf2; shmctl(op.hintID, IPC_STAT, &buf1); do { shmctl(op.mainID, IPC_STAT, &buf2); } while (buf2.shm_nattch != buf1.shm_nattch); tr_output(TOUT_DEBUG, "Marking shared memory for removal.\n"); shmctl(op.hintID, IPC_RMID, &buf1); shmctl(op.mainID, IPC_RMID, &buf2); /* Set progress indicator and return success: */ tr->pi |= TRPI_OPACITY; return 0; } else { while ((op.hint->status & TSHM_WRITTEN) == 0) { /* If there's an error with the shared memory, abort. */ if (op.hint->status & TSHM_ERROR) { tr_output(TOUT_WARN, "Shared memory error. Aborting.\n"); /* Read the grid of opacities from file: */ tr_output(TOUT_INFO, "Reading opacity file: '%s'.\n", tr->f_opa); readopacity(tr, tr->fp_opa); /* Set progress indicator and return success: */ tr->pi |= TRPI_OPACITY; return 0; } } } /* If there's an error attaching or mounting the memory, abort. */ if (attachopacity(tr) || mountopacity(tr)) { tr_output(TOUT_WARN, "Shared memory att/mt error. Aborting.\n"); /* Read the grid of opacities from file: */ tr_output(TOUT_INFO, "Reading opacity file: '%s'.\n", tr->f_opa); readopacity(tr, tr->fp_opa); } } /* Should not attempt to use shared memory: */ else { /* Read the grid of opacities from file: */ tr_output(TOUT_INFO, "Reading opacity file: '%s'.\n", tr->f_opa); readopacity(tr, tr->fp_opa); } /* Set progress indicator and return success: */ tr->pi |= TRPI_OPACITY; 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 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 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; }
/* FUNCTION: Fill up the extinction information in tr->ds.ex TD: Scattering parameters should be added at some point here. Return: 0 on success, else computeextradius() */ int extwn(struct transit *tr){ struct transithint *th=tr->ds.th; static struct extinction st_ex; tr->ds.ex = &st_ex; struct extinction *ex = &st_ex; int i; /* Check these routines have been called: */ transitcheckcalled(tr->pi, "extwn", 4, "readinfo_tli", TRPI_READINFO, "readdatarng", TRPI_READDATA, "makewnsample", TRPI_MAKEWN, "makeradsample", TRPI_MAKERAD); transitacceptflag(tr->fl, tr->ds.th->fl, TRU_EXTBITS); struct isotopes *iso = tr->ds.iso; int niso = iso->n_i; int nrad = tr->rads.n; int nwn = tr->wns.n; /* Check there is at least one atmospheric layer: */ /* FINDME: Move to readatm */ if(tr->rads.n < 1){ tr_output(TOUT_ERROR, "There are no atmospheric parameters specified. I need at " "least one atmospheric point to calculate a spectra.\n"); return -2; } /* Check there are at least two wavenumber sample points: */ /* FINDME: Move to makewnsample */ if(tr->wns.n < 2){ tr_output(TOUT_ERROR, "I need at least 2 wavenumber points to compute anything; " "I need resolution.\n"); return -3; } /* Check there is at least one isotope linelist */ /* FINDME: This should not be a condition, we may want to calculate an atmosphere with only CIA for example. */ if(niso < 1){ tr_output(TOUT_WARN, "You are requiring a spectra of zero isotopes.\n"); } /* Get the extinction coefficient threshold: */ ex->ethresh = th->ethresh; /* Declare extinction-coefficient array: */ ex->e = (PREC_RES **)calloc(nrad, sizeof(PREC_RES *)); if((ex->e[0] = (PREC_RES *)calloc(nrad*nwn, sizeof(PREC_RES)))==NULL) { tr_output(TOUT_ERROR, "Unable to allocate %li = %li*%li " "for the extinction coefficient.\n", nrad*nwn, nrad, nwn); exit(EXIT_FAILURE); } for(i=1; i<nrad; i++){ ex->e[i] = ex->e[0] + i*nwn; } /* Has the extinction been computed at given radius boolean: */ ex->computed = (_Bool *)calloc(nrad, sizeof(_Bool)); /* Set progress indicator, and print and output extinction if one P,T was desired, otherwise return success: */ tr->pi |= TRPI_EXTWN; return 0; }