MetOffice / CSET

Toolkit for evaluation and investigation of numerical models for weather and climate applications.
https://metoffice.github.io/CSET/
Apache License 2.0
10 stars 4 forks source link

Allow recipes to take variables on full and half levels #732

Open Sylviabohnenstengel opened 3 months ago

Sylviabohnenstengel commented 3 months ago

What problem does your feature request solve?

At the moment we can only process variables on either full_levels or half_levels with the same recipe. This is annoying for the user as they need to only provide variables on full or alternatively on half levels. Is there a way to allow full or half levels as a consttraint in a yaml file?

Describe the solution you'd like

rose-meta: split LFRIC_MODEL_LEVEL_MODEL_FIELDS into LFRIC_FULL_LEVEL_MODEL_FIELDS and LFRIC_HALF_LEVEL_MODEL_FIELDS.

generic_histogram_series.yaml: : split into 2 yaml files. One dealing with full and the other with half levels

deterministic_domain_histogram_series.cylc: modify first loop to loop over full levels. then copy that section and append and loop over half levels.

That way the user only needs to enable a single script.

We need to modify all recipes to loop over full_levels and half levels

Describe alternatives you've considered

@jfrost-mo I assume there is no way to generate a constraint that allows full or half levels as alternatives in a single constraint?

is there a way to create an optional constraint for full and half levels. When the cube gets loaded it gets asssessed if the coordinate exists and if true the optional constraint is applied. The problem with this is that we would not be able to reject cubes that don't have either of the full or half levels if they are surface variables and might end up with too many dimensions,.

Sylviabohnenstengel commented 3 months ago

def generate_optional_constraint(coordinate: str, levels: int | list[int]) -> iris.Constraint: def optional_constraint(cube):

Check if the cube has the specified coordinate

    if cube.coords(coordinate):
        # If it does, apply the constraint
        return cube.extract(iris.Constraint(**{coordinate: levels})) is not None
    else:
        # If it doesn't, don't apply the constraint
        return True
return iris.Constraint(cube_func=optional_constraint)
Sylviabohnenstengel commented 3 months ago

Alternative:`{% if DOMAIN_HISTOGRAM_SERIES_FIELD %} [runtime] {% for model_field in LFRIC_FULL_LEVEL_MODEL_FIELDS %} {% for mlevel in LFRIC_MODEL_LEVELS %} [[pre_process_deterministic_domain_histogramseries{{modelfield}}{{mlevel}}]] inherit = PARALLEL [[[environment]]] CSET_RECIPE_NAME = "generic_histogram_series.yaml" CSET_ADDOPTS = "--VARNAME='{{model_field}}' --MLEVEL='{{mlevel}}'"

[[collate_deterministic_domain_histogram_series_{{model_field}}_{{mlevel}}]]
inherit = COLLATE
    [[[environment]]]
    CSET_RECIPE_NAME = "generic_histogram_series.yaml"
    CSET_ADDOPTS = "--VARNAME='{{model_field}}' --MLEVEL='{{mlevel}}'"

{% endfor %} {% endfor %}

repeat above block with half llevel fields {% endif %} `

jwarner8 commented 1 month ago

@jfrost-mo was there any thinking around this? Finding this could be a bottleneck now, given the umified data doesn't work due to spurious model-level coords. In the meantime, I might just write a quick script that goes through umified data and corrects the model level coord for the quick look this month at least.

jfrost-mo commented 1 month ago

Nothing more than what is written here. The two approaches are either adding a separate recipe for half levels, or adding/changing the level constraint operator to support multiple coordinates.