Skip to content

Commit

Permalink
Use verbatim field-table file (ufs-community#465)
Browse files Browse the repository at this point in the history
  • Loading branch information
maddenp-noaa authored Apr 19, 2024
1 parent 968aacf commit 7914064
Show file tree
Hide file tree
Showing 8 changed files with 12 additions and 223 deletions.
2 changes: 1 addition & 1 deletion docs/sections/user_guide/yaml/components/fv3.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ See :ref:`here <execution_yaml>` for details.
field_table:
^^^^^^^^^^^^

Supports ``base_file:`` and ``update_values:`` blocks (see the :ref:`updating_values` for details). See FV3 ``field_table`` documentation :weather-model-io:`here<field-table-file>`, or :ref:`defining_a_field_table` for UW YAML-specific details.
The path to a :weather-model-io:`valid field-table file<field-table-file>` to be copied into the run directory.

files_to_copy:
^^^^^^^^^^^^^^
Expand Down
52 changes: 0 additions & 52 deletions docs/sections/user_guide/yaml/field_table.rst

This file was deleted.

1 change: 0 additions & 1 deletion docs/sections/user_guide/yaml/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,5 @@ UW YAML
execution
files
updating_values
field_table
rocoto
tags
7 changes: 0 additions & 7 deletions docs/shared/fv3.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,6 @@ fv3:
threads: 1
field_table:
base_file: /path/to/field_table_to_use
update_values:
liq_wat:
longname: cloud water mixing ratio
profile_type:
name: fixed
surface_value: 2
units: kg/kg
files_to_copy:
INPUT/gfs_ctrl.nc: /path/to/gfs_ctrl.nc
INPUT/gfs_data.nc: /path/to/gfs_data.nc
Expand Down
8 changes: 1 addition & 7 deletions src/uwtools/drivers/fv3.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

from iotaa import asset, dryrun, task, tasks

from uwtools.config.formats.fieldtable import FieldTableConfig
from uwtools.config.formats.nml import NMLConfig
from uwtools.config.formats.yaml import YAMLConfig
from uwtools.drivers.driver import Driver
Expand Down Expand Up @@ -90,12 +89,7 @@ def field_table(self):
yield self._taskname(fn)
path = self._rundir / fn
yield asset(path, path.is_file)
yield None
self._create_user_updated_config(
config_class=FieldTableConfig,
config_values=self._driver_config["field_table"],
path=path,
)
yield filecopy(src=self._driver_config["field_table"]["base_file"], dst=path)

@tasks
def files_copied(self):
Expand Down
77 changes: 4 additions & 73 deletions src/uwtools/resources/jsonschema/fv3.jsonschema
Original file line number Diff line number Diff line change
Expand Up @@ -34,84 +34,14 @@
},
"field_table": {
"additionalProperties": false,
"anyOf": [
{
"required": [
"base_file"
]
},
{
"required": [
"update_values"
]
}
],
"properties": {
"base_file": {
"type": "string"
},
"update_values": {
"minProperties": 1,
"patternProperties": {
"^.*$": {
"additionalProperties": false,
"properties": {
"longname": {
"type": "string"
},
"profile_type": {
"additionalProperties": false,
"allOf": [
{
"if": {
"properties": {
"name": {
"const": "profile"
}
}
},
"then": {
"required": [
"top_value"
]
}
}
],
"properties": {
"name": {
"enum": [
"fixed",
"profile"
]
},
"surface_value": {
"type": "number"
},
"top_value": {
"type": "number"
}
},
"required": [
"name",
"surface_value"
],
"type": "object"
},
"units": {
"type": "string"
}
},
"required": [
"longname",
"profile_type",
"units"
],
"type": "object"
}
},
"type": "object"
}
},
"required": [
"base_file"
],
"type": "object"
},
"files_to_copy": {
Expand Down Expand Up @@ -211,6 +141,7 @@
"required": [
"domain",
"execution",
"field_table",
"length",
"run_dir"
],
Expand Down
8 changes: 5 additions & 3 deletions src/uwtools/tests/drivers/test_fv3.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ def config(tmp_path):
"executable": "fv3",
"mpicmd": "srun",
},
"field_table": {
"base_file": "/path/to/field_table_to_copy",
},
"lateral_boundary_conditions": {
"interval_hours": 1,
"offset": 0,
Expand Down Expand Up @@ -107,8 +110,7 @@ def test_FV3_diag_table_warn(caplog, driverobj):

def test_FV3_field_table(driverobj):
src = driverobj._rundir / "field_table.in"
with open(src, "w", encoding="utf-8") as f:
yaml.dump({}, f)
src.touch()
dst = driverobj._rundir / "field_table"
assert not dst.is_file()
driverobj._driver_config["field_table"] = {"base_file": src}
Expand Down Expand Up @@ -161,7 +163,7 @@ def test_FV3_namelist_file(driverobj):


@pytest.mark.parametrize("domain", ("global", "regional"))
def test_FV3_provisioned_run_directory_global(domain, driverobj):
def test_FV3_provisioned_run_directory(domain, driverobj):
driverobj._driver_config["domain"] = domain
with patch.multiple(
driverobj,
Expand Down
80 changes: 1 addition & 79 deletions src/uwtools/tests/test_schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,6 @@ def chgres_cube_prop():
return partial(schema_validator, "chgres-cube", "properties", "chgres_cube", "properties")


@fixture
def fv3_field_table_vals():
return (
{
"foo": {
"longname": "foofoo",
"profile_type": {"name": "fixed", "surface_value": 1},
"units": "cubits",
}
},
{
"bar": {
"longname": "barbar",
"profile_type": {"name": "profile", "surface_value": 2, "top_value": 3},
"units": "rods",
}
},
)


@fixture
def fv3_prop():
return partial(schema_validator, "fv3", "properties", "fv3", "properties")
Expand Down Expand Up @@ -196,6 +176,7 @@ def test_schema_fv3():
config = {
"domain": "regional",
"execution": {"executable": "fv3"},
"field_table": {"base_file": "/path"},
"lateral_boundary_conditions": {"interval_hours": 1, "offset": 0, "path": "/tmp/file"},
"length": 3,
"run_dir": "/tmp",
Expand All @@ -211,7 +192,6 @@ def test_schema_fv3():
{
**config,
"diag_table": "/path",
"field_table": {"base_file": "/path"},
"files_to_copy": {"fn": "/path"},
"files_to_link": {"fn": "/path"},
"model_configure": {"base_file": "/path"},
Expand All @@ -238,64 +218,6 @@ def test_schema_fv3_domain(fv3_prop):
assert "'foo' is not one of ['global', 'regional']" in errors("foo")


def test_schema_fv3_field_table(fv3_prop, fv3_field_table_vals):
val, _ = fv3_field_table_vals
base_file = {"base_file": "/some/path"}
update_values = {"update_values": val}
errors = fv3_prop("field_table")
# Just base_file is ok:
assert not errors(base_file)
# Just update_values is ok:
assert not errors(update_values)
# A combination of base_file and update_values is ok:
assert not errors({**base_file, **update_values})
# At least one is required:
assert "is not valid" in errors({})


def test_schema_fv3_field_table_update_values(fv3_prop, fv3_field_table_vals):
val1, val2 = fv3_field_table_vals
errors = fv3_prop("field_table", "properties", "update_values")
# A "fixed" profile-type entry is ok:
assert not errors(val1)
# A "profile" profile-type entry is ok:
assert not errors(val2)
# A combination of two valid entries is ok:
assert not errors({**val1, **val2})
# At least one entry is required:
assert "{} should be non-empty" in errors({})
# longname is required:
assert "'longname' is a required property" in errors(with_del(val1, "foo", "longname"))
# longname must be a string:
assert "88 is not of type 'string'" in errors(with_set(val1, 88, "foo", "longname"))
# units is required:
assert "'units' is a required property" in errors(with_del(val1, "foo", "units"))
# units must be a string:
assert "88 is not of type 'string'" in errors(with_set(val1, 88, "foo", "units"))
# profile_type is required:
assert "'profile_type' is a required property" in errors(with_del(val1, "foo", "profile_type"))
# profile_type name has to be "fixed" or "profile":
assert "'bogus' is not one of ['fixed', 'profile']" in errors(
with_set(val1, "bogus", "foo", "profile_type", "name")
)
# surface_value is required:
assert "'surface_value' is a required property" in errors(
with_del(val1, "foo", "profile_type", "surface_value")
)
# surface_value is numeric:
assert "'a string' is not of type 'number'" in errors(
with_set(val1, "a string", "foo", "profile_type", "surface_value")
)
# top_value is required if name is "profile":
assert "'top_value' is a required property" in errors(
with_del(val2, "bar", "profile_type", "top_value")
)
# top_value is numeric:
assert "'a string' is not of type 'number'" in errors(
with_set(val2, "a string", "bar", "profile_type", "top_value")
)


def test_schema_fv3_lateral_boundary_conditions(fv3_prop):
config = {
"interval_hours": 1,
Expand Down

0 comments on commit 7914064

Please sign in to comment.