// stop at just above P0 for (int i = is; i <= ie; ++i) { pthermo->Extrapolate(&air, -dlnp / 2., Thermodynamics::Method::DryAdiabat); if (air.w[IPR] < P0) break; }
// extrapolate down to where air is pthermo->Extrapolate(&air, log(P0 / air.w[IPR]), Thermodynamics::Method::DryAdiabat);
// make up for the difference Ts += T0 - air.w[IDN]; if (std::abs(T0 - air.w[IDN]) < 0.01) break;
// Replace adiabatic atmosphere with isothermal atmosphere if temperature // is too low pthermo->Extrapolate(&air, dlnp, Thermodynamics::Method::DryAdiabat); for (; i <= ie; ++i) { pthermo->Extrapolate(&air, -dlnp, Thermodynamics::Method::Isothermal); AirParcelHelper::distribute_to_primitive(this, k, j, i, air); } }
// if requested // modify atmospheric stability Real adlnTdlnP = pin->GetOrAddReal("problem", "adlnTdlnP", 0.); Real adlnNH3dlnP = pin->GetOrAddReal("problem", "adlnNH3dlnP", 0.);
if (adlnTdlnP != 0.) { Real pmin = pin->GetOrAddReal("problem", "adlnTdlnP.pmin", 1.); Real pmax = pin->GetOrAddReal("problem", "adlnTdlnP.pmax", 20.);
for (int k = ks; k <= ke; ++k) for (int j = js; j <= je; ++j) { int ibegin = find_pressure_level_lesser(pmax, phydro->w, k, j, is, ie); int iend = find_pressure_level_lesser(pmin, phydro->w, k, j, is, ie);
auto &&air = AirParcelHelper::gather_from_primitive(this, k, j, ibegin); air.ToMoleFraction();
for (int i = ibegin; i < iend; ++i) { pthermo->Extrapolate(&air, -dlnp, Thermodynamics::Method::DryAdiabat, 0., adlnTdlnP); AirParcelHelper::distribute_to_primitive(this, k, j, i + 1, air); } } }
if (adlnNH3dlnP != 0.) { Real pmin = pin->GetOrAddReal("problem", "adlnNH3dlnP.pmin", 1.); Real pmax = pin->GetOrAddReal("problem", "adlnNH3dlnP.pmax", 20.);
for (int k = ks; k <= ke; ++k) for (int j = js; j <= je; ++j) { int ibegin = find_pressure_level_lesser(pmax, phydro->w, k, j, is, ie); int iend = find_pressure_level_lesser(pmin, phydro->w, k, j, is, ie);
auto &&air = AirParcelHelper::gather_from_primitive(this, k, j, ibegin); air.ToMoleFraction();
for (int i = ibegin; i < iend; ++i) { pthermo->Extrapolate(&air, -dlnp, Thermodynamics::Method::DryAdiabat); air.w[iNH3] += adlnNH3dlnP * air.w[iNH3] * dlnp; auto rates = pthermo->TryEquilibriumTP_VaporCloud(air, iNH3); air.w[iNH3] += rates[0]; AirParcelHelper::distribute_to_primitive(this, k, j, i + 1, air); } } }
设置痕量气体和电子,碱金属。计算蒸汽压和浓度:
cpp
// set tracers, electron and Na int ielec = pindex->GetTracerId("e-"); int iNa = pindex->GetTracerId("Na"); auto ptracer = pimpl->ptracer;
for (int k = ks; k <= ke; ++k) for (int j = js; j <= je; ++j) for (int i = is; i <= ie; ++i) { Real temp = pthermo->GetTemp(this, k, j, i); Real pH2S = xH2S * phydro->w(IPR, k, j, i); Real pNa = xNa * phydro->w(IPR, k, j, i); Real svp = sat_vapor_p_Na_H2S_Visscher(temp, pH2S); pNa = std::min(svp, pNa);
// primitive to conserved conversion (hydro) peos->PrimitiveToConserved(phydro->w, pfield->bcc, phydro->u, pcoord, is, ie, js, je, ks, ke);
// conserved to primitive conversion (tracer) peos->PassiveScalarConservedToPrimitive(pscalars->s, phydro->u, pscalars->r, pscalars->r, pcoord, is, ie, js, je, ks, ke);
最后是辐射传输计算。
cpp
// Microwave radiative transfer needs temperatures at cell interfaces, which // are interpolated from cell centered hydrodynamic variables. Normally, the // boundary conditions are taken care of internally. But, since we call // radiative tranfer directly in pgen, we would need to update the boundary // conditions manually. The following lines of code updates the boundary // conditions. phydro->hbvar.SwapHydroQuantity(phydro->w, HydroBoundaryQuantity::prim); pbval->ApplyPhysicalBoundaries(0., 0., pbval->bvars_main_int);
// calculate radiative transfer auto prad = pimpl->prad;
for (int k = ks; k <= ke; ++k) { // run RT models app->Log("run microwave radiative transfer"); for (int j = js; j <= je; ++j) prad->CalRadiance(this, k, j); }
本节涉及到了使用湿绝热垂直递减率来构建大气温度廓线的方法,考虑了多种水凝物潜热释放的情形,具体请参考文献【Moist Adiabats with Multiple Condensing Species: A New Theory with Application to Giant-Planet Atmospheres】