11import ephem
22import numpy as np
3+ import xarray as xr
34
45from mwr_raw2l1 .errors import UnknownManufacturer
56from mwr_raw2l1 .log import logger
@@ -26,6 +27,11 @@ def check_receiver_sanity(data, channel):
2627 masks_and_checks = [] # collect all output tuples from flag_check here
2728 masks_and_checks .append (flag_check (data , 'channel_quality_ok' , 0 , channel ))
2829 masks_and_checks .append (flag_check (data , 'alarm' , 1 , channel = None ))
30+ masks_and_checks .append (flag_check (data , 'noisediode_ok_hum' , 0 , channel = None ))
31+ masks_and_checks .append (flag_check (data , 'noisediode_ok_temp' , 0 , channel = None ))
32+ masks_and_checks .append (flag_check (data , 'Tstab_ok_hum' , 0 , channel = None ))
33+ masks_and_checks .append (flag_check (data , 'Tstab_ok_temp' , 0 , channel = None ))
34+ masks_and_checks .append (flag_check (data , 'Tstab_ok_amb' , 0 , channel = None ))
2935 # TODO: could add checks for noisediode_ok_hum, noisediode_ok_temp, Tstab_ok_hum, Tstab_ok_temp, Tstab_ok_amb
3036 check_applied_all = [m [1 ] for m in masks_and_checks ]
3137 if any (check_applied_all ):
@@ -164,3 +170,73 @@ def flag_check(data, varname, value, channel=None):
164170 else :
165171 logger .info ("Cannot apply check for '{}' during quality control as variable does not exist" .format (varname ))
166172 return None , False
173+
174+ def find_lwcl_from_mwr (data , multiplying_factor = 0.075 ):
175+ """
176+ This is a copy of the MWRpy function to find liquid water cloud free periods using 31.4 GHz TB variability.
177+ It uses water vapor channel as proxy for a humidity dependent threshold.
178+
179+ For now, it works only for HATPRO instrument as this includes some empirically derived parameters.
180+
181+ Refactored to work directly with xarray data instead of dict
182+
183+ Args:
184+ data: dataset, commonly Measurement.data
185+ multiplying_factor: factor to multiply the threshold with, empirically derived
186+
187+ Returns:
188+ dataset with liquid cloud flag set
189+ """
190+ # Different frequencies for window and water vapor channels depending on instrument type
191+ freq_win = np .where (
192+ (np .isclose (data ["frequency" ].values , 31.4 , atol = 2 ))
193+ | (np .isclose (data ["frequency" ].values , 190.8 , atol = 1 ))
194+ )[0 ]
195+ freq_win = np .array ([freq_win [0 ]]) if len (freq_win ) > 1 else freq_win
196+ freq_wv = np .where (
197+ (np .isclose (np .round (data ["frequency" ][:], 1 ), 22.2 ))
198+ | (np .isclose (np .round (data ["frequency" ][:], 1 ), 183.9 ))
199+ )[0 ]
200+
201+ if len (freq_win ) == 1 and len (freq_wv ) == 1 :
202+ tb = data ["Tb" ].isel (frequency = freq_win )
203+ tb = tb .squeeze (dim = 'frequency' , drop = True )
204+ tb_zenith = tb .where (data ["scanflag" ] == 0 , drop = True ).where ((data ["ele" ] > 89.0 ) & (data ["ele" ] < 91.0 ), drop = True )
205+ mean_diff_t = np .nanmean (tb .time .diff (dim = 'time' ).dt .seconds )
206+ number_of_samples = 180 / mean_diff_t .round () if mean_diff_t < 1.8 else 180 / mean_diff_t .round ()
207+ # tb_std = tb_df.rolling(
208+ # pd.tseries.frequencies.to_offset(offset), center=True, min_periods=50
209+ # ).std()
210+ tb_std = tb_zenith .rolling (
211+ time = int (number_of_samples ), center = True
212+ ).std ()
213+ number_of_samples = 600 / mean_diff_t .round () if mean_diff_t < 1.8 else 600 / mean_diff_t .round ()
214+ # tb_mx = tb_std.rolling(
215+ # pd.tseries.frequencies.to_offset(offset), center=True, min_periods=100
216+ # ).max()
217+ tb_mx = tb_std .rolling (
218+ time = int (number_of_samples ), center = True
219+ ).max ()
220+ #tb_wv = np.squeeze(ds["tb"][:, freq_wv])
221+ tb_wv = data ["Tb" ].isel (frequency = freq_wv )
222+ tb_wv = tb_wv .squeeze (dim = 'frequency' , drop = True )
223+ # In order to compute the ratio, we need to get rid of the frequency coordinates
224+
225+ tb_rat = tb_wv / tb
226+ tb_rat = tb_rat .rolling (
227+ time = int (number_of_samples ), center = True
228+ ).max ()
229+
230+ threshold_rat = tb_rat * multiplying_factor
231+
232+
233+ data ['liquid_cloud_flag' ] = xr .where (
234+ tb_mx < threshold_rat ,
235+ 0 ,
236+ 1
237+ )
238+ data ['liquid_cloud_flag' ] = xr .where ((data ["ele" ] > 89.0 ) & (data ["ele" ] < 91.0 ), data ['liquid_cloud_flag' ], 2 )
239+ # also fill nans with 2
240+ data ['liquid_cloud_flag' ] = data ['liquid_cloud_flag' ].fillna (2 )
241+
242+ return data
0 commit comments