Default Dictionaries Module

The _default_dicts module contains default configurations and mappings used throughout MarrmotFlow.

Default dictionaries for MarrmotFlow.

Default Forcing Units

marrmotflow._default_dicts.default_forcing_units = {'precipitation': 'millimeter / day', 'temperature': 'celsius'}

dict() -> new empty dictionary dict(mapping) -> new dictionary initialized from a mapping object’s

(key, value) pairs

dict(iterable) -> new dictionary initialized as if via:

d = {} for k, v in iterable:

d[k] = v

dict(**kwargs) -> new dictionary initialized with the name=value pairs

in the keyword argument list. For example: dict(one=1, two=2)

Default units for forcing variables used when units are not explicitly specified.

Type:

Dict[str, str]

Example values:

default_forcing_units = {
    "precip": "mm/day",
    "temp": "celsius",
    "pet": "mm/day",
    "rad": "W/m2",
    "wind": "m/s",
    "rh": "percent"
}

These units follow Pint conventions and are used for automatic unit conversion when processing forcing data.

Default Forcing Variables

marrmotflow._default_dicts.default_forcing_vars = {'precipitation': 'precip', 'temperature': 'temp'}

dict() -> new empty dictionary dict(mapping) -> new dictionary initialized from a mapping object’s

(key, value) pairs

dict(iterable) -> new dictionary initialized as if via:

d = {} for k, v in iterable:

d[k] = v

dict(**kwargs) -> new dictionary initialized with the name=value pairs

in the keyword argument list. For example: dict(one=1, two=2)

Default variable name mappings for common forcing data formats.

Type:

Dict[str, str]

Example values:

default_forcing_vars = {
    "precip": "precipitation",
    "temp": "temperature",
    "pet": "potential_evapotranspiration"
}

These mappings are used when forcing_vars is not explicitly provided to the MARRMOTWorkflow constructor.

Default Model Dictionary

marrmotflow._default_dicts.default_model_dict = {1: 'm_01_collie1_1p_1s', 2: 'm_02_wetland_4p_1s', 3: 'm_03_collie2_4p_1s', 4: 'm_04_newzealand1_6p_1s', 5: 'm_05_ihacres_7p_1s', 6: 'm_06_alpine1_4p_2s', 7: 'm_07_gr4j_4p_2s', 8: 'm_08_us1_5p_2s', 9: 'm_09_susannah1_6p_2s', 10: 'm_10_susannah2_6p_2s', 11: 'm_11_collie3_6p_2s', 12: 'm_12_alpine2_6p_2s', 13: 'm_13_hillslope_7p_2s', 14: 'm_14_topmodel_7p_2s', 15: 'm_15_plateau_8p_2s', 16: 'm_16_newzealand2_8p_2s', 17: 'm_17_penman_4p_3s', 18: 'm_18_simhyd_7p_3s', 19: 'm_19_australia_8p_3s', 20: 'm_20_gsfb_8p_3s', 21: 'm_21_flexb_9p_3s', 22: 'm_22_vic_10p_3s', 23: 'm_23_lascam_24p_3s', 24: 'm_24_mopex1_5p_4s', 25: 'm_25_tcm_6p_4s', 26: 'm_26_flexi_10p_4s', 27: 'm_27_tank_12p_4s', 28: 'm_28_xinanjiang_12p_4s', 29: 'm_29_hymod_5p_5s', 30: 'm_30_mopex2_7p_5s', 31: 'm_31_mopex3_8p_5s', 32: 'm_32_mopex4_10p_5s', 33: 'm_33_sacramento_11p_5s', 34: 'm_34_flexis_12p_5s', 35: 'm_35_mopex5_12p_5s', 36: 'm_36_modhydrolog_15p_5s', 37: 'm_37_hbv_15p_5s', 38: 'm_38_tank2_16p_5s', 39: 'm_39_mcrm_16p_5s', 40: 'm_40_smar_8p_6s', 41: 'm_41_nam_10p_6s', 42: 'm_42_hycymodel_12p_6s', 43: 'm_43_gsmsocont_12p_6s', 44: 'm_44_echo_16p_6s', 45: 'm_45_prms_18p_7s', 46: 'm_46_classic_12p_8s', 47: 'm_47_IHM19_16p_4s'}

dict() -> new empty dictionary dict(mapping) -> new dictionary initialized from a mapping object’s

(key, value) pairs

dict(iterable) -> new dictionary initialized as if via:

d = {} for k, v in iterable:

d[k] = v

dict(**kwargs) -> new dictionary initialized with the name=value pairs

in the keyword argument list. For example: dict(one=1, two=2)

Default configuration dictionary for MARRMOT models.

Type:

Dict[int, Dict[str, Any]]

Structure:

default_model_dict = {
    7: {  # HBV-96
        "name": "HBV-96",
        "description": "HBV-96 conceptual model",
        "parameters": {
            "TT": {"default": 0.0, "range": [-3, 3], "description": "Temperature threshold"},
            "C0": {"default": 3.0, "range": [1, 6], "description": "Degree-day factor"},
            # ... more parameters
        },
        "states": ["snow_storage", "soil_moisture", "groundwater"],
        "fluxes": ["snowmelt", "evapotranspiration", "recharge", "discharge"]
    },
    37: {  # GR4J
        "name": "GR4J",
        "description": "GR4J daily model",
        "parameters": {
            "X1": {"default": 100, "range": [1, 3000], "description": "Production store capacity"},
            "X2": {"default": 0, "range": [-10, 10], "description": "Intercatchment exchange"},
            # ... more parameters
        },
        "states": ["production_store", "routing_store"],
        "fluxes": ["evapotranspiration", "percolation", "exchange", "discharge"]
    }
}

