22 #define SORMAXITERS 1000
26 static real kappa0[7] = {2.0e-4, 2.0e16, 0.1, 2.0e81, 1.0e-8, 1.0e-36, 1.5e20};
27 static real a[7] = {0.0, 0.0, 0.0, 1.0, 2.0/3.0, 1.0/3.0, 1.0};
28 static real b[7] = {2.0, -7.0, 0.5, -24.0, 3.0, 10.0, -5.0/2.0};
80 real *rho, *opacity, *qminus, *temper;
86 opacity = Opacity->
Field;
89 #pragma omp parallel for default(none) shared(nr,ns,opacity,rho,temper,qminus,OPACITYDROP) \
90 private(i,j,l,tau,taueff)
91 for (i=0; i<nr; i++) {
92 for (j=0; j<ns; j++) {
108 real *rho, *opacity, *qirr, *flaring;
109 real Teff4, Rstar2, tau, taueff, Tirr4, r2inv;
110 static real Tirr4fac=0.0;
114 Teff4 = pow(Teff4, 4.0);
115 Rstar2 = 6.957e8/
AU_SI;
122 opacity = Opacity->
Field;
123 qirr = Qirradiation->
Field;
124 flaring = Flaring->
Field;
125 #pragma omp parallel for default(none) \
126 shared(nr,ns,rho,opacity,Rmed2,qirr,Tirr4fac,flaring,OPACITYDROP) \
127 private(i,j,l,tau,taueff,Tirr4,r2inv)
128 for (i=0; i<nr; i++) {
129 r2inv = 1.0/
Rmed2[i];
130 for (j=0; j<ns; j++) {
132 if (flaring[l] > 0.0) {
135 Tirr4 = Tirr4fac*r2inv*flaring[l];
149 int i,j,l,lim,lip,nr,ns;
150 real csin, csout, Hin, Hout, dHdr, H;
152 static real Rstar=0.0;
154 flaring = Flaring->
Field;
158 #pragma omp parallel for default(none) \
159 shared(nr,ns,cs,Rmed,Rinf,Rsup,InvDiffRsup,Rstar, \
160 flaring,SQRT_ADIABIND_INV,InvRmed,OmegaInv) \
161 private(i,j,l,lip,lim,csin,csout,Hin,Hout,dHdr,H)
162 for (i=1; i<nr-1; i++) {
163 for (j=0; j<ns; j++) {
167 csin = 0.5*(cs[l] + cs[lim]);
168 csout = 0.5*(cs[l] + cs[lip]);
173 flaring[l] = atan(dHdr) - atan((H-0.4*Rstar)*
InvRmed[i]);
174 if (flaring[l] >= 0.0) {
175 flaring[l] = sin(flaring[l]);
181 flaring[lim] = atan(dHdr) - atan((H-0.4*Rstar)/
Rmed[i-1]);
182 if (flaring[lim] >= 0.0) {
183 flaring[lim] = sin(flaring[lim]);
190 flaring[lip] = atan(dHdr) - atan((H-0.4*Rstar)/
Rmed[i+1]);
191 if (flaring[lip] >= 0.0) {
192 flaring[lip] = sin(flaring[lip]);
206 real *A, *B, *Ml, *Mlip, *Mlim, *Mljp, *Mljm, *RHS;
207 real *temper, *rho, *energynew, *cs, *Dr, *Dt;
208 real *qplus, *qminus, *divergence, *qirr;
209 int nr, ns, i, j, l, lip, ljp, Niter, k;
210 real dxtheta, invdxtheta2, H, afac, bfac;
211 static boolean first=
YES;
212 static int Niterlast;
218 energynew = EnergyNew->Field;
221 Dr = DiffCoefIfaceRad->
Field;
222 Dt = DiffCoefIfaceTheta->
Field;
223 A = DiscretizationCoefA->
Field;
224 B = DiscretizationCoefB->
Field;
225 Ml = MatrixNexttoTemperl->
Field;
226 Mlip = MatrixNexttoTemperlip->
Field;
227 Mlim = MatrixNexttoTemperlim->
Field;
228 Mljp = MatrixNexttoTemperljp->
Field;
229 Mljm = MatrixNexttoTemperljm->
Field;
230 RHS = RightHandSide->
Field;
234 qirr = Qirradiation->
Field;
256 #pragma omp parlallel default(none) \
257 shared(nr, ns, One_or_active, MaxMO_or_active, Rmed, Rinf, \
258 InvDiffRmed, InvDiffRsup, A, B, Dr, Dt, cs, dt, Ml, Mlip, \
259 Mlim, Mljp, Mljm, RHS, CV, divergence, qminus, temper, qplus, ADIABIND) \
260 private(i, j, l, lip, dxtheta, invdxtheta2, ljp, H, afac, bfac)
263 for (i=1; i<nr; i++) {
265 invdxtheta2 = 1.0/dxtheta/dxtheta;
266 for (j=0; j<ns; j++) {
270 B[l] = Dt[l]*invdxtheta2*2.0*H;
275 for (j=0; j<ns; j++) {
279 if (j == ns-1) ljp = i*ns;
281 bfac = dt/(rho[l]*
CV);
283 Ml[l] = 1.0 + divergence[l]*(
ADIABIND-1.0)*dt + 4.0*bfac*qminus[l] + afac*(A[lip] + A[l]) + bfac*(B[ljp] + B[l]);
284 Mlip[l] = - afac*A[lip];
285 Mlim[l] = - afac*A[l];
286 Mljp[l] = - bfac*B[ljp];
287 Mljm[l] = - bfac*B[l];
288 RHS[l] = temper[l] + bfac*(qplus[l] + 3.0*qminus[l]*temper[l]);
305 if (omega > 1.999999) {
318 for (j=0; j<ns; j++) {
319 temper[j] = temper[j+ns];
323 for (j=0; j<ns; j++) {
324 temper[j+(nr-1)*ns] = temper[j+(nr-2)*ns];
327 for (i=0; i<nr; i++) {
328 for (j=0; j<ns; j++) {
330 energynew[l] = rho[l]*temper[l]*
CV;
340 real omegamin=1.0, omegamax=1.999999, omega=1.0;
341 int nr, ns, n, i, j, l, nsplit=9, Niter =
SORMAXITERS, count=0;
342 real *temper, *tempbckp;
347 tempbckp = (
real *) malloc(
sizeof(
real) * (nr + 3) * (ns + 1) + 5);
348 for (i=0; i<nr; i++) {
349 for (j=0; j<ns; j++) {
351 tempbckp[l] = temper[l];
354 domega = (omegamax - omegamin)/nsplit;
358 for (n=0; n<=nsplit; n++) {
366 for (i=0; i<nr; i++) {
367 for (j=0; j<ns; j++) {
369 temper[l] = tempbckp[l];
374 masterprint (
"Warning! SOR did not converge when estimating the initial over-relaxation parameter.\n");
375 masterprint (
"Try using larger SORMAXITERS. Terminating now...\n");
378 if (count==nsplit+1) {
379 domega = omegamax-omegamin;
388 if (omegamin < 1.0) omegamin = 1.0;
389 if (omegamax > 1.999999) omegamax = 1.999999;
390 domega = (omegamax - omegamin)/nsplit;
400 int n, i, j, l, nr, ns, ipass, jchess;
401 int lip, lim, ljp, ljm;
402 real resid, normres0 = 0.0, normres, temp;
403 real *temper, *Ml, *Mlip, *Mlim, *Mljp, *Mljm, *RHS;
404 static boolean first=
YES;
409 Ml = MatrixNexttoTemperl->
Field;
410 Mlip = MatrixNexttoTemperlip->
Field;
411 Mlim = MatrixNexttoTemperlim->
Field;
412 Mljp = MatrixNexttoTemperljp->
Field;
413 Mljm = MatrixNexttoTemperljm->
Field;
414 RHS = RightHandSide->
Field;
425 for (j=0; j<ns; j++) {
430 if (j == ns-1) ljp = i*ns;
432 if (j == 0) ljm = i*ns + ns-1;
433 resid = temper[l]*Ml[l] + temper[lip]*Mlip[l] \
434 + temper[lim]*Mlim[l] + temper[ljp]*Mljp[l] \
435 + temper[ljm]*Mljm[l] - RHS[l];
436 normres0 += fabs(resid);
443 for (ipass = 1; ipass <= 2; ipass++) {
447 #pragma omp parallel for default(none) \
448 shared(One_or_active, MaxMO_or_active, ns, temper, Ml, Mlip, \
449 Mlim, Mljp, Mljm, RHS, omega) \
450 private(i, j, l, lip, lim, ljp, ljm, resid) \
451 firstprivate(jchess) reduction(+ : normres)
453 for (j=jchess; j<ns; j+=2) {
458 if (j == ns-1) ljp = i*ns;
460 if (j == 0) ljm = i*ns + ns-1;
461 resid = temper[l]*Ml[l] + temper[lip]*Mlip[l] \
462 + temper[lim]*Mlim[l] + temper[ljp]*Mljp[l] \
463 + temper[ljm]*Mljm[l] - RHS[l];
464 normres += fabs(resid);
465 temper[l] -= omega*resid/Ml[l];
473 if (normres <
SOREPS*normres0)
return n;
477 masterprint (
"The SOR solution of the radiative diffusion equation did not converge.\n");
488 int send[3], recv[3], prevcpu, nextcpu, nractive;
496 if (nractive % 2 == 0) {
514 if (nractive % 2 == 0) {
529 int nr, ns, i, j, l, lim, ljm;
530 real *voldens, *temper, *opacity, *D, *Dr, *Dt, *gradtmag;
531 real gradt, s, fluxlimiter, fac;
533 voldens = VolumeDensity->
Field;
537 opacity = Opacity->
Field;
538 gradtmag = GradTemperMagnitude->
Field;
539 D = DiffCoefCentered->
Field;
540 Dr = DiffCoefIfaceRad->
Field;
541 Dt = DiffCoefIfaceTheta->
Field;
543 #pragma omp parallel default(none) \
544 shared(nr,ns,voldens,opacity,temper,gradtmag,D,Dr,Dt) \
545 private(i,j,l,lim,ljm,gradt,s,fluxlimiter,fac)
548 for (i=0; i<nr; i++) {
549 for (j=0; j<ns; j++) {
552 gradt = gradtmag[l+ns];
553 }
else if (i==nr-1) {
554 gradt = gradtmag[l-ns];
558 fac = 1.0/(voldens[l]*opacity[l]);
559 s = 4.0*gradt*fac/temper[l];
565 for (i=1; i<nr; i++) {
566 for (j=0; j<ns; j++) {
570 if (j==0) ljm = i*ns+ns-1;
571 Dr[l] = 0.5*(D[l] + D[lim]);
572 Dt[l] = 0.5*(D[l] + D[ljm]);
582 int i, j, l, lim, ljm, lip, ljp, ns, nr;
583 real *temper, *gradtr, *gradtt, *gradtmag;
584 real dxtheta, invdxtheta, r, t;
587 gradtr = GradTemperRad->
Field;
588 gradtt = GradTemperTheta->
Field;
589 gradtmag = GradTemperMagnitude->
Field;
592 #pragma omp parallel default(none) \
593 shared(nr,ns,temper,InvDiffRmed,Rmed,gradtr,gradtt,gradtmag) \
594 private(i,j,l,lim,ljm,lip,ljp,dxtheta,invdxtheta,r,t)
597 for (i=1; i<nr; i++) {
599 invdxtheta = 1.0/dxtheta;
600 for (j=0; j<ns; j++) {
604 gradtr[l] = (temper[l] - temper[lim])*
InvDiffRmed[i];
606 if (j==0) ljm = i*ns+ns-1;
608 gradtt[l] = (temper[l] - temper[ljm])*invdxtheta;
612 for (i=1; i<nr-1; i++) {
613 for (j=0; j<ns; j++) {
617 if (j == ns-1) ljp = i*ns;
618 r = 0.5*(gradtr[lip]+gradtr[l]);
619 t = 0.5*(gradtt[ljp]+gradtt[l]);
620 gradtmag[l] = sqrt(r*r + t*t);
633 real *rho, *voldens, *cs, H;
639 voldens = VolumeDensity->
Field;
640 #pragma omp parallel for default(none) shared(nr,ns,cs,Rmed,rho,voldens,SQRT_ADIABIND_INV,OmegaInv) \
642 for (i=0; i<nr; i++) {
643 for (j=0; j<ns; j++) {
659 real kappa1, kappa2, kappa3, tmp1, tmp2;
660 real *opacity, *temper, *voldens;
662 static boolean FillParametricOpacity =
YES;
664 opacity = Opacity->
Field;
668 voldens = VolumeDensity->
Field;
670 if (FillParametricOpacity) {
671 FillParametricOpacity =
NO;
672 for (i=0; i<nr; i++) {
673 for (j=0; j<ns; j++) {
682 #pragma omp parallel for default(none) shared(nr,ns,temper,voldens,opacity,kappa0,a,b) \
683 private(i,j,l,T,Dens,kappa1,kappa2,kappa3,tmp1,tmp2)
684 for (i=0; i<nr; i++) {
685 for (j=0; j<ns; j++) {
691 if (T <= 2286.8*pow(Dens,0.0408)) {
692 kappa1 =
kappa0[0] * pow(Dens,
a[0]) * pow(T,
b[0]);
693 kappa2 =
kappa0[1] * pow(Dens,
a[1]) * pow(T,
b[1]);
694 kappa3 =
kappa0[2] * pow(Dens,
a[2]) * pow(T,
b[2]);
695 tmp1 = 1.0/(kappa1*kappa1) + 1.0/(kappa2*kappa2);
696 tmp1 = 1.0/(tmp1*tmp1);
697 tmp2 = pow(kappa3/(1.0 + 1.0e22*pow(T,-10.0)), 4.0);
698 opacity[l] = pow(tmp1+tmp2, 0.25);
700 else if (T > 2286.8*pow(Dens,0.0408) && T <= 2029.8*pow(Dens,0.0123)) {
701 opacity[l] =
kappa0[3] * pow(Dens,
a[3]) * pow(T,
b[3]);
703 else if (T > 2029.8*pow(Dens,0.0123) && T <= 1.0e5*pow(Dens,0.0476)) {
704 opacity[l] =
kappa0[4] * pow(Dens,
a[4]) * pow(T,
b[4]);
706 else if (T > 1.0e5*pow(Dens,0.0476) && T <= (31195.2)*pow(Dens,0.0533)) {
707 opacity[l] =
kappa0[5] * pow(Dens,
a[5]) * pow(T,
b[5]);
710 opacity[l] =
kappa0[6] * pow(Dens,
a[6]) * pow(T,
b[6]);
712 opacity[l] = opacity[l]*
OPA2CU;
724 tmp = 3.0 + sqrt(9.0+10.0*s*s);
727 tmp = 10.0*s + 9.0 + sqrt(81.0+180.0*s);
741 value = 0.375*tau + 0.5 + 0.25/tau;
743 value = 0.375*tau + 0.25*sqrt(3.0) + 0.25/tau;
756 static real *SendBufferInner, *SendBufferOuter;
757 static real *RecvBufferInner, *RecvBufferOuter;
758 static boolean allocate=
YES;
759 int prevcpu, nextcpu, size;
760 int sendoffsetin, sendoffsetout, recvoffsetin, recvoffsetout;
763 printf (
"Error! Requested number of rings to be synchronized by the MPI communication is larger than CPUOVERLAP.\n");
764 printf (
"Terminating now...\n");
778 sendoffsetout = (nr -
CPUOVERLAP - nsync)*NSEC;
781 if (
CPU_Rank > 0) memcpy (SendBufferInner, field+sendoffsetin, size*
sizeof(
real));
805 memcpy (field+recvoffsetin, RecvBufferInner, size*
sizeof(
real));
810 memcpy (field+recvoffsetout, RecvBufferOuter, size*
sizeof(
real));
820 real *cs, *temper, *pressure, *surfdens;
823 real Omega, kappa1, kappa2, kappa3, tmp1, tmp2;
832 surfdens = Surfdens->
Field;
834 sprintf (name,
"%storquemap_infile%d.dat",
OUTPUTDIR, istep);
835 output =
fopenp (name,
"w");
851 if (tmpr <= 2286.8*pow(Rho,0.0408)) {
852 kappa1 =
kappa0[0] * pow(Rho,
a[0]) * pow(tmpr,
b[0]);
853 kappa2 =
kappa0[1] * pow(Rho,
a[1]) * pow(tmpr,
b[1]);
854 kappa3 =
kappa0[2] * pow(Rho,
a[2]) * pow(tmpr,
b[2]);
855 tmp1 = 1.0/(kappa1*kappa1) + 1.0/(kappa2*kappa2);
856 tmp1 = 1.0/(tmp1*tmp1);
857 tmp2 = pow(kappa3/(1.0 + 1.0e22*pow(tmpr,-10.0)), 4.0);
858 Opacity = pow(tmp1+tmp2, 0.25);
860 else if (tmpr > 2286.8*pow(Rho,0.0408) && tmpr <= 2029.8*pow(Rho,0.0123)) {
861 Opacity =
kappa0[3] * pow(Rho,
a[3]) * pow(tmpr,
b[3]);
863 else if (tmpr > 2029.8*pow(Rho,0.0123) && tmpr <= 1.0e5*pow(Rho,0.0476)) {
864 Opacity =
kappa0[4] * pow(Rho,
a[4]) * pow(tmpr,
b[4]);
866 else if (tmpr > 1.0e5*pow(Rho,0.0476) && tmpr <= (31195.2)*pow(Rho,0.0533)) {
867 Opacity =
kappa0[5] * pow(Rho,
a[5]) * pow(tmpr,
b[5]);
870 Opacity =
kappa0[6] * pow(Rho,
a[6]) * pow(tmpr,
b[6]);
880 fprintf (output,
"%#.18g\t%#.18g\t%#.18g\t%#.18g\t%#.18g\t%#.18g\t%#.18g\t%#.18g\n",\
double real
Definition of the type 'real' used throughout the code.
static PolarGrid * DiffCoefCentered
real EffectiveOpticalDepth(real tau)
Calculates the effective optical depth in a simple gray model of the disk's vertical structure; see H...
void ImplicitRadiativeDiffusion(PolarGrid *Rho, PolarGrid *EnergyInt, PolarGrid *EnergyNew, real dt)
The main numerical solver of the energy equation.
real EFFECTIVETEMPERATURE
boolean StellarIrradiation
void ChessBoardIndexing()
Function ensures the odd-even ordering of the SOR method when the grid is split on multiple CPUs...
PolarGrid * CreatePolarGrid(int Nr, int Ns, char *name)
A structure used to store any scalar fied on the computational domain.
FILE * fopenp(char *string, char *mode)
static PolarGrid * MatrixNexttoTemperljp
int Nrad
Radial size of the grid, in number of zones.
static PolarGrid * MatrixNexttoTemperlip
void CalculateQminus(PolarGrid *Rho)
Estimate of the heat loss due to radiation escape in the vertical direction with respect to the midpl...
void DiffusionCoefs()
Calculation of the diffusion coefficients.
void MidplaneVolumeDensity(PolarGrid *Rho)
Translates the surface density into the midplane volume density using the local pressure scale height...
static PolarGrid * DiffCoefIfaceRad
static PolarGrid * GradTemperMagnitude
static PolarGrid * DiscretizationCoefB
static PolarGrid * GradTemperRad
void SynchronizeOverlapFields(real *field, int nr, int nsync)
For a MPI-split grid, synchronizes the values in a requested number 'nsync' of the overlapping radial...
void CreateTorqueMapInfile(int istep, PolarGrid *Surfdens)
Writes an input file for the 'torquemap' code written by Bertram Bitsch.
boolean heatsrc_index[MAXPLANETS]
static PolarGrid * Opacity
void IterateRelaxationParameter()
When solving the energy equation for the first time, the function spans through various values of the...
static PolarGrid * DiscretizationCoefA
static PolarGrid * MatrixNexttoTemperlim
void OpacityProfile()
Fills the opacity polar grid, either with a fixed parametric value or using the Bell & Lin (1994) opa...
static PolarGrid * MatrixNexttoTemperl
void MPI_Allreduce(void *ptr, void *ptr2, int count, int type, int foo3, int foo4)
void CalculateFlaring()
Calculates the sine of the grazing angle by reconstructing the surface from the pressure scale height...
static PolarGrid * Flaring
static PolarGrid * DiffCoefIfaceTheta
PolarGrid * DivergenceVelocity
void InitRadiatDiffusionFields()
Initialises the polar arrays associated with the heating/cooling processes.
Contains all the include directives requested by the code.
int Nsec
Azimuthal size of the grid, in number of zones.
int SuccessiveOverrelaxation(real omega, boolean errcheck)
The SOR method algorithm inspired by the one from Numerical Recipes.
void TemperatureGradient()
Finds the temperature gradients and their magnitude over the mesh.
static PolarGrid * RightHandSide
static PolarGrid * EnergyNew
static PolarGrid * MatrixNexttoTemperljm
static PolarGrid * EnergyInt
void ComputeTemperatureField()
void CalculateQirr(PolarGrid *Rho)
Calculates the stellar irradiation source term.
static PolarGrid * Qirradiation
static PolarGrid * VolumeDensity
static PolarGrid * GradTemperTheta
real FluxLimiterValue(real s)
Calculates the flux limiter according to Kley (1989)
void mpi_make1Dprofile(real *gridfield, real *axifield)
void masterprint(const char *template,...)