Skip to content
Merged
Show file tree
Hide file tree
Changes from 85 commits
Commits
Show all changes
127 commits
Select commit Hold shift + click to select a range
743098a
Add query_paramfile tool.
samsrabin Aug 7, 2025
0e2e1e3
query_paramfile: Accept comma-separated variable list.
samsrabin Aug 7, 2025
72a27f7
query_paramfile: Print PFT name next to PFT-specific params.
samsrabin Aug 7, 2025
56aa742
query_paramfile: Align PFT-specific values.
samsrabin Aug 7, 2025
8e70046
query_paramfile: Add optional -p/--pft option.
samsrabin Aug 7, 2025
debbe36
Rename query_parameters/ to param_utils/.
samsrabin Aug 12, 2025
e1f29b2
query_paramfile: Add unit tests of get_arguments().
samsrabin Aug 12, 2025
71f2aff
query_paramfile: Add unit tests of print_values().
samsrabin Aug 12, 2025
99baf01
query_paramfile: Add simple system test; failing.
samsrabin Aug 12, 2025
bf39325
query_paramfile: Fix call w/o -p/--pft.
samsrabin Aug 12, 2025
35bac74
query_paramfile: Add more system tests; failing.
samsrabin Aug 12, 2025
b2f08bd
query_paramfile: Always get pft_names if on paramfile.
samsrabin Aug 12, 2025
6429f00
query_parameters: Add docstrings.
samsrabin Aug 12, 2025
29ff74d
query_paramfile: Move some parser stuff to paramfile_shared.
samsrabin Aug 12, 2025
2a178bc
query_paramfile: Split comma-separated lists in parse_args().
samsrabin Aug 12, 2025
958aaf2
Add set_paramfile tool and tests. So far just parses some args.
samsrabin Aug 12, 2025
337a072
set_paramfile: Can now copy a file.
samsrabin Aug 12, 2025
cea3f12
set_paramfile: Use -v/--variables to only include some vars.
samsrabin Aug 12, 2025
93f29e2
set_paramfile: Can now change params. Tested w/ scalars.
samsrabin Aug 12, 2025
22bdf2d
set_paramfile: Include just some PFTs with -p/--pft.
samsrabin Aug 12, 2025
3aeb040
set_paramfile: Can now change 1-d parameters.
samsrabin Aug 12, 2025
a148838
query_paramfile: Fix call for PFT param w/o -p/--pft.
samsrabin Aug 12, 2025
bedf08d
Update _paramfile tool help descriptions.
samsrabin Aug 12, 2025
f0ba3e0
set_paramfile: Check that new value has right ndim.
samsrabin Aug 13, 2025
73d0a01
set_paramfile sys tests: Check dtype didn't change.
samsrabin Aug 13, 2025
fed3ba4
set_paramfile: Add is_integer(). Tested but not yet used.
samsrabin Aug 13, 2025
3056c36
set_paramfile: Test changing scalar int param. Failing.
samsrabin Aug 13, 2025
552f979
set_paramfile: Can now change scalar int params.
samsrabin Aug 13, 2025
b1c0c75
Turns out set_paramfile works for 1d int params too.
samsrabin Aug 13, 2025
6872d2b
set_paramfile: Don't mask or scale when reading parameter file.
samsrabin Aug 13, 2025
f37c301
test_sys_set_paramfile: Check that fill val didn't change.
samsrabin Aug 13, 2025
a8d90d6
set_paramfile: Avoid calling is_integer().
samsrabin Aug 13, 2025
5602a7d
test_sys_set_paramfile: Test setting scalar double NaN using 'nan'
samsrabin Aug 13, 2025
89f0c42
set_paramfile: Don't allow setting NaN if param doesn't have FillValue.
samsrabin Aug 13, 2025
152ac60
set_paramfile: Don't allow setting NaN in integer params.
samsrabin Aug 13, 2025
cb8fadf
Resolve or delete some testing TODOs.
samsrabin Aug 13, 2025
492bcea
set_paramfile: Require --drop-other-pfts to actually trim the PFT list.
samsrabin Aug 13, 2025
14bb2f8
set_paramfile: Can now change just a few PFT values.
samsrabin Aug 13, 2025
f42d816
set_paramfile: Can now change just one PFT without touching others.
samsrabin Aug 13, 2025
7eb17f3
Reformat with black.
samsrabin Aug 13, 2025
5462b0e
Add previous commit to .git-blame-ignore-revs.
samsrabin Aug 13, 2025
187a8e4
Satisfy pylint.
samsrabin Aug 13, 2025
4e9d2fe
query_paramfiles: Use space-separated variables to match set_paramfile.
samsrabin Aug 14, 2025
c4d6ac6
query_paramfile now prints all variables if none specified.
samsrabin Aug 14, 2025
4019a5a
query_paramfile: Handle multi-dim vars.
samsrabin Aug 14, 2025
ae22703
set_paramfile sys tests: Explicitly check that a 'nan' is saved as th…
samsrabin Aug 14, 2025
79059bc
set_paramfile: Fix a comment.
samsrabin Aug 14, 2025
65daa85
set_paramfile now preserves non-NaN _FillValue.
samsrabin Aug 14, 2025
9f5e4b4
Fix subset_data when selecting just 1 pft.
samsrabin Aug 14, 2025
a6011fb
set_paramfile: Explain nan in help text.
samsrabin Aug 15, 2025
042f5f4
netcdf_utils: Add are_xr_dataarrays_identical().
samsrabin Aug 15, 2025
9552803
Use are_xr_dataarrays_identical() in set_paramfile system tests. Fail…
samsrabin Aug 15, 2025
24ba0de
are_xr_dataarrays_identical(): NaNs equal; ignore source/original_shape.
samsrabin Aug 15, 2025
ee70147
set_paramfile: Don't add fill value to parameters without one.
samsrabin Aug 15, 2025
952a355
are_xr_dataarrays_identical(): Refactor for pylint.
samsrabin Aug 15, 2025
895a8df
are_xr_dataarrays_identical(): Don't ignore anything by default.
samsrabin Aug 15, 2025
5492fff
set_paramfile: Add save_paramfile().
samsrabin Aug 15, 2025
31894b1
set_paramfile: Refactor to reduce branching.
samsrabin Aug 15, 2025
8e3e382
set_paramfile: Improve error when assigning fill for param w/o one.
samsrabin Aug 15, 2025
b9b9420
save_paramfile(): test saving an integer parameter with a fill value
samsrabin Aug 15, 2025
fce7287
set_paramfile(): Improve text about integer fill values.
samsrabin Aug 15, 2025
62d7711
Reformat with black.
samsrabin Aug 15, 2025
8246f54
Add previous commit to .git-blame-ignore-revs.
samsrabin Aug 15, 2025
eac7e81
Satisfy pylint.
samsrabin Aug 16, 2025
ac849e6
save_paramfile: Save calling command to history.
samsrabin Aug 16, 2025
f1856ab
set_paramfile: Functionize _convert_to_output_dtype().
samsrabin Aug 16, 2025
bc2f068
set_paramfile: Improve/test error when given float for integer param.
samsrabin Aug 16, 2025
0207b46
Move are_dicts_identical_nansequal() to netcdf_utils.
samsrabin Aug 17, 2025
f36f3f9
Add SETPARAMFILE SystemTest.
samsrabin Aug 17, 2025
49ad0f7
Reformat with black.
samsrabin Aug 17, 2025
4465b0f
Add prevous commit to .git-blame-ignore-revs.
samsrabin Aug 17, 2025
2eb293c
Merge remote-tracking branch 'escomp/b4b-dev' into query-paramfile
samsrabin Aug 17, 2025
5f4ca9c
set_paramfile: Small refactor.
samsrabin Aug 17, 2025
3211033
query/set_paramfile: Improve help text.
samsrabin Aug 18, 2025
7ff67d6
query/set_paramfile: Update docstrings.
samsrabin Aug 18, 2025
f36f1d3
test_sys_set_paramfile: Delete some print()s.
samsrabin Aug 17, 2025
be8191d
Improve netcdf_utils and testing.
samsrabin Aug 17, 2025
86dd02c
set_paramfile: Simplify _replace_nans_with_fill().
samsrabin Aug 18, 2025
9040f4a
set_paramfile: Avoid using ds_in for robustness.
samsrabin Aug 18, 2025
af2d7dd
set_paramfile: Functionize apply_new_value_to_parameter().
samsrabin Aug 18, 2025
8163648
set_paramfile: chg now optional kw arg if just used in err msg.
samsrabin Aug 18, 2025
e49e793
set_paramfile: Improve a comment.
samsrabin Aug 18, 2025
2032633
set_paramfile: Delete questionably-useful, confusing -v/--variables.
samsrabin Aug 18, 2025
6c80312
test_unit_netcdf_utils: Satisfy pylint.
samsrabin Aug 18, 2025
e339339
Add docs for paramfile tools.
samsrabin Aug 18, 2025
5b5c40c
Suppress crop cold temp msgs when generate_crop_gdds true.
samsrabin Jul 16, 2025
14a27f0
Move log() and error() from generate_gdds_functions to cropcal_utils.
samsrabin Jul 25, 2025
444fa54
Add logging in GDD generation.
samsrabin Jul 31, 2025
8b5c90d
cropcal_utils log(), error(): Prepend datetime string.
samsrabin Aug 11, 2025
2132750
Reformat with black.
samsrabin Aug 11, 2025
97e2bfe
Add previous commit to .git-blame-ignore-revs.
samsrabin Aug 11, 2025
4113ece
Refactoring to satisfy pylint.
samsrabin Aug 11, 2025
ebef8c7
Move 3 functions from cropcal_utils.
samsrabin Aug 19, 2025
c057113
ctsm_logging: Add error_type option to error().
samsrabin Aug 19, 2025
191e119
Try adding caller name to log() and error() msgs.
samsrabin Aug 19, 2025
e277c92
Finalize caller name in log()/error() msgs.
samsrabin Aug 20, 2025
037ae1b
ctsm_logging: Functionize _compose_log_msg().
samsrabin Aug 20, 2025
dcb39b4
Add unit tests of log() and error().
samsrabin Aug 20, 2025
75c6794
Initial add of a unit test for endrun
ekluzek Aug 13, 2025
4053c0a
Add more tests for more of the options
ekluzek Aug 14, 2025
4dc49a9
Move subgrid setup and teardown to setup and teardown methods, add ex…
ekluzek Aug 15, 2025
1586175
Continue the endrun call even if subgrid_level is bad so that the err…
ekluzek Aug 15, 2025
6c38d62
Change to the new expected behavior where the error isn't about the s…
ekluzek Aug 15, 2025
7d25eba
Update to using shr_abort_abort as talked about in #3417
ekluzek Aug 15, 2025
a13dcdb
Update to using shr_abort_abort as talked about in #3417
ekluzek Aug 15, 2025
33a8e00
Add testing for bad point in the pt_context which fails because of su…
ekluzek Aug 15, 2025
ef54137
Add handling in case the input point is bad to end_run_pt_context
ekluzek Aug 16, 2025
33907d7
Add more error checking if a bad point is input to get_global_index, …
ekluzek Aug 16, 2025
7df48b9
Allow passing file and line to endrun, output it through shr_log_errM…
ekluzek Aug 16, 2025
986fe31
Add some tests for sending in file and line and one with just file to…
ekluzek Aug 16, 2025
9a6bf53
Correct data type of bad_point to logical
ekluzek Aug 16, 2025
fc884eb
Replace most uses of npcropmin/max with is_prognostic_crop().
samsrabin Aug 6, 2025
8ca7af5
Avoid using npcropmin/max for looping outside pftconMod.
samsrabin Aug 6, 2025
0dfa907
Add get_crop_n_from_veg_type().
samsrabin Aug 6, 2025
0901503
Add get_veg_type_from_crop_n().
samsrabin Aug 6, 2025
c77a405
Add pftconMod public var num_cfts_possible.
samsrabin Aug 6, 2025
ff4ead6
npcropmin/max are now private to pftconMod.
samsrabin Aug 6, 2025
8920ed7
CNFUNMod: Improve readability of a line.
samsrabin Aug 18, 2025
c20859f
is_prognostic_crop(): Improve note.
samsrabin Aug 19, 2025
d685e6f
Change the directory name for the new endrun tests
ekluzek Aug 19, 2025
5ac7e3b
Change the names from the specific subroutine endrun to abortutils th…
ekluzek Aug 19, 2025
854a364
Move the descriptions of test subroutines to just after the subroutin…
ekluzek Aug 19, 2025
5b40496
Reformat with black.
samsrabin Aug 20, 2025
a6e2309
Add previous commit to .git-blame-ignore-revs.
samsrabin Aug 20, 2025
22a56e5
Small change for pylint.
samsrabin Aug 20, 2025
1a879d9
set_paramfile: Test & document changing 1-d non-pft param.
samsrabin Aug 21, 2025
73303fb
Merge remote-tracking branch 'escomp/b4b-dev' into query-paramfile
samsrabin Aug 21, 2025
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
3 changes: 3 additions & 0 deletions .git-blame-ignore-revs
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,6 @@ cdf40d265cc82775607a1bf25f5f527bacc97405
4ad46f46de7dde753b4653c15f05326f55116b73
75db098206b064b8b7b2a0604d3f0bf8fdb950cc
84609494b54ea9732f64add43b2f1dd035632b4c
7eb17f3ef0b9829fb55e0e3d7f02e157b0e41cfb
62d7711506a0fb9a3ad138ceceffbac1b79a6caa
49ad0f7ebe0b07459abc00a5c33c55a646f1e7e0
95 changes: 95 additions & 0 deletions cime_config/SystemTests/setparamfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
"""
CTSM-specific test that first runs the set_paramfile tool and then ensures that CTSM does not fail
using the just-generated parameter file
"""

