Skip to content

Add the Ability to Load and Save External Metadata - #173

Open
Theo Geddes (mo-tgeddes) wants to merge 95 commits into
MetOffice:mainfrom
mo-tgeddes:load_save_feature_branch
Open

Theo Geddes (mo-tgeddes) wants to merge 95 commits into
MetOffice:mainfrom
mo-tgeddes:load_save_feature_branch

Conversation

@mo-tgeddes

@mo-tgeddes Theo Geddes (mo-tgeddes) commented Sep 7, 2026

Copy link
Copy Markdown
Collaborator

Closes #32, #33
To be completed prior to review request and updated as required during the review process.

If the answer to an item on the list is not applicable, feel free to replace the checkbox with 'N/A' to give extra clarity.

All developers are reminded to follow the ancil working practices


Branch

Related branches (e.g. ancillary-file-science):

[please link any related branches here]

ANTS rose stem logs

dev-ants-core/run136

ancillary-file-science rose stem logs

contrib/run34


Testing

For core ANTS only tests, the bare minimum that will be accepted is the group=unittests but many, if not most, changes will need to test other groups to ensure they meet reviewer expectations. In general, it should be possible and is advised to run the group=all group prior to review submission as this will catch any consequential issues. Additionally you must run the ancillary-file-science tests, pointing at your branch, with group=all to capture any behaviour changes affecting Science codes.

If your change will alter existing science results, you will need to seek appropriate Scientific validation and confirm that the model has been initialised with your new development. Inspecting a change in xconv/pyplot/visualiser of choice is not sufficient to demonstrate the model can be initialised from your file.


Impact of change

  • This will maintain results for ANTS cylc vip ./rose-stem -z group=all tests
  • This will this maintain results for ancillary-file-science cylc vip ./rose-stem -z group=all tests
  • If this change adds a new capability, evidence has been supplied to show testing of ancillary generation across different resolutions e.g. For global ancillary generation capabilities for use in NWP n1280e is expected to have been tested
  • This change has significantly impacted required resources (runtime and memory) in existing ancillary generation (if yes, give details)
  • This change alters existing ancils
Add further comments/details for your reviewers here on the impacts of the change......

Approvals for this change

  • I have approval from the ANTS core development team for these changes

New functionality further testing

  • If adding new functionality to existing codes, I confirm that the new code doesn't change results when it is switched off and ''works'' when switched on
  • Unittests have been added
  • Rose stem tests have been added for any new functionality
  • If adding new functionality please confirm that the new code compares across different standard decompositions.
  • I have not encountered any failures in my rose-stem output(s)
    These tasks must succeed for your ticket to pass review.
  • I have remembered to run the code style check tasks/tools
Add details of any further testing here.

Other

  • I have read the Contributor Licence Agreement
  • I have added my name and affiliation to the Contributors list if I am not already on there in this PR.
  • The issue labels, milestones, etc. are correct
  • Links to all related issues have been provided in the pull request description
  • I have requested a code reviewer
  • Source data has been added or changed - please include a link to the license
I confirm that all code is my own and that my contributions are not subject to copyright or license restrictions (see Contributor Licence Agreement). Theo Geddes
I confirm I have not knowingly violated intellectual property rights (IPR) and have taken sensible measures to prevent doing so, including appropriate attribution for usage of Generative AI. I confirm that this work is my own, and I understand that it is my responsibility to ensure I am not violating others’ IPR. This includes taking reasonable steps to ensure that all tools used while creating this contribution did not infringe IPR. Theo Geddes
Please add any further notes here. If Generative AI tools have been used, a brief summary (e.g. "Github copilot used to add extra unittests") should be provided.

Rose stem logs

Please copy in the contents of your trac_status.log file(s) below (found in the cylc-run directory for your rose stem run) to your rose-stem testing here. Note: if your changes lead to a change in answers, you must run cylc vip ./rose-stem -z group=all to help ensure all affected configurations has been flagged up.

linkcheck currently failing - it looks unrelated

Mon 7 Sep 13:16:28 BST 2026 Git status: [ "?? ../ants.tests", "?? ../history-test.nc", "?? ../import-test.py", "?? ../mpi-fix.lock", "?? ../new-env.lock", "?? ../stash_cci.nc", "?? ../stash_cci.nc.attribution", "?? ../stash_cci2.nc", "?? ../stash_cci2.nc.license", "?? ../wildcard1.pp", "?? ../wildcard1.pp.references", "?? ../wildcard2.pp" ] Commit: fd5cec4

