Models API
The modflow_devtools.models module provides programmatic access to MODFLOW 6 (and other) model input files from official test and example repositories. It can also be used with local model repositories.
This module builds on Pooch for file fetching and caching. While it leverages Pooch’s capabilities, it provides an independent layer with:
Registration, discovery and synchronization
Support for multiple sources and refs
Hierarchical model addressing
Model registries can be synchronized from remote sources on demand. The user or developer can inspect and load models published by the MODFLOW organization, from a personal fork, or from the local filesystem.
Overview
The Models API provides:
Model registration: Index local or remote model repositories
Model discovery: Browse available models from multiple repositories
Model retrieval: Copy model input files to local workspaces
Model metadata is provided by registries which are published by model repositories. On first use, modflow-devtools automatically attempts to sync these registries.
A model registry contains three main components:
files: Map of model input files to metadata (hash, path/URL)models: Map of model names to lists of their input filesexamples: Map of example scenarios to lists of models
An example is an ordered set of models which together form a complete example scenario.
The MODFLOW organization publishes a set of models for demonstration and testing, some of which are grouped into example scenarios, from the following repositories:
MODFLOW-ORG/modflow6-examplesMODFLOW-ORG/modflow6-testmodelsMODFLOW-ORG/modflow6-largetestmodels
Usage
Syncing registries
Registries can be manually synchronized:
from modflow_devtools.models import ModelSourceConfig
config = ModelSourceConfig.load()
# Sync all configured sources
results = config.sync(verbose=True)
# Sync specific source
results = config.sync(source="modflow6-testmodels", verbose=True)
# Check sync status
status = config.status
for source_name, source_status in status.items():
print(f"{source_name}: {source_status.cached_refs}")
Or via CLI (both forms are equivalent):
# Using the mf command
mf models sync
mf models sync --source modflow6-testmodels
mf models sync --source modflow6-testmodels --ref develop
mf models sync --force
# Or using the module form
python -m modflow_devtools.models sync
python -m modflow_devtools.models sync --source modflow6-testmodels
python -m modflow_devtools.models sync --source modflow6-testmodels --ref develop
python -m modflow_devtools.models sync --force
Inspecting available models
from modflow_devtools.models import get_models, get_examples
models = get_models()
print(f"Available models: {len(models)}")
for name in list(models.keys())[:5]:
print(f" {name}")
examples = get_examples()
for example_name, model_list in list(examples.items())[:3]:
print(f"{example_name}: {len(model_list)} models")
Or by CLI (both forms are equivalent):
# Using the mf command
mf models info # Show sync status
mf models list # Show model summary...
mf models list --verbose # ..or full list
# Filter by source
mf models list --source mf6/test --verbose
# Or using the module form
python -m modflow_devtools.models info # Show sync status
python -m modflow_devtools.models list # Show model summary...
python -m modflow_devtools.models list --verbose # ..or full list
# Filter by source
python -m modflow_devtools.models list --source mf6/test --verbose
Copying models to a workspace
Models can be copied to a workspace programmatically:
from tempfile import TemporaryDirectory
from modflow_devtools.models import copy_to, cp # cp is an alias
with TemporaryDirectory() as workspace:
model_path = copy_to(workspace, "mf6/example/ex-gwf-twri01", verbose=True)
# Or use the shorter alias
model_path = cp(workspace, "mf6/example/ex-gwf-twri01", verbose=True)
Or via CLI (both forms are equivalent):
# Using the mf command
mf models copy mf6/test/test001a_Tharmonic ./my-workspace
mf models cp mf6/example/ex-gwf-twri01 /path/to/workspace --verbose # cp is an alias
# Or using the module form
python -m modflow_devtools.models copy mf6/test/test001a_Tharmonic ./my-workspace
python -m modflow_devtools.models cp mf6/example/ex-gwf-twri01 /path/to/workspace --verbose
The copy command:
Automatically attempts to sync registries before copying (if
MODFLOW_DEVTOOLS_AUTO_SYNC=1)Creates the workspace directory if it doesn’t exist
Copies all input files for the specified model
Preserves subdirectory structure within the workspace
Use
--verboseor-vflag to see detailed progress
Using the default registry
The module provides explicit access to the default registry used by get_models() etc.
from modflow_devtools.models import DEFAULT_REGISTRY
models = DEFAULT_REGISTRY.models
files = DEFAULT_REGISTRY.files
examples = DEFAULT_REGISTRY.examples
workspace = DEFAULT_REGISTRY.copy_to("./workspace", "mf6/example/ex-gwf-twri01")
Customizing model sources
Create a user config file to add custom sources or override defaults:
Windows:
%APPDATA%/modflow-devtools/models.tomlmacOS:
~/Library/Application Support/modflow-devtools/models.tomlLinux:
~/.config/modflow-devtools/models.toml
Example user config:
[sources.modflow6-testmodels]
repo = "myusername/modflow6-testmodels" # Use a fork for testing
name = "mf6/test"
refs = ["feature-branch"]
The user config is automatically merged with the bundled config, allowing you to test against forks or add private repositories.
Working with specific sources
Access individual model sources:
from modflow_devtools.models import ModelSourceConfig, _DEFAULT_CACHE
# Load configuration
config = ModelSourceConfig.load()
# Work with specific source
source = config.sources["modflow6-testmodels"]
# Check if synced
if source.is_synced("develop"):
print("Already cached!")
# List synced refs
synced_refs = source.list_synced_refs()
# Sync specific ref
result = source.sync(ref="develop", verbose=True)
# Load cached registry
registry = _DEFAULT_CACHE.load("mf6/test", "develop")
if registry:
print(f"Models: {len(registry.models)}")
print(f"Files: {len(registry.files)}")
Model Names
Model names follow a hierarchical addressing scheme: {source}@{ref}/{path/to/model}.
The path/to/ part is referred to as the prefix. Valid prefixes include:
mf6/example/...: MODFLOW 6 example models from modflow6-examplesmf6/test/...: MODFLOW 6 test models from modflow6-testmodelsmf6/large/...: Large MODFLOW 6 test models from modflow6-largetestmodelsmf2005/...: MODFLOW-2005 models from modflow6-testmodels
Example model names:
mf6/example/ex-gwf-twri01
mf6/test/test001a_Tharmonic
mf6/large/prudic2004t2
Local Registries
For development or testing with local models, create a local registry:
from modflow_devtools.models import LocalRegistry
# Create and index a local registry
registry = LocalRegistry()
registry.index("path/to/models")
# Index with custom namefile pattern (e.g., for MODFLOW-2005)
registry.index("path/to/mf2005/models", namefile_pattern="*.nam")
# Use the local registry
models = registry.models
workspace = registry.copy_to("./workspace", "my-model-name")
Model subdirectories are identified by the presence of a namefile. By default, only MODFLOW 6 models are indexed (mfsim.nam). Use namefile_pattern to include other model types.
Cache Management
Model registries and files are cached locally for fast access:
Registries:
~/.cache/modflow-devtools/models/registries/{source}/{ref}/Model files:
~/.cache/modflow-devtools/models/(managed by Pooch)
The cache enables:
Fast model access without re-downloading
Offline access to previously used models
Efficient switching between repository refs
Check cache status:
from modflow_devtools.models import _DEFAULT_CACHE
# List all cached registries
cached = _DEFAULT_CACHE.list() # Returns: [(source, ref), ...]
for source, ref in cached:
print(f"{source}@{ref}")
# Check specific cache
is_cached = _DEFAULT_CACHE.has("mf6/test", "develop")
# Clear cache programmatically
_DEFAULT_CACHE.clear() # Clear all
_DEFAULT_CACHE.clear(source="mf6/test") # Clear specific source
_DEFAULT_CACHE.clear(source="mf6/test", ref="develop") # Clear specific source@ref
Or via CLI:
# List cached registries
mf models list
# Clear all cached registries (with confirmation prompt)
mf models clear
# Clear specific source
mf models clear --source mf6/test
# Clear specific source and ref
mf models clear --source mf6/test --ref develop
# Skip confirmation prompt
mf models clear --force
Automatic Synchronization
Auto-sync is opt-in (experimental). To enable:
export MODFLOW_DEVTOOLS_AUTO_SYNC=1 # or "true" or "yes"
When enabled, modflow-devtools attempts to sync registries:
On first access (best-effort, fails silently on network errors)
When accessing models via the API or CLI
Then manually sync when needed:
mf models sync
# Or: python -m modflow_devtools.models sync
Repository Integration
Model repositories publish registry files (models.toml) describing available models, input files, and example groupings.
Registry Generation
The make_registry tool generates registry files from version-controlled or release asset models.
Version-controlled models:
python -m modflow_devtools.models.make_registry \
--repo MODFLOW-ORG/modflow6-testmodels \
--ref master \
--name mf6/test \
--path mf6 \
--output .registry
Release asset models:
python -m modflow_devtools.models.make_registry \
--repo MODFLOW-ORG/modflow6-examples \
--ref current \
--asset-file mf6examples.zip \
--name mf6/example \
--output .registry
Publishing Registries
Registry files can be published under version control or as release assets.
Under version control:
For instance, to commit a generated registry to a .registry/ directory:
- name: Generate registry
run: |
python -m modflow_devtools.models.make_registry \
--repo ${{ github.repository }} \
--ref ${{ github.ref_name }} \
--name mf6/test \
--path mf6 \
--output .registry
- name: Commit registry
run: |
git add .registry/models.toml
git commit -m "Update registry [skip ci]"
git push
As release assets:
For instance, to upload a registry as a release asset:
- name: Generate registry
run: |
python -m modflow_devtools.models.make_registry \
--repo ${{ github.repository }} \
--ref ${{ github.ref_name }} \
--asset-file mf6examples.zip \
--name mf6/example \
--output .registry
- name: Upload registry as release asset
uses: actions/upload-release-asset@v1
with:
asset_path: .registry/models.toml
asset_name: models.toml
Registry Format
The generated models.toml file contains:
files: Map of filenames to hashes (URLs constructed dynamically)models: Map of model names to file listsexamples: Map of example names to model lists
See the developer documentation for detailed registry format specifications.