import os
import sys
import logging
import re
from CIME.SystemTests.system_tests_common import SystemTestsCommon

# In case we need to import set_paramfile later
_CTSM_PYTHON = os.path.join(
os.path.dirname(os.path.realpath(__file__)), os.pardir, os.pardir, "python"
)
sys.path.insert(1, _CTSM_PYTHON)

logger = logging.getLogger(__name__)


class SETPARAMFILE(SystemTestsCommon):
def __init__(self, case):
"""
initialize an object interface to the SMS system test
"""
SystemTestsCommon.__init__(self, case)

# Create out-of-the-box lnd_in to obtain paramfile
case.create_namelists(component="lnd")

# Find the paramfile to modify
lnd_in_path = os.path.join(self._get_caseroot(), "CaseDocs", "lnd_in")
self._paramfile_in = None
with open(lnd_in_path, "r", encoding="utf-8") as lnd_in:
for line in lnd_in:
paramfile_in = re.match(r" *paramfile *= *'(.*)'", line)
if paramfile_in:
self._paramfile_in = paramfile_in.group(1)
break
if not self._paramfile_in:
raise RuntimeError(f"paramfile not found in {lnd_in_path}")

# Get the output file
self.paramfile_out = os.path.join(self._get_caseroot(), "paramfile.nc")

