Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
105 commits
Select commit Hold shift + click to select a range
2d54399
#32: Basic prototype callback addition
mo-tgeddes Oct 23, 2025
116ddb2
#32: update pytest tempdir config
mo-tgeddes Nov 12, 2025
ab3f3cc
#32: Working prototype
mo-tgeddes Nov 13, 2025
9af1590
#32: Working prototype with improved logic
mo-tgeddes Nov 13, 2025
dff558e
#32: Update argument handler to correctly pass in user callback
mo-tgeddes Nov 18, 2025
de3d650
#32: revert changes to the ancil loading
mo-tgeddes Nov 18, 2025
877a88e
#32: Add etsts for new loading functionality
mo-tgeddes Nov 18, 2025
fa39ac1
#32: Revert changes to ancil/__init__.py
mo-tgeddes Nov 18, 2025
4c354b7
#32: Revert pp tests
mo-tgeddes Nov 18, 2025
3dc860b
#32: Remove unused imports
mo-tgeddes Nov 18, 2025
e9a30f3
Merge branch 'main' of github.com:MetOffice/ANTS into 32_add_ancil_lo…
mo-tgeddes Dec 9, 2025
da8e951
#32: Commit to save work on adding new load functionality to command …
mo-tgeddes Dec 10, 2025
36148d5
Merge branch 'main' of github.com:MetOffice/ANTS into 32_add_ancil_lo…
mo-tgeddes Jan 5, 2026
79793ee
#32: Working rose stem with new load functionality
mo-tgeddes Jan 5, 2026
119dfcf
#32: Run black
mo-tgeddes Jan 5, 2026
04b3f9c
#32: Remove unneeded argument flag
mo-tgeddes Jan 5, 2026
abcdeae
#32: Fix to work with unittests
mo-tgeddes Jan 6, 2026
212dd0b
#32: Add working tests
mo-tgeddes Jan 8, 2026
ae8aab8
#32: Run stylechecks
mo-tgeddes Jan 13, 2026
2c00cd4
#32: remove print statements
mo-tgeddes Jan 29, 2026
1519caa
add more unit tests
mo-tgeddes Jan 29, 2026
0af2ece
remove unused import
mo-tgeddes Jan 29, 2026
8f49436
Update iris punctuation
mo-tgeddes Mar 31, 2026
95538de
Update docstring in _add_callback()
mo-tgeddes Apr 2, 2026
8b33349
Add speechmarks around license
mo-tgeddes Apr 2, 2026
077b0db
Update _CallbackMetadata docstring
mo-tgeddes Apr 2, 2026
4bbb166
Remove checks for misspelling
mo-tgeddes Apr 7, 2026
feac1b3
Merge callback_metadata_subbranch
mo-tgeddes Apr 8, 2026
1761aee
Changes implementing the loading of metadata
mo-tgeddes Apr 8, 2026
23f56ef
Run black
mo-tgeddes Apr 8, 2026
03bf800
fix flake8 line lengths
mo-tgeddes Apr 8, 2026
8dc2919
#2 Implementing the load
mo-tgeddes Apr 20, 2026
106714d
Add command line support
mo-tgeddes Apr 22, 2026
1835b26
Update extra argument to be correct
mo-tgeddes Apr 22, 2026
3d37136
Add full command parse integration and test
mo-tgeddes Apr 22, 2026
8b5447e
partial commit to save work on adding rose stem test
mo-tgeddes Jun 8, 2026
b808ac9
update rose stem
mo-tgeddes Jun 11, 2026
d9c6d05
Clean up rose stem to only have general regrid additions
mo-tgeddes Jun 11, 2026
d71456b
remove whitespcae
mo-tgeddes Jun 24, 2026
886ff24
Add loading metadata command line option
mo-tgeddes Jun 24, 2026
4ec679b
add functionality for checking for multiple attributes to be saved
mo-tgeddes Jun 24, 2026
f79cc0d
Fix spelling
mo-tgeddes Jun 24, 2026
9b71d8f
Fix variable spelling
mo-tgeddes Jun 24, 2026
7fcbbc3
Add handling for one single cube being passed in
mo-tgeddes Jun 24, 2026
f1e4f8c
Add checking for multiple metadata attributes
mo-tgeddes Jun 24, 2026
9e7e27a
add the ability to write metadata to sidecar files
mo-tgeddes Jun 29, 2026
a0e13e8
Update rose stem source for roseana
mo-tgeddes Jun 29, 2026
e1b0595
Apply suggestions from code review
mo-tgeddes Jun 29, 2026
5e70363
Change name of variable for turning off the save option
mo-tgeddes Jun 29, 2026
8480857
Clarify variable name
mo-tgeddes Jun 29, 2026
acbf778
Remove print statement
mo-tgeddes Jun 29, 2026
f1d7906
Update name and docstring of function
mo-tgeddes Jun 29, 2026
3ef2e61
change docstring syntax
mo-tgeddes Jun 29, 2026
7c5d69c
Update unittest to use mock
mo-tgeddes Jun 30, 2026
7453293
Update warning to log info
mo-tgeddes Jun 30, 2026
67301b0
Update code comment to be more clear
mo-tgeddes Jun 30, 2026
cc97f9f
Rewrite check_and_sort_metadata to use a dictionary
mo-tgeddes Jun 30, 2026
9abe77c
Change save behaviour to add newlines
mo-tgeddes Jun 30, 2026
df08391
Rename test__write_metadata.py to test__check_and_sort_metadata_attri…
mo-tgeddes Jun 30, 2026
ccce4db
Clean up unittests
mo-tgeddes Jun 30, 2026
84362b5
Add support for other attributes to be written out
mo-tgeddes Jul 1, 2026
cc84db7
Change test placeholder reference
mo-tgeddes Jul 1, 2026
ae88f57
Update comment
mo-tgeddes Jul 13, 2026
a159bc7
Remove print statement
mo-tgeddes Jul 13, 2026
7df8ca4
Update spelling
mo-tgeddes Jul 13, 2026
0e14c70
Merge pull request #5 from mo-tgeddes/add_writing_metadata
mo-tgeddes Jul 13, 2026
fe9c9bd
Merge branch 'load_save_feature_branch' into updated_load_save_featur…
mo-tgeddes Jul 13, 2026
cff3f66
Merge pull request #6 from mo-tgeddes/updated_load_save_feature_branch
mo-tgeddes Jul 14, 2026
d0478ec
remove merging artifacts
mo-tgeddes Jul 14, 2026
296fce1
Merge pull request #7 from mo-tgeddes/updated_load_save_feature_branch
mo-tgeddes Jul 14, 2026
f3b85fb
Add fix for netcdf saving error
mo-tgeddes Jul 15, 2026
e3aea7e
Update unittests with new load format
mo-tgeddes Jul 15, 2026
98813d8
Merge pull request #8 from mo-tgeddes/updated_load_save_feature_branch
mo-tgeddes Jul 15, 2026
fcf45a4
Cleanup and add fix for using constraints
mo-tgeddes Jul 20, 2026
d9294f8
Add tests for _add_callback()
mo-tgeddes Jul 22, 2026
a672626
Merge pull request #9 from mo-tgeddes/update_for_constraints
arjclark Aug 4, 2026
5676e05
Add copy metadata attributes
mo-tgeddes Aug 10, 2026
209b4c6
Add tests for copying metadata
mo-tgeddes Aug 10, 2026
c0e3128
Add check for licence spelling when saving
mo-tgeddes Aug 10, 2026
37ccb13
Add test for licence key change
mo-tgeddes Aug 10, 2026
5db76c4
Merge pull request #11 from mo-tgeddes/add_check_for_misspelt_license
mo-tgeddes Aug 10, 2026
1a95458
Update attribute name
mo-tgeddes Aug 17, 2026
7cff684
add test for changing metadata list
mo-tgeddes Aug 17, 2026
8910d4a
Add parameter to docstring
mo-tgeddes Aug 17, 2026
39e5229
Add logic comments
mo-tgeddes Aug 17, 2026
288ef80
Add logic comments
mo-tgeddes Aug 17, 2026
bedd16c
add whitespace stripping
mo-tgeddes Aug 17, 2026
d1163ea
Update lib/ants/utils/cube.py
mo-tgeddes Aug 20, 2026
30c68ae
Merge pull request #10 from mo-tgeddes/add_copy_metadata
arjclark Aug 20, 2026
fd98e00
Merge branch 'MetOffice:main' into load_save_feature_branch
mo-tgeddes Aug 27, 2026
8b299c8
#32: Add more accepted metadata attributes to load
mo-tgeddes Sep 7, 2026
f1f4f3e
#32: Add documentation on handling metadata
mo-tgeddes Sep 7, 2026
fd5cec4
#33: add metadata rose stem
mo-tgeddes Sep 7, 2026
64152eb
#32: Add documentation on turning off metadata load
mo-tgeddes Sep 7, 2026
1239cf3
#32: Add whitepsace
mo-tgeddes Sep 7, 2026
e47fe2d
#32: Update loading to use signatures for argument parsing
mo-tgeddes Sep 21, 2026
a7fa4ce
Apply batched suggestions from code review
mo-tgeddes Sep 21, 2026
c84fc07
#32: Update argument parsing to work correctly with signatures
mo-tgeddes Sep 22, 2026
b1fc0c9
#32: Update test to check not in attribute list
mo-tgeddes Sep 22, 2026
f983dfb
#32: Update function to not have default list in signature
mo-tgeddes Sep 22, 2026
4cca8c4
Merge branch 'MetOffice:main' into load_save_feature_branch
mo-tgeddes Oct 5, 2026
bcbe768
Implement changes from jrackham-mo
mo-tgeddes Oct 21, 2026
1680642
Update tutorial and make variable names more consistent
mo-tgeddes Oct 21, 2026
9450882
Add save variable name change
mo-tgeddes Oct 21, 2026
11e03c8
Documenattion update
mo-tgeddes Oct 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 62 additions & 2 deletions docs/source/tutorial_load_save.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.. meta::
:description lang=en: Tutorial on loading and saving data with ANTS
:keywords: load, save, netcdf, ancil, tutorial
:keywords: load, save, netcdf, ancil, metadata, license, licensing, attribution, references, tutorial
:property=og:locale: en_GB

