Example #1
0
/* \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;
}
Example #2
0
/* \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;
}
Example #3
0
/* \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;
}
Example #4
0
/* \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);
}
Example #5
0
/* \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__);
}
Example #6
0
/* \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);
}
Example #7
0
/* \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++;
}
Example #8
0
/* \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);
}
Example #9
0
/* \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;
  }
}
Example #10
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;
  }
}
Example #11
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);
}
Example #12
0
/* \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;
}
Example #13
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. 
 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);
}
Example #14
0
/* 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);
}
Example #15
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;
}
Example #16
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;
}
Example #17
0
/* \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;
}
Example #18
0
/* \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;
}
Example #19
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;
}
/* \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;
}
Example #21
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;
}