# Define set_paramfile command
self.set_paramfile_cmd = [
"set_paramfile",
"-i",
self._paramfile_in,
"-o",
self.paramfile_out,
# Change two parameters for one PFT
"-p",
"needleleaf_deciduous_boreal_tree",
"rswf_min=0.35",
"rswf_max=0.7",
]

def build_phase(self, sharedlib_only=False, model_only=False):
"""
Run set_paramfile and then build the model
"""

# Run set_paramfile.
# build_phase gets called twice:
# - once with sharedlib_only = True and
# - once with model_only = True
# Because we only need set_paramfile run once, we only do it for the sharedlib_only call.
# We could also check for the existence of the set_paramfile outputs, but that might lead to
# a situation where the user expects set_paramfile to be called but it's not. Better to run
# unnecessarily (e.g., if you fixed some FORTRAN code and just need to rebuild).
if sharedlib_only:
self._run_set_paramfile()

# Do the build
self.build_indv(sharedlib_only=sharedlib_only, model_only=model_only)

def _run_set_paramfile(self):
"""
Run set_paramfile
"""
# Import set_paramfile. Do it here rather than at top because otherwise the import will
# be attempted even during RUN phase.
# pylint: disable=wrong-import-position,import-outside-toplevel
from ctsm.param_utils.set_paramfile import main as set_paramfile