Test Results - Summary

tasks total
failed 1
succeeded 65

Test Results - Detail

task status
install_cold succeeded
ancil_general_regrid_grid_to_grid_spiral_split2 succeeded
ancil_general_regrid_with_time_constraint_kdtree_split2 succeeded
ancil_general_regrid_invert_mask_latitude_weighted_kdtree_split2 succeeded
ancil_general_regrid_metadata succeeded
ancil_general_regrid_grid_to_n48e_namelist_split1 succeeded
ancil_general_regrid_grid_to_grid_latitude_weighted_kdtree_split2 succeeded
ancil_general_regrid_with_time_constraint_latitude_weighted_kdtree_split1 succeeded
ancil_2anc_split1 succeeded
ancil_general_regrid_invert_mask_latitude_weighted_kdtree_split0 succeeded
ancil_general_regrid_3d_to_3d_split0 succeeded
ancil_general_regrid_with_time_constraint_spiral_split1 succeeded
ancil_general_regrid_grid_to_n48_namelist_split1 succeeded
ancil_general_regrid_3d_to_3d_split1 succeeded
ancil_general_regrid_invert_mask_spiral_split1 succeeded
ancil_general_regrid_invert_mask_kdtree_split0 succeeded
ancil_general_regrid_grid_to_grid_spiral_split0 succeeded
ancil_general_regrid_invert_mask_latitude_weighted_kdtree_split1 succeeded
ancil_general_regrid_grid_to_n48e_namelist_split2 succeeded
ancil_general_regrid_with_time_constraint_latitude_weighted_kdtree_split0 succeeded
ancil_general_regrid_grid_to_n48e_namelist_split0 succeeded
ancil_general_regrid_3d_to_3d_with_extrapolation_split0 succeeded
ancil_general_regrid_grid_to_grid_spiral_split1 succeeded
ancil_general_regrid_3d_to_3d_split2 succeeded
ancil_fill_n_merge_invert_mask_kdtree succeeded
ancil_general_regrid_with_time_constraint_kdtree_split1 succeeded
flake8 succeeded
ancil_general_regrid_grid_to_grid_kdtree_split2 succeeded
ancil_general_regrid_invert_mask_kdtree_split2 succeeded
ancil_general_regrid_with_time_constraint_kdtree_split0 succeeded
build_docs succeeded
ancil_general_regrid_invert_mask_spiral_split0 succeeded
ancil_general_regrid_grid_to_grid_latitude_weighted_kdtree_split0 succeeded
unittests succeeded
ancil_general_regrid_grid_to_n48_namelist_split2 succeeded
ancil_general_regrid_with_time_constraint_spiral_split2 succeeded
ancil_general_regrid_invert_mask_spiral_split2 succeeded
ancil_fill_n_merge_invert_mask_latitude_weighted_kdtree succeeded
ancil_general_regrid_grid_to_grid_kdtree_split0 succeeded
ancil_2anc_split2 succeeded
black succeeded
ancil_fill_n_merge_invert_mask_spiral succeeded
ancil_2anc_split0 succeeded
ancil_general_regrid_grid_to_variable_resolution_grid_split2 succeeded
ancil_general_regrid_grid_to_n48_namelist_split0 succeeded
ancil_general_regrid_3d_to_3d_with_extrapolation_split2 succeeded
ancil_general_regrid_grid_to_grid_kdtree_split1 succeeded
ancil_general_regrid_grid_to_grid_latitude_weighted_kdtree_split1 succeeded
ancil_general_regrid_3d_to_3d_with_extrapolation_split1 succeeded
ancil_create_ite_shapefile succeeded
ancil_general_regrid_grid_to_variable_resolution_grid_split1 succeeded
ancil_general_regrid_grid_to_variable_resolution_grid_split0 succeeded
ancil_general_regrid_invert_mask_kdtree_split1 succeeded
ancil_general_regrid_with_time_constraint_spiral_split0 succeeded
ancil_general_regrid_with_time_constraint_latitude_weighted_kdtree_split2 succeeded
isort succeeded
ancil_fill_n_merge_land_cover_spiral succeeded
ancil_fill_n_merge_land_cover_kdtree succeeded
ancil_fill_n_merge_land_cover_latitude_weighted_kdtree succeeded
rose_ana_general_regrid_latitude_weighted_kdtree succeeded
rose_ana_fill_n_merge succeeded
rose_ana_2anc succeeded
rose_ana_general_regrid succeeded
rose_ana_general_regrid_kdtree succeeded
rose_ana_general_regrid_spiral succeeded
linkcheck failed

