Move parameter derivation to sounding.py

This commit is contained in:
XANTRONIX 2025-03-08 12:02:42 -05:00
parent 50cdf4052d
commit 53ea99803e
2 changed files with 47 additions and 88 deletions

View file

@ -180,92 +180,6 @@ class SkewTGraph():
cr.stroke()
cr.restore()
def follow_dry_adiabat(self, temp: float, pressure: float) -> dict:
levels = dict()
for level in loft_parcel(temp, pressure, lambda t, p: LAPSE_RATE_DRY):
t2, p2 = level
levels[p2] = t2
return levels
def follow_moist_adiabat(self, temp: float, pressure: float) -> dict:
levels = dict()
for level in loft_parcel(temp, pressure, moist_lapse_rate):
t2, p2 = level
levels[p2] = t2
return levels
def follow_saturated_mixing_ratio(self, temp: float, pressure: float) -> dict:
levels = dict()
ratio = saturated_mixing_ratio(temp, pressure)
p2 = pressure
while p2 >= PRESSURE_MIN:
levels[p2] = mixing_ratio_temp(ratio, p2)
p2 -= 10
return levels
def follow_sounding(self, sounding: Sounding) -> dict:
levels = dict()
for sample in sounding.samples:
levels[sample.pressure] = sample.temp
return levels
def intersect(self, series1: dict, series2: dict):
pairs = nearest(sorted(series1.keys(), reverse=True),
sorted(series2.keys(), reverse=True))
sign_last = None
for pair in pairs:
v1, v2 = series1[pair[0]], series2[pair[1]]
sign = cmp(v1, v2)
if sign == 0 or (sign_last is not None and sign_last != sign):
return pair[0]
sign_last = sign
def find_lfc(self, temp: float, pressure: float, sounding: Sounding) -> float:
moist_adiabat = self.follow_moist_adiabat(temp, pressure)
temp_line = self.follow_sounding(sounding)
pairs = nearest(sorted(moist_adiabat.keys(), reverse=True),
sorted(temp_line.keys(), reverse=True))
for pair in pairs:
v1, v2 = moist_adiabat[pair[0]], temp_line[pair[1]]
if v1 > v2:
return pair[0]
def derive_parameters(self, sounding: Sounding):
dry_adiabat = self.follow_dry_adiabat(sounding.samples[0].temp,
sounding.samples[0].pressure)
saturated_mr_line = self.follow_saturated_mixing_ratio(sounding.samples[0].dewpoint,
sounding.samples[0].pressure)
lcl = self.intersect(dry_adiabat, saturated_mr_line)
lfc = self.find_lfc(dry_adiabat[lcl], lcl, sounding)
return {
'lcl': lcl,
'lfc': lfc
}
def draw(self,
cr: cairo.Context,
x: float,

View file

@ -1,8 +1,13 @@
import datetime
import shapely
from xmet.db import Database, DatabaseTable, DatabaseOrder
from xmet.coord import COORD_SYSTEM
from xmet.db import Database, DatabaseTable, DatabaseOrder
from xmet.coord import COORD_SYSTEM
from xmet.list import nearest
from xmet.series import Series
from xmet.thermo import follow_dry_adiabat, \
follow_moist_adiabat, \
follow_saturated_mixing_ratio
LAPSE_RATE_DRY = 9.8 # degrees C per 1000m
LAPSE_RATE_MOIST = 4.0
@ -42,6 +47,9 @@ class SoundingSample(DatabaseTable):
def is_saturated(self) -> bool:
return self.humidity >= 100.0
class SoundingParameters():
pass
class Sounding(DatabaseTable):
__slots__ = (
'id', 'station', 'timestamp_observed', 'timestamp_released',
@ -168,3 +176,40 @@ class Sounding(DatabaseTable):
]]).fetchall())
return sounding
def follow_temp(self) -> Series:
series = Series()
for sample in self.samples:
series[sample.pressure] = sample.temp
return series
def find_lfc(self, temp: float, pressure: float) -> float:
moist_adiabat = follow_moist_adiabat(temp, pressure)
temp_line = self.follow_temp()
pairs = nearest(sorted(moist_adiabat.keys(), reverse=True),
sorted(temp_line.keys(), reverse=True))
for pair in pairs:
v1, v2 = moist_adiabat[pair[0]], temp_line[pair[1]]
if v1 > v2:
return pair[0]
def derive_parameters(self) -> SoundingParameters:
dry_adiabat = follow_dry_adiabat(self.samples[0].temp,
self.samples[0].pressure)
saturated_mr_line = follow_saturated_mixing_ratio(self.samples[0].dewpoint,
self.samples[0].pressure)
lcl = dry_adiabat.intersect(saturated_mr_line)
lfc = self.find_lfc(dry_adiabat[lcl], lcl)
params = SoundingParameters()
params.lcl = lcl
params.lfc = lfc
return params