hmp.Project#
Project is the object-oriented face of the Python API. Where the verbs of Python API take a config and return a
result, hydromodpy.project.Project keeps the resolved config, the workspace, the geographic runtime, the loaded
data, the mesh and the catalog handle alive between calls. It is the setup-once, run-many surface used by notebooks,
calibration loops and custom analysis scripts.
Project is a facade, not an engine. The execution engine is hydromodpy.workflow.runner.Pipeline, which runs
ordered steps with checkpoint and resume support. Both drive the same hydromodpy.workflow.steps helpers;
Project only offers a more interactive way to call them.
Construction#
Construction is cheap. __init__ validates the configuration, resolves the time grid and the data plan, and builds an
empty runtime context. It performs no heavy I/O.
import hydromodpy as hmp
project = hmp.Project("project.toml")
The constructor is polymorphic: it accepts a TOML path, a HydroModPyConfig, a dict
payload, or a JSON string, auto-detected. Keyword options are solver (auto-detected from the config otherwise),
headless (disable display and postprocess runners, useful in calibration loops) and no_display.
The heavy model phase builds lazily on the first simulate() call or on the first
accessor that needs it. Build it eagerly with prepare(), which returns self, or
call the phase verbs one by one.
Model phase#
The model phase turns a validated config into a runnable model. Each verb is callable on its own, and each one runs the phases below it when they have not happened yet.
Method |
Role |
|---|---|
|
Bootstrap the shared runtime anchor: workspace, geographic context, domain and process objects. Opens the catalog as a side effect. Idempotent: calling it twice resets those objects. |
|
Mark the geographic and domain runtime ready, record the project phase, and invalidate downstream data and mesh
state. Runs |
|
Drop the setup products and rerun the geographic pipeline, invalidating the mesh. |
|
Load the external forcings declared in the |
|
Reload a named subset of data variables. |
|
Build the mesh used by the solver. Keyword overrides patch the mesh configuration before the step runs. |
|
Run geographic, data and mesh in order. Returns the project. |
The fields of the [data] section are defined in [data] DataManagersConfig, not here.
Run phase#
simulate() runs one simulation through the configured workflow and returns its
Run. It builds the model phase on first call, then runs the Pipeline. Flow parameter
overrides such as Sy, K and Ss, plus the special keys thickness, first_clim and properties, are
applied to the plan before the Pipeline runs. Other keywords cover the run name, resume from a workflow journal,
from_step and until_step bounds, dry_run, frozen input references, no_display and parallel.
A dry run, and some non-simulation workflows, return None.
run = project.simulate(name="baseline", Sy=0.05)
There is no sweep verb. A sweep is a plain Python loop over simulate():
for value in [1e-3, 5e-3, 1e-2]:
project.simulate(name=f"sy_{value}", Sy=value)
calibrate() runs a calibration campaign on the project, either from a TOML path passed
as config_path or from parameters, outputs, objective blocks and a method given in Python.
spinup() runs the cyclic spin-up loop, restarting the representative window each cycle
from the previous cycle’s state until heads and lake stage converge. It defaults to the [spinup] section of the
project config. The returned SpinupResult carries restart_from, ready to feed a production run’s
flow.restart_from.
rerun() is a classmethod. It takes a persisted Run,
rebuilds the configuration from its snapshot, applies an optional config_overrides deep-merge patch, and launches a
new simulation whose parent_sim_id points at the original. A run with no config snapshot raises ConfigMissingError.
Overview, comparison, testbed and site selection are TOML workflows, not Project methods. They run through
hydromodpy.run() on the [workflow] mode selector, whose values are simulation, calibration,
overview, comparison, testbed and site_selection. Use Project for repeated simulations, calibration
and spin-up; use hydromodpy.run() for the one-shot workflows.
Lifecycle#
A project owns an open DuckDB catalog handle and a few cached preprocessing files.
close() closes the catalog and cleans the preprocessing tree. It reads the geographic
object straight from the context, so closing an unused project never triggers a lazy build. The preprocessing tree
survives when the geographic configuration asked for the intermediate rasters on disk.
Use the project as a context manager so close runs even when an exception is raised:
import hydromodpy as hmp
with hmp.Project("project.toml") as project:
project.setup_workspace()
project.build_geographic()
project.load_data()
project.build_mesh()
run = project.simulate(name="baseline", Sy=0.05)
Project state#
hydromodpy.project.state.ProjectState is the typed dataclass that owns the runtime state of a project. The
twenty-one private attributes that were once mutated directly on the Project instance live in this container.
The runtime state mixes immutable inputs (the resolved configuration, the solver name), cached preprocessing results
(the geographic context, the mesh inputs) and live counters (the run counter, the run history). Spread as
dunder-attributes on Project they made the surface noisy and resisted static typing. In one slots=True dataclass
they give mypy and pyright a single typed view and read as state rather than behaviour.
The fields group by concern:
Configuration:
config_path,cfg,solver,time_grid.Display flags:
headless,no_display.Mesh inputs:
mesh_section_data,external_mesh_input,mesh_constraints_mode,spatial_support_registry,requested_support_ids,requested_domain_supports.Workflow runtime:
ctx, theWorkflowContext, andstore, the openCatalog.Bookkeeping:
project_name,run_counter,active_runs,last_wall_seconds,phase,data_loaded,run_history.
Project proxies private reads and writes through __getattr__ and __setattr__, so call sites that touch the
legacy names keep working:
project._cfg # reads project._state.cfg
project._config_path # reads project._state.config_path
project._run_history # reads project._state.run_history
The mapping lives in hydromodpy.project.state.PROJECT_ATTR_TO_STATE_FIELD. A name absent from the map falls back
to the regular attribute machinery, so project._runner and project._catalog keep living on the instance. The
public read-only view of the config is project.config.
Read-only properties#
config, data, runs, data_loaded, has_mesh, geographic, domain, store, time_grid,
loaded_data and workflow_context expose the same runtime state that TOML workflows populate through the
Pipeline. geographic, domain, store, loaded_data, runs and project[sim_id] trigger the lazy model
build; config, has_mesh and time_grid do not. project[sim_id] returns the
Run for that identifier.
Accessors#
Two properties return small accessor objects. They scope catalog queries and data introspection to the current project, which keeps the facade surface small while staying explicit at the call site.
project.data returns a ProjectDataAccessor. It lists the input-data variables
already loaded and reports the ones the declared plan still expects.
import hydromodpy as hmp
with hmp.Project("project.toml") as project:
df = project.data.list() # variables loaded in cache
todo = project.data.missing() # declared but not loaded
Use it when a workflow step complains about a missing variable, or to confirm that a manual
project.load_data(types=...) covered the expected set.
project.runs returns a ProjectRunsAccessor. It wraps the project’s
Catalog and pre-filters every query by the current project name.
list()returns a DataFrame summary of every persisted run for the project.find(**filters)filters by metadata such assolver,statusor run name.latest()returns the most recent run, orNonewhen the project has none yet.best(metric)returns the run ranking first on a metric stored in the catalog, highest value first.delete(sim_id, remove_storage=True)removes a simulation from the catalog and, by default, its artefacts.
with hmp.Project("project.toml") as project:
project.simulate(Sy=0.05, name="probe-1")
project.simulate(Sy=0.08, name="probe-2")
last = project.runs.latest()
probes = project.runs.find(name="probe-1")
best = project.runs.best("nse")
The accessor yields full Run objects, not identifiers, so the caller can chain into
run.field(...), run.timeseries(...) or hmp.read(run, "head").
The catalog without a project#
A project handle is convenient for the run loop but unnecessary when the caller only wants to read previously persisted
runs. hydromodpy.open() returns a Catalog rooted at one project. It is the
read-side complement of simulate() and mirrors the xarray.open_dataset intent: one
call, a ready-to-query object.
The argument is a project directory, the one holding project.toml and .hmp/index.duckdb. A workspace root
such as ~/hydromodpy is not a project and owns no index: pass ~/hydromodpy/projects/<name> instead. With the
default create=False the call raises FileNotFoundError when no index exists; pass create=True to initialise
an empty catalog.
cat is scoped to that one project: it sees every run persisted under the project root and nothing from its
neighbours. Federation across projects is the job of hydromodpy.index(), which registers one row per project root
and expands a workspace root into the project roots it holds.
The catalog is the single door for queries. cat.find is the one filtered entry point and returns a RunSet; an
unknown filter key raises ValueError listing the valid filters. cat.frame returns the full DataFrame. Schema
discovery and selectors live on the same object: cat.describe, cat.tables, cat.columns, cat.variables,
cat.metrics, cat.stations, then cat.latest, cat.best, cat.worst, cat.rank, cat[ref],
cat.resolve, cat.sql and cat.read for the by-id read path. Input data is reached through
hydromodpy.catalog.InputsNamespace or the hmp data CLI.
Catalog and reader compose naturally inside a notebook session:
hydromodpy.read() auto-dispatches the variable name through the field registry (Zarr), the timeseries table
(DuckDB) and the geographic features table (GeoParquet), so a single call handles the three storage kinds.
When to prefer TOML and the CLI#
Use TOML plus hmp run for reproducible research, teaching material and CI. Use Project when a notebook, a
calibration method, a custom analysis loop or an application needs to orchestrate the same steps directly. The two
surfaces execute the same workflow steps, so a script and its TOML equivalent produce the same run.
Reference#
- class hydromodpy.project.Project(config, *, solver=None, headless=False, no_display=False)[source]
Setup-once, run-many interface for HydroModPy simulations.
Project(config)is cheap: it validates the configuration and builds an empty runtime context. The heavy model phase (geographic, data, mesh) is built lazily on the firstsimulate()(or eagerly viaprepare()or the per-phase verbsbuild_geographic/load_data/build_mesh). Run many simulations with parameter overrides; inspect past runs throughrunsand inputs throughdata.Parameters#
- configstr, Path, HydroModPyConfig, dict, or JSON str
A TOML path, a fully-built
HydroModPyConfig, adictpayload, or a JSON string (auto-detected).- solverstr, optional
Flow solver name. Auto-detected from the config, defaults to
"modflow_nwt".- headlessbool, optional
Disable display and postprocess runners (useful for calibration loops where generating figures per iteration is wasteful).
- no_displaybool, optional
Skip display generation for later run phases.
Examples#
>>> import hydromodpy as hmp >>> project = hmp.Project("project.toml") >>> run = project.simulate(Sy=0.05) >>> project.close()
- param config:
- type config:
- param solver:
- type solver:
- param headless:
- type headless:
- param no_display:
- type no_display:
Validate
configand build an empty runtime context (cheap).No heavy I/O: geographic delineation, data download and meshing are deferred to the first
simulate()(orprepare()).- param config:
- type config:
- param solver:
- type solver:
- param headless:
- type headless:
- param no_display:
- type no_display:
- build_geographic(*, reuse_dem=False)[source]
Mark geographic/domain runtime ready and invalidate downstream state.
- build_mesh(**overrides)[source]
Build the catchment mesh from the current geographic context.
- Return type:
- calibrate(*, config_path=None, parameters=None, outputs=None, objective_blocks=None, method=None, max_iter=None, save_runs=None, seed=None, phase=None, **kwargs)[source]
Run a calibration campaign on this project.
Three modes are supported:
TOML mode (
config_pathsupplied): delegate torun_calibration_cliwith the given TOML path. Extra keyword arguments are forwarded.Python mode (
parameterssupplied): build aCalibrationConfigin memory from the declarations and run the same loop.Embedded mode (neither supplied): use the
[calibration]section carried by this project’s config, so a fully in-memoryHydroModPyConfigcalibrates without re-declaring parameters.
A configuration declaring
[[calibration.phases]]routes torun_staged_calibration()in TOML mode, and in embedded mode when this project was built from a file. An embedded declaration on a project built in memory is refused: each phase forks a fresh configuration from the source file, and there is none. Python mode declares its own parameter space, so the phases of the project config do not apply to it.Parameters#
- config_path
Calibration TOML path for TOML mode.
- parameters
Python-mode parameter declarations.
- outputs
Python-mode output declarations.
- objective_blocks
Python-mode objective block declarations.
- method
Optimizer method name.
- max_iter
Maximum number of optimizer iterations.
- save_runs
Policy controlling which trial runs remain persisted.
- seed
Optional optimizer seed.
- phase
Run only the named phase of a staged calibration.
- kwargs
Extra options forwarded to the calibration runner.
Returns#
- CalibrationReport or StagedCalibrationReport or Any
Structured calibration report when
return_reportis true, otherwise the runner-specific result.
Raises#
- ConfigMissingError
Raised when neither
config_pathnorparametersis supplied.- ConfigError
Raised when
phaseis given andconfig_pathcannot be read, because the answer is what the file says.- CalibrationError
Raised when
[[calibration.phases]]cannot be run as declared, and whenphasenames a phase no configuration declares.
- param config_path:
- type config_path:
- param parameters:
- type parameters:
- param outputs:
- type outputs:
- param objective_blocks:
- type objective_blocks:
- param method:
- type method:
- param max_iter:
- type max_iter:
- param save_runs:
- type save_runs:
- param seed:
- type seed:
- param phase:
- type phase:
- property config: HydroModPyConfig
Validated configuration driving this project (read-only).
- property data: ProjectDataAccessor
Accessor for the input-data cache scoped to this project.
- property geographic: CatchmentDelineation | None
Geographic runtime object (DEM, watershed, CRS). Triggers build.
- property has_mesh: bool
True once the mesh has been built for the project.
- load_data(*, types=None)[source]
Load the external forcings declared in [data].
- property loaded_data: LoadedDataContext
Loaded data context (recharge, geology, hydrometry, etc.). Triggers build.
- prepare()[source]
Eagerly build the model phase (geographic, data, mesh). Returns self.
- Return type:
- rebuild_geographic(*, reuse_dem=False)[source]
Rerun the geographic pipeline and invalidate the mesh.
- reload_data(*, types)[source]
Reload a subset of data variables without touching the others.
- classmethod rerun(run, *, name=None, config_overrides=None, solver=None, headless=False, no_display=False, **overrides)[source]
Launch a new simulation from a persisted run snapshot.
runremains a read-only result view; this Project-level helper owns the orchestration required to rebuild the configuration, execute the workflow, and record the new run withparent_sim_idpointing to the original simulation.- Return type:
Run- Parameters:
Parameters#
- run
Persisted run to use as the reproducible source snapshot.
- name
Optional name for the derived run.
- config_overrides
Deep-merge patch applied to the stored config snapshot. Keys must match
HydroModPyConfigtop-level fields; the merged payload is validated by Pydantic, so unknown keys raise.- solver, headless, no_display
Options forwarded to the derived
Project.- overrides
Flow parameter overrides forwarded to
Project.simulate().
Returns#
- Run
Persisted run view for the derived simulation.
Raises#
- ConfigMissingError
If
runhas no persisted config snapshot.- PipelineError
If the derived pipeline produces no new Run, e.g.
dry_runmode.
- property runs: ProjectRunsAccessor
Accessor for the simulation catalog scoped to this project.
- setup_workspace()[source]
Bootstrap shared runtime state for the project session.
This Project-level verb prepares the workspace/catalog anchor and the shared geographic/domain/process objects used by later data, mesh, and solver phases. It is not a standalone Pipeline step; Pipeline runs get the same setup through
BuildGeographicStep.- Return type:
- simulate(*, name=None, resume=None, from_step=None, until_step=None, dry_run=False, frozen=False, no_display=False, parallel=True, **overrides)[source]
Run one simulation through the configured workflow and return its result.
Builds the model phase on first call (lazy), then runs the Pipeline. Flow parameter overrides (
Sy,K,Ss) and the special keysthickness,first_clim,propertiesare applied to the plan before the Pipeline runs. Call once per point to sweep a parameter.- Return type:
Run|None- Parameters:
Parameters#
- name
Optional run name persisted in the catalog.
- resume
Existing run identifier to resume from the workflow journal.
- from_step, until_step
Optional step bounds for partial workflow execution.
- dry_run
Build and validate the workflow without executing solver work.
- frozen
Require frozen input-data references.
- no_display
Skip display rendering for this run.
- overrides
Parameter overrides applied to the simulation plan.
Returns#
- Run or None
Persisted run view for simulation workflows. Dry runs and some non-simulation workflows may return
None.
Raises#
- PipelineError
If a workflow step fails during execution.
- SolverError
If the configured solver crashes or fails to converge.
- ResumeError
If
resumereferences an incompatible journal state.
Examples#
>>> run = project.simulate(Sy=0.05, name="probe") >>> run.summary()
See Also#
- hydromodpy.run
Functional facade for one-off TOML execution.
- hydromodpy.results.run.Run
Per-simulation result view returned by successful runs.
- param name:
- type name:
- param resume:
- type resume:
- param from_step:
- type from_step:
- param until_step:
- type until_step:
- param dry_run:
- type dry_run:
- param frozen:
- type frozen:
- param no_display:
- type no_display:
- param parallel:
- type parallel:
- spinup(*, spinup=None, name_prefix='spinup')[source]
Run the cyclic spin-up loop on this project.
Restarts the representative window each cycle from the previous cycle’s state until the aquifer heads and the lake stage converge. Defaults to the
[spinup]section of this project’s config; passspinupto override it in memory. Feedresult.restart_fromto a production run’s[flow] restart_from.- Return type:
SpinupResult- Parameters:
spinup (SpinupConfig | None)
name_prefix (str)
Parameters#
- spinup
Spin-up settings override.
Noneusesconfig.spinup.- name_prefix
Prefix for the per-cycle run names recorded in the catalog.
Returns#
- hydromodpy.project.spinup.SpinupResult
The loop outcome (converged state,
restart_fromhandle).
- property time_grid: ResolvedSimulationTimeGrid | ResolvedSteadySimulationTimeGrid | None
Resolved simulation time grid.
- property workflow_context: WorkflowContext
Mutable workflow runtime state threaded through workflow steps.
See Also#
Configuration overview – the TOML side of every option named on this page.
CLI reference – the command-line equivalents of these verbs.
hmp.open – the catalog verb documented on its own page.
hmp.run – the one-shot workflow launcher.
hydromodpy.results.run.Run– per-simulation result view.hydromodpy.project.phases– model-phase functions that mutate the state in place.API Reference – autosummary reference for every module.