Mon 7 Sep 14:28:50 BST 2026 Git status: [ " M app/ancil_canopy_heights/rose-app.conf", " M app/install_cold/rose-app.conf", "?? ../canopy", "?? ../config.conf", "?? ../something", "?? ../soul-rough-test1", "?? ../soul-rough-test1.attribution", "?? ../soul-rough-test1.license", "?? ../soul-rough-test1.nc", "?? ../soul-rough-test1.restrictions" ] Commit: 0c4f49b108aab4a7a41712c2901e78e08036a9e7

Test Results - Summary

tasks total
failed 4
succeeded 259

Test Results - Detail

task status
install_cold succeeded
ancil_soil_roughness_preproc_split1 succeeded
ancil_ozone_redistribution_360_day succeeded
ancil_orography_filtered_preproc_gmted_ramp2 succeeded
ancil_lct_postproc_c4_split2 succeeded
river_storage_unittests succeeded
ancil_lai_high_res_split1 succeeded
ancil_sst_seaice_preproc_HadISST succeeded
canopy_heights_unittests succeeded
ancil_easy_aerosol_preproc_easy_cdnc succeeded
ancil_pop_den_hyde_preproc succeeded
ancil_lct_postproc_c4_split0 succeeded
ancil_soil_roughness_split2 succeeded
topographic_index_unittests succeeded
ancil_soil_roughness_preproc_split2 succeeded
ancil_easy_aerosol_preproc_easy_absorption_lw succeeded
prescribed_time_varying_veg_unittests succeeded
ancil_topographic_index_preproc succeeded
ancil_lct_preproc_igbp_split2 succeeded
ancil_lct_preproc_ite_split2 succeeded
ancil_orography_unfiltered_preproc_gmted_ramp2 succeeded
ancil_dms_chloro_climatology_dms succeeded
ancil_ozone_redistribution_gregorian succeeded
ancil_lai_high_res_split0 succeeded
ancil_sample_tracemalloc_split1 succeeded
pop_den_unittests succeeded
lct_unittests succeeded
ancil_easy_aerosol_preproc_easy_asymmetry_sw succeeded
soils_unittests succeeded
flake8 succeeded
ancil_lct_cci_split0 succeeded
ancil_coastal_distance succeeded
ancil_river_routing_1d_river_coupling_split1 succeeded
soil_roughness_unittests succeeded
ancil_model_derived_sst_si_timeseries_cmip7_sst succeeded
ancil_lct_preproc_cci_split1 succeeded
ancil_lct_preproc_cci_split0 succeeded
ancil_soils_clapp_hornberger_split1 succeeded
ancil_easy_aerosol_preproc_easy_asymmetry_lw succeeded
ancil_soils_clapp_hornberger_split0 succeeded
ancil_soils_clapp_hornberger_split2 succeeded
ancil_lake_depth_preproc succeeded
ancil_canopy_heights_split1 succeeded
lai_unittests succeeded
ancil_model_derived_sst_si_climatology_cmip7_si succeeded
ancil_lct_preproc_cci_split2 succeeded
ancil_lai_split1 succeeded
ancil_river_routing_gc6_split2 succeeded
ancil_dms_chloro_timeseries_chl succeeded
ancil_canopy_heights_split2 succeeded
ancil_lai_split2 succeeded
ancil_lct_preproc_igbp_split0 succeeded
ancil_river_routing_preproc succeeded
ancil_lai_high_res_split2 succeeded
ancil_river_storage_preproc succeeded
ancil_orography_unfiltered_preproc_globe30 succeeded
ancil_generate_masks_split0 succeeded
ancil_prescribed_time_varying_veg_split1 succeeded
ancil_lct_preproc_ite_split0 succeeded
ancil_sample_split0 succeeded
ancil_dms_chloro_timeseries_dms succeeded
ancil_easy_aerosol_preproc_easy_absorption_sw succeeded
ancil_soil_roughness_split0 succeeded
ancil_lct_postproc_c4_split1 succeeded
ancil_sample_tracemalloc_split0 succeeded
cmip7_utils_unittests succeeded
ancil_orography_filtered_preproc_globe30 succeeded
ancil_easy_aerosol_preproc_easy_extinction_lw succeeded
ancil_prescribed_time_varying_veg_split2 succeeded
ancil_dms_chloro_climatology_chl succeeded
ancil_model_derived_sst_si_climatology_cmip7_sst succeeded
ancil_canopy_heights_split0 succeeded
ozone_redistribution_unittests succeeded
ancil_sample_split2 succeeded
ancil_river_routing_gc6_split1 succeeded
ancil_prescribed_time_varying_veg_split0 succeeded
isort succeeded
ancil_soil_albedo_split1 succeeded
ancil_pop_den succeeded
ancil_lai_split0 succeeded
ancil_generate_masks_split2 succeeded
ancil_generate_masks_split1 succeeded
ancil_lct_preproc_igbp_split1 succeeded
ancil_lct_cci_split2 succeeded
ancil_soil_roughness_split1 succeeded
black succeeded
sst_cmip7_unittests succeeded
ancil_river_routing_1d_river_coupling_split0 succeeded
soil_dust_unittests succeeded
sst_seaice_unittests succeeded
ancil_river_routing_1d_river_coupling_split2 succeeded
ancil_orographic_formdrag_preproc succeeded
ancil_orographic_wavedrag_preproc_globe30 succeeded
ancil_soil_albedo_split2 succeeded
ancil_soil_albedo_split0 succeeded
ancil_sample_tracemalloc_split2 succeeded
ancil_lct_cci_split1 succeeded
ancil_river_routing_gc6_split0 succeeded
ancil_easy_aerosol_preproc_easy_extinction_sw succeeded
cmip7_dms_chloro_unittests succeeded
ancil_soil_roughness_preproc_split0 succeeded
ancil_model_derived_sst_si_timeseries_cmip7_si succeeded
ancil_coastal_distance_unittests succeeded
ancil_sst_seaice_preproc_oper_AMM15_UKV succeeded
ancil_sample_split1 succeeded
river_routing_unittests succeeded
ancil_lct_preproc_ite_split1 succeeded
orography_unittests succeeded
sample_unittests succeeded
ancil_topographic_index_split0 succeeded
ancil_topographic_index_split1 succeeded
ancil_topographic_index_split2 succeeded
rose_ana_dms_chloro_climatology_dms succeeded
rose_ana_easy_aerosol_preproc succeeded
ancil_orography_mean_blended_max_slope_0p01_max_smooth_1_gmted_ramp2_split0 succeeded
ancil_orography_mean_epsilon_default_gmted_ramp2_split2 succeeded
ancil_orography_mean_blended_max_slope_from_smooth_dilation_gmted_ramp2_split2 succeeded
ancil_orography_mean_epsilon_default_gmted_ramp2_split0 succeeded
ancil_orography_mean_epsilon_value_gmted_ramp2_split0 succeeded
ancil_orography_mean_blended_max_slope_from_smooth_dilation_gmted_ramp2_split1 succeeded
ancil_orography_mean_blended_max_slope_0p01_max_smooth_1_gmted_ramp2_split1 succeeded
ancil_orography_mean_epsilon_default_gmted_ramp2_split1 succeeded
ancil_orography_mean_epsilon_value_rotated_pole_LAM_split1 succeeded
ancil_orography_mean_blended_max_slope_from_smooth_dilation_gmted_ramp2_split0 succeeded
rose_ana_orographic_wavedrag_gmted_ramp2 succeeded
ancil_orography_mean_blended_max_slope_0p01_max_smooth_1_gmted_ramp2_split2 succeeded
ancil_orography_mean_epsilon_value_rotated_pole_LAM_split0 succeeded
ancil_orography_mean_epsilon_value_rotated_pole_LAM_split2 succeeded
ancil_orography_mean_epsilon_value_gmted_ramp2_split2 succeeded
ancil_orography_mean_epsilon_value_gmted_ramp2_split1 succeeded
ancil_lct_ite_split2 succeeded
ancil_sst_seaice_HadISST_split0 succeeded
ancil_sst_seaice_HadISST_split1 succeeded
ancil_sst_seaice_HadISST_split2 succeeded
ancil_soil_roughness_regrid_split1 succeeded
ancil_soil_roughness_regrid_split2 succeeded
rose_ana_lai_high_res succeeded
ancil_lct_igbp_split2 succeeded
rose_ana_ozone_redistribution succeeded
ancil_radiation_parameters_split0 succeeded
ancil_radiation_parameters_split1 succeeded
ancil_radiation_parameters_split2 succeeded
ancil_orography_slopes_preproc succeeded
rose_ana_pop_den succeeded
rose_ana_coastal_distance succeeded
ancil_soil_dust_split1 succeeded
rose_ana_soils failed
ancil_soil_dust_split0 succeeded
rose_ana_dms_chloro_timeseries_chl succeeded
rose_ana_lai succeeded
rose_ana_canopy_heights succeeded
ancil_river_routing_gc4_split0 succeeded
ancil_river_routing_gc4_split1 succeeded
ancil_river_routing_gc4_split2 succeeded
rose_ana_dms_chloro_timeseries_dms succeeded
rose_ana_model_derived_sst_si_timeseries_cmip7_sst succeeded
rose_ana_lake_depth_preproc succeeded
ancil_soil_dust_split2 succeeded
rose_ana_model_derived_sst_si_climatology_cmip7_si succeeded
rose_ana_prescribed_time_varying_veg succeeded
rose_ana_dms_chloro_climatology_chl succeeded
ancil_lct_igbp_split1 succeeded
ancil_lct_igbp_split0 succeeded
rose_ana_sample_tracemalloc succeeded
ancil_orography_mean_epsilon_value_globe30_split0 succeeded
ancil_orography_mean_epsilon_value_globe30_split1 succeeded
ancil_orography_mean_blended_max_slope_0p01_max_smooth_1_globe30_split1 succeeded
ancil_orography_mean_epsilon_value_globe30_split2 succeeded
ancil_orography_mean_blended_max_slope_0p01_max_smooth_1_globe30_split0 succeeded
ancil_orography_mean_blended_max_slope_0p01_max_smooth_1_globe30_split2 succeeded
ancil_river_storage_1d_river_coupling succeeded
ancil_river_storage_gc6 succeeded
ancil_add_lakes succeeded
rose_ana_sample succeeded
ancil_lct_ite_split1 succeeded
ancil_lct_ite_split0 succeeded
rose_ana_soil_albedo succeeded
rose_ana_orographic_wavedrag_globe30 succeeded
rose_ana_model_derived_sst_si_climatology_cmip7_sst succeeded
ancil_soil_roughness_regrid_split0 succeeded
ancil_sst_seaice_oper_AMM15_UKV_split1 succeeded
ancil_sst_seaice_oper_AMM15_UKV_split0 succeeded
ancil_sst_seaice_oper_AMM15_UKV_split2 succeeded
ancil_sst_seaice_postproc succeeded
ancil_time_header_postproc succeeded
ancil_orographic_formdrag_split2 succeeded
ancil_orographic_formdrag_split1 succeeded
ancil_orographic_formdrag_split0 succeeded
ancil_soil_roughness_postproc_split1 succeeded
ancil_soil_roughness_postproc_split2 succeeded
ancil_orographic_wavedrag_epsilon_value_gmted_ramp2_split0 succeeded
rose_ana_orography_mean_gmted_ramp2 succeeded
ancil_orographic_wavedrag_blended_max_slope_from_smooth_dilation_gmted_ramp2_split0 succeeded
rose_ana_orography_dilation_mean_gmted_ramp2 succeeded
ancil_orographic_wavedrag_blended_max_slope_0p01_max_smooth_1_gmted_ramp2_split2 succeeded
ancil_orographic_wavedrag_epsilon_default_45_deg_polar_cutoff_gmted_ramp2_split0 succeeded
ancil_orographic_wavedrag_epsilon_default_gmted_ramp2_split0 succeeded
ancil_orography_submean_height_gmted_ramp2 succeeded
ancil_orographic_wavedrag_blended_max_slope_0p01_max_smooth_1_gmted_ramp2_split0 succeeded
ancil_orographic_wavedrag_blended_max_slope_from_smooth_dilation_gmted_ramp2_split2 succeeded
ancil_orography_submean_height_LAM succeeded
ancil_orographic_wavedrag_epsilon_value_rotated_pole_LAM_split2 succeeded
rose_ana_orography_mean_LAM succeeded
ancil_orographic_wavedrag_epsilon_value_gmted_ramp2_split1 succeeded
ancil_orographic_wavedrag_epsilon_default_gmted_ramp2_split1 succeeded
ancil_orographic_wavedrag_epsilon_default_45_deg_polar_cutoff_gmted_ramp2_split1 succeeded
ancil_orographic_wavedrag_epsilon_default_gmted_ramp2_split2 succeeded
ancil_orographic_wavedrag_epsilon_default_45_deg_polar_cutoff_gmted_ramp2_split2 succeeded
rose_ana_model_derived_sst_si_timeseries_cmip7_si succeeded
ancil_orographic_wavedrag_epsilon_value_rotated_pole_LAM_split0 succeeded
ancil_orographic_wavedrag_blended_max_slope_0p01_max_smooth_1_gmted_ramp2_split1 succeeded
ancil_orographic_wavedrag_epsilon_value_gmted_ramp2_split2 succeeded
ancil_orographic_wavedrag_blended_max_slope_from_smooth_dilation_gmted_ramp2_split1 succeeded
ancil_orographic_wavedrag_epsilon_value_rotated_pole_LAM_split1 succeeded
rose_ana_soil_dust failed
move_lct_files_split0 succeeded
rose_ana_river_routing failed
rose_ana_radiation_parameters succeeded
rose_ana_orography_slopes_preproc succeeded
rose_ana_orography_blended_mean_globe30 succeeded
ancil_orographic_wavedrag_blended_max_slope_0p01_max_smooth_1_globe30_split0 succeeded
ancil_orographic_wavedrag_blended_max_slope_0p01_max_smooth_1_globe30_split2 succeeded
ancil_orographic_wavedrag_blended_max_slope_0p01_max_smooth_1_globe30_split1 succeeded
ancil_orographic_wavedrag_epsilon_value_globe30_split0 succeeded
rose_ana_orography_mean_globe30 succeeded
ancil_orography_submean_height_globe30 succeeded
ancil_orographic_wavedrag_epsilon_value_globe30_split2 succeeded
ancil_orographic_wavedrag_epsilon_value_globe30_split1 succeeded
move_lct_files_split1 succeeded
ancil_soil_roughness_postproc_split0 succeeded
rose_ana_sst_seaice succeeded
rose_ana_soil_roughness succeeded
seaice_field_reordering succeeded
rose_ana_orography_dilation_gmted_ramp2 succeeded
rose_ana_orography_blended_gmted_ramp2 succeeded
rose_ana_45_deg_polar_cutoff_gmted_ramp2 succeeded
rose_ana_orographic_wavedrag_LAM succeeded
rose_ana_orography_submean_height_gmted_ramp2 succeeded
ancil_orography_submean_gradient_gmted_ramp2 succeeded
move_lct_files_split2 succeeded
ancil_orography_submean_gradient_LAM succeeded
rose_ana_orography_submean_height_LAM succeeded
rose_ana_river_storage succeeded
rose_ana_orographic_formdrag succeeded
rose_ana_time_header_postproc succeeded
rose_ana_orography_blended_globe30 succeeded
rose_ana_orography_submean_height_globe30 succeeded
ancil_orography_submean_gradient_globe30 succeeded
rose_ana_orography_submean_gradient_gmted_ramp2 succeeded
rose_ana_orography_submean_gradient_LAM succeeded
rose_ana_orography_submean_gradient_globe30 succeeded
rose_ana_topographic_index succeeded
rose_ana_lct_ite_mask_split2 succeeded
rose_ana_lct_cci_mask_split0 succeeded
rose_ana_lct_ite_mask_split0 succeeded
rose_ana_lct_cci_mask_split2 succeeded
rose_ana_lct_igbp_mask_split2 succeeded
rose_ana_lct_igbp_mask_split0 succeeded
rose_ana_lct_ite_mask_split1 succeeded
rose_ana_masks succeeded
rose_ana_lct_cci_mask_split1 succeeded
rose_ana_lct failed
rose_ana_lct_igbp_mask_split1 succeeded

