forked from classmodel/modelgui
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathepmodel.cpp
More file actions
179 lines (156 loc) · 5.54 KB
/
epmodel.cpp
File metadata and controls
179 lines (156 loc) · 5.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#include <iostream>
#include <algorithm>
#include <iterator>
#include <string>
#include <cmath>
#include <vector>
#include <tuple>
#include "model.h"
#include "epmodel.h"
using namespace std;
double epmodel::calc_sat(double temp, double pref) {
double esat = 610.78 * exp(17.2694 * (temp - 273.16)/(temp - 35.86));
double qsat = Rd / Rv * esat / (pref + (1 - Rd / Rv) * esat);
return qsat;
}
void epmodel::init(){
Rd = 287;
Rv = 461.5;
Lv = 2.5e6;
cp = 1005;
g = 9.81;
tv_const = Rv / Rd - 1;
c1 = 0.5; // vertical velocity constants from Simpson and Wiggert (1969), Jakob and Siebesma (2003)
c2 = 0.33333;
// initialize first height level
z = 0;
pres = input.Ps;
env.thl = input.theta;
env.qt = input.q;
parcel.qt = input.q + input.phi_cu * sqrt(input.sigmaq2);
parcel.thl = input.theta;
parcel.w = input.wstar;
parcel.cin = 0;
parcel.B = 0;
inhibited = false;
above_lfc = false;
above_lcl = false;
}
void epmodel::runmodel(){
for (int i = 0; i < input.imax; i++) {
entrainment(); // effect of lateral entrainment rate on parcel thl, qt
z += input.dz;
get_env_stats(); // determine state of static environment at current height level
calc_thermo(); // parcel thermodynamics
if ((parcel.thv < env.thv) and (z >= input.h)){ // calculate decrease in vertical velocity in CIN layer
calc_w();
}
cont_bool = check_if_stop(); // check if the simulation can stop
if (!cont_bool) {
data_zsize = i; // size of vertical profile data
output = get_output();
break;
}
save_zstep(); // save data of current height level to create vertical profile
}
}
void epmodel::get_env_stats() {
if (z < input.h) {
env.thl = input.theta;
env.qt = input.q;
}
else {
env.thl = input.theta_ft0 + input.gammatheta * z;
env.qt = input.q_ft0 + input.gammaq * z;
if (input.sw_ft_storage) {
if (z < input.h + input.hstore) {
env.thl += input.Stheta / input.hstore;
env.qt += input.Sq / input.hstore;
}
}
}
calc_pres();
env.temp = exner * env.thl;
env.qsat = calc_sat(env.temp, pres);
env.thv = env.thl * (1 + tv_const * env.qt);
}
void epmodel::calc_thermo() {
// parcel thermodynamics
double T_old = 0; // overwritten later
double T_i = parcel.thl * exner;
int i = 0;
double eps = 1e-8;
while ((abs(T_i - T_old) > 1e-6) && (i < 100)) { // hard-coded error margin
T_old = T_i;
double dfdT = (func(T_old + eps) - func(T_old - eps)) / (2 * eps);
T_i -= func(T_old) / dfdT;
i++;
if (i == 100) {
cout << "ERROR: Calc_thermo loop did not converge!!" << endl;
}
}
parcel.qsat = calc_sat(T_i, pres);
parcel.ql = max(0., parcel.qt - parcel.qsat);
parcel.thv = (T_i / exner) * (1 + tv_const * parcel.qt - (1 + tv_const) * parcel.ql);
}
double epmodel::func(double temp) {
double qsat_f = calc_sat(temp, pres);
double ql_f = max(0., parcel.qt - qsat_f);
double function = temp - exner * parcel.thl - Lv * ql_f / cp;
return function;
}
void epmodel::calc_pres() {
double Tv0 = input.theta_ft0 * (1 + tv_const * input.q_ft0);
double gtv = (1 + tv_const * input.q_ft0) * (input.gammatheta - g / cp) + tv_const * input.theta_ft0 * input.gammaq;
pres = input.Ps * pow(1 + gtv * z / Tv0, -g / (Rd * gtv));
exner = pow(pres / input.Ps, Rd / cp);
}
void epmodel::entrainment() {
if (z < input.h) {
ent = 0;
} else if (above_lcl) {
ent = input.ent_corr_factor * 1.15 * env.qt / (env.qsat * ((z - z_lcl) + 300)); //parametrization of lateral entrainment rate by Lu et al. (2018)
} else {
ent = 3e-3; // specify constant entrainment rate between h and LCL since the parametrization does not work in this region
}
parcel.qt -= ent * input.dz * (parcel.qt - env.qt);
parcel.thl -= ent * input.dz * (parcel.thl - env.thl);
}
void epmodel::calc_w() {
// calculate vertical velocity based on constants from Simpson and Wiggert (1969), Jakob and Siebesma (2003)
parcel.B = g * (parcel.thv - env.thv) / env.thv;
parcel.w += input.dz * (- c1 * ent * parcel.w + c2 * parcel.B / parcel.w);
parcel.cin -= parcel.B * input.dz;
}
bool epmodel::check_if_stop() {
// check if the simulation should stop
if (!above_lcl) {
if (parcel.ql > 0) {
above_lcl = true;
z_lcl = z;
}
}
above_lfc = (above_lcl && (parcel.thv > env.thv) && (z > input.h));
if (parcel.w < 0) {
parcel.w = 0;
inhibited = true;
}
cond_list = {inhibited, above_lfc}; // list of reasons to stop the loop
cont_bool = find(begin(cond_list), end(cond_list), true) == end(cond_list); // boolean that determines whether simulation should continue
return cont_bool;
}
epmodel::output_struct epmodel::get_output() {
// save resulting vertical velocity etc.
output_struct output;
output.w_lfc = parcel.w;
output.cin = parcel.cin;
output.thvp = parcel.thv;
output.thve = env.thv;
output.inhibited = inhibited;
return output;
}
void epmodel::save_zstep() {
// save vertical profiles
out_z.w.push_back(parcel.w);
out_z.cin.push_back(parcel.cin);
}