generated from NOAA-OWP/owp-open-source-project-template
-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add soil moisture profile init config model
- Loading branch information
Showing
1 changed file
with
154 additions
and
0 deletions.
There are no files selected for viewing
154 changes: 154 additions & 0 deletions
154
python/ngen_conf/src/ngen/config/init_config/soil_moisture_profile.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
from typing import Any, Dict, Literal, Optional, Union | ||
|
||
from ngen.init_config import serializer_deserializer | ||
from pydantic import Field, root_validator | ||
from typing_extensions import override | ||
|
||
from .utils import CSList | ||
|
||
bmi = Literal["BMI", "bmi"] | ||
soil_storage_model = Literal[ | ||
"Conceptual", "conceptual", "Layered", "layered", "TopModel", "topmodel", "TOPMODEL" | ||
] | ||
soil_moisture_profile_option = Literal["Constant", "constant", "Linear", "linear"] | ||
water_table_based_method = Literal["deficit_based", "flux_based"] | ||
|
||
|
||
class SoilMoistureProfile(serializer_deserializer.IniSerializerDeserializer): | ||
soil_z: CSList[float] | ||
""" | ||
vertical resolution of the soil moisture profile (depths from the surface) | ||
""" | ||
|
||
# https://github.com/NOAA-OWP/SoilMoistureProfiles/blob/2d61b86a3d7010be93af0d67f4d01fa6d0993029/src/soil_moisture_profile.cxx#L243-L249 | ||
soil_depth_layers: Optional[Union[CSList[float], bmi]] | ||
""" | ||
Absolute depth of soil layers. | ||
Specify as `BMI` if the variable will be provided by another BMI module. | ||
Required if soil_storage_model = `layered`. | ||
""" | ||
|
||
# alt: soil_params.smcmax | ||
# TODO: fix how lists are handled | ||
smcmax: Union[CSList[float], bmi] | ||
""" | ||
The maximum moisture content (i.e., porosity). | ||
Note porosity for layered-based models vary by layers. | ||
""" | ||
|
||
# alt: soil_params.b | ||
# b > 0 | ||
# https://github.com/NOAA-OWP/SoilMoistureProfiles/blob/832d5a70d632d9978dec40a480e970a6b59720c5/src/soil_moisture_profile.cxx#L169C23-L169C23 | ||
b: float = Field(gt=0) | ||
""" | ||
The pore size distribution, beta exponent in Clapp-Hornberger function. | ||
Must be greater that 0. | ||
""" | ||
|
||
# alt: soil_params.satpsi | ||
satpsi: float | ||
"""saturated capillary head (saturated moisture potential)""" | ||
|
||
soil_storage_model: soil_storage_model | ||
""" | ||
if conceptual, conceptual models are used for computing the soil moisture profile (e.g., CFE). | ||
If layered, layered-based soil moisture models are used (e.g., LGAR). | ||
If topmodel, topmodel's variables are used. | ||
""" | ||
soil_moisture_profile_option: Optional[soil_moisture_profile_option] | ||
""" | ||
constant for layered-constant profile. | ||
linear for linearly interpolated values between two consecutive layers. | ||
Needed if soil_storage_model = layered. | ||
""" | ||
|
||
# soil_storage_depth > 0 | ||
# https://github.com/NOAA-OWP/SoilMoistureProfiles/blob/832d5a70d632d9978dec40a480e970a6b59720c5/src/soil_moisture_profile.cxx#L199 | ||
soil_storage_depth: Optional[float] = Field(None, gt=0) | ||
""" | ||
depth of the soil reservoir model (e.g., CFE). | ||
must be greater than 0. | ||
Note: this depth can be different from the depth of the soil moisture profile which is based on soil_z | ||
""" | ||
|
||
# 6.0 default from: | ||
# https://github.com/NOAA-OWP/SoilMoistureProfiles/blob/832d5a70d632d9978dec40a480e970a6b59720c5/src/soil_moisture_profile.cxx#L294 | ||
# https://github.com/NOAA-OWP/SoilMoistureProfiles/blob/832d5a70d632d9978dec40a480e970a6b59720c5/src/soil_moisture_profile.cxx#L298 | ||
water_table_depth: float = Field(6.0, gte=0) | ||
|
||
# 0.4 meter default from: | ||
# https://github.com/NOAA-OWP/SoilMoistureProfiles/blob/832d5a70d632d9978dec40a480e970a6b59720c5/src/soil_moisture_profile.cxx#L270 | ||
soil_moisture_fraction_depth: float = 0.4 # in meters | ||
""" | ||
**user specified depth for the soil moisture fraction (default is 40 cm) | ||
""" | ||
|
||
water_table_based_method: Optional[water_table_based_method] | ||
""" | ||
Needed if soil_storage_model = topmodel. | ||
flux-based uses an iterative scheme, and deficit-based uses catchment deficit to compute soil moisture profile | ||
""" | ||
|
||
# NOTE: confirm this is optional | ||
verbosity: Optional[Literal["high", "low", "none"]] | ||
|
||
@override | ||
def to_ini_str(self) -> str: | ||
data = self.dict(by_alias=True, exclude_none=True, exclude_unset=True) | ||
return self._to_ini_str(data) | ||
|
||
@root_validator(pre=True) | ||
@classmethod | ||
def _root_validator(cls, values: Dict[str, Any]): | ||
# soil_params.<var_name> _are_ supported, but deprecated. | ||
soil_params_mapping = ( | ||
("soil_params.b", "b"), | ||
("soil_params.satpsi", "satpsi"), | ||
("soil_params.smcmax", "smcmax"), | ||
) | ||
# map from the deprecated names to the supported names _if_ only the deprecated name is provided | ||
for alt, actual in soil_params_mapping: | ||
if alt in values and actual not in values: | ||
values[actual] = values[alt] | ||
# delete is not required, pydantic will ignore the values. | ||
# del values[alt] | ||
return values | ||
|
||
@root_validator() | ||
def _assert_invariants(cls, values: Dict[str, Any]): | ||
# https://github.com/NOAA-OWP/SoilMoistureProfiles/blob/832d5a70d632d9978dec40a480e970a6b59720c5/src/soil_moisture_profile.cxx#L273 | ||
soil_storage_model = values["soil_storage_model"] | ||
soil_storage_depth = values.get("soil_storage_depth") | ||
if soil_storage_depth is None and soil_storage_model.lower() == "conceptual": | ||
raise ValueError( | ||
f"'soil_storage_depth' required for 'soil_storage_model': {soil_storage_model!r}" | ||
) | ||
|
||
# https://github.com/NOAA-OWP/SoilMoistureProfiles/blob/832d5a70d632d9978dec40a480e970a6b59720c5/src/soil_moisture_profile.cxx#L286 | ||
smp_opt = values.get("soil_moisture_profile_option") | ||
if soil_storage_model.lower() == "layered" and smp_opt is None: | ||
raise ValueError( | ||
f"'soil_moisture_profile_option' required for 'soil_storage_model': {soil_storage_model!r}" | ||
) | ||
|
||
# https://github.com/NOAA-OWP/SoilMoistureProfiles/blob/832d5a70d632d9978dec40a480e970a6b59720c5/src/soil_moisture_profile.cxx#L313 | ||
wtm = values.get("water_table_based_method") | ||
if soil_storage_model.lower() == "topmodel" and wtm is None: | ||
raise ValueError( | ||
f"'water_table_based_method' required for 'soil_storage_model': {soil_storage_model!r}" | ||
) | ||
|
||
# https://github.com/NOAA-OWP/SoilMoistureProfiles/blob/2d61b86a3d7010be93af0d67f4d01fa6d0993029/src/soil_moisture_profile.cxx#L243-L249 | ||
sdl = values.get("soil_depth_layers") | ||
if sdl is None and soil_storage_model.lower() == "layered": | ||
raise ValueError( | ||
f"'soil_depth_layers' required for 'soil_storage_model': {soil_storage_model!r}" | ||
) | ||
|
||
return values | ||
|
||
class Config(serializer_deserializer.IniSerializerDeserializer.Config): | ||
no_section_headers: bool = True | ||
# extra space is not accounted for | ||
# https://github.com/NOAA-OWP/SoilMoistureProfiles/blob/2d61b86a3d7010be93af0d67f4d01fa6d0993029/src/soil_moisture_profile.cxx#L114 | ||
space_around_delimiters: bool = False |