See Metoffice/ancillary-file-science#102 for explanation of failures

Co-authored-by: Andrew Clark <2562650+arjclark@users.noreply.github.com>
Signed-off-by: Theo Geddes <theo.geddes@metoffice.gov.uk>
Merge CallBackMetadata Class to feature branch
@mo-tgeddes Theo Geddes (mo-tgeddes) added this to the 4.0 milestone Sep 7, 2026
@mo-tgeddes

Copy link
Copy Markdown
Collaborator Author

There is a metadata test that would usually be attached to the general_regrid roseana, however to modify the KGO to just that file I have temporarily made a new rose stem .conf, I intend to put it back once it is approved before deployment of a new KGO.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Passing this back after a first review, there are still some areas I will need to look into in more detail (e.g. the saver side) but this should hopefully be enough on the loader side to be useful for you

directly affect that data. For example, licensing information or attributions.

Some ancillary file formats cannot include metadata. Metadata can be very important to
keep alongside the data as often data will have rome form of requirement or restriction

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
keep alongside the data as often data will have rome form of requirement or restriction
keep alongside the data as often data will have some form of requirement or restriction

Metadata will only be saved to a sidecar file, if the ancil loader is used. This is
because NetCDF files will include the attributes within the file.

The sidecar files produced by ANTS follow the same naming covenstions at those loaded in

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The sidecar files produced by ANTS follow the same naming covenstions at those loaded in
The sidecar files produced by ANTS follow the same naming coventions at those loaded in

