Skip to content

Commit 932d4e6

Browse files
authored
Merge pull request #171 from martinjanssens/fix-saturation-adjustment
Fix to translate saturation adjustment to buoyancy in plume
2 parents 216d4e5 + 0bfa64f commit 932d4e6

File tree

2 files changed

+16
-9
lines changed

2 files changed

+16
-9
lines changed

packages/class/src/fire.ts

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,9 @@ const defaultPlumeConfig: PlumeConfig = {
4646
export interface Parcel {
4747
z: number; // Height levels [m]
4848
w: number; // Vertical velocity [m/s]
49+
thetal: number; // Liquid-water potential temperature (conserved) [K]
4950
theta: number; // Potential temperature [K]
50-
qt: number; // Total specific humidity [kg/kg]
51+
qt: number; // Total specific humidity (conserved) [kg/kg]
5152
thetav: number; // Virtual potential temperature [K]
5253
qsat: number; // Saturation specific humidity [kg/kg]
5354
b: number; // Buoyancy [m/s²]
@@ -71,7 +72,7 @@ function initializeFireParcel(
7172
): Parcel {
7273
// Start with parcel props from ambient air
7374
const z = background.z[0];
74-
let theta = background.theta[0];
75+
let thetal = background.theta[0]; // CLASS assumes RH_near-surf < 100%
7576
const thetavAmbient = background.thetav[0];
7677
let qt = background.qt[0];
7778
const rho = background.rho[0];
@@ -83,24 +84,25 @@ function initializeFireParcel(
8384
const FFire =
8485
((fire.omega * fire.C * fire.spread) / fire.d) * (1 - fire.radiativeLoss);
8586
const FqFire = (fire.omega * fire.Cq * fire.spread) / fire.d;
86-
const FvFire = FFire * (1 + 0.61 * theta * FqFire);
87+
const FvFire = FFire * (1 + 0.61 * thetal * FqFire);
8788

8889
// Use cube root as the root may be negative and js will yield NaN for a complex number result
8990
const fac_w =
9091
(3 * g * plumeConfig.aW * FvFire) /
9192
(2 * rho * cp * thetavAmbient * (1 + plumeConfig.bW));
9293
const w = Math.cbrt(fac_w * fire.h0);
9394

94-
// Add excess temperature/humidity and update thetav/qsat accordingly
95+
// Add excess temperature/humidity
9596
const dtheta = FFire / (rho * cp * w);
9697
const dqv = FqFire / (rho * w);
97-
theta += dtheta;
98+
thetal += dtheta;
9899
qt += dqv;
99100

100-
// Thermodynamics
101-
const T = saturationAdjustment(theta, qt, p, exner);
101+
// Update thetav/qsat accordingly
102+
const T = saturationAdjustment(thetal, qt, p, exner);
102103
const qsat = qsatLiq(p, T);
103104
const ql = Math.max(qt - qsat, 0);
105+
const theta = thetal + (Lv / cp / exner) * ql;
104106
const thetav = virtualTemperature(theta, qt, ql);
105107
const rh = ((qt - ql) / qsat) * 100;
106108
const Td = dewpoint(qt, p / 100);
@@ -118,6 +120,7 @@ function initializeFireParcel(
118120
return {
119121
z,
120122
w,
123+
thetal,
121124
theta,
122125
qt,
123126
thetav,
@@ -156,13 +159,15 @@ export function calculatePlume(
156159
// Mass flux through plume
157160
const m = parcel.m + (parcel.e - parcel.d) * dz;
158161
const emz = (parcel.e / parcel.m) * dz;
159-
const theta = parcel.theta - emz * (parcel.theta - bg.theta[i - 1]);
162+
// FIXME: Line below assumes background state is unsaturated
163+
const thetal = parcel.thetal - emz * (parcel.thetal - bg.theta[i - 1]);
160164
const qt = parcel.qt - emz * (parcel.qt - bg.qt[i - 1]);
161165

162166
// Thermodynamics and buoyancy
163-
const T = saturationAdjustment(theta, qt, bg.p[i], bg.exner[i]);
167+
const T = saturationAdjustment(thetal, qt, bg.p[i], bg.exner[i]);
164168
const qsat = qsatLiq(bg.p[i], T);
165169
const ql = Math.max(qt - qsat, 0);
170+
const theta = thetal + (Lv / cp / bg.exner[i]) * ql;
166171
const thetav = virtualTemperature(theta, qt, ql);
167172
const rh = ((qt - ql) / qsat) * 100;
168173
const Td = dewpoint(qt, bg.p[i] / 100);
@@ -191,6 +196,7 @@ export function calculatePlume(
191196
parcel = {
192197
z,
193198
w,
199+
thetal,
194200
theta,
195201
qt,
196202
thetav,

packages/class/src/thermodynamics.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const Lv = 2.5e6; // Latent heat of vaporization [J/kg]
88
const ep = Rd / Rv;
99

1010
export function virtualTemperature(t: number, qt: number, ql: number): number {
11+
// Note t is theta, not thl as conserved by the plume
1112
return t * (1.0 - (1.0 - Rv / Rd) * qt - (Rv / Rd) * ql);
1213
}
1314

0 commit comments

Comments
 (0)