diff --git a/lib/xmet/raob.py b/lib/xmet/raob.py index 9c7e825..0fd2384 100644 --- a/lib/xmet/raob.py +++ b/lib/xmet/raob.py @@ -60,39 +60,19 @@ class RAOBSounding(): return sounding - def sample(self, pressure: float): - if pressure in self.samples: - return self.samples[pressure] + def record(self, sample: SoundingSample): + dest = SoundingSample() + 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() - 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 + self.samples[sample.pressure] = dest class RAOBObs(): DATA_SOURCE = 'UCAR' @@ -312,7 +292,7 @@ class RAOBObs(): return sample - def parse_ttaa(self) -> Sounding: + def parse_ttaa(self) -> dict: # # Return None if there is no height data up to 100mb. # @@ -330,16 +310,9 @@ class RAOBObs(): if sample is None: return - timestamp = self.parse_timestamp(self.tokens[0]) - - sounding = Sounding() - 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) + station = self.tokens[1] + timestamp = self.tokens[0] + samples = list() for i in range(5, len(self.tokens), 3): if len(self.tokens) < i+3 or self.tokens[i][-1] == '=': @@ -356,9 +329,13 @@ class RAOBObs(): if sample is None: continue - sounding.samples.append(sample) + samples.append(sample) - return sounding + return { + 'station': station, + 'timestamp': timestamp, + 'samples': samples + } class RAOBChunk(): def __init__(self, @@ -390,15 +367,15 @@ class RAOBChunk(): if obs is not None: yield obs - def each_sounding(self): + def each_data(self): for obs in self.each_obs(): 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 - yield sounding + yield data class RAOBReader(): """ @@ -414,6 +391,18 @@ class RAOBReader(): self.fh = fh 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: meta = { 'wfo': None, # NWS forecast office @@ -474,26 +463,34 @@ class RAOBReader(): tokens.extend(re.split(r'\s+', line)) return RAOBChunk(meta['wfo'], - meta['product'], - tokens) + meta['product'], + tokens) def each_chunk(self): for text in each_chunk(self.fh, CHUNK_SEP, CHUNK_STRIP_CHARS): yield self.parse_chunk(text) - def each_obs(self): + def load_soundings(self): 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): - for chunk in self.each_chunk(): - yield from chunk.each_sounding() + sounding = self.sounding(station, timestamp) + + for sample in samples: + sounding.record(sample) + + for key in self.soundings: + yield self.soundings[key].finish() @staticmethod def each_sounding_from_fh(fh: io.TextIOBase): reader = RAOBReader(fh) - yield from reader.each_sounding() + for sounding in reader.load_soundings(): + yield sounding @staticmethod def each_sounding_from_file(path: str):