Skip to content

Commit 9c63fe2

Browse files
authored
Merge pull request #3560 from samsrabin/ndims-error-in-set_paramfile
set_paramfile: Allow simply setting all of a parameter to a single value
2 parents 37661b7 + adc13e1 commit 9c63fe2

File tree

4 files changed

+67
-15
lines changed

4 files changed

+67
-15
lines changed

doc/source/users_guide/using-clm-tools/paramfile-tools.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,14 @@ Change a one-dimensional parameter (`mimics_fmet` has the `segment` dimension, l
5757
tools/param_utils/set_paramfile -i paramfile.nc -o output.nc mimics_fmet=0.1,0.2,0.3,0.4
5858
```
5959

60+
Change a one-dimensional parameter to be all one value (`mxmat` has the `pft` dimension, length 79):
61+
```bash
62+
tools/param_utils/set_paramfile -i paramfile.nc -o output.nc mxmat=360
63+
```
64+
6065
Change a parameter for specific PFTs:
6166
```bash
62-
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
67+
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 mxmat=199
6368
```
6469

6570
Set a parameter to the fill value:

python/ctsm/param_utils/set_paramfile.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ def check_correct_ndims(da, new_value, throw_error=False):
130130
"""
131131
expected = da.ndim
132132
actual = np.array(new_value).ndim
133-
is_ndim_correct = expected == actual
133+
is_ndim_correct = actual in (0, expected) # If actual 0, apply it to all
134134
if throw_error and not is_ndim_correct:
135135
raise RuntimeError(f"Incorrect N dims: Expected {expected}, got {actual}")
136136
return is_ndim_correct
@@ -323,11 +323,12 @@ def apply_new_value_to_parameter(args, ds_out, var, new_value, var_encoding, *,
323323
# Ensure that any NaNs are replaced with the fill value
324324
new_value = _replace_nans_with_fill(var_encoding, new_value, chg=chg)
325325

326-
# This can be needed if, e.g., you're selecting and changing just one PFT
326+
# This can be needed if, (a) you're selecting and changing just one PFT or (b) you're changing
327+
# all values in a dimensioned parameter to match one value.
327328
if ds_out[var].values.ndim > 0 and new_value.ndim == 0:
328-
new_value = np.atleast_1d(new_value)
329-
330-
ds_out[var].values = new_value
329+
ds_out[var].values[:] = new_value
330+
else:
331+
ds_out[var].values = new_value
331332
return ds_out
332333

333334

python/ctsm/test/test_sys_set_paramfile.py

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -121,19 +121,65 @@ def test_set_paramfile_changeparams_scalar_errors_given_list(self):
121121
with self.assertRaisesRegex(RuntimeError, "Incorrect N dims"):
122122
sp.main()
123123

124-
def test_set_paramfile_changeparam_1d_errors_given_scalar(self):
125-
"""Test that set_paramfile errors if given a scalar for a 1-d parameter"""
124+
def test_set_paramfile_changeparam_1d_given_scalar(self):
125+
"""
126+
Test that set_paramfile works correctly if given a scalar for a 1-d parameter. We want it
127+
to set all members of the 1d array to the given scalar.
128+
"""
126129
output_path = os.path.join(self.tempdir, "output.nc")
127130
sys.argv = [
128131
"set_paramfile",
129132
"-i",
130133
PARAMFILE,
131134
"-o",
132135
output_path,
133-
"xl=0.724",
136+
"mxmat=1987",
134137
]
135-
with self.assertRaisesRegex(RuntimeError, "Incorrect N dims"):
136-
sp.main()
138+
sp.main()
139+
self.assertTrue(os.path.exists(output_path))
140+
ds_in = open_paramfile(PARAMFILE)
141+
ds_out = open_paramfile(output_path)
142+
143+
for var in ds_in.variables:
144+
# Check that all variables/coords are equal except the ones we changed, which should be
145+
# set to what we asked
146+
if var == "mxmat":
147+
self.assertTrue(np.all(ds_out[var].values == 1987))
148+
else:
149+
self.assertTrue(are_paramfile_dataarrays_identical(ds_in[var], ds_out[var]))
150+
151+
def test_set_paramfile_changeparam_1d_given_scalar_and_pftlist(self):
152+
"""
153+
Test that set_paramfile works correctly if given a scalar for a 1-d parameter. We want it
154+
to set all members of the 1d array to the given scalar. As
155+
test_set_paramfile_changeparam_1d_given_scalar, but here we give a pft list.
156+
"""
157+
output_path = os.path.join(self.tempdir, "output.nc")
158+
sys.argv = [
159+
"set_paramfile",
160+
"-i",
161+
PARAMFILE,
162+
"-o",
163+
output_path,
164+
"-p",
165+
"temperate_corn,irrigated_temperate_corn",
166+
"mxmat=1987",
167+
]
168+
sp.main()
169+
self.assertTrue(os.path.exists(output_path))
170+
ds_in = open_paramfile(PARAMFILE)
171+
ds_out = open_paramfile(output_path)
172+
173+
for var in ds_in.variables:
174+
# Check that all variables/coords are equal except the ones we changed, which should be
175+
# set to what we asked
176+
if var == "mxmat":
177+
# First, check that they weren't 1987 before
178+
self.assertFalse(np.any(ds_in[var].values[17:18] == 1987))
179+
# Now check that they are 1987
180+
self.assertTrue(np.all(ds_out[var].values[17:18] == 1987))
181+
else:
182+
self.assertTrue(are_paramfile_dataarrays_identical(ds_in[var], ds_out[var]))
137183

138184
def test_set_paramfile_changeparams_scalar_double(self):
139185
"""Test that set_paramfile can copy to a new file with some scalar double params changed"""

python/ctsm/test/test_unit_set_paramfile.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,14 @@ def test_checkcorrectndims_0d_int_np(self):
6565
self.assertTrue(sp.check_correct_ndims(da, np.int32(1)))
6666

6767
def test_checkcorrectndims_1d_int(self):
68-
"""Check False when given a standard int for a 0d parameter"""
68+
"""Check True when given a standard int for a 0d parameter"""
6969
da = xr.DataArray(data=[1, 2])
70-
self.assertFalse(sp.check_correct_ndims(da, 1))
70+
self.assertTrue(sp.check_correct_ndims(da, 1))
7171

7272
def test_checkcorrectndims_1d_int_np(self):
73-
"""Check False when given a numpy int for a 0d parameter"""
73+
"""Check True when given a numpy int for a 0d parameter"""
7474
da = xr.DataArray(data=[1, 2])
75-
self.assertFalse(sp.check_correct_ndims(da, np.int32(1)))
75+
self.assertTrue(sp.check_correct_ndims(da, np.int32(1)))
7676

7777
def test_checkcorrectndims_0d_list(self):
7878
"""Check False when given a list for a 0d parameter"""

0 commit comments

Comments
 (0)