Saving Metadata
---------------

Metadata will only be saved to a sidecar file, if the ancil loader is used. This is

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to check, should it be the ancil saver rather than loader that determines whether sidecar files are saved?

Suggested change
Metadata will only be saved to a sidecar file, if the ancil loader is used. This is
Metadata will only be saved to a sidecar file, if the ancil saver is used. This is

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really like this documentation, but I do wonder if it is really a tutorial as such, maybe it would make sense somewhere else? Perhaps under Ancillary Generation Pipeline? Alternatively, it could be made into a tutorial with some more examples

Some ancillary file formats cannot include metadata. Metadata can be very important to
keep alongside the data as often data will have rome form of requirement or restriction
on it. Because of this, ANTS can handle in external metadata files, provided they match
the naming convention of `filename.attribute.accepted-metadata`. The current accepted

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed, can this be clarified a bit? It would be good to have a concrete example here, e.g. for file.pp, a license will be loaded from file.pp.license.

Suggested change
the naming convention of `filename.attribute.accepted-metadata`. The current accepted
the naming convention of `filename.extension.accepted-metadata`. The current accepted

Comment thread lib/ants/io/load.py
"""
if type(filename) is list:
filename = filename[0]
metadata_filenames = "".join([filename, ".*"])

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor style recommendation, use an f-string for readability

Suggested change
metadata_filenames = "".join([filename, ".*"])
metadata_filenames = f"{filename}.*"

Comment thread lib/ants/io/load.py
return args, kwargs


class _CallbackMetadata(object):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
class _CallbackMetadata(object):
class _CallbackMetadata:

No need to inherit from object

Comment thread lib/ants/io/save.py


def ancil(cubes, filename):
def ancil(cubes, filename, ignore_writing_metadata_files=False):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can I make a small suggestion for readability? It might be better to have write_metadata_files=True rather than ignore_writing_metadata_files=False since it avoids a double negative of if not ignore_writing_metadata_files meaning "write metdata files" (i.e. "do this" instead of "don't not to this")

Suggested change
def ancil(cubes, filename, ignore_writing_metadata_files=False):
def ancil(cubes, filename, write_metadata_files=True):

I know what you've got here is consistent with the loaders, maybe it should be swapped over there as well?

# Copy the metadata
copy_metadata_attributes(source, reference)
expected_msg = "a value not in the allowed list"
with pytest.raises(KeyError, match=expected_msg):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could test this with the following?

assert "a value not in the allowed list" not in source.attributes

Comment thread lib/ants/utils/cube.py
Comment on lines +1145 to +1152
metadata_to_copy=[
"license",
"attribution",
"restrictions",
"institution",
"acknowledgement",
"references",
],

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Beware of mutable defaults, maybe best to replace this with a tuple? Or replace with None and use a default list defined within the function (as in the example in the link)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add loading separate metadata files to cube attributes

3 participants