# Run set_paramfile
sys.argv = self.set_paramfile_cmd
set_paramfile()

# Append
user_nl_clm_path = os.path.join(self._get_caseroot(), "user_nl_clm")
with open(user_nl_clm_path, "a", encoding="utf-8") as user_nl_clm:
user_nl_clm.write(f"paramfile = '{self.paramfile_out}'\n")
10 changes: 10 additions & 0 deletions cime_config/config_tests.xml
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,16 @@ This defines various CTSM-specific system tests
<HIST_N>$STOP_N</HIST_N>
</test>

<test NAME="SETPARAMFILE">
<DESC>Modify a copy of the paramfile and run with it.</DESC>
<INFO_DBUG>1</INFO_DBUG>
<DOUT_S>FALSE</DOUT_S>
<CONTINUE_RUN>FALSE</CONTINUE_RUN>
<REST_OPTION>never</REST_OPTION>
<HIST_OPTION>$STOP_OPTION</HIST_OPTION>
<HIST_N>$STOP_N</HIST_N>
</test>

<!--
SSP smoke CLM spinup test (only valid for CLM compsets with CLM45)
do an initial spin test (setting CLM_ACCELERATED_SPINUP to on)
Expand Down
10 changes: 10 additions & 0 deletions cime_config/testdefs/testlist_clm.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4495,5 +4495,15 @@
</options>
</test>

