Skip to main content
You can find your model’s GitHub repository URL in the model’s Settings page on app.veydra.io. For more details on how models connect to GitHub, see GitHub Integration.

Overview

Every Veydra model is a standalone Python project hosted on GitHub. You can clone any model repository and run it locally with standard Python tooling — no special platform or runtime required. This page walks through the repository structure, setup, execution, and testing workflow that all models follow.

Quick Start

1

Clone the Repository

Each model lives in its own GitHub repo. Clone it to your machine:
2

Create a Virtual Environment

3

Install Dependencies

4

Run the Model

Requirements

Python 3.11+

A local Python installation. Any recent 3.11+ version works.

pip

Used to install dependencies from requirements.txt.

Dependencies

All models declare their dependencies in requirements.txt. A typical model requires:

Repository Structure

Every model repository follows the same layout:

Key Files

The command-line entry point. Initializes the model, runs a default simulation, then runs an interactive simulation with the same defaults to validate the full pipeline.
Contains the master orchestrator class (inherits from VeydraModelStandard) and the two contract functions — initialize_model() and run_interactive_simulation(). This is where submodels are wired together, derivatives are computed, and the ODE solver is invoked.
Controls which stocks and flows are included in simulation results. All variables are computed internally, but only those listed here are returned.
Defines named scenarios with specific parameter overrides. Each preset has an id, a description, and a variables dict of parameter values.
Full metadata for every parameter: label, min/max, step, default, units, category, and namespace. Generated automatically by the Veydra AST analysis pipeline.

The Model Contract

Every VMS-compliant model exposes two functions from src/model.py:
  • initialize_model() — creates the model instance, runs a simulation with default parameters, and returns both the instance and the default results dict.
  • run_interactive_simulation() — takes an existing model instance and a dict of parameter overrides, re-runs the simulation, and returns updated results. Pass return_json=True to get a JSON string instead of a Python dict.

Results Format

Both functions return a results dictionary with this shape:
Stock and flow keys use the full namespaced parameter name (submodel.variable_name).

Running Simulations

Default Run

This initializes the model with default parameters and prints key outputs to the console.

Custom Parameters

You can override parameters programmatically by passing a dictionary to run_interactive_simulation():

Running Presets

Presets from config/presets.json can be loaded and passed directly:

Testing

All models ship with two test files:

Smoke Tests

Runs quick validation: can the model be imported, initialized, and executed?

Full Test Suite

Uses pytest to run structured tests including:
  • Default parameters — model runs and returns valid numeric results
  • All presets — every preset from config/presets.json is run and validated automatically
The generic test_main.py works with any VMS-compliant model — it discovers presets automatically, so you don’t need to update tests when adding new scenarios.

Model Architecture

Submodels

Models are decomposed into submodels — one per domain (e.g., population_submodel.py, resource_submodel.py). Each submodel:
  1. Defines its own VARIABLES dict with parameter metadata
  2. Inherits from the Submodel base class in veydra_model_standard.py
  3. Implements a calculate_derivatives_and_flows() method
The master orchestrator in src/model.py wires all submodels together, collects their derivatives, and passes them to SciPy’s ODE solver (solve_ivp).

Parameter Namespacing

All parameters use a submodel.variable_name naming convention to avoid collisions:

Simulation Variables

In addition to submodel parameters, every model has a set of simulation.* variables controlling execution: