From 61689bab2a35b83654fd1611780927ece04e9482 Mon Sep 17 00:00:00 2001 From: Vincent LHEUREUX Date: Tue, 17 Sep 2024 13:23:46 +0200 Subject: [PATCH 01/11] adding wind_convention parameters ; need to be up to date with xsarsea --- grdwindinversion/config_prod.yaml | 1 + grdwindinversion/inversion.py | 121 ++++++++++++++++++++++++------ tests/config_test.yaml | 1 + 3 files changed, 101 insertions(+), 22 deletions(-) diff --git a/grdwindinversion/config_prod.yaml b/grdwindinversion/config_prod.yaml index 2a83c2a..ed019f1 100644 --- a/grdwindinversion/config_prod.yaml +++ b/grdwindinversion/config_prod.yaml @@ -1,4 +1,5 @@ no_subdir: True +wind_convention: "oceanographic" S1A: GMF_VV_NAME: "gmf_cmod5n" GMF_VH_NAME: "gmf_s1_v2" diff --git a/grdwindinversion/inversion.py b/grdwindinversion/inversion.py index 44136c9..aa650fa 100644 --- a/grdwindinversion/inversion.py +++ b/grdwindinversion/inversion.py @@ -224,7 +224,7 @@ def inverse(dual_pol, inc, sigma0, sigma0_dual, ancillary_wind, dsig_cr, model_v sigma0 to be inverted for dualpol ancillary_wind=: xarray.DataArray (numpy.complex28) ancillary wind - | (for example ecmwf winds), in **GMF convention** (-np.conj included), + | (for example ecmwf winds), in **ANTENNA convention**, dsig_cr=: float or xarray.DataArray parameters used for @@ -237,7 +237,7 @@ def inverse(dual_pol, inc, sigma0, sigma0_dual, ancillary_wind, dsig_cr, model_v Returns ------- xarray.DataArray or tuple - inverted wind in **gmf convention** . + inverted wind in ** antenna convention** . See Also -------- @@ -532,6 +532,7 @@ def preprocess(filename, outdir, config_path, overwrite=False, add_streaks=False Loader=yaml.FullLoader ) try: + # check if sensor is in the config config = config_base[sensor] except Exception: raise KeyError("sensor %s not in this config" % sensor) @@ -543,6 +544,19 @@ def preprocess(filename, outdir, config_path, overwrite=False, add_streaks=False meta = fct_meta(filename) no_subdir_cfg = config_base.get("no_subdir", False) + config["no_subdir"] = no_subdir_cfg + + if "wind_convention" in config_base: + wind_convention = config_base["wind_convention"] + else: + wind_convention = "meteorological" + logging.warning( + f"Using meteorological convention because wind_convention was not found in config.") + config["wind_convention"] = wind_convention + + # creating a dictionnary of parameters + config["l2_params"] = {} + out_file = getOutputName2(filename, outdir, sensor, meta, subdir=not no_subdir_cfg) @@ -610,6 +624,15 @@ def preprocess(filename, outdir, config_path, overwrite=False, add_streaks=False model_vv = config["GMF_"+copol_gmf+"_NAME"] model_vh = config["GMF_"+crosspol_gmf+"_NAME"] + # register paramaters in config + config["l2_params"]["dual_pol"] = dual_pol + config["l2_params"]["copol"] = copol + config["l2_params"]["crosspol"] = crosspol + config["l2_params"]["copol_gmf"] = copol_gmf + config["l2_params"]["crosspol_gmf"] = crosspol_gmf + config["l2_params"]["model_vv"] = model_vv + config["l2_params"]["model_vh"] = model_vh + # need to load gmfs before inversion gmfs_impl = [x for x in [model_vv, model_vh] if "gmf_" in x] windspeed.gmfs.GmfModel.activate_gmfs_impl(gmfs_impl) @@ -705,7 +728,7 @@ def preprocess(filename, outdir, config_path, overwrite=False, add_streaks=False xr_dataset['ancillary_wind_speed'].attrs['standart_name'] = 'wind_speed' xr_dataset['ancillary_wind'] = xr.where(xr_dataset['mask'], np.nan, - (xr_dataset.ancillary_wind_speed * np.exp(1j * xsarsea.dir_geo_to_sample(xr_dataset.ancillary_wind_direction, xr_dataset.ground_heading))).compute()).transpose( + (xr_dataset.ancillary_wind_speed * np.exp(1j * xsarsea.dir_meteo_to_sample(xr_dataset.ancillary_wind_direction, xr_dataset.ground_heading))).compute()).transpose( *xr_dataset['ancillary_wind_speed'].dims) xr_dataset.attrs['ancillary_source'] = xr_dataset['model_U10'].attrs['history'].split('decoded: ')[ @@ -806,7 +829,7 @@ def preprocess(filename, outdir, config_path, overwrite=False, add_streaks=False xr_dataset['streaks_direction'] = get_streaks( xr_dataset, xr_dataset_100) - return xr_dataset, dual_pol, copol, crosspol, copol_gmf, crosspol_gmf, model_vv, model_vh, sigma0_ocean_cross, dsig_cross, sensor_longname, out_file, config + return xr_dataset, sigma0_ocean_cross, dsig_cross, sensor_longname, out_file, config def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, add_streaks=False, resolution='1000m'): @@ -836,9 +859,17 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, add final dataset """ - xr_dataset, dual_pol, copol, crosspol, copol_gmf, crosspol_gmf, model_vv, model_vh, sigma0_ocean_cross, dsig_cross, sensor_longname, out_file, config = preprocess( + xr_dataset, sigma0_ocean_cross, dsig_cross, sensor_longname, out_file, config = preprocess( filename, outdir, config_path, overwrite, add_streaks, resolution) + model_vv = config["l2_params"]["model_vv"] + model_vh = config["l2_params"]["model_vh"] + copol = config["l2_params"]["copol"] + crosspol = config["l2_params"]["crosspol"] + copol_gmf = config["l2_params"]["copol_gmf"] + crosspol_gmf = config["l2_params"]["crosspol_gmf"] + dual_pol = config["l2_params"]["dual_pol"] + kwargs = { "inc_step_lr": config.pop("inc_step_lr", None), "wpsd_step_lr": config.pop("wspd_step_lr", None), @@ -859,6 +890,8 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, add model_vv=model_vv, model_vh=model_vh, ** kwargs) + wind_co.compute() + wind_dual.compute() # windspeed_co xr_dataset['windspeed_co'] = np.abs(wind_co) @@ -870,13 +903,9 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, add del xr_dataset["windspeed_co"].attrs['comment'] # winddir_co - xr_dataset['winddir_co'] = ( - 90 - (np.angle(wind_co, deg=True)) + xr_dataset.ground_heading) % 360 - xr_dataset["winddir_co"].attrs["units"] = "degrees_north" - xr_dataset["winddir_co"].attrs["long_name"] = "Wind direction in meteorological convention, 0=North, 90=East, inverted from model %s (%s)" % ( - model_vv, copol) - xr_dataset["winddir_co"].attrs["standart_name"] = "wind_direction" - xr_dataset["winddir_co"].attrs["model"] = wind_co.attrs["model"] + xr_dataset['winddir_co'] = transform_winddir( + wind_co, xr_dataset.ground_heading, convention=config["wind_convention"]) + xr_dataset['winddir_co'].attrs["model"] = "%s (%s)" % (model_vv, copol) # windspeed_dual / windspeed_cr / /winddir_dual / winddir_cr if dual_pol: @@ -888,13 +917,10 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, add xr_dataset["windspeed_dual"].attrs["model"] = wind_dual.attrs["model"] del xr_dataset["windspeed_dual"].attrs['comment'] - xr_dataset['winddir_dual'] = ( - 90 - (np.angle(wind_dual, deg=True)) + xr_dataset.ground_heading) % 360 - xr_dataset["winddir_dual"].attrs["units"] = "degrees_north" - xr_dataset["winddir_dual"].attrs["long_name"] = "Wind direction in meteorological convention, 0=North, 90=East inverted from model %s (%s) & %s (%s)" % ( + xr_dataset['winddir_dual'] = transform_winddir( + wind_dual, xr_dataset.ground_heading, convention=config["wind_convention"]) + xr_dataset['winddir_dual'].attrs["model"] = "%s (%s) & %s (%s)" % ( model_vv, copol, model_vh, crosspol) - xr_dataset["winddir_dual"].attrs["standart_name"] = "wind_direction" - xr_dataset["winddir_dual"].attrs["model"] = wind_dual.attrs["model"] xr_dataset = xr_dataset.assign( windspeed_cross=(['line', 'sample'], windspeed_cr)) @@ -905,11 +931,15 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, add xr_dataset["windspeed_cross"].attrs["model"] = "%s" % (model_vh) xr_dataset['winddir_cross'] = xr_dataset['winddir_dual'].copy() - xr_dataset["winddir_cross"].attrs["units"] = "degrees_north" - xr_dataset["winddir_cross"].attrs["long_name"] = "Wind direction in meteorological convention, 0=North, 90=East, copied from dualpol" - xr_dataset["winddir_cross"].attrs["standart_name"] = "wind_direction" + xr_dataset['winddir_cross'].attrs = xr_dataset['winddir_dual'].attrs xr_dataset["winddir_cross"].attrs["model"] = "No model used ; content is a copy of dualpol wind direction" + if config["wind_convention"] == "oceanographic": + attrs = xr_dataset['ancillary_wind_direction'].attrs + xr_dataset['ancillary_wind_direction'] = xsarsea.dir_meteo_to_oceano( + xr_dataset['ancillary_wind_direction']) + xr_dataset['ancillary_wind_direction'].attrs = attrs + xr_dataset, encoding = makeL2asOwi( xr_dataset, dual_pol, copol, crosspol, add_streaks=add_streaks) @@ -960,7 +990,8 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, add "wnf_3km_average": "False", "owiWindSpeedSrc": "owiWindSpeed", "owiWindDirectionSrc": "/", - "ancillary_source": xr_dataset.attrs['ancillary_source'] + "ancillary_source": xr_dataset.attrs['ancillary_source'], + "wind_convention": config["wind_convention"] } for recalib_attrs in ["path_aux_pp1_new", 'path_aux_pp1_old', "path_aux_cal_new", "path_aux_cal_old"]: @@ -1000,3 +1031,49 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, add logging.info("OK for %s ", os.path.basename(filename)) return out_file, xr_dataset + + +def transform_winddir(wind_cpx, ground_heading, convention='meteorological'): + """ + + Parameters + ---------- + wind_cpx : xr.DataArray | np.complex64 + complex wind, relative to antenna, anticlockwise + + ground_heading : xr.DataArray + heading angle in degrees + + convention : str + convention to use, either 'meteorological' or 'oceanographic' + + Returns + ------- + xr.DataArray + wind direction in degrees in the selected convention with appropriate long_name attribute + """ + # to meteo convention + dataArray = xsarsea.dir_sample_to_meteo( + np.angle(wind_cpx, deg=True), ground_heading) + long_name = "Wind direction in meteorological convention (clockwise, from), ex: 0°=from north, 90°=from east" + + if convention == "meteorological": + # do nothing + pass + elif convention == "oceanographic": + # to oceano convention + dataArray = xsarsea.dir_meteo_to_oceano(dataArray) + long_name = "Wind direction in oceanographic convention (clockwise, to), ex: 0°=to north, 90°=to east" + else: + #  warning + logging.warning( + f"convention {convention} is not supported, using meteorological",) + long_name = "Wind direction in meteorological convention (clockwise, from), ex: 0°=from north, 90°=from east" + + dataArray = xsarsea.dir_to_360(dataArray) + dataArray.attrs = {} + dataArray.attrs["units"] = "degrees_north" + dataArray.attrs["long_name"] = long_name + dataArray.attrs["standart_name"] = "wind_direction" + + return dataArray diff --git a/tests/config_test.yaml b/tests/config_test.yaml index 2a83c2a..92337e8 100644 --- a/tests/config_test.yaml +++ b/tests/config_test.yaml @@ -1,4 +1,5 @@ no_subdir: True +convention: "meteorological" S1A: GMF_VV_NAME: "gmf_cmod5n" GMF_VH_NAME: "gmf_s1_v2" From e82d432a4ee0548be44abbd2ff962407e65ed400 Mon Sep 17 00:00:00 2001 From: Vincent LHEUREUX Date: Tue, 17 Sep 2024 15:46:41 +0200 Subject: [PATCH 02/11] change attrs for oceano ancillary wind direction --- grdwindinversion/config_prod.yaml | 2 +- grdwindinversion/inversion.py | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/grdwindinversion/config_prod.yaml b/grdwindinversion/config_prod.yaml index ed019f1..dc6625d 100644 --- a/grdwindinversion/config_prod.yaml +++ b/grdwindinversion/config_prod.yaml @@ -1,5 +1,5 @@ no_subdir: True -wind_convention: "oceanographic" +wind_convention: "meteorological" S1A: GMF_VV_NAME: "gmf_cmod5n" GMF_VH_NAME: "gmf_s1_v2" diff --git a/grdwindinversion/inversion.py b/grdwindinversion/inversion.py index aa650fa..ef483d4 100644 --- a/grdwindinversion/inversion.py +++ b/grdwindinversion/inversion.py @@ -713,7 +713,7 @@ def preprocess(filename, outdir, config_path, overwrite=False, add_streaks=False xr_dataset['ancillary_wind_direction'].attrs = {} xr_dataset['ancillary_wind_direction'].attrs['units'] = 'degrees_north' xr_dataset['ancillary_wind_direction'].attrs[ - 'long_name'] = f'{ancillary_name} wind direction (meteorological convention)' + 'long_name'] = f'{ancillary_name} wind direction in meteorological convention (clockwise, from), ex: 0°=from north, 90°=from east' xr_dataset['ancillary_wind_direction'].attrs['standart_name'] = 'wind_direction' xr_dataset['ancillary_wind_speed'] = np.sqrt( @@ -869,6 +869,7 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, add copol_gmf = config["l2_params"]["copol_gmf"] crosspol_gmf = config["l2_params"]["crosspol_gmf"] dual_pol = config["l2_params"]["dual_pol"] + ancillary_name = config["ancillary"] kwargs = { "inc_step_lr": config.pop("inc_step_lr", None), @@ -939,6 +940,8 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, add xr_dataset['ancillary_wind_direction'] = xsarsea.dir_meteo_to_oceano( xr_dataset['ancillary_wind_direction']) xr_dataset['ancillary_wind_direction'].attrs = attrs + xr_dataset['ancillary_wind_direction'].attrs[ + "long_name"] = f"{ancillary_name} wind direction in oceanographic convention (clockwise, to), ex: 0°=to north, 90°=to east" xr_dataset, encoding = makeL2asOwi( xr_dataset, dual_pol, copol, crosspol, add_streaks=add_streaks) From 822688e2312765a36a2b38413b4bad5017410784 Mon Sep 17 00:00:00 2001 From: Vincent LHEUREUX Date: Thu, 19 Sep 2024 08:09:53 +0200 Subject: [PATCH 03/11] renamed wind_convention to winddir_convention --- grdwindinversion/config_prod.yaml | 2 +- grdwindinversion/inversion.py | 34 +++++++++++++++---------------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/grdwindinversion/config_prod.yaml b/grdwindinversion/config_prod.yaml index dc6625d..4e34246 100644 --- a/grdwindinversion/config_prod.yaml +++ b/grdwindinversion/config_prod.yaml @@ -1,5 +1,5 @@ no_subdir: True -wind_convention: "meteorological" +winddir_convention: "meteorological" S1A: GMF_VV_NAME: "gmf_cmod5n" GMF_VH_NAME: "gmf_s1_v2" diff --git a/grdwindinversion/inversion.py b/grdwindinversion/inversion.py index ef483d4..da209aa 100644 --- a/grdwindinversion/inversion.py +++ b/grdwindinversion/inversion.py @@ -546,13 +546,13 @@ def preprocess(filename, outdir, config_path, overwrite=False, add_streaks=False no_subdir_cfg = config_base.get("no_subdir", False) config["no_subdir"] = no_subdir_cfg - if "wind_convention" in config_base: - wind_convention = config_base["wind_convention"] + if "winddir_convention" in config_base: + winddir_convention = config_base["winddir_convention"] else: - wind_convention = "meteorological" + winddir_convention = "meteorological" logging.warning( - f"Using meteorological convention because wind_convention was not found in config.") - config["wind_convention"] = wind_convention + f'Using meteorological convention because "winddir_convention" was not found in config.') + config["winddir_convention"] = winddir_convention # creating a dictionnary of parameters config["l2_params"] = {} @@ -905,7 +905,7 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, add # winddir_co xr_dataset['winddir_co'] = transform_winddir( - wind_co, xr_dataset.ground_heading, convention=config["wind_convention"]) + wind_co, xr_dataset.ground_heading, convention=config["winddir_convention"]) xr_dataset['winddir_co'].attrs["model"] = "%s (%s)" % (model_vv, copol) # windspeed_dual / windspeed_cr / /winddir_dual / winddir_cr @@ -919,7 +919,7 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, add del xr_dataset["windspeed_dual"].attrs['comment'] xr_dataset['winddir_dual'] = transform_winddir( - wind_dual, xr_dataset.ground_heading, convention=config["wind_convention"]) + wind_dual, xr_dataset.ground_heading, convention=config["winddir_convention"]) xr_dataset['winddir_dual'].attrs["model"] = "%s (%s) & %s (%s)" % ( model_vv, copol, model_vh, crosspol) @@ -935,7 +935,7 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, add xr_dataset['winddir_cross'].attrs = xr_dataset['winddir_dual'].attrs xr_dataset["winddir_cross"].attrs["model"] = "No model used ; content is a copy of dualpol wind direction" - if config["wind_convention"] == "oceanographic": + if config["winddir_convention"] == "oceanographic": attrs = xr_dataset['ancillary_wind_direction'].attrs xr_dataset['ancillary_wind_direction'] = xsarsea.dir_meteo_to_oceano( xr_dataset['ancillary_wind_direction']) @@ -994,7 +994,7 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, add "owiWindSpeedSrc": "owiWindSpeed", "owiWindDirectionSrc": "/", "ancillary_source": xr_dataset.attrs['ancillary_source'], - "wind_convention": config["wind_convention"] + "winddir_convention": config["winddir_convention"] } for recalib_attrs in ["path_aux_pp1_new", 'path_aux_pp1_old', "path_aux_cal_new", "path_aux_cal_old"]: @@ -1036,7 +1036,7 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, add return out_file, xr_dataset -def transform_winddir(wind_cpx, ground_heading, convention='meteorological'): +def transform_winddir(wind_cpx, ground_heading, winddir_convention='meteorological'): """ Parameters @@ -1047,30 +1047,30 @@ def transform_winddir(wind_cpx, ground_heading, convention='meteorological'): ground_heading : xr.DataArray heading angle in degrees - convention : str - convention to use, either 'meteorological' or 'oceanographic' + winddir_convention : str + wind direction convention to use, either 'meteorological' or 'oceanographic' Returns ------- xr.DataArray wind direction in degrees in the selected convention with appropriate long_name attribute """ - # to meteo convention + # to meteo winddir_convention dataArray = xsarsea.dir_sample_to_meteo( np.angle(wind_cpx, deg=True), ground_heading) long_name = "Wind direction in meteorological convention (clockwise, from), ex: 0°=from north, 90°=from east" - if convention == "meteorological": + if winddir_convention == "meteorological": # do nothing pass - elif convention == "oceanographic": - # to oceano convention + elif winddir_convention == "oceanographic": + # to oceano winddir_convention dataArray = xsarsea.dir_meteo_to_oceano(dataArray) long_name = "Wind direction in oceanographic convention (clockwise, to), ex: 0°=to north, 90°=to east" else: #  warning logging.warning( - f"convention {convention} is not supported, using meteorological",) + f"wind direction convention {winddir_convention} is not supported, using meteorological",) long_name = "Wind direction in meteorological convention (clockwise, from), ex: 0°=from north, 90°=from east" dataArray = xsarsea.dir_to_360(dataArray) From 15277d0d8333b717ba4a36aabb31dfb9dd9b969b Mon Sep 17 00:00:00 2001 From: Vincent LHEUREUX Date: Thu, 19 Sep 2024 09:16:06 +0200 Subject: [PATCH 04/11] preprocess now returns xr_dataset, out_file & config --- grdwindinversion/inversion.py | 50 +++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/grdwindinversion/inversion.py b/grdwindinversion/inversion.py index da209aa..464d915 100644 --- a/grdwindinversion/inversion.py +++ b/grdwindinversion/inversion.py @@ -632,6 +632,7 @@ def preprocess(filename, outdir, config_path, overwrite=False, add_streaks=False config["l2_params"]["crosspol_gmf"] = crosspol_gmf config["l2_params"]["model_vv"] = model_vv config["l2_params"]["model_vh"] = model_vh + config["sensor_longname"] = sensor_longname # need to load gmfs before inversion gmfs_impl = [x for x in [model_vv, model_vh] if "gmf_" in x] @@ -779,15 +780,13 @@ def preprocess(filename, outdir, config_path, overwrite=False, add_streaks=False xr_dataset.nesz_cross_final.attrs['long_name'] = 'Noise Equivalent SigmaNaught' # dsig - sigma0_ocean_cross = xr_dataset['sigma0_ocean'].sel(pol=crosspol) xr_dataset["dsig_cross"] = windspeed.get_dsig(config["dsig_"+crosspol_gmf+"_NAME"], xr_dataset.incidence, - sigma0_ocean_cross, xr_dataset.nesz_cross_final) + xr_dataset['sigma0_ocean'].sel(pol=crosspol), xr_dataset.nesz_cross_final) xr_dataset.dsig_cross.attrs['comment'] = 'variable used to ponderate copol and crosspol' - dsig_cross = xr_dataset.dsig_cross - else: - sigma0_ocean_cross = None - dsig_cross = 0.1 # default value set in xsarsea + xr_dataset.dsig_cross.attrs['formula_used'] = config["dsig_" + + crosspol_gmf+"_NAME"] + xr_dataset.dsig_cross.attrs['apply_flattening'] = config["apply_flattening"] if ((recalibration) & ("SENTINEL" in sensor_longname)): xr_dataset.attrs["path_aux_pp1_new"] = os.path.basename(os.path.dirname( @@ -810,17 +809,19 @@ def preprocess(filename, outdir, config_path, overwrite=False, add_streaks=False xr_dataset_100['sigma0_detrend'] = xsarsea.sigma0_detrend( xr_dataset_100.sigma0.sel(pol=copol), xr_dataset_100.incidence, model=model_vv) - xr_dataset_100['sigma0_detrend_cross'] = xsarsea.sigma0_detrend( - xr_dataset_100.sigma0.sel(pol=crosspol), xr_dataset_100.incidence, model=model_vh) + if dual_pol: + xr_dataset_100['sigma0_detrend_cross'] = xsarsea.sigma0_detrend( + xr_dataset_100.sigma0.sel(pol=crosspol), xr_dataset_100.incidence, model=model_vh) + + sigma0_detrend_combined = xr.concat( + [xr_dataset_100['sigma0_detrend'], + xr_dataset_100['sigma0_detrend_cross']], + dim='pol' + ) + sigma0_detrend_combined['pol'] = [copol, crosspol] - sigma0_detrend_combined = xr.concat( - [xr_dataset_100['sigma0_detrend'], - xr_dataset_100['sigma0_detrend_cross']], - dim='pol' - ) - sigma0_detrend_combined['pol'] = [copol, crosspol] + xr_dataset_100['sigma0_detrend'] = sigma0_detrend_combined - xr_dataset_100['sigma0_detrend'] = sigma0_detrend_combined xr_dataset_100.land_mask.values = binary_dilation(xr_dataset_100['land_mask'].values.astype('uint8'), structure=np.ones((3, 3), np.uint8), iterations=3) xr_dataset_100['sigma0_detrend'] = xr.where( @@ -829,7 +830,7 @@ def preprocess(filename, outdir, config_path, overwrite=False, add_streaks=False xr_dataset['streaks_direction'] = get_streaks( xr_dataset, xr_dataset_100) - return xr_dataset, sigma0_ocean_cross, dsig_cross, sensor_longname, out_file, config + return xr_dataset, out_file, config def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, add_streaks=False, resolution='1000m'): @@ -859,7 +860,7 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, add final dataset """ - xr_dataset, sigma0_ocean_cross, dsig_cross, sensor_longname, out_file, config = preprocess( + xr_dataset, out_file, config = preprocess( filename, outdir, config_path, overwrite, add_streaks, resolution) model_vv = config["l2_params"]["model_vv"] @@ -870,6 +871,14 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, add crosspol_gmf = config["l2_params"]["crosspol_gmf"] dual_pol = config["l2_params"]["dual_pol"] ancillary_name = config["ancillary"] + sensor_longname = config["sensor_longname"] + + if dual_pol: + sigma0_ocean_cross = xr_dataset['sigma0_ocean'].sel(pol=crosspol) + dsig_cross = xr_dataset['dsig_cross'] + else: + sigma0_ocean_cross = None + dsig_cross = 0.1 # default value set in xsarsea kwargs = { "inc_step_lr": config.pop("inc_step_lr", None), @@ -892,7 +901,8 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, add model_vh=model_vh, ** kwargs) wind_co.compute() - wind_dual.compute() + if dual_pol and wind_dual is not None: + wind_dual.compute() # windspeed_co xr_dataset['windspeed_co'] = np.abs(wind_co) @@ -905,7 +915,7 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, add # winddir_co xr_dataset['winddir_co'] = transform_winddir( - wind_co, xr_dataset.ground_heading, convention=config["winddir_convention"]) + wind_co, xr_dataset.ground_heading, winddir_convention=config["winddir_convention"]) xr_dataset['winddir_co'].attrs["model"] = "%s (%s)" % (model_vv, copol) # windspeed_dual / windspeed_cr / /winddir_dual / winddir_cr @@ -919,7 +929,7 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, add del xr_dataset["windspeed_dual"].attrs['comment'] xr_dataset['winddir_dual'] = transform_winddir( - wind_dual, xr_dataset.ground_heading, convention=config["winddir_convention"]) + wind_dual, xr_dataset.ground_heading, winddir_convention=config["winddir_convention"]) xr_dataset['winddir_dual'].attrs["model"] = "%s (%s) & %s (%s)" % ( model_vv, copol, model_vh, crosspol) From e1ca8e668070943b92c7d4968ffbe42938ce69ce Mon Sep 17 00:00:00 2001 From: Vincent LHEUREUX Date: Fri, 20 Sep 2024 05:48:09 +0200 Subject: [PATCH 05/11] check incidence withing LUT incidence range --- grdwindinversion/inversion.py | 77 +++++++++++++++++--------------- grdwindinversion/main.py | 2 +- grdwindinversion/utils.py | 73 +++++++++++++++--------------- grdwindinversion/utils_memory.py | 46 +++++++++++++++++++ 4 files changed, 127 insertions(+), 71 deletions(-) create mode 100644 grdwindinversion/utils_memory.py diff --git a/grdwindinversion/inversion.py b/grdwindinversion/inversion.py index 464d915..b16bca4 100644 --- a/grdwindinversion/inversion.py +++ b/grdwindinversion/inversion.py @@ -16,6 +16,7 @@ import string import os from grdwindinversion.streaks import get_streaks +from grdwindinversion.utils import check_incidence_range from grdwindinversion.load_config import getConf # optional debug messages import logging @@ -208,7 +209,7 @@ def getAncillary(meta, ancillary_name='ecmwf'): ancillary_name) -def inverse(dual_pol, inc, sigma0, sigma0_dual, ancillary_wind, dsig_cr, model_vv, model_vh, **kwargs): +def inverse(dual_pol, inc, sigma0, sigma0_dual, ancillary_wind, dsig_cr, model_co, model_cross, **kwargs): """ Invert sigma0 to retrieve wind using model (lut or gmf). @@ -229,9 +230,9 @@ def inverse(dual_pol, inc, sigma0, sigma0_dual, ancillary_wind, dsig_cr, model_v parameters used for | `Jsig_cr=((sigma0_gmf - sigma0) / dsig_cr) ** 2` - model_vv=: str + model_co=: str model to use for VV or HH polarization. - model_vh=: str + model_cross=: str model to use for VH or HV polarization. Returns @@ -248,12 +249,12 @@ def inverse(dual_pol, inc, sigma0, sigma0_dual, ancillary_wind, dsig_cr, model_v list_mods = windspeed.available_models().index.tolist( ) + windspeed.available_models().alias.tolist() + [None] - if model_vv not in list_mods: + if model_co not in list_mods: raise ValueError( - f"model_vv {model_vv} not in windspeed.available_models() : not going further") - if model_vh not in list_mods: + f"model_co {model_co} not in windspeed.available_models() : not going further") + if model_cross not in list_mods: raise ValueError( - f"model_vh {model_vh} not in windspeed.available_models() : not going further") + f"model_cross {model_cross} not in windspeed.available_models() : not going further") winds = windspeed.invert_from_model( inc, @@ -261,7 +262,7 @@ def inverse(dual_pol, inc, sigma0, sigma0_dual, ancillary_wind, dsig_cr, model_v sigma0_dual, ancillary_wind=ancillary_wind, dsig_cr=dsig_cr, - model=(model_vv, model_vh), + model=(model_co, model_cross), **kwargs) if dual_pol: @@ -271,7 +272,7 @@ def inverse(dual_pol, inc, sigma0, sigma0_dual, ancillary_wind, dsig_cr, model_v inc.values, sigma0_dual.values, dsig_cr=dsig_cr.values, - model=model_vh, + model=model_cross, **kwargs) return wind_co, wind_dual, wind_cross @@ -621,8 +622,8 @@ def preprocess(filename, outdir, config_path, overwrite=False, add_streaks=False copol_gmf = 'HH' crosspol_gmf = 'VH' - model_vv = config["GMF_"+copol_gmf+"_NAME"] - model_vh = config["GMF_"+crosspol_gmf+"_NAME"] + model_co = config["GMF_"+copol_gmf+"_NAME"] + model_cross = config["GMF_"+crosspol_gmf+"_NAME"] # register paramaters in config config["l2_params"]["dual_pol"] = dual_pol @@ -630,25 +631,25 @@ def preprocess(filename, outdir, config_path, overwrite=False, add_streaks=False config["l2_params"]["crosspol"] = crosspol config["l2_params"]["copol_gmf"] = copol_gmf config["l2_params"]["crosspol_gmf"] = crosspol_gmf - config["l2_params"]["model_vv"] = model_vv - config["l2_params"]["model_vh"] = model_vh + config["l2_params"]["model_co"] = model_co + config["l2_params"]["model_cross"] = model_cross config["sensor_longname"] = sensor_longname # need to load gmfs before inversion - gmfs_impl = [x for x in [model_vv, model_vh] if "gmf_" in x] + gmfs_impl = [x for x in [model_co, model_cross] if "gmf_" in x] windspeed.gmfs.GmfModel.activate_gmfs_impl(gmfs_impl) - sarwings_luts = [x for x in [model_vv, model_vh] + sarwings_luts = [x for x in [model_co, model_cross] if x.startswith("sarwing_lut_")] if len(sarwings_luts) > 0: windspeed.register_sarwing_luts(getConf()["sarwing_luts_path"]) - nc_luts = [x for x in [model_vv, model_vh] if x.startswith("nc_lut")] + nc_luts = [x for x in [model_co, model_cross] if x.startswith("nc_lut")] if len(nc_luts) > 0: windspeed.register_nc_luts(getConf()["nc_luts_path"]) - if (model_vv == "gmf_cmod7"): + if (model_co == "gmf_cmod7"): windspeed.register_cmod7(getConf()["lut_cmod7_path"]) #  Step 2 - clean and prepare dataset @@ -758,13 +759,13 @@ def preprocess(filename, outdir, config_path, overwrite=False, add_streaks=False xr_dataset['sigma0_ocean_raw'].attrs = xr_dataset['sigma0_raw'].attrs xr_dataset['sigma0_detrend'] = xsarsea.sigma0_detrend( - xr_dataset.sigma0.sel(pol=copol), xr_dataset.incidence, model=model_vv) + xr_dataset.sigma0.sel(pol=copol), xr_dataset.incidence, model=model_co) # processing if dual_pol: xr_dataset['sigma0_detrend_cross'] = xsarsea.sigma0_detrend( - xr_dataset.sigma0.sel(pol=crosspol), xr_dataset.incidence, model=model_vh) + xr_dataset.sigma0.sel(pol=crosspol), xr_dataset.incidence, model=model_cross) if config["apply_flattening"]: xr_dataset = xr_dataset.assign(nesz_cross_final=( ['line', 'sample'], windspeed.nesz_flattening(xr_dataset.nesz.sel(pol=crosspol), xr_dataset.incidence))) @@ -807,11 +808,11 @@ def preprocess(filename, outdir, config_path, overwrite=False, add_streaks=False # adding sigma0 detrend xr_dataset_100['sigma0_detrend'] = xsarsea.sigma0_detrend( - xr_dataset_100.sigma0.sel(pol=copol), xr_dataset_100.incidence, model=model_vv) + xr_dataset_100.sigma0.sel(pol=copol), xr_dataset_100.incidence, model=model_co) if dual_pol: xr_dataset_100['sigma0_detrend_cross'] = xsarsea.sigma0_detrend( - xr_dataset_100.sigma0.sel(pol=crosspol), xr_dataset_100.incidence, model=model_vh) + xr_dataset_100.sigma0.sel(pol=crosspol), xr_dataset_100.incidence, model=model_cross) sigma0_detrend_combined = xr.concat( [xr_dataset_100['sigma0_detrend'], @@ -863,8 +864,8 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, add xr_dataset, out_file, config = preprocess( filename, outdir, config_path, overwrite, add_streaks, resolution) - model_vv = config["l2_params"]["model_vv"] - model_vh = config["l2_params"]["model_vh"] + model_co = config["l2_params"]["model_co"] + model_cross = config["l2_params"]["model_cross"] copol = config["l2_params"]["copol"] crosspol = config["l2_params"]["crosspol"] copol_gmf = config["l2_params"]["copol_gmf"] @@ -890,6 +891,11 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, add "resolution": config.pop("resolution", None), } + logging.info("Checking incidence range within LUTS incidence range") + #  warning if incidence is out of lut incidence range + inc_check_co, inc_check_cross = check_incidence_range( + xr_dataset['incidence'], [model_co, model_cross], **kwargs) + wind_co, wind_dual, windspeed_cr = inverse(dual_pol, inc=xr_dataset['incidence'], sigma0=xr_dataset['sigma0_ocean'].sel( @@ -897,18 +903,16 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, add sigma0_dual=sigma0_ocean_cross, ancillary_wind=xr_dataset['ancillary_wind'], dsig_cr=dsig_cross, - model_vv=model_vv, - model_vh=model_vh, + model_co=model_co, + model_cross=model_cross, ** kwargs) wind_co.compute() - if dual_pol and wind_dual is not None: - wind_dual.compute() # windspeed_co xr_dataset['windspeed_co'] = np.abs(wind_co) xr_dataset["windspeed_co"].attrs["units"] = "m.s⁻1" xr_dataset["windspeed_co"].attrs["long_name"] = "Wind speed inverted from model %s (%s)" % ( - model_vv, copol) + model_co, copol) xr_dataset["windspeed_co"].attrs["standart_name"] = "wind_speed" xr_dataset["windspeed_co"].attrs["model"] = wind_co.attrs["model"] del xr_dataset["windspeed_co"].attrs['comment'] @@ -916,14 +920,15 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, add # winddir_co xr_dataset['winddir_co'] = transform_winddir( wind_co, xr_dataset.ground_heading, winddir_convention=config["winddir_convention"]) - xr_dataset['winddir_co'].attrs["model"] = "%s (%s)" % (model_vv, copol) + xr_dataset['winddir_co'].attrs["model"] = "%s (%s)" % (model_co, copol) # windspeed_dual / windspeed_cr / /winddir_dual / winddir_cr - if dual_pol: + if dual_pol and wind_dual is not None: + wind_dual.compute() xr_dataset['windspeed_dual'] = np.abs(wind_dual) xr_dataset["windspeed_dual"].attrs["units"] = "m.s⁻1" xr_dataset["windspeed_dual"].attrs["long_name"] = "Wind speed inverted from model %s (%s) & %s (%s)" % ( - model_vv, copol, model_vh, crosspol) + model_co, copol, model_cross, crosspol) xr_dataset["windspeed_dual"].attrs["standart_name"] = "wind_speed" xr_dataset["windspeed_dual"].attrs["model"] = wind_dual.attrs["model"] del xr_dataset["windspeed_dual"].attrs['comment'] @@ -931,15 +936,15 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, add xr_dataset['winddir_dual'] = transform_winddir( wind_dual, xr_dataset.ground_heading, winddir_convention=config["winddir_convention"]) xr_dataset['winddir_dual'].attrs["model"] = "%s (%s) & %s (%s)" % ( - model_vv, copol, model_vh, crosspol) + model_co, copol, model_cross, crosspol) xr_dataset = xr_dataset.assign( windspeed_cross=(['line', 'sample'], windspeed_cr)) xr_dataset["windspeed_cross"].attrs["units"] = "m.s⁻1" xr_dataset["windspeed_cross"].attrs["long_name"] = "Wind Speed inverted from model %s (%s)" % ( - model_vh, crosspol) + model_cross, crosspol) xr_dataset["windspeed_cross"].attrs["standart_name"] = "wind_speed" - xr_dataset["windspeed_cross"].attrs["model"] = "%s" % (model_vh) + xr_dataset["windspeed_cross"].attrs["model"] = "%s" % (model_cross) xr_dataset['winddir_cross'] = xr_dataset['winddir_dual'].copy() xr_dataset['winddir_cross'].attrs = xr_dataset['winddir_dual'].attrs @@ -1004,7 +1009,9 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, add "owiWindSpeedSrc": "owiWindSpeed", "owiWindDirectionSrc": "/", "ancillary_source": xr_dataset.attrs['ancillary_source'], - "winddir_convention": config["winddir_convention"] + "winddir_convention": config["winddir_convention"], + "incidence_within_lut_copol_incidence_range": str(inc_check_co), + "incidence_within_lut_crosspol_incidence_range": str(inc_check_cross) } for recalib_attrs in ["path_aux_pp1_new", 'path_aux_pp1_old', "path_aux_cal_new", "path_aux_cal_old"]: diff --git a/grdwindinversion/main.py b/grdwindinversion/main.py index 4f460c5..d9456d6 100644 --- a/grdwindinversion/main.py +++ b/grdwindinversion/main.py @@ -1,5 +1,5 @@ from grdwindinversion.inversion import makeL2 -from grdwindinversion.utils import get_memory_usage +from grdwindinversion.utils_memory import get_memory_usage import grdwindinversion import time import logging diff --git a/grdwindinversion/utils.py b/grdwindinversion/utils.py index 01ff9db..25bf3ad 100644 --- a/grdwindinversion/utils.py +++ b/grdwindinversion/utils.py @@ -1,42 +1,45 @@ -def get_memory_usage(unit='Go', var='ru_maxrss', force_psutil=False): - """ - var str: ru_maxrss or ru_ixrss or ru_idrss or ru_isrss or current - Returns - ------- +import logging +import xsarsea + +def check_incidence_range(incidence, models, **kwargs): """ - if unit == 'Go': - factor = 1000000. - elif unit == 'Mo': - factor = 1000. - elif unit == 'Ko': - factor = 1. - else: - raise Exception('not handle unit') + Check if the incidence range of the dataset is within the range of the LUT of the model. + If not, warn the user : inversion will be approximate. - try: - if force_psutil: - on_purpose_error - import resource - mems = {} - mems['ru_maxrss'] = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss / factor - mems['ru_ixrss'] = resource.getrusage(resource.RUSAGE_SELF).ru_ixrss / factor - mems['ru_idrss'] = resource.getrusage(resource.RUSAGE_SELF).ru_idrss / factor - mems['ru_isrss'] = resource.getrusage(resource.RUSAGE_SELF).ru_isrss / factor - mems['current'] = getCurrentMemoryUsage() / factor - # memory_used_go = resource.getrusage(resource.RUSAGE_SELF).get(var) /factor - memory_used_go = mems[var] - except: # on windows resource is not usable - import psutil - memory_used_go = psutil.virtual_memory().used / factor / 1000. - str_mem = 'RAM usage: %1.1f %s' % (memory_used_go, unit) - return str_mem + Parameters + ---------- + incidence : xr.DataArray + incidence angle in degrees + models : list of str + list of model names + Returns + ------- + list of bool + for each model, + True if the incidence range is within the range of the LUT of the model (correct) + False otherwise + """ + if isinstance(models, str): + models = [models] + elif not isinstance(models, list): + raise TypeError("models should be a string or a list of strings") -def getCurrentMemoryUsage(): - ''' Memory usage in kB ''' + rets = [] + for model_name in models: + lut_range = xsarsea.windspeed.get_model(model_name).inc_range + if 'inc_range' in kwargs: + logging.debug( + f"GMF {model_name} inc_range will be changed by kwargs to {kwargs['inc_range']}") + lut_range = kwargs['inc_range'] - with open('/proc/self/status') as f: - memusage = f.read().split('VmRSS:')[1].split('\n')[0][:-3] + inc_range = [incidence.values.min(), incidence.values.max()] + if (inc_range[0] >= lut_range[0] and inc_range[1] <= lut_range[1]): + rets.append(True) + else: + logging.warn( + f"incidence range {inc_range} is not within the range of the LUT of the model {model_name} {lut_range} : inversion will be approximate using LUT minmium|maximum incidences") + rets.append(False) - return int(memusage.strip()) + return rets diff --git a/grdwindinversion/utils_memory.py b/grdwindinversion/utils_memory.py new file mode 100644 index 0000000..a938a44 --- /dev/null +++ b/grdwindinversion/utils_memory.py @@ -0,0 +1,46 @@ +def get_memory_usage(unit='Go', var='ru_maxrss', force_psutil=False): + """ + var str: ru_maxrss or ru_ixrss or ru_idrss or ru_isrss or current + Returns + ------- + + """ + if unit == 'Go': + factor = 1000000. + elif unit == 'Mo': + factor = 1000. + elif unit == 'Ko': + factor = 1. + else: + raise Exception('not handle unit') + + try: + if force_psutil: + on_purpose_error + import resource + mems = {} + mems['ru_maxrss'] = resource.getrusage( + resource.RUSAGE_SELF).ru_maxrss / factor + mems['ru_ixrss'] = resource.getrusage( + resource.RUSAGE_SELF).ru_ixrss / factor + mems['ru_idrss'] = resource.getrusage( + resource.RUSAGE_SELF).ru_idrss / factor + mems['ru_isrss'] = resource.getrusage( + resource.RUSAGE_SELF).ru_isrss / factor + mems['current'] = getCurrentMemoryUsage() / factor + # memory_used_go = resource.getrusage(resource.RUSAGE_SELF).get(var) /factor + memory_used_go = mems[var] + except: # on windows resource is not usable + import psutil + memory_used_go = psutil.virtual_memory().used / factor / 1000. + str_mem = 'RAM usage: %1.1f %s' % (memory_used_go, unit) + return str_mem + + +def getCurrentMemoryUsage(): + ''' Memory usage in kB ''' + + with open('/proc/self/status') as f: + memusage = f.read().split('VmRSS:')[1].split('\n')[0][:-3] + + return int(memusage.strip()) From 2a115b9d7918a0c6cc96aa225263faf88dc7430d Mon Sep 17 00:00:00 2001 From: Vincent LHEUREUX Date: Mon, 23 Sep 2024 07:58:17 +0200 Subject: [PATCH 06/11] changed output format for rcm --- .github/workflows/ci.yml | 2 +- grdwindinversion/inversion.py | 11 ++++++----- grdwindinversion/utils.py | 25 +++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1487469..f0c874d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: test: runs-on: ubuntu-latest timeout-minutes: 360 # 6 hours limit for the job - + steps: # Checkout the code - name: Checkout code diff --git a/grdwindinversion/inversion.py b/grdwindinversion/inversion.py index b16bca4..14a4612 100644 --- a/grdwindinversion/inversion.py +++ b/grdwindinversion/inversion.py @@ -16,7 +16,7 @@ import string import os from grdwindinversion.streaks import get_streaks -from grdwindinversion.utils import check_incidence_range +from grdwindinversion.utils import check_incidence_range, get_pol_ratio_name from grdwindinversion.load_config import getConf # optional debug messages import logging @@ -97,11 +97,12 @@ def getOutputName2(input_file, outdir, sensor, meta, subdir=True): elif sensor == 'RCM': regex = re.compile( "([A-Z0-9]+)_OK([0-9]+)_PK([0-9]+)_(.*?)_(.*?)_(.*?)_(.*?)_(.*?)_(.*?)_(.*?)") + RCM1_OK2767220_PK2769320_1_SCLND_20230930_214014_VV_VH_GRD template = string.Template( - "${MISSIONID}_OK${DATA1}_PK${DATA2}_${DATA3}_${DATA4}_${DATE}_${TIME}_${POLARIZATION1}_${POLARIZATION2}_${PRODUCT}") + "${MISSIONID}_OK${DATA1}_PK${DATA2}_${DATA3}_${BEAM_MODE}_${DATE}_${TIME}_${POLARIZATION1}_${POLARIZATION2}_${PRODUCT}") match = regex.match(basename_match) - MISSIONID, DATA1, DATA2, DATA3, DATA4, DATE, TIME, POLARIZATION1, POLARIZATION2, LAST = match.groups() - new_format = f"{MISSIONID.lower()}--owi-xx-{meta_start_date.lower()}-{meta_stop_date.lower()}-_____-_____.nc" + MISSIONID, DATA1, DATA2, DATA3, BEAM_MODE, DATE, TIME, POLARIZATION1, POLARIZATION2, LAST = match.groups() + new_format = f"{MISSIONID.lower()}-{BEAM_MODE.lower()}-owi-xx-{meta_start_date.lower()}-{meta_stop_date.lower()}-_____-_____.nc" else: raise ValueError( "sensor must be S1A|S1B|RS2|RCM, got sensor %s" % sensor) @@ -991,7 +992,7 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, add "xsar_version": xsar.__version__, "xsarsea_version": xsarsea.__version__, "pythonVersion": f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}", - "polarisationRatio": "/", + "polarisationRatio": get_pol_ratio_name(model_co), "l2ProcessingUtcTime": datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ"), "processingCenter": "IFREMER", "firstMeasurementTime": firstMeasurementTime, diff --git a/grdwindinversion/utils.py b/grdwindinversion/utils.py index 25bf3ad..72ca4d3 100644 --- a/grdwindinversion/utils.py +++ b/grdwindinversion/utils.py @@ -43,3 +43,28 @@ def check_incidence_range(incidence, models, **kwargs): rets.append(False) return rets + + +def get_pol_ratio_name(model_co): + """ + Return polarization ration name of copol model + + Parameters + ---------- + model_co : str + copol model name + + Returns + ------- + str + if pol = 'HH', return polarization ratio name ; else return '/' + """ + + model = xsarsea.windspeed.get_model(model_co) + if model.pol == 'HH': + try: + return model.model + except AttributeError: + return "not_written_in_lut" + else: + return '/' From 68dc430980c1ea8249fde7a3b8e05ba01355be50 Mon Sep 17 00:00:00 2001 From: Vincent LHEUREUX Date: Mon, 23 Sep 2024 08:31:35 +0200 Subject: [PATCH 07/11] get polarization name in attrs --- grdwindinversion/inversion.py | 1 - grdwindinversion/utils.py | 15 ++++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/grdwindinversion/inversion.py b/grdwindinversion/inversion.py index 14a4612..f5ca80d 100644 --- a/grdwindinversion/inversion.py +++ b/grdwindinversion/inversion.py @@ -97,7 +97,6 @@ def getOutputName2(input_file, outdir, sensor, meta, subdir=True): elif sensor == 'RCM': regex = re.compile( "([A-Z0-9]+)_OK([0-9]+)_PK([0-9]+)_(.*?)_(.*?)_(.*?)_(.*?)_(.*?)_(.*?)_(.*?)") - RCM1_OK2767220_PK2769320_1_SCLND_20230930_214014_VV_VH_GRD template = string.Template( "${MISSIONID}_OK${DATA1}_PK${DATA2}_${DATA3}_${BEAM_MODE}_${DATE}_${TIME}_${POLARIZATION1}_${POLARIZATION2}_${PRODUCT}") match = regex.match(basename_match) diff --git a/grdwindinversion/utils.py b/grdwindinversion/utils.py index 72ca4d3..014ee0c 100644 --- a/grdwindinversion/utils.py +++ b/grdwindinversion/utils.py @@ -63,7 +63,20 @@ def get_pol_ratio_name(model_co): model = xsarsea.windspeed.get_model(model_co) if model.pol == 'HH': try: - return model.model + import re + + def check_format(s): + pattern = r'^([a-zA-Z0-9]+)_R(high|low)_hh_([a-zA-Z0-9_]+)$' + match = re.match(pattern, s) + if match: + vvgmf, res, polrationame = match.groups() + return polrationame + else: + logging.warn( + f"String format is not correct for polarization ratio name = {s}\nReturning '/'") + return "/" + get_pol_ratio_name = check_format(model_co) + return get_pol_ratio_name except AttributeError: return "not_written_in_lut" else: From b064aee33873849e66698f6852b582f53c5be5aa Mon Sep 17 00:00:00 2001 From: Vincent LHEUREUX Date: Mon, 23 Sep 2024 10:04:46 +0200 Subject: [PATCH 08/11] little change in args --- grdwindinversion/inversion.py | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/grdwindinversion/inversion.py b/grdwindinversion/inversion.py index f5ca80d..d6feb74 100644 --- a/grdwindinversion/inversion.py +++ b/grdwindinversion/inversion.py @@ -787,7 +787,8 @@ def preprocess(filename, outdir, config_path, overwrite=False, add_streaks=False xr_dataset.dsig_cross.attrs['comment'] = 'variable used to ponderate copol and crosspol' xr_dataset.dsig_cross.attrs['formula_used'] = config["dsig_" + crosspol_gmf+"_NAME"] - xr_dataset.dsig_cross.attrs['apply_flattening'] = config["apply_flattening"] + xr_dataset.dsig_cross.attrs['apply_flattening'] = str( + config["apply_flattening"]) if ((recalibration) & ("SENTINEL" in sensor_longname)): xr_dataset.attrs["path_aux_pp1_new"] = os.path.basename(os.path.dirname( @@ -1011,25 +1012,29 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, add "ancillary_source": xr_dataset.attrs['ancillary_source'], "winddir_convention": config["winddir_convention"], "incidence_within_lut_copol_incidence_range": str(inc_check_co), - "incidence_within_lut_crosspol_incidence_range": str(inc_check_cross) + "incidence_within_lut_crosspol_incidence_range": str(inc_check_cross), + "swath": xr_dataset.attrs['swath'], + "footprint": xr_dataset.attrs['footprint'], + "coverage": xr_dataset.attrs['coverage'], + } for recalib_attrs in ["path_aux_pp1_new", 'path_aux_pp1_old', "path_aux_cal_new", "path_aux_cal_old"]: if recalib_attrs in xr_dataset.attrs: attrs[recalib_attrs] = xr_dataset.attrs[recalib_attrs] - # new one to match convention - _S1_added_attrs = ["product", "ipf", "multi_dataset", "footprint", - "coverage", "orbit_pass", "platform_heading"] - _RS2_added_attrs = ["passDirection", "swath", "footprint", "coverage"] - _RCM_added_attrs = ["swath", "footprint", "coverage", "productId",] + for arg in ["passDirection", "orbit_pass"]: + if arg in xr_dataset.attrs: + attrs["passDirection"] = xr_dataset.attrs[arg] + + _S1_added_attrs = ["ipf", "platform_heading"] + _RCM_added_attrs = ["productId"] - for sup_attr in _S1_added_attrs + _RS2_added_attrs + _RCM_added_attrs: + for sup_attr in _S1_added_attrs + _RCM_added_attrs: if sup_attr in xr_dataset.attrs: attrs[sup_attr] = xr_dataset.attrs[sup_attr] - for var in ['footprint', 'multidataset']: - if var in attrs: - attrs[var] = str(attrs[var]) + + attrs['footprint'] = str(attrs['footprint']) # add in kwargs in attrs for key in kwargs: From 3a3e57cb82828fae7816a87360ff7e852f886118 Mon Sep 17 00:00:00 2001 From: Skealz Date: Mon, 23 Sep 2024 14:40:57 +0200 Subject: [PATCH 09/11] Update ci.yml to use another channel --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f0c874d..f3d0c09 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,7 +39,7 @@ jobs: run: | eval "$(micromamba shell hook --shell bash)" micromamba activate grdwind_env - conda install --use-local grdwindinversion -y + conda install --use-local grdwindinversion -y -c conda-forge -c tcevaer # Cache the test data if previously downloaded (up to 10 GB limit for the cache) # WARNING : modify the key if the data is modified !! From 474192648b5f902e5f464384df9e0ba8db99cf3f Mon Sep 17 00:00:00 2001 From: Skealz Date: Mon, 23 Sep 2024 14:59:27 +0200 Subject: [PATCH 10/11] Update ci.yml, also add channel to build step --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f3d0c09..5987a2d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,7 +32,7 @@ jobs: cd recipe eval "$(micromamba shell hook --shell bash)" micromamba activate grdwind_env - conda mambabuild . + conda mambabuild . -c conda-forge -c tcevaer # Install the built package into the environment - name: Install the built package From 1b491f7d5ab704da26818339d9a3dbed82ad8168 Mon Sep 17 00:00:00 2001 From: Skealz Date: Mon, 23 Sep 2024 16:06:02 +0200 Subject: [PATCH 11/11] Update ci.yml, try to install updated package from other channel --- .github/workflows/ci.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5987a2d..a650501 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,25 +21,26 @@ jobs: - uses: mamba-org/setup-micromamba@v1 with: micromamba-version: "1.5.9-1" # any version from https://github.com/mamba-org/micromamba-releases + channels: tcevaer, conda-forge, defaults init-shell: bash post-cleanup: "all" - name: Create environment and install tools - run: micromamba create -n grdwind_env pytest conda-build boa python=3.10 -y + run: micromamba create -n grdwind_env pytest conda-build boa python=3.10 -y -c tcevaer -c conda-forge - name: Build package run: | cd recipe eval "$(micromamba shell hook --shell bash)" micromamba activate grdwind_env - conda mambabuild . -c conda-forge -c tcevaer + conda mambabuild . -c tcevaer -c conda-forge # Install the built package into the environment - name: Install the built package run: | eval "$(micromamba shell hook --shell bash)" micromamba activate grdwind_env - conda install --use-local grdwindinversion -y -c conda-forge -c tcevaer + conda install --use-local grdwindinversion -y -c tcevaer -c conda-forge # Cache the test data if previously downloaded (up to 10 GB limit for the cache) # WARNING : modify the key if the data is modified !!