{"id":51842901,"url":"https://github.com/pasteurlabs/mosaic","last_synced_at":"2026-07-23T08:30:46.888Z","repository":{"id":368165640,"uuid":"1229163118","full_name":"pasteurlabs/mosaic","owner":"pasteurlabs","description":"A benchmark suite and re-usable collection of differentiable physics solvers.","archived":false,"fork":false,"pushed_at":"2026-07-06T21:49:10.000Z","size":77526,"stargazers_count":11,"open_issues_count":15,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-07-06T22:17:46.057Z","etag":null,"topics":["automatic-differentiation","benchmark","differentiable-physics","differentiable-programming","scientific-computing","scientific-machine-learning","tesseract"],"latest_commit_sha":null,"homepage":"https://docs.pasteurlabs.ai/projects/mosaic/stable","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pasteurlabs.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-04T19:07:03.000Z","updated_at":"2026-07-06T20:55:33.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/pasteurlabs/mosaic","commit_stats":null,"previous_names":["pasteurlabs/mosaic"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/pasteurlabs/mosaic","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pasteurlabs%2Fmosaic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pasteurlabs%2Fmosaic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pasteurlabs%2Fmosaic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pasteurlabs%2Fmosaic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pasteurlabs","download_url":"https://codeload.github.com/pasteurlabs/mosaic/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pasteurlabs%2Fmosaic/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35796815,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-07-20T02:08:10.276Z","status":"online","status_checked_at":"2026-07-23T02:00:06.683Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["automatic-differentiation","benchmark","differentiable-physics","differentiable-programming","scientific-computing","scientific-machine-learning","tesseract"],"created_at":"2026-07-23T08:30:46.118Z","updated_at":"2026-07-23T08:30:46.882Z","avatar_url":"https://github.com/pasteurlabs.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/logo.png\" width=\"520\" alt=\"Mosaic logo\"\u003e\n\u003c/p\u003e\n\n# Mosaic\n\n**A benchmark suite and reusable collection of differentiable physics solvers.** \u003cbr\u003e\nThink OpenAI Gym, but for differentiable physics: a growing catalog of tasks across physical domains, with a standardized interface and evaluation protocol for every solver and their gradients.\n\n\u003ca href=\"https://docs.pasteurlabs.ai/projects/mosaic/stable/docs/results_ns_grid.html\"\u003e\u003cimg src=\"https://img.shields.io/badge/%F0%9F%93%8A_results-browse-3b6fb6\" alt=\"Results\"\u003e\u003c/a\u003e\n\u003ca href=\"#run-the-benchmarks\"\u003e\u003cimg src=\"https://img.shields.io/badge/%E2%96%B6_run-the_benchmarks-555\" alt=\"Run\"\u003e\u003c/a\u003e\n\u003ca href=\"#use-tesseracts-in-your-own-code\"\u003e\u003cimg src=\"https://img.shields.io/badge/%F0%9F%A7%A9_use-in_your_code-555\" alt=\"Use\"\u003e\u003c/a\u003e\n\u003ca href=\"#contribute\"\u003e\u003cimg src=\"https://img.shields.io/badge/%F0%9F%A4%9D_contribute-add_a_solver-555\" alt=\"Contribute\"\u003e\u003c/a\u003e\n\u003ca href=\"https://docs.pasteurlabs.ai/projects/mosaic/stable/\"\u003e\u003cimg src=\"https://img.shields.io/badge/docs-stable-3b6fb6\" alt=\"Stable docs\"\u003e\u003c/a\u003e\n\u003ca href=\"https://arxiv.org/abs/2606.27895\"\u003e\u003cimg src=\"https://img.shields.io/badge/paper-arXiv-b31b1b\" alt=\"Paper\"\u003e\u003c/a\u003e\n\u003ca href=\"LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/badge/license-Apache--2.0-green\" alt=\"License\"\u003e\u003c/a\u003e\n\n![Overview of Mosaic: diverse solver backends are wrapped behind a uniform containerized interface (Tesseract), enabling cross-solver comparison on shared benchmark tasks across different physical domains.](docs/visual_abstract.png)\n\n## What Mosaic measures\n\nIf you optimize or train _through_ a physics simulation, the solver must return two correct things: the forward prediction **and** its gradient (the vector–Jacobian product, VJP). Most benchmarks check only the forward pass. Mosaic checks both, and scores every solver on three axes:\n\n- **Gradient accuracy** — does the VJP match a finite-difference ground truth?\n- **Computational cost** — wall-clock time (forward + VJP) and peak memory.\n- **Setup compatibility** — does the solver even _run_ on the task, or do structural constraints rule it out?\n\nEach solver is packaged as a [Tesseract](https://github.com/pasteurlabs/tesseract-core) container exposing a uniform `apply` / `vjp` interface. A single harness can therefore compare solvers across languages and AD backends (JAX, PyTorch, Julia, hand-written C++ adjoints) by talking only to that common interface.\n\n## Domains \u0026 solvers\n\n| ID     | Domain                     | Optimization task              | Solvers                                                |\n| :----- | :------------------------- | :----------------------------- | :----------------------------------------------------- |\n| **H**  | Heat transfer              | Conductivity inversion         | deal.II, FEniCS, Firedrake, JAX-FEM, torch-fem         |\n| **S**  | Structural mechanics       | Compliance minimization (SIMP) | deal.II, FEniCS, Firedrake, JAX-FEM, TopOpt.jl         |\n| **F2** | Incompressible fluids (2D) | Inflow optimization (drag)     | JAX-CFD, PhiFlow, INS.jl, XLB, PICT, Warp-NS, OpenFOAM |\n| **F3** | 3D Navier–Stokes           | Initial condition recovery     | PhiFlow, XLB, PICT, Warp-NS, Exponax, INS.jl, OpenFOAM |\n\n## 📊 Results\n\n**[Browse the benchmark results →](https://docs.pasteurlabs.ai/projects/mosaic/stable/docs/results_ns_grid.html)** — no setup required.\n\nPer-domain pages with every plot, solver rankings, and the full evaluation protocol, refreshed on each release:\n[Navier–Stokes 2D](https://docs.pasteurlabs.ai/projects/mosaic/stable/docs/results_ns_grid.html) ·\n[Navier–Stokes 3D](https://docs.pasteurlabs.ai/projects/mosaic/stable/docs/results_ns_3d_grid.html) ·\n[Structural mechanics](https://docs.pasteurlabs.ai/projects/mosaic/stable/docs/results_structural_mesh.html) ·\n[Heat transfer](https://docs.pasteurlabs.ai/projects/mosaic/stable/docs/results_thermal_mesh.html)\n\n## So, which solver is best?\n\nIt depends, and there likely isn't even a \"best\" solver for a given task. These solvers were built for different jobs, in different languages, with different differentiation strategies, and very different user experiences. Mosaic runs them side by side to make those differences visible, but also marginalizes over a lot of nuance.\n\nWhat we can offer are a few patterns that recur across domains and are unlikely to shift with more configuration tuning, because they follow from fundamental constraints rather than from how exactly a solver is set up.\n\n\u003e [!NOTE]\n\u003e These takeaways are the high-level version and are glossing over a lot of detail. For the full analysis see our [paper](https://arxiv.org/abs/2606.27895).\n\n**On well-conditioned problems, compute performance and integration effort matter most.** Heat transfer and structural mechanics are our controlled cases, where the physics is linear and the objective is smooth. Every differentiable solver reproduces the finite-difference gradient direction almost exactly (cosine similarity above 0.999), and although pointwise accuracy still spans a few orders of magnitude, that spread does not decide the outcome, since all backends agree on the forward solution and converge to effectively the same optimum. What is left to distinguish them is how fast the forward-plus-VJP pass runs and how much work it took to wire up. For a large class of inverse and design problems, you can simply pick the solver that is fastest and/or easiest to integrate.\n\n**Rollout length is a fundamental bottleneck.** Pushing the 3D Navier–Stokes gradient out to longer and longer horizons separates a solver's success into two separate properties. The first is _gradient conditioning_, set by the numerical discretization: as the flow turns chaotic, projection-based schemes tend to accumulate spurious non-physical modes that corrupt the gradient (return non-finite values within a couple hundred steps), whereas lattice-Boltzmann and finite-volume schemes keep the gradient bounded far longer. The second is _memory_, set by the differentiation strategy: tape-based reverse-mode AD stores every step and eventually runs out, while methods that avoid unrolling the full trace stay within budget. So at long horizons, prefer a well-conditioned discretization with an AD strategy that does not grow with the rollout, and always check the gradient magnitude rather than trusting that a run which completes has produced a usable gradient.\n\n**Whether a solver can even run the task is a major constraint.** For example, on the 2D drag-minimization problem, only three of seven fluid solvers can participate at all. Some assume periodic boundaries and cannot represent the obstacle, others rely on a spectral projection incompatible with the geometry. Before comparing gradient quality, check whether a solver's assumptions match your problem.\n\nNote that today's tasks are deliberately on the simpler end — laminar flow, linear elasticity, modest horizons — and configurations are mostly out-of-the-box rather than expert-tuned. Harder regimes may well surface cases where raw gradient quality becomes the binding constraint.\n\n\u003e [!TIP]\n\u003e Browse the [per-domain pages](https://docs.pasteurlabs.ai/projects/mosaic/stable/docs/results.html) for the numbers behind each of these claims.\n\n## 📖 Documentation\n\nTwo versions are published. **You most likely want to use [stable](https://docs.pasteurlabs.ai/projects/mosaic/stable/) — it tracks the latest release and is the most reliable (all solvers benchmarked in the same run).** [Latest](https://docs.pasteurlabs.ai/projects/mosaic/latest/) tracks the `main` branch and may aggregate results from different runs.\n\nStart here:\n[Getting Started](https://docs.pasteurlabs.ai/projects/mosaic/stable/docs/getting-started.html) ·\n[Use Solvers Elsewhere](https://docs.pasteurlabs.ai/projects/mosaic/stable/docs/standalone.html) ·\n[Solver Reference](https://docs.pasteurlabs.ai/projects/mosaic/stable/docs/solvers.html) ·\n[How it works](https://docs.pasteurlabs.ai/projects/mosaic/stable/docs/internals.html) ·\n[Add a Backend](https://docs.pasteurlabs.ai/projects/mosaic/stable/docs/tutorial.html)\n\n\u003e [!TIP]\n\u003e **Reproducing our paper?** See the [`v0.1+paper-repro`](https://github.com/pasteurlabs/mosaic/tree/v0.1+paper-repro) tag for figure-generation code, pinned dependencies, and step-by-step instructions.\n\n---\n\n## Run the benchmarks\n\n**Requires** Python ≥ 3.10, Docker, and — for GPU solvers — the [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html).\n\n\u003e [!WARNING]\n\u003e We strongly recommend **Linux with Docker Engine**. Docker Desktop on macOS/Windows runs containers in a VM, adding significant overhead and ARM compatibility issues on Apple Silicon. On macOS/Windows, prefer a Linux VM or WSL 2 with Docker Engine installed natively.\n\n```bash\ngit clone https://github.com/pasteurlabs/mosaic \u0026\u0026 cd mosaic\nuv sync          # or: pip install -e .\nmosaic run       # builds containers, runs experiments, generates plots\n```\n\n**Verify your setup** with a single-problem `--debug` run (reduced grid sizes, finishes in minutes):\n\n```bash\n$ mosaic run -p thermal-mesh --suites forward --debug\n──────────────────────────── problem: thermal-mesh ─────────────────────────────\n──────────────────────────────────── build ─────────────────────────────────────\n  deal.II          → dealii_heat_thermal_mesh:latest     (3.6s)\n  FEniCS           → fenics_heat_thermal_mesh:latest     (3.2s)\n  Firedrake        → firedrake_heat_thermal_mesh:latest  (2.4s)\n  JAX-FEM          → jax_fem_thermal_mesh:latest         (5.1s)\n  torch-fem        → torch_fem_thermal_mesh:latest       (4.8s)\n─────────────────────────────────── summary ────────────────────────────────────\n┏━━━━━━━━━━━━━━┳━━━━━━━━━┓\n┃ problem      ┃ forward ┃\n┡━━━━━━━━━━━━━━╇━━━━━━━━━┩\n│ thermal-mesh │   ok    │\n└──────────────┴─────────┘\n```\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eCommon workflows\u003c/strong\u003e — inspect results, pick solvers, re-run a subset\u003c/summary\u003e\n\n#### Inspect results\n\n```bash\nmosaic status                        # per-experiment completion table\nmosaic status -p ns-grid -f          # single domain with failure reasons\nmosaic status --format md \u003e report.md\nmosaic status --format json \u003e snap.json\n```\n\n#### Pick which solvers run\n\n`-s` / `--solvers` takes either a flat CSV (union across every problem) or a per-problem map:\n\n```bash\n# Flat CSV — each problem keeps only the listed solvers that exist there.\nmosaic run -s OpenFOAM,XLB,deal.II,JAX-FEM\n\n# Per-problem map — explicit picks per domain.\nmosaic run -s \"ns-grid=XLB,jax-cfd;structural-mesh=Firedrake,JAX-FEM\"\n```\n\n#### Re-run a subset\n\n`mosaic run --only \u003cstate[,…]\u003e` re-executes only cells in the given state, leaving fresh-ok cells alone — handy for iterating on one solver or recovering from a partial failure.\n\n```bash\nmosaic run --only failed              # re-run only failed cells\nmosaic run --only failed,stale        # plus anything invalidated by the harness/source\nmosaic run --only missing             # first-time runs only\nmosaic run -s PhiFlow --only excluded # re-check after dropping an exclusion\n```\n\nStates: `failed`, `anom`, `missing`, `stale`, `excluded`. Combine with `-p` / `--suites` / `-e` / `-s` for finer scoping.\n\n\u003c/details\u003e\n\nThe full CLI reference and smoke-test workflow live in [Getting Started](https://docs.pasteurlabs.ai/projects/mosaic/stable/docs/getting-started.html).\n\n## Use Tesseracts in your own code\n\nEvery solver is a standalone [Tesseract](https://github.com/pasteurlabs/tesseract-core) you can call from your own research code — no benchmark harness required.\n\n```bash\n# Shared schemas (deps: pydantic + tesseract-core only)\npip install -e mosaic/mosaic_shared\n\n# For containerised usage (recommended): also install tesseract-jax\npip install tesseract-core tesseract-jax jax\n```\n\n**Via container** (works for every solver regardless of language). Build the image once, then call it from JAX with full `grad` support:\n\n```python\nimport jax\nimport jax.numpy as jnp\nfrom tesseract_core import Tesseract\nfrom tesseract_jax import apply_tesseract\nfrom mosaic_shared.problems.navier_stokes_grid.schemas import make_vortex_ic\n\nic = make_vortex_ic(N=64, seed=42)\ninputs = {\"v0\": ic, \"viscosity\": jnp.array([0.01]), \"steps\": 50}\n\nwith Tesseract.from_image(\"exponax_navier_stokes_grid:latest\") as t:\n    outputs = apply_tesseract(t, inputs)\n    grad_v0 = jax.grad(lambda v0: jnp.mean(\n        apply_tesseract(t, {**inputs, \"v0\": v0})[\"result\"] ** 2\n    ))(inputs[\"v0\"])\n```\n\nA **local (no Docker)** path is also available for Python-only solvers — see the full guide below.\n\n📖 [Standalone Usage](https://docs.pasteurlabs.ai/projects/mosaic/stable/docs/standalone.html) (GPU, mesh-based solvers, gotchas) · [Solver Reference](https://docs.pasteurlabs.ai/projects/mosaic/stable/docs/solvers.html) (per-solver catalog with image names)\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eProgrammatic API\u003c/strong\u003e — run evaluations without the CLI\u003c/summary\u003e\n\n```python\nfrom mosaic import get_config, PROBLEMS\n\ncfg = get_config(\"ns-grid\")           # Problem for 2-D Navier-Stokes\nprint(cfg.solver_names)               # available solver backends\n\n# Each (suite, experiment) is registered on the Problem as an Experiment\n# closure. Invoke one directly with a {solver_name: image_tag} mapping:\ntags = {s.name: s.image_tag for s in cfg.solvers}\nresults = cfg.experiments[\"gradient/fd_check\"].fn(cfg, tags)\n```\n\nTop-level imports: `PROBLEMS`, `get_config`, `Problem`, `SolverSpec`, `IcSpec`, and the shared suite-kernel modules `forward`, `gradient`, `cost`, `optimization` (from `mosaic.benchmarks.problems.shared`).\n\n\u003c/details\u003e\n\n## Contribute\n\nMosaic is designed to grow with the community. Three ways in, roughly by scope:\n\n- **Tune an existing solver** — improve an out-of-the-box config. Snapshot `mosaic status --format json` before/after and include the diff. → [CONTRIBUTING.md](CONTRIBUTING.md#tuning-an-existing-solver)\n- **Add a solver** to an existing domain — three files under `mosaic/tesseracts/\u003cdomain\u003e/\u003csolver-name\u003e/`. → [Add a Solver tutorial](https://docs.pasteurlabs.ai/projects/mosaic/stable/docs/tutorial.html#part-a--add-a-solver-to-an-existing-domain)\n- **Add a benchmark domain** — scaffold with `mosaic new-domain \u003cname\u003e --from-template \u003ctemplate\u003e`. → [Add a Domain tutorial](https://docs.pasteurlabs.ai/projects/mosaic/stable/docs/tutorial.html#part-b--add-a-new-benchmark-domain)\n\n[CONTRIBUTING.md](CONTRIBUTING.md) covers code style, the PR workflow, and building the docs locally. For questions, visit the [Tesseract Forum](https://si-tesseract.discourse.group/).\n\n## Project structure\n\n```\nmosaic/\n  benchmarks/             # evaluation harness (Python package: mosaic.benchmarks)\n    cli.py                # command-line interface\n    core/                 # runner, config, hardware detection, solver auto-discovery\n    problems/             # per-domain packages (ns-grid, ns-3d-grid, structural-mesh, thermal-mesh)\n      shared/             # cross-domain suite kernels (forward, gradient, cost, optimization) + plots\n    plots/                # plotting infrastructure\n  templates/              # task templates for scaffolding new domains\n  tesseracts/             # solver backends (each is a Tesseract container)\n    mosaic_shared/        # shared Tesseract interface schemas (also pip-installable)\n    navier-stokes-grid/   # JAX-CFD, PhiFlow, XLB, PICT, Warp-NS, etc.\n    structural-mesh/      # deal.II, FEniCS, Firedrake, JAX-FEM, TopOpt.jl\n    thermal-mesh/         # deal.II, FEniCS, Firedrake, JAX-FEM, torch-fem\n  tests/                  # unit tests (run with pytest)\ndocs/                     # Quarto documentation site\n```\n\n## Citation\n\nIf you use Mosaic in your research, please cite the paper ([arXiv:2606.27895](https://arxiv.org/abs/2606.27895)):\n\n```bibtex\n@misc{rehmann2026mosaic,\n  title         = {Mosaic: A Benchmark Suite for Differentiable Physics Solvers},\n  author        = {Rehmann, Andrin and Zimmermann, Heiko and H{\\\"a}fner, Dion},\n  year          = {2026},\n  eprint        = {2606.27895},\n  archivePrefix = {arXiv},\n  primaryClass  = {physics.comp-ph},\n  url           = {https://arxiv.org/abs/2606.27895}\n}\n```\n\n## License\n\nApache 2.0. Individual solver backends retain their upstream licenses, documented per solver in the repository.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpasteurlabs%2Fmosaic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpasteurlabs%2Fmosaic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpasteurlabs%2Fmosaic/lists"}