.. include:: common.txt
Expand Down Expand Up @@ -29,10 +29,13 @@ some ANTS specific ones, see :mod:`ants.fileformats`), then additionally:
none, and
3. removes any ``forecast_reference_time`` and ``forecast_period``
coordinates, which are not usually wanted in ancillary fields.
4. preserves metadata by loading sidecar metdata files alongside the data
files.

:mod:`ants.io.save` similarly extends :py:func:`iris.save` with support for
the F03 UM ancillary fileformat and a UKCA specific flavour of NetCDF, neither
of which Iris can write natively.
of which Iris can write natively, and has the option to write metadata files
alongside the saved files in the case of saving an F03 UM ancillary fileformat.

Loading data
------------
Expand Down Expand Up @@ -82,6 +85,45 @@ a land binary mask field or a land fraction field:
"/path/to/target_lsm.nc", land_threshold=0.5
)

Loading metadata
----------------
Metadata in this tutorial refers to information about the data in a file, that does not
directly affect that data. For example, licensing information or attributions.

Metadata in this tutorial refers to information about the data in a file, that does not
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 some 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.extension.accepted-metadata`. The current accepted
metadata attributes are "license", "attribution", "restrictions", "institution",
"acknowledgement", and "references".

This functionality can be turned off through the use of the argument
``--ignore-metadata-read`` on the command line or when calling the ANTS load:

.. code-block:: python

cube = ants.io.load.load("/path/to/source_file" ,ignore_metadata_read=True)


.. note::
Any attributes or files referencing licensing should use the 'license' spelling for
consistency.

ANTS can load in external metadata files or 'sidecar' files, if they are kept in the
same directory as the data files, and have the same name (including the extension).
Metadata can be loaded alongside all files, including NetCDF files, however ANTS will
not allow you to load a file with a metadata attribute and a sidecar file with the same
attribute. This is to prevent unintentional loss or overwriting of metadata information.

.. note::
When using wildcards for loading with sidecar files, add the file extension to the
end to prevent issues with ANTS attempting to load the sidecar files. E.g.
`data*.pp` rather than `data*`.


Saving data
-----------

Expand Down Expand Up @@ -114,6 +156,24 @@ data type coercion and attribute renaming) on top of a standard NetCDF save:

save.ukca_netcdf(source_cubes, "/path/to/output_ukca.nc")

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

This functionality can be turned off through the use of the argument
``--ignore-metadata-write`` on the command line or when calling the ANTS save:

.. code-block:: python

import ants.io.save as save

save.ancil(source_cubes, "/path/to/output_ancil", ignore_metadata_write=True)

The sidecar files produced by ANTS follow the same naming coventions at those loaded in
`filename.attribute.accepted-metadata`. Only accepted metadata will be written out.


Key Points
----------

Expand Down
29 changes: 24 additions & 5 deletions lib/ants/cli/ancil_2anc.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,23 @@
import iris


def load_data(source):
def load_data(source, ignore_metadata_read):
with warnings.catch_warnings():
warnings.filterwarnings(
"ignore", "NetCDF default loading", iris._deprecation.IrisDeprecation
)
cubes = ants.io.load.load(source)
cubes = ants.io.load.load(source, ignore_metadata_read=ignore_metadata_read)
return cubes


def main(source_path, output_path, grid_staggering, netcdf_only):
def main(
source_path,
output_path,
grid_staggering,
netcdf_only,
ignore_metadata_read,
ignore_metadata_write,
):
"""
Convert specified source file to an ancillary.

Expand All @@ -58,6 +65,12 @@ def main(source_path, output_path, grid_staggering, netcdf_only):
Output ancillary file path. A NetCDF will also be written.
grid_staggering : :obj:`int`, optional
Grid staggering lookup, see UM F03 - FLH(9).
netcdf_only : bool
If True, only write to netCDF. If False, write to both netCDF and ancillary.
ignore_metadata_read : :obj:`bool`, optional
If True, do not read metadata sidecar files alongside the source.
ignore_metadata_write : :obj:`bool`, optional
If True, do not write metadata sidecar files alongside the ancillary.

Returns
-------
Expand All @@ -66,13 +79,17 @@ def main(source_path, output_path, grid_staggering, netcdf_only):
written to an ancillary.

"""
source_cubes = load_data(source_path)
source_cubes = load_data(source_path, ignore_metadata_read)
if grid_staggering is not None:
for source_cube in source_cubes:
source_cube.attributes["grid_staggering"] = grid_staggering

if not netcdf_only:
save.ancil(source_cubes, output_path)
save.ancil(
source_cubes,
output_path,
ignore_metadata_write=ignore_metadata_write,
)
save.netcdf(source_cubes, output_path)

return source_cubes
Expand All @@ -98,6 +115,8 @@ def cli_interface():
args.output,
args.grid_staggering,
args.netcdf_only,
args.ignore_metadata_read,
args.ignore_metadata_write,
)


Expand Down
25 changes: 22 additions & 3 deletions lib/ants/cli/ancil_fill_n_merge.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ def load_data(
land_fraction_threshold=None,
begin=None,
end=None,
ignore_metadata_read=False,
):
"""
Load the necessary data for performing a merge and fill operation.
Expand All @@ -45,6 +46,9 @@ def load_data(
Datetime to start the processing.
end: :obj:`datetime`, optional
Datetime to end the processing.
ignore_metadata_read : :obj:`bool`, optional
When set to True, files containing metadata will not be loaded alongside data
and added as attributes to the cube.


Returns
Expand All @@ -56,12 +60,16 @@ def load_data(
respectively.

"""
primary_cubes = ants.io.load.load(primary_source)
primary_cubes = ants.io.load.load(
primary_source, ignore_metadata_read=ignore_metadata_read
)
if begin is not None:
primary_cubes = create_time_constrained_cubes(primary_cubes, begin, end)
alternate_cubes = None
if alternate_source:
alternate_cubes = ants.io.load.load(alternate_source)
alternate_cubes = ants.io.load.load(
alternate_source, ignore_metadata_read=ignore_metadata_read
)
if begin is not None:
alternate_cubes = create_time_constrained_cubes(alternate_cubes, begin, end)

Expand Down Expand Up @@ -97,6 +105,8 @@ def main(
netcdf_only,
search_method,
blending_distance,
ignore_metadata_read,
ignore_metadata_write,
):
"""
Perform merge and fill operation on the provided sources.
Expand Down Expand Up @@ -152,6 +162,12 @@ def main(
is applied. Note that this is in units of grid cells, not a physical distance.
If ``None``, no blending is applied, and there will be a hard edge between
the two sources.
ignore_metadata_read : :obj:`bool`, optional
When set to True, files containing metadata will not be loaded alongside data
and added as attributes to the cube.
ignore_metadata_write : bool
If True, do not write metadata sidecar files alongside the ancillary.


Returns
-------
Expand All @@ -171,6 +187,7 @@ def main(
land_fraction_threshold,
begin,
end,
ignore_metadata_read,
)

result = primary_cubes
Expand All @@ -182,7 +199,7 @@ def main(
ants.analysis.make_consistent_with_lsm(result, lbm, invert_mask, search_method)

if not netcdf_only:
save.ancil(result, output)
save.ancil(result, output, ignore_metadata_write=ignore_metadata_write)
save.netcdf(result, output)

return result
Expand Down Expand Up @@ -271,6 +288,8 @@ def cli_interface():
netcdf_only=args.netcdf_only,
search_method=args.search_method,
blending_distance=args.blending_distance,
ignore_metadata_read=args.ignore_metadata_read,
ignore_metadata_write=args.ignore_metadata_write,
)


Expand Down
27 changes: 23 additions & 4 deletions lib/ants/cli/ancil_general_regrid.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,20 @@ def load_data(
land_fraction_threshold=None,
begin=None,
end=None,
ignore_metadata_read=False,
):
source_cubes = ants.io.load.load(source)
source_cubes = ants.io.load.load(source, ignore_metadata_read=ignore_metadata_read)
if begin is not None:
source_cubes = create_time_constrained_cubes(source_cubes, begin, end)
if target_grid:
target_cube = ants.io.load.load_grid(target_grid)
target_cube = ants.io.load.load_grid(
target_grid, ignore_metadata_read=ignore_metadata_read
)
else:
target_cube = ants.io.load.load_landsea_mask(
target_landseamask, land_fraction_threshold
target_landseamask,
land_fraction_threshold,
ignore_metadata_read=ignore_metadata_read,
)
return source_cubes, target_cube

Expand All @@ -76,6 +81,8 @@ def main(
save_ukca,
netcdf_only,
search_method,
ignore_metadata_read,
ignore_metadata_write,
):
"""
General regrid application top level call function.
Expand Down Expand Up @@ -118,6 +125,11 @@ def main(
provided source(s) consistent with the provided land sea mask.
This should only be provided if a target land sea mask is also
provided via target_lsm_path.
ignore_metadata_read : :obj:`bool`, optional
When set to True, files containing metadata will not be loaded alongside data
and added as attributes to the cube.
ignore_metadata_write : :obj:`bool`, optional
If True, do not write metadata sidecar files alongside the ancillary.

Returns
-------
Expand All @@ -132,6 +144,7 @@ def main(
land_fraction_threshold,
begin,
end,
ignore_metadata_read,
)
if ants.utils.cube._is_ugrid(target_cube):
raise ValueError(
Expand All @@ -149,7 +162,11 @@ def main(
save.ukca_netcdf(regridded_cubes, output_path)
else:
if not netcdf_only:
save.ancil(regridded_cubes, output_path)
save.ancil(
regridded_cubes,
output_path,
ignore_metadata_write=ignore_metadata_write,
)
save.netcdf(regridded_cubes, output_path)

return regridded_cubes
Expand Down Expand Up @@ -210,6 +227,8 @@ def cli_interface():
args.save_ukca,
args.netcdf_only,
args.search_method,
args.ignore_metadata_read,
args.ignore_metadata_write,
)


Expand Down
23 changes: 17 additions & 6 deletions lib/ants/cli/ancil_vertical_regrid.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ def load_data(
target_grid,
begin=None,
end=None,
ignore_metadata_read=None,
):
source_cubes = ants.io.load.load(source)
source_cubes = ants.io.load.load(source, ignore_metadata_read=ignore_metadata_read)
if begin is not None:
source_cubes = create_time_constrained_cubes(source_cubes, begin, end)

Expand Down Expand Up @@ -87,6 +88,8 @@ def main(
end,
save_ukca,
netcdf_only,
ignore_metadata_read,
ignore_metadata_write,
):
"""
Vertical regrid application top level call function.
Expand All @@ -112,6 +115,11 @@ def main(
end : :obj:`datetime`, optional
If provided, all source data after this year is discarded. Default is to
include all source data.
ignore_metadata_read : :obj:`bool`, optional
When set to True, files containing metadata will not be loaded alongside data
and added as attributes to the cube.
ignore_metadata_write : bool
If True, do not write metadata sidecar files alongside the ancillary.


Returns
Expand All @@ -121,10 +129,7 @@ def main(

"""
source_cubes, target_cube = load_data(
source_path,
target_path,
begin,
end,
source_path, target_path, begin, end, ignore_metadata_read
)

regridded_cubes = regrid(source_cubes, target_cube)
Expand All @@ -133,7 +138,11 @@ def main(
save.ukca_netcdf(regridded_cubes, output_path)
else:
if not netcdf_only:
save.ancil(regridded_cubes, output_path)
save.ancil(
regridded_cubes,
output_path,
ignore_metadata_write=ignore_metadata_write,
)
save.netcdf(regridded_cubes, output_path)

return regridded_cubes
Expand Down Expand Up @@ -163,6 +172,8 @@ def cli_interface():
args.end,
args.save_ukca,
args.netcdf_only,
args.ignore_metadata_read,
args.ignore_metadata_write,
)


Expand Down
Loading
Loading