/* \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); }
/* DEF */ static PREC_RES eclipsetau(struct transit *tr, PREC_RES height, /* Altitude down to where calculate tau */ PREC_RES *ex){ /* Extinction per layer [rad] */ /* Incident angle: */ //PREC_RES angle = tr->angles[tr->angleIndex]; //PREC_RES angle_rad = angle * DEGREES; /* Layers radius array: */ prop_samp *rads = &tr->rads; /* Radius sampling */ PREC_RES *rad = rads->v; /* Radius array */ /* Get the index rs, of the sampled radius immediately below or equal to height (i.e. rad[rs] <= height < rad[rs+1]): */ int rs = binsearchapprox(rad, height, 0, tr->rads.n-1); /* Returns 0 if this is the top layer (no distance travelled): */ if (rs == tr->rads.n-1) return 0.0; /* Move pointers to the location of height: */ rad += rs; ex += rs; /* Number of layers beween height and the top layer: */ int nrad = tr->rads.n - rs; PREC_RES res; /* Optical depth divided by units of radius */ PREC_RES x3[3], r3[3]; /* Interpolation variables */ /* Conversion to radian: */ //PREC_RES angle_rad = angle * DEGREES; /* Distance along the path: */ PREC_RES s[nrad]; /* Providing three necessary points for spline integration: */ const PREC_RES tmpex = *ex; const PREC_RES tmprad = *rad; if(nrad==2) *ex = interp_parab(rad-1, ex-1, rad[0]); else *ex = interp_parab(rad, ex, rad[0]); 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++; } /* Distance along the path: */ s[0] = 0.0; for(int i=1; i < nrad; i++){ s[i] = s[i-1] + (rad[i] - rad[i-1]); // /cos(angle_rad); } /* Integrate extinction along the path: */ /* 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 */ /* Safety mode: GSL is acting up sometimes */ res = integ_trapz(s, ex, nrad); /* Optical depth divided by units of radius: */ return res; }