/* \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);
}
Beispiel #2
0
/* 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;
}
Beispiel #3
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;
}
Beispiel #4
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;
}