<test name="SETPARAMFILE_Ld5" grid="f10_f10_mg37" compset="I1850Clm60BgcCrujra" testmods="clm/default">
<machines>
<machine name="derecho" compiler="gnu" category="aux_clm"/>
<machine name="derecho" compiler="gnu" category="clm_pymods"/>
</machines>
<options>
<option name="wallclock">00:20:00</option>
</options>
</test>


</testlist>
1 change: 1 addition & 0 deletions doc/source/users_guide/using-clm-tools/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ Using CLM tools
creating-domain-files.rst
observational-sites-datasets.rst
cprnc.rst
paramfile-tools.md
63 changes: 63 additions & 0 deletions doc/source/users_guide/using-clm-tools/paramfile-tools.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@

# Tools for working with parameter files

This guide describes the features and usage of the `query_paramfile` and `set_paramfile` tools, located in `tools/param_utils/`. These utilities help users inspect and modify CLM parameter files.

Note that you need to have the `ctsm_pylib` conda environment activated to use these tools. See Sect. :numref:`using-ctsm-pylib` for more information.

## `query_paramfile`
**Purpose:** Print the values of one or more parameters from a CTSM parameter file (NetCDF format).

**Features:**
- Print values for specified parameters or all.
- Optionally filter output by Plant Functional Types (PFTs) for PFT-specific parameters.

For more information, do `tools/param_utils/query_paramfile --help`.


### Example usage

Print all variables in a parameter file:
```bash
tools/param_utils/query_paramfile -i paramfile.nc
```

Print specific variables:
```bash
tools/param_utils/query_paramfile -i paramfile.nc jmaxha jmaxhd
```

Print values for specific PFTs:
```bash
tools/param_utils/query_paramfile -i paramfile.nc -p needleleaf_evergreen_temperate_tree,c4_grass medlynintercept medlynslope
```

## `set_paramfile`
**Purpose:** Change values of one or more parameters in a CTSM parameter file (NetCDF format).

**Features:**
- Modify parameter values for all or selected PFTs.
- Optionally drop PFTs not specified.
- Set parameter values to fill (missing) values using `nan`.
- Ensures safe file handling and checks for argument validity.

Note that the output file must not already exist.

For more information, do `tools/param_utils/set_paramfile --help`.

### Example usage

Change a parameter for all PFTs:
```bash
tools/param_utils/set_paramfile -i paramfile.nc -o output.nc jmaxha=51000
```

Change a parameter for specific PFTs:
```bash
tools/param_utils/set_paramfile -i paramfile.nc -o output.nc -p needleleaf_evergreen_temperate_tree,c4_grass medlynintercept=99.9,100.1 medlynslope=2.99,1.99
```

Set a parameter to the fill value:
```bash
tools/param_utils/set_paramfile -i paramfile.nc -o output.nc -p needleleaf_evergreen_temperate_tree,c4_grass fleafcn=nan,nan
```
9 changes: 9 additions & 0 deletions python/ctsm/args_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,12 @@ def plon_type(plon):
"ERROR: Longitude should be between 0 and 360 or -180 and 180."
)
return plon_float


