From f9ce6783d4e4200cff22fc4c4f43253256cbda80 Mon Sep 17 00:00:00 2001 From: Baudouin Raoult Date: Thu, 16 May 2024 06:07:48 +0000 Subject: [PATCH 1/3] add alpha --- src/anemoi/datasets/compute/perturbations.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/anemoi/datasets/compute/perturbations.py b/src/anemoi/datasets/compute/perturbations.py index f86c1256..7e0321d4 100644 --- a/src/anemoi/datasets/compute/perturbations.py +++ b/src/anemoi/datasets/compute/perturbations.py @@ -58,6 +58,7 @@ def perturbations( members, center, clip_variables=CLIP_VARIABLES, + alpha=1.0, output=None, ): @@ -130,7 +131,7 @@ def perturbations( assert e.shape == c.shape == m.shape, (e.shape, c.shape, m.shape) - x = c - m + e + x = c + (e - m) * alpha if param in clip_variables: # LOG.warning(f"Clipping {param} to be positive") From 0f2292862328766cdfc430f3ff194e02cb369cb9 Mon Sep 17 00:00:00 2001 From: Baudouin Raoult Date: Thu, 16 May 2024 06:10:18 +0000 Subject: [PATCH 2/3] renem center to centre --- docs/building/sources/perturbations.rst | 10 ++--- src/anemoi/datasets/compute/perturbations.py | 42 +++++++++---------- .../create/functions/sources/perturbations.py | 6 +-- src/anemoi/datasets/grids.py | 4 +- 4 files changed, 31 insertions(+), 31 deletions(-) diff --git a/docs/building/sources/perturbations.rst b/docs/building/sources/perturbations.rst index 400b12ad..2085d22a 100644 --- a/docs/building/sources/perturbations.rst +++ b/docs/building/sources/perturbations.rst @@ -7,15 +7,15 @@ Perturbations refers to the small variations centered around a nominal value of a parameter. When dealing with `ensemble forecasting`_, the perturbations are related to the difference between `ensemble members` -and their given `center`. +and their given `centre`. The `perturbations` function computes a set of new ensemble members -centered on a different center from previous ensemble members using the +centered on a different centre from previous ensemble members using the following formula: .. math:: - members_{new} = center + ( members - \overline{members} ) + members_{new} = centre + ( members - \overline{members} ) Additionally, some variables must be non-negative to have a physical meaning (e.g. accumulated variables or `specific humidity`). To ensure @@ -23,7 +23,7 @@ this, positive clipping is performed using the alternative fomula : .. math:: - members_{new} = max(0, center + ( members - \overline{members} )) + members_{new} = max(0, centre + ( members - \overline{members} )) The current implementation enforces that following variables are positive when using the `perturbations` function : @@ -45,7 +45,7 @@ It uses the following arguments: members A :ref:`reference ` to the ensemble members. -center +centre A :ref:`reference ` to the new center requested. Examples diff --git a/src/anemoi/datasets/compute/perturbations.py b/src/anemoi/datasets/compute/perturbations.py index 7e0321d4..f88b4119 100644 --- a/src/anemoi/datasets/compute/perturbations.py +++ b/src/anemoi/datasets/compute/perturbations.py @@ -32,7 +32,7 @@ SKIP = ("class", "stream", "type", "number", "expver", "_leg_number", "anoffset") -def check_compatible(f1, f2, center_field_as_mars, ensemble_field_as_mars): +def check_compatible(f1, f2, centre_field_as_mars, ensemble_field_as_mars): assert f1.mars_grid == f2.mars_grid, (f1.mars_grid, f2.mars_grid) assert f1.mars_area == f2.mars_area, (f1.mars_area, f2.mars_area) assert f1.shape == f2.shape, (f1.shape, f2.shape) @@ -43,12 +43,12 @@ def check_compatible(f1, f2, center_field_as_mars, ensemble_field_as_mars): f2.metadata("valid_datetime"), ) - for k in set(center_field_as_mars.keys()) | set(ensemble_field_as_mars.keys()): + for k in set(centre_field_as_mars.keys()) | set(ensemble_field_as_mars.keys()): if k in SKIP: continue - assert center_field_as_mars[k] == ensemble_field_as_mars[k], ( + assert centre_field_as_mars[k] == ensemble_field_as_mars[k], ( k, - center_field_as_mars[k], + centre_field_as_mars[k], ensemble_field_as_mars[k], ) @@ -56,7 +56,7 @@ def check_compatible(f1, f2, center_field_as_mars, ensemble_field_as_mars): def perturbations( *, members, - center, + centre, clip_variables=CLIP_VARIABLES, alpha=1.0, output=None, @@ -71,16 +71,16 @@ def perturbations( LOG.info("Ordering fields") members = members.order_by(*keys) - center = center.order_by(*keys) + centre = centre.order_by(*keys) LOG.info("Done") - if len(center) * n_numbers != len(members): - LOG.error("%s %s %s", len(center), n_numbers, len(members)) + if len(centre) * n_numbers != len(members): + LOG.error("%s %s %s", len(centre), n_numbers, len(members)) for f in members: LOG.error("Member: %r", f) - for f in center: - LOG.error("Center: %r", f) - raise ValueError(f"Inconsistent number of fields: {len(center)} * {n_numbers} != {len(members)}") + for f in centre: + LOG.error("centre: %r", f) + raise ValueError(f"Inconsistent number of fields: {len(centre)} * {n_numbers} != {len(members)}") if output is None: # prepare output tmp file so we can read it back @@ -94,32 +94,32 @@ def perturbations( seen = set() - for i, center_field in enumerate(center): - param = center_field.metadata("param") - center_field_as_mars = center_field.as_mars() + for i, centre_field in enumerate(centre): + param = centre_field.metadata("param") + centre_field_as_mars = centre_field.as_mars() - # load the center field - center_np = center_field.to_numpy() + # load the centre field + centre_np = centre_field.to_numpy() # load the ensemble fields and compute the mean - members_np = np.zeros((n_numbers, *center_np.shape)) + members_np = np.zeros((n_numbers, *centre_np.shape)) for j in range(n_numbers): ensemble_field = members[i * n_numbers + j] ensemble_field_as_mars = ensemble_field.as_mars() - check_compatible(center_field, ensemble_field, center_field_as_mars, ensemble_field_as_mars) + check_compatible(centre_field, ensemble_field, centre_field_as_mars, ensemble_field_as_mars) members_np[j] = ensemble_field.to_numpy() ensemble_field_as_mars = tuple(sorted(ensemble_field_as_mars.items())) assert ensemble_field_as_mars not in seen, ensemble_field_as_mars seen.add(ensemble_field_as_mars) - # cmin=np.amin(center_np) + # cmin=np.amin(centre_np) # emin=np.amin(members_np) # if cmin < 0 and emin >= 0: # LOG.warning(f"Negative values in {param} cmin={cmin} emin={emin}") - # LOG.warning(f"Center: {center_field_as_mars}") + # LOG.warning(f"centre: {centre_field_as_mars}") mean_np = members_np.mean(axis=0) @@ -127,7 +127,7 @@ def perturbations( template = members[i * n_numbers + j] e = members_np[j] m = mean_np - c = center_np + c = centre_np assert e.shape == c.shape == m.shape, (e.shape, c.shape, m.shape) diff --git a/src/anemoi/datasets/create/functions/sources/perturbations.py b/src/anemoi/datasets/create/functions/sources/perturbations.py index 53428da8..e3c44f59 100644 --- a/src/anemoi/datasets/create/functions/sources/perturbations.py +++ b/src/anemoi/datasets/create/functions/sources/perturbations.py @@ -50,10 +50,10 @@ def load_if_needed(context, dates, dict_or_dataset): return dict_or_dataset -def perturbations(context, dates, members, center, remapping={}, patches={}): +def perturbations(context, dates, members, centre, remapping={}, patches={}): members = load_if_needed(context, dates, members) - center = load_if_needed(context, dates, center) - return compute_perturbations(members, center) + centre = load_if_needed(context, dates, centre) + return compute_perturbations(members, centre) execute = perturbations diff --git a/src/anemoi/datasets/grids.py b/src/anemoi/datasets/grids.py index 1646eedb..e4df47ee 100644 --- a/src/anemoi/datasets/grids.py +++ b/src/anemoi/datasets/grids.py @@ -178,7 +178,7 @@ def cutout_mask( min_dlats = np.min(np.diff(glats)) min_dlons = np.min(np.diff(glons)) - # Use the center of the LAM grid as the reference point + # Use the centre of the LAM grid as the reference point centre = np.mean(lats), np.mean(lons) centre_xyz = np.array(latlon_to_xyz(*centre)) @@ -198,7 +198,7 @@ def cutout_mask( t = Triangle3D(lam_points[index[0]], lam_points[index[1]], lam_points[index[2]]) # distance = np.min(distance) # The point is inside the triangle if the intersection with the ray - # from the point to the center of the Earth is not None + # from the point to the centre of the Earth is not None # (the direction of the ray is not important) intersect = t.intersect(zero, global_point) From a66db0bd0bec77ba60393bdd99b54fd1541f3d74 Mon Sep 17 00:00:00 2001 From: Baudouin Raoult Date: Thu, 16 May 2024 06:20:06 +0000 Subject: [PATCH 3/3] rename perturbations to recentre --- docs/building/sources.rst | 2 +- .../{perturbations.rst => recentre.rst} | 16 ++++++++-------- .../compute/{perturbations.py => recentre.py} | 2 +- .../sources/{perturbations.py => recentre.py} | 8 ++++---- .../{perturbations.yaml => recentre.yaml} | 18 +++++++++--------- tests/create/test_create.py | 2 +- 6 files changed, 24 insertions(+), 24 deletions(-) rename docs/building/sources/{perturbations.rst => recentre.rst} (87%) rename src/anemoi/datasets/compute/{perturbations.py => recentre.py} (99%) rename src/anemoi/datasets/create/functions/sources/{perturbations.py => recentre.py} (86%) rename tests/create/{perturbations.yaml => recentre.yaml} (87%) diff --git a/docs/building/sources.rst b/docs/building/sources.rst index d81990e1..99fb8415 100644 --- a/docs/building/sources.rst +++ b/docs/building/sources.rst @@ -15,4 +15,4 @@ The following `sources` are currently available: sources/opendap sources/forcings sources/accumulations - sources/perturbations + sources/recentre diff --git a/docs/building/sources/perturbations.rst b/docs/building/sources/recentre.rst similarity index 87% rename from docs/building/sources/perturbations.rst rename to docs/building/sources/recentre.rst index 2085d22a..f095ef26 100644 --- a/docs/building/sources/perturbations.rst +++ b/docs/building/sources/recentre.rst @@ -1,17 +1,17 @@ -.. _perturbations: +.. _recentre: -############### - perturbations -############### +########## + recentre +########## Perturbations refers to the small variations centered around a nominal value of a parameter. When dealing with `ensemble forecasting`_, the perturbations are related to the difference between `ensemble members` and their given `centre`. -The `perturbations` function computes a set of new ensemble members -centered on a different centre from previous ensemble members using the -following formula: +The `recentre` function computes a set of new ensemble members centered +on a different centre from previous ensemble members using the following +formula: .. math:: @@ -50,7 +50,7 @@ centre Examples -.. literalinclude:: yaml/perturbations.yaml +.. literalinclude:: yaml/recentre.yaml :language: yaml .. _convective precipitation: https://codes.ecmwf.int/grib/param-db/?id=143 diff --git a/src/anemoi/datasets/compute/perturbations.py b/src/anemoi/datasets/compute/recentre.py similarity index 99% rename from src/anemoi/datasets/compute/perturbations.py rename to src/anemoi/datasets/compute/recentre.py index f88b4119..4759fafd 100644 --- a/src/anemoi/datasets/compute/perturbations.py +++ b/src/anemoi/datasets/compute/recentre.py @@ -53,7 +53,7 @@ def check_compatible(f1, f2, centre_field_as_mars, ensemble_field_as_mars): ) -def perturbations( +def recentre( *, members, centre, diff --git a/src/anemoi/datasets/create/functions/sources/perturbations.py b/src/anemoi/datasets/create/functions/sources/recentre.py similarity index 86% rename from src/anemoi/datasets/create/functions/sources/perturbations.py rename to src/anemoi/datasets/create/functions/sources/recentre.py index e3c44f59..6c56d9c8 100644 --- a/src/anemoi/datasets/create/functions/sources/perturbations.py +++ b/src/anemoi/datasets/create/functions/sources/recentre.py @@ -8,7 +8,7 @@ # from copy import deepcopy -from anemoi.datasets.compute.perturbations import perturbations as compute_perturbations +from anemoi.datasets.compute.recentre import recentre as compute_perturbations from .mars import mars @@ -50,10 +50,10 @@ def load_if_needed(context, dates, dict_or_dataset): return dict_or_dataset -def perturbations(context, dates, members, centre, remapping={}, patches={}): +def recentre(context, dates, members, centre, alpha=1.0, remapping={}, patches={}): members = load_if_needed(context, dates, members) centre = load_if_needed(context, dates, centre) - return compute_perturbations(members, centre) + return compute_perturbations(members, centre, alpha=alpha) -execute = perturbations +execute = recentre diff --git a/tests/create/perturbations.yaml b/tests/create/recentre.yaml similarity index 87% rename from tests/create/perturbations.yaml rename to tests/create/recentre.yaml index 4bf70abb..8aad587f 100644 --- a/tests/create/perturbations.yaml +++ b/tests/create/recentre.yaml @@ -36,7 +36,7 @@ common: type: an number: [1, 2, 4] # number: [1, 2, 3, 4, 5, 6, 7, 8, 9] - center: ¢er + centre: ¢re stream: oper type: an @@ -53,27 +53,27 @@ data_sources: - accumulations: <<: *ensembles <<: *acc - center: + centre: join: - mars: - <<: *center + <<: *centre <<: *sfc - mars: - <<: *center + <<: *centre <<: *pl - accumulations: - <<: *center + <<: *centre <<: *acc input: join: - - perturbations: + - recentre: # the ensemble data which has one additional dimension members: ${data_sources.ensembles} - # the new center of the data - center: ${data_sources.center} + # the new centre of the data + centre: ${data_sources.centre} - forcings: - template: ${input.join.0.perturbations} + template: ${input.join.0.recentre} param: - cos_latitude - cos_longitude diff --git a/tests/create/test_create.py b/tests/create/test_create.py index 7edb68f8..0c33908d 100755 --- a/tests/create/test_create.py +++ b/tests/create/test_create.py @@ -29,7 +29,7 @@ HERE = os.path.dirname(__file__) # find_yamls NAMES = sorted([os.path.basename(path).split(".")[0] for path in glob.glob(os.path.join(HERE, "*.yaml"))]) -SKIP = ["perturbations"] +SKIP = ["recentre"] NAMES = [name for name in NAMES if name not in SKIP] assert NAMES, "No yaml files found in " + HERE