Canoe
Comprehensive Atmosphere N' Ocean Engine
rk4_integrate_z.cpp
Go to the documentation of this file.
1 // C/C++
2 #include <algorithm>
3 #include <iomanip>
4 #include <iostream>
5 
6 // thermodynamics
7 #include "thermodynamics.hpp"
8 
9 void Thermodynamics::rk4IntegrateZ(AirParcel *air, Real dz, Method method,
10  Real grav, Real adTdz) const {
11  Real step[] = {0.5, 0.5, 1.};
12  Real temp = air->w[IDN];
13  Real pres = air->w[IPR];
14  Real dTdz[4], chi[4];
15  Real latent[1 + NVAPOR];
16 
17  for (int rk = 0; rk < 4; ++rk) {
18  EquilibrateTP(air);
19  if (method != Method::ReversibleAdiabat) {
20  for (int j = 0; j < NCLOUD; ++j) air->c[j] = 0;
21  }
22 
23  for (int i = 1; i <= NVAPOR; ++i) {
24  // make a trial run to get latent heat
25  air->w[i] += 1.E-6;
26  auto rates = TryEquilibriumTP_VaporCloud(*air, i);
27  latent[i] = GetLatentHeatMole(i, rates, air->w[IDN]) /
28  (Constants::Rgas * air->w[IDN]);
29  air->w[i] -= 1.E-6;
30  }
31 
32  Real q_gas = 1., q_eps = 1.;
33  for (int i = 1; i <= NVAPOR; ++i) {
34  q_eps += air->w[i] * (mu_ratio_[i] - 1.);
35  }
36 
37  for (int j = 0; j < NCLOUD; ++j) {
38  q_eps += air->c[j] * (mu_ratio_[1 + NVAPOR + j] - 1.);
39  q_gas += -air->c[j];
40  }
41 
42  Real g_ov_Rd = grav / Rd_;
43  Real R_ov_Rd = q_gas / q_eps;
44 
45  if (method == Method::ReversibleAdiabat ||
46  method == Method::PseudoAdiabat) {
47  chi[rk] = calDlnTDlnP(*air, latent);
48  } else if (method == Method::DryAdiabat) {
49  for (int i = 1; i <= NVAPOR; ++i) latent[i] = 0;
50  chi[rk] = calDlnTDlnP(*air, latent);
51  } else { // isothermal
52  chi[rk] = 0.;
53  }
54 
55  dTdz[rk] = -chi[rk] * g_ov_Rd / R_ov_Rd + adTdz;
56  chi[rk] = -R_ov_Rd / g_ov_Rd * dTdz[rk];
57 
58  // integrate over dz
59  Real chi_avg;
60  if (rk < 3) {
61  air->w[IDN] = temp + dTdz[rk] * dz * step[rk];
62  chi_avg = chi[rk];
63  } else {
64  air->w[IDN] =
65  temp +
66  1. / 6. * (dTdz[0] + 2. * dTdz[1] + 2. * dTdz[2] + dTdz[3]) * dz;
67  chi_avg = 1. / 6. * (chi[0] + 2. * chi[1] + 2. * chi[2] + chi[3]);
68  }
69 
70  if (!(air->w[IDN] > 0.)) air->w[IDN] = temp;
71 
72  if (fabs(air->w[IDN] - temp) > 0.01) {
73  air->w[IPR] = pres * pow(air->w[IDN] / temp, 1. / chi_avg);
74  } else { // isothermal limit
75  air->w[IPR] =
76  pres * exp(-2. * g_ov_Rd * dz / (R_ov_Rd * (air->w[IDN] + temp)));
77  }
78  }
79 
80  // recondensation
81  EquilibrateTP(air);
82  if (method != Method::ReversibleAdiabat) {
83  for (int j = 0; j < NCLOUD; ++j) air->c[j] = 0;
84  }
85 }
Real *const w
Definition: air_parcel.hpp:36
Real *const c
cloud data
Definition: air_parcel.hpp:39
RealArrayX TryEquilibriumTP_VaporCloud(AirParcel const &qfrac, int ivapor, Real cv_hat=0., bool misty=false) const
Calculate the equilibrium mole transfer by cloud reaction vapor -> cloud.
Real calDlnTDlnP(AirParcel const &qfrac, Real latent[]) const
Calculate moist adiabatic temperature gradient.
Real GetLatentHeatMole(int i, std::vector< Real > const &rates, Real temp) const
std::array< Real, Size > mu_ratio_
ratio of mean molecular weights
Real Rd_
ideal gas constant of dry air in J/kg
void EquilibrateTP(AirParcel *qfrac) const
void rk4IntegrateZ(AirParcel *qfrac, Real dlnp, Method method, Real grav, Real adlnTdlnP) const
double const Rgas
Definition: constants.hpp:5
float temp
Definition: fit_ammonia.py:6