Model Configuration Details

Each model entry in the default_model_dict contains:

Model Dictionary Structure

Key

Type

Description

name

str

Human-readable model name

description

str

Brief description of the model

parameters

Dict[str, Dict]

Model parameters with defaults and ranges

states

List[str]

List of model state variable names

fluxes

List[str]

List of model flux variable names

Parameter Configuration

Each parameter in the model configuration has the following structure:

Parameter Structure

Key

Type

Description

default

float

Default parameter value

range

List[float, float]

Valid parameter range [min, max]

description

str

Physical meaning of the parameter

units

str (optional)

Parameter units

Examples

Accessing Default Values

from marrmotflow._default_dicts import (
    default_forcing_units,
    default_forcing_vars,
    default_model_dict
)

# Get default units for precipitation
precip_unit = default_forcing_units["precip"]
print(f"Default precipitation unit: {precip_unit}")

# Get default variable mapping
precip_var = default_forcing_vars["precip"]
print(f"Default precipitation variable name: {precip_var}")

# Get HBV-96 model information
hbv_config = default_model_dict[7]
print(f"Model name: {hbv_config['name']}")
print(f"Parameters: {list(hbv_config['parameters'].keys())}")

Working with Model Parameters

# Access parameter information for HBV-96
hbv_params = default_model_dict[7]["parameters"]

# Get temperature threshold parameter
tt_param = hbv_params["TT"]
print(f"TT default: {tt_param['default']}")
print(f"TT range: {tt_param['range']}")
print(f"TT description: {tt_param['description']}")

# Get all parameter defaults for a model
param_defaults = {
    name: config["default"]
    for name, config in hbv_params.items()
}
print(f"HBV-96 defaults: {param_defaults}")

Custom Configurations

# Create custom configuration based on defaults
custom_forcing_units = default_forcing_units.copy()
custom_forcing_units["precip"] = "mm/hour"  # Override default

# Extend default model configuration
custom_model_dict = default_model_dict.copy()
custom_model_dict[999] = {  # Custom model
    "name": "CustomModel",
    "description": "Custom hydrological model",
    "parameters": {
        "K": {"default": 1.0, "range": [0.1, 10], "description": "Flow coefficient"}
    },
    "states": ["storage"],
    "fluxes": ["outflow"]
}

Usage in Workflows

Default Configuration

These defaults are used automatically when not specified:

from marrmotflow import MARRMOTWorkflow

# This workflow will use default units and variable mappings
workflow = MARRMOTWorkflow(
    name="DefaultConfig",
    cat="catchments.shp",
    forcing_files="climate_data.nc"
    # forcing_vars and forcing_units will use defaults
)

Override Defaults

You can override defaults by providing explicit values:

# Override default units
custom_units = {
    "precip": "inches/day",  # Override default mm/day
    "temp": "fahrenheit"     # Override default celsius
}

workflow = MARRMOTWorkflow(
    name="CustomUnits",
    cat="catchments.shp",
    forcing_files="climate_data.nc",
    forcing_vars={"precip": "rainfall", "temp": "air_temp"},
    forcing_units=custom_units
)

Model Selection

# Check available models
available_models = list(default_model_dict.keys())
print(f"Available models: {available_models}")

# Get model names
model_names = {
    num: config["name"]
    for num, config in default_model_dict.items()
}
print(f"Model mapping: {model_names}")

# Select models based on characteristics
conceptual_models = [
    num for num, config in default_model_dict.items()
    if "conceptual" in config["description"].lower()
]

Validation Functions

Unit Validation

def validate_forcing_units(units_dict):
    """Validate that forcing units are recognized."""
    import pint

    ureg = pint.UnitRegistry()
    valid_units = {}

    for var, unit in units_dict.items():
        try:
            ureg.parse_expression(unit)
            valid_units[var] = unit
        except pint.UndefinedUnitError:
            print(f"Warning: Unrecognized unit '{unit}' for variable '{var}'")
            # Use default
            valid_units[var] = default_forcing_units.get(var, "dimensionless")

    return valid_units

Model Validation

def validate_model_number(model_number):
    """Validate that model number is supported."""
    if isinstance(model_number, int):
        model_numbers = [model_number]
    else:
        model_numbers = list(model_number)

    unsupported = [
        num for num in model_numbers
        if num not in default_model_dict
    ]

    if unsupported:
        available = list(default_model_dict.keys())
        raise ValueError(
            f"Unsupported model numbers: {unsupported}. "
            f"Available models: {available}"
        )

    return model_numbers

Best Practices

  1. Use defaults when possible - they are tested and validated

  2. Override only when necessary - maintain consistency

  3. Validate custom configurations - ensure units and ranges are appropriate

  4. Document changes - explain why defaults were overridden

  5. Test custom configurations - verify they work with your data

  6. Consider backward compatibility - when modifying defaults

  7. Use standard units - prefer SI or commonly accepted units

Constants

The module may also define various constants used throughout the package:

# Example constants (check actual implementation)
DEFAULT_PET_METHOD = "penman_monteith"
DEFAULT_MODEL_NUMBERS = [7, 37]
SUPPORTED_FILE_FORMATS = [".nc", ".nc4", ".h5", ".hdf5"]