Begin refactoring RAOB parser
This commit is contained in:
parent
3b33faa78b
commit
453a0efe89
1 changed files with 54 additions and 57 deletions
107
lib/xmet/raob.py
107
lib/xmet/raob.py
|
@ -60,39 +60,19 @@ class RAOBSounding():
|
||||||
|
|
||||||
return sounding
|
return sounding
|
||||||
|
|
||||||
def sample(self, pressure: float):
|
def record(self, sample: SoundingSample):
|
||||||
if pressure in self.samples:
|
dest = SoundingSample()
|
||||||
return self.samples[pressure]
|
dest.pressure_qa = ' '
|
||||||
|
dest.height_qa = ' '
|
||||||
|
dest.temp_qa = ' '
|
||||||
|
dest.pressure = sample.pressure
|
||||||
|
dest.height = sample.height
|
||||||
|
dest.temp = sample.temp
|
||||||
|
dest.dewpoint = sample.dewpoint
|
||||||
|
dest.wind_speed = sample.wind_speed
|
||||||
|
dest.wind_dir = sample.wind_dir
|
||||||
|
|
||||||
sample = SoundingSample()
|
self.samples[sample.pressure] = dest
|
||||||
sample.pressure = pressure
|
|
||||||
sample.pressure_qa = ' '
|
|
||||||
sample.height_qa = ' '
|
|
||||||
sample.temp_qa = ' '
|
|
||||||
|
|
||||||
self.samples[pressure] = sample
|
|
||||||
|
|
||||||
return sample
|
|
||||||
|
|
||||||
def record_height(self, pressure: float, height: float):
|
|
||||||
sample = self.sample(pressure)
|
|
||||||
sample.height = height
|
|
||||||
|
|
||||||
def record_temp_dewpoint(self,
|
|
||||||
pressure: float,
|
|
||||||
temp: float,
|
|
||||||
dewpoint: float):
|
|
||||||
sample = self.sample(pressure)
|
|
||||||
sample.temp = temp
|
|
||||||
sample.dewpoint = dewpoint
|
|
||||||
|
|
||||||
def record_wind_speed_dir(self,
|
|
||||||
pressure: float,
|
|
||||||
wind_speed: float,
|
|
||||||
wind_dir: float):
|
|
||||||
sample = self.sample(pressure)
|
|
||||||
sample.wind_speed = wind_speed
|
|
||||||
sample.wind_dir = wind_dir
|
|
||||||
|
|
||||||
class RAOBObs():
|
class RAOBObs():
|
||||||
DATA_SOURCE = 'UCAR'
|
DATA_SOURCE = 'UCAR'
|
||||||
|
@ -312,7 +292,7 @@ class RAOBObs():
|
||||||
|
|
||||||
return sample
|
return sample
|
||||||
|
|
||||||
def parse_ttaa(self) -> Sounding:
|
def parse_ttaa(self) -> dict:
|
||||||
#
|
#
|
||||||
# Return None if there is no height data up to 100mb.
|
# Return None if there is no height data up to 100mb.
|
||||||
#
|
#
|
||||||
|
@ -330,16 +310,9 @@ class RAOBObs():
|
||||||
if sample is None:
|
if sample is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
timestamp = self.parse_timestamp(self.tokens[0])
|
station = self.tokens[1]
|
||||||
|
timestamp = self.tokens[0]
|
||||||
sounding = Sounding()
|
samples = list()
|
||||||
sounding.samples = [sample]
|
|
||||||
sounding.station = self.tokens[1]
|
|
||||||
|
|
||||||
sounding.data_source_pressure = self.DATA_SOURCE
|
|
||||||
sounding.data_source_other = self.DATA_SOURCE
|
|
||||||
sounding.timestamp_observed = timestamp
|
|
||||||
sounding.timestamp_released = timestamp - datetime.timedelta(minutes=45)
|
|
||||||
|
|
||||||
for i in range(5, len(self.tokens), 3):
|
for i in range(5, len(self.tokens), 3):
|
||||||
if len(self.tokens) < i+3 or self.tokens[i][-1] == '=':
|
if len(self.tokens) < i+3 or self.tokens[i][-1] == '=':
|
||||||
|
@ -356,9 +329,13 @@ class RAOBObs():
|
||||||
if sample is None:
|
if sample is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
sounding.samples.append(sample)
|
samples.append(sample)
|
||||||
|
|
||||||
return sounding
|
return {
|
||||||
|
'station': station,
|
||||||
|
'timestamp': timestamp,
|
||||||
|
'samples': samples
|
||||||
|
}
|
||||||
|
|
||||||
class RAOBChunk():
|
class RAOBChunk():
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
|
@ -390,15 +367,15 @@ class RAOBChunk():
|
||||||
if obs is not None:
|
if obs is not None:
|
||||||
yield obs
|
yield obs
|
||||||
|
|
||||||
def each_sounding(self):
|
def each_data(self):
|
||||||
for obs in self.each_obs():
|
for obs in self.each_obs():
|
||||||
if obs.kind == 'TTAA':
|
if obs.kind == 'TTAA':
|
||||||
sounding = obs.parse_ttaa()
|
data = obs.parse_ttaa()
|
||||||
|
|
||||||
if sounding is None or len(sounding.samples) == 0:
|
if data is None or len(data['samples']) == 0:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
yield sounding
|
yield data
|
||||||
|
|
||||||
class RAOBReader():
|
class RAOBReader():
|
||||||
"""
|
"""
|
||||||
|
@ -414,6 +391,18 @@ class RAOBReader():
|
||||||
self.fh = fh
|
self.fh = fh
|
||||||
self.soundings = dict()
|
self.soundings = dict()
|
||||||
|
|
||||||
|
def sounding(self, station: str, timestamp: str) -> RAOBSounding:
|
||||||
|
key = station + '.' + timestamp
|
||||||
|
|
||||||
|
if key in self.soundings:
|
||||||
|
return self.soundings[key]
|
||||||
|
|
||||||
|
sounding = RAOBSounding(station, timestamp)
|
||||||
|
|
||||||
|
self.soundings[key] = sounding
|
||||||
|
|
||||||
|
return sounding
|
||||||
|
|
||||||
def parse_chunk(self, text: str) -> RAOBChunk:
|
def parse_chunk(self, text: str) -> RAOBChunk:
|
||||||
meta = {
|
meta = {
|
||||||
'wfo': None, # NWS forecast office
|
'wfo': None, # NWS forecast office
|
||||||
|
@ -481,19 +470,27 @@ class RAOBReader():
|
||||||
for text in each_chunk(self.fh, CHUNK_SEP, CHUNK_STRIP_CHARS):
|
for text in each_chunk(self.fh, CHUNK_SEP, CHUNK_STRIP_CHARS):
|
||||||
yield self.parse_chunk(text)
|
yield self.parse_chunk(text)
|
||||||
|
|
||||||
def each_obs(self):
|
def load_soundings(self):
|
||||||
for chunk in self.each_chunk():
|
for chunk in self.each_chunk():
|
||||||
yield from chunk.each_obs()
|
for data in chunk.each_data():
|
||||||
|
station = data['station']
|
||||||
|
timestamp = data['timestamp']
|
||||||
|
samples = data['samples']
|
||||||
|
|
||||||
def each_sounding(self):
|
sounding = self.sounding(station, timestamp)
|
||||||
for chunk in self.each_chunk():
|
|
||||||
yield from chunk.each_sounding()
|
for sample in samples:
|
||||||
|
sounding.record(sample)
|
||||||
|
|
||||||
|
for key in self.soundings:
|
||||||
|
yield self.soundings[key].finish()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def each_sounding_from_fh(fh: io.TextIOBase):
|
def each_sounding_from_fh(fh: io.TextIOBase):
|
||||||
reader = RAOBReader(fh)
|
reader = RAOBReader(fh)
|
||||||
|
|
||||||
yield from reader.each_sounding()
|
for sounding in reader.load_soundings():
|
||||||
|
yield sounding
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def each_sounding_from_file(path: str):
|
def each_sounding_from_file(path: str):
|
||||||
|
|
Loading…
Add table
Reference in a new issue