def comma_separated_list(value):
"""
Helper function for argparse to split comma-separated strings into a list.
"""
if value is None:
return None
return [v.strip() for v in value.split(",")]
141 changes: 141 additions & 0 deletions python/ctsm/netcdf_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
"""
Helper functions for working with netCDF files
"""

import numpy as np
import xarray as xr
from netCDF4 import Dataset # pylint: disable=no-name-in-module


def _is_dtype_nan_capable(ndarray: np.ndarray):
"""
Given a numpy array, return True if it's capable of taking a NaN
"""
try:
np.isnan(ndarray)
return True
except TypeError:
return False


def _are_dicts_identical_nansequal(dict0: dict, dict1: dict, keys_to_ignore=None):
"""
Compare two dictionaries, considering NaNs to be equal. Don't be strict here about types; if
they can be coerced to comparable types and then they match, return True.
"""
# pylint: disable=too-many-return-statements

if keys_to_ignore is None:
keys_to_ignore = []
keys_to_ignore = np.array(keys_to_ignore)

if len(dict0) != len(dict1):
return False
for key, value0 in dict0.items():
if key in keys_to_ignore:
continue
if key not in dict1:
return False
value1 = dict1[key]

# Coerce to numpy arrays to simplify comparison code
value0 = np.array(value0)
value1 = np.array(value1)

# Compare, only asking to check equal NaNs if both are capable of taking NaN values
both_are_nan_capable = _is_dtype_nan_capable(value0) and _is_dtype_nan_capable(value1)
if not np.array_equal(value0, value1, equal_nan=both_are_nan_capable):
return False

return True


def get_netcdf_format(file_path):
"""
Get format of netCDF file
"""
with Dataset(file_path, "r") as netcdf_file:
netcdf_format = netcdf_file.data_model
return netcdf_format


def _is_dataarray_metadata_identical(da0: xr.DataArray, da1: xr.DataArray, keys_to_ignore=None):
"""
Check whether two DataArrays have identical-enough metadata
"""

# Check data type
if da0.dtype != da1.dtype:
return False

# Check encoding
if not _are_dicts_identical_nansequal(
da0.encoding, da1.encoding, keys_to_ignore=keys_to_ignore
):
return False

# Check attributes
if not _are_dicts_identical_nansequal(da0.attrs, da1.attrs):
return False

# Check name
if da0.name != da1.name:
return False

# Check dims
if da0.dims != da1.dims:
return False

return True


def _is_dataarray_data_identical(da0: xr.DataArray, da1: xr.DataArray):
"""
Check whether two DataArrays have identical data
"""
# pylint: disable=too-many-return-statements

# Check sizes
if da0.sizes != da1.sizes:
return False

# Check coordinates
if bool(da0.coords) or bool(da1.coords):
if not bool(da0.coords) or not bool(da1.coords):
return False
if not da0.coords.equals(da1.coords):
return False

# Check values ("The array's data converted to numpy.ndarray")
if not np.array_equal(da0.values, da1.values):
# Try-except to avoid TypeError from putting NaN-incapable dtypes through
# np.array_equal(..., equal_nan=True)
try:
if not np.array_equal(da0.values, da1.values, equal_nan=True):
return False
except TypeError:
return False

# Check data ("The DataArray's data as an array. The underlying array type (e.g. dask, sparse,
# pint) is preserved.")
da0_data_type = type(da0.data)
if not isinstance(da1.data, da0_data_type):
return False
if not isinstance(da0.data, np.ndarray):
raise NotImplementedError(f"Add support for comparing two objects of type {da0_data_type}")

return True


def are_xr_dataarrays_identical(da0: xr.DataArray, da1: xr.DataArray, keys_to_ignore=None):
"""
Comprehensively check whether two DataArrays are identical
"""
if not _is_dataarray_metadata_identical(da0, da1, keys_to_ignore=keys_to_ignore):
return False

if not _is_dataarray_data_identical(da0, da1):
return False

# Fallback to however xarray defines equality, in case we missed something above
return da0.equals(da1)
Empty file.
Loading
Loading