Project Components

Project Components#

Submodule Map#

Module

Purpose

Language

Stability

zoomy_core

Symbolic models, FVM numerics, mesh hierarchy, code generators

Python

Stable

zoomy_jax

JAX-accelerated solvers, JIT compilation

Python

Evolving

zoomy_gui

Web-based GUI (static site), cards, sessions, Pyodide execution

JS/HTML/CSS/Python

Active

zoomy_cli

Command-line interface (mirrors GUI workflow)

Node.js

Active

zoomy_server

FastAPI backend, solver adapters, job management, card registry

Python

Active

zoomy_mesh

Mesh format converters (HDF5, Gmsh)

Python

Stable

zoomy_dmplex

PETSc/DMPlex backend (C++ codegen, MPI)

Python/C++

Stable

zoomy_amrex

AMReX backend (C++ codegen, AMR)

Python/C++

Stable

zoomy_firedrake

Firedrake/FEniCSx backends (UFL, DG)

Python

Stable

zoomy_client

Lightweight HTTP client for server API

Python

Minimal

zoomy_foam

OpenFOAM code generation

Python

Stable

zoomy_js

JavaScript utilities (shared)

JS

Minimal

zoomy_tests

Shared test infrastructure

Python

Stable

Server Adapter Pattern#

Each solver backend implements the SolverAdapter interface:

class SolverAdapter:
    tag = "numpy"  # identifier for backend routing

    def solve(self, case_dir, output_dir, on_progress):
        """Run simulation from case folder to output folder."""
        # 1. Execute mesh.py (optional preprocessing)
        # 2. Load model from model.py
        # 3. Load mesh from case files
        # 4. Create solver and run
        # 5. Write results to output_dir/simulation.h5
        # 6. Report progress via on_progress(iteration, time, dt)

Case folder format (what adapters receive):

case_dir/
  model.py          Python file defining `model` instance
  numerics.py       Optional: numerical scheme configuration
  mesh.py           Optional: preprocessing script (generates mesh)
  settings.json     Solver parameters (time_end, cfl, output_snapshots)
  mesh.h5 / mesh.msh   Mesh file (from mesh.py or pre-existing)

Job lifecycle:

  1. Client POSTs to /api/v1/jobs with case data

  2. Server creates job ID, spawns worker in process pool

  3. Worker calls adapter.solve(case_dir, output_dir, on_progress)

  4. Client polls GET /api/v1/jobs/{id} for status

  5. On completion, results available at /api/v1/jobs/{id}/results/hdf5