Metadata-Version: 2.4
Name: funz-fz
Version: 2.0
Summary: Parametric scientific computing package
Author: FZ Team
Maintainer: FZ Team
License: BSD-3-Clause
Project-URL: Bug Reports, https://github.com/funz/fz/issues
Project-URL: Source, https://github.com/funz/fz
Keywords: parametric,computing,simulation,scientific,hpc,ssh
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: paramiko>=2.7.0
Requires-Dist: pandas>=1.0.0
Requires-Dist: charset-normalizer>=3.0.0
Provides-Extra: dev
Requires-Dist: pytest>=6.0; extra == "dev"
Requires-Dist: pytest-cov; extra == "dev"
Requires-Dist: black; extra == "dev"
Requires-Dist: flake8; extra == "dev"
Provides-Extra: r
Requires-Dist: rpy2>=3.4.0; extra == "r"
Provides-Extra: mcp
Requires-Dist: mcp>=1.2.0; python_version >= "3.10" and extra == "mcp"
Dynamic: license-file

# FZ - Parametric Scientific Computing Framework

[![CI](https://github.com/Funz/fz/workflows/CI/badge.svg)](https://github.com/Funz/fz/actions/workflows/ci.yml)
[![License](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)
[![Version](https://img.shields.io/badge/version-2.0-blue.svg)](https://github.com/Funz/fz/releases)

FZ wraps a simulation code driven by text input files and turns it into a parametric
study: it substitutes variable values into input templates, runs every case (locally, over
SSH, on SLURM or a Funz server, in parallel, with caching and retries) and returns the
results as a pandas DataFrame.

- [Features](#features) · [Installation](#installation) · [Quick Start](#quick-start) ·
  [The six functions](#the-six-functions) · [Key concepts](#key-concepts) ·
  [Configuration](#configuration) · [Threat Model](#threat-model) ·
  [AI agents and MCP](#using-fz-with-ai-coding-agents) · [Documentation](#documentation)

## Features

- **Parametric studies**: factorial designs (dict, Cartesian product) or explicit cases (DataFrame).
- **Templates with formulas**: `$var` substitution and `@{...}` Python or R expressions in any text input file.
- **Local, SSH, SLURM and Funz execution**, with automatic file transfer and protocol-specific error reports.
- **Parallel execution** over several calculators, **retries** on another calculator, **caching** of previous results.
- **Adaptive design of experiments** (`fzd`) with pluggable algorithms.
- **Traceability**: one `manifest.json` (and an RO-Crate) per campaign.
- **Interrupt handling**: Ctrl+C stops cleanly and keeps partial results.
- Linux, macOS and Windows (MSYS2/Git Bash); requires `bash`.

## Installation

```bash
pip install funz-fz          # or: pipx install funz-fz  (isolated CLI install)
pip install -e .             # from a clone of https://github.com/Funz/fz
```

Required dependencies (`paramiko`, `pandas`, `charset-normalizer`) are installed
automatically. Optional extras: `funz-fz[r]` (R formulas, needs R), `funz-fz[mcp]`
(MCP server, Python >= 3.10). Python 3.9 to 3.14 are supported. More options:
[Installation](doc/installation.md).

## Quick Start

A complete parametric study (ideal gas pressure, 4 × 3 = 12 cases).

`input.txt` (the template; `$var` are variables, `@{...}` formulas, `#@` preprocessing lines):

```text
# input file for Perfect Gaz Pressure, with variables n_mol, T_celsius, V_L
n_mol=$n_mol
T_kelvin=@{$T_celsius + 273.15}
#@ def L_to_m3(L):
#@     return(L / 1000)
V_m3=@{L_to_m3($V_L)}
```

`PerfectGazPressure.sh` (the calculation; receives the compiled input as `$1`; make it executable with `chmod +x`):

```bash
#!/bin/bash
source $1
sleep 5 # simulate a calculation time
echo 'pressure = '`echo "scale=4;$n_mol*8.314*$T_kelvin/$V_m3" | bc` > output.txt
```

`run_study.py`:

```python
import fz

model = {
    "varprefix": "$",
    "formulaprefix": "@",
    "delim": "{}",
    "commentline": "#",
    "output": {
        "pressure": "grep 'pressure = ' output.txt | awk '{print $3}'"
        # shell-free alternative: "python://grep(r'pressure = (\\S+)', 'output.txt')"
    },
}

input_variables = {
    "T_celsius": [10, 20, 30, 40],  # 4 temperatures
    "V_L": [1, 2, 5],               # 3 volumes
    "n_mol": 1.0,                   # fixed amount
}

results = fz.fzr(
    "input.txt",
    input_variables,
    model,
    calculators="sh://bash PerfectGazPressure.sh",
    results_dir="results",
)
print(results)
```

```
   T_celsius  V_L  n_mol     pressure status calculator       error command
0         10  1.0    1.0  235358.1200   done     sh://        None    bash...
1         10  2.0    1.0  117679.0600   done     sh://        None    bash...
...
```

Each case runs in its own directory under `results/` with its compiled input, `out.txt`,
`err.txt` and `log.txt`. More examples: [`examples/examples.md`](examples/examples.md)
and the notebooks in [`examples/`](examples/). Extended version (R formulas, other output
extractors): [Quick Start](doc/quick-start.md).

## The six functions

Each function has a CLI twin with the same semantics (`fz <name>`, or `fzi`, `fzc`, ...);
CLI output is parseable with `--format json`.

| Function | Purpose |
|----------|---------|
| `fzi` | **I**nspect input files: list the variables (and defaults) |
| `fzc` | **C**ompile input files by substituting variable values |
| `fzo` | Parse **o**utput files of finished calculations |
| `fzr` | **R**un a complete parametric study, end to end |
| `fzd` | Iterative **d**esign of experiments with adaptive algorithms |
| `fzl` | **L**ist and validate installed models and calculators |

Full reference: [Python API](doc/core-functions.md) and [CLI](doc/cli-usage.md).
`fz install <name|url>` installs models and algorithms ([details](doc/installing-models.md)).

## Key concepts

**Model**: a dict or JSON file (or installed alias) telling fz how to read templates
(`varprefix`, `formulaprefix`, `delim`, `commentline`) and how to extract results
(`output`: shell commands, or shell-free `python://`, `jq://`, `yq://`, `xpath://`).
See [Model definition](doc/model-definition.md).

**Calculator**: where and how a case runs, given as a URI (or an installed alias):

| URI | Runs on |
|-----|---------|
| `sh://command` | local shell |
| `ssh://user@host[:port]/command` | remote host over SSH (key authentication recommended) |
| `slurm://[user@host:]:partition/command` | SLURM (`srun`); `slurm-array://` batches cases in a job array (local only) |
| `funz://host:port/Code` | legacy Java Funz server |
| `cache://path` | reuse results of a previous run (matched by input hash and, if declared, code identity) |

Pass a list to spread cases over several calculators. See [Calculator types](doc/calculators.md).

**Execution**: cases run in parallel with automatic load balancing, failed cases are
retried on another calculator, `cache://` resumes an interrupted or extended study, and
Ctrl+C stops gracefully. See [Advanced features](doc/parallel-and-caching.md) and
[Interrupt handling](doc/interrupt-handling.md).

## Configuration

Main environment variables (all optional; full list in [Configuration](doc/configuration.md)):

| Variable | Meaning |
|----------|---------|
| `FZ_LOG_LEVEL` | `DEBUG`, `INFO`, `WARNING`, `ERROR` |
| `FZ_MAX_WORKERS` | maximum parallel cases |
| `FZ_MAX_RETRIES` | attempts per failed case (default 5) |
| `FZ_RUN_TIMEOUT` | per-calculation timeout in seconds (default 3600 for `sh://` and `funz://`; unlimited for `ssh://` and `slurm://` unless set) |
| `FZ_SHELL_PATH` | directories searched for shell tools (mainly Windows/MSYS2) |
| `FZ_CACHE_STRICT` | `1`: refuse `cache://` matches whose code identity cannot be verified |

## Threat Model

fz does not sandbox the models, algorithms, or calculators it runs. This is a
deliberate, current choice, not an oversight to be fixed later: any isolation
(e.g. restricting formulas to a safe subset) would break real, existing usage
of this repository (`#@import math` and other multi-line preprocessing
directives, multi-line Python/R formulas, output-parsing commands that shell
out, `python -c` calculator invocations). Isolation is deferred until there is
a concrete need for it (network-facing exposure, running third-party models
you did not author) rather than added speculatively.

Concretely, everything below runs as code, with your user's privileges, when
you call `fzi`/`fzc`/`fzr`/`fzd`:

- **Template preprocessing lines** (`#@...`) and **formulas** (`@{...}`) in
  input files are evaluated (Python `eval`/`exec`, or R).
- **Output-parsing commands** declared in a model's `"output"` (e.g. a shell
  pipeline, or a `python://`/`python -c` snippet) are executed to extract
  results.
- **Calculator commands** (`sh://`, `ssh://`, ...) run whatever command string
  you or a model/calculator alias declare.
- **`version_cmd`** of a calculator alias (used to resolve `code_id` for
  `cache://`, see [Calculator Aliases](doc/calculators.md#calculator-aliases)) is a shell command run by fz itself,
  locally for `sh://` or on the remote host for `ssh://`, when a campaign
  resolves its calculators (once per calculator and process, before any case
  runs). It carries the same trust requirement as the calculator command.

**Don't run a model, algorithm, or calculator alias from a source you don't
trust** — it is equivalent to running a shell script from that source.
`fz install <url>` (see [Installing Plugins](doc/installing-models.md)) prints a one-time
reminder of this when installing from a network source. The same applies to
`fz-mcp` (see [MCP server](#mcp-server-fz-mcp) below): giving an AI agent access to it in its
default (trusted) mode is equivalent to giving that agent shell access.


## Using fz with AI Coding Agents

An [Agent Skill](https://agentskills.io) is bundled in [`skills/fz/`](skills/fz/): it teaches
coding agents (Claude Code and other agents supporting the skills format) the fz workflow.
In Claude Code:

```
/plugin marketplace add Funz/fz
/plugin install fz@funz
```

or copy `skills/fz/` into `.claude/skills/` (project) or `~/.claude/skills/` (user). The
skill holds the workflow ([`skills/fz/SKILL.md`](skills/fz/SKILL.md)), a condensed
API/CLI reference ([`skills/fz/reference.md`](skills/fz/reference.md)) and wrapper guides.
Walkthrough with example prompts: [`skills/howto.md`](skills/howto.md); plugin slash commands
and manual install: [AI agents](doc/ai-agents.md).

### MCP server (`fz-mcp`)

**Trusted mode (the default) is equivalent to giving the agent shell access** (see
[Threat Model](#threat-model) and [`doc/mcp-server.md`](doc/mcp-server.md)).

`fz-mcp` exposes `fzi`, `fzc`, `fzr`, `fzo` and `fzl` as [MCP](https://modelcontextprotocol.io)
tools over `stdio` (the only transport by default). Install with `pip install 'funz-fz[mcp]'`
(Python >= 3.10), then e.g. `claude mcp add fz -- fz-mcp`. File paths are confined to
`FZ_MCP_ROOT` (default: working directory). `FZ_MCP_TRUSTED=0` restricts models and
calculators to installed aliases; it does not sandbox formula evaluation inside fz.
Details: [MCP server](doc/mcp-server.md).

## Documentation

- **Documentation in `doc/`** (one file per topic; start at [`doc/INDEX.md`](doc/INDEX.md)): [CLI](doc/cli-usage.md), [Python API](doc/core-functions.md), [models](doc/model-definition.md), [calculators](doc/calculators.md), [parallelism and caching](doc/parallel-and-caching.md), [configuration](doc/configuration.md), [troubleshooting](doc/troubleshooting.md), [examples](doc/quick-examples.md), [custom `fzd` algorithms](doc/custom-algorithms.md), [plugins](doc/installing-models.md), [development](doc/development.md), [breaking changes](doc/breaking-changes.md), [MCP server](doc/mcp-server.md), [constraints and pitfalls](doc/limitations.md).
- **Examples**: [`examples/examples.md`](examples/examples.md), [`examples/`](examples/) notebooks and scripts.
- **All resources and test examples**: [Resources](doc/resources.md).
- **Release notes**: [`NEWS.md`](NEWS.md).

### Former README sections

Links such as `README.md#cli-usage` land here: the sections below moved to `doc/` (text unchanged).

- <a id="cli-usage"></a><a id="installation-of-cli-tools"></a><a id="fzi---parse-input-variables"></a><a id="fzc---compile-input-files"></a><a id="fzo---read-output-files"></a><a id="fzl---list-and-validate-modelscalculators"></a><a id="fzr---run-parametric-calculations"></a><a id="fzd---design-of-experiments"></a><a id="fz-install--uninstall"></a><a id="cli-options-reference"></a><a id="common-options-all-commands"></a><a id="exit-codes-and-output-streams"></a><a id="argument-formats"></a><a id="model-definition-options"></a><a id="fzr-specific-options"></a><a id="complete-cli-examples"></a><a id="example-1-quick-variable-discovery"></a><a id="example-2-quick-compilation-test"></a><a id="example-3-parse-existing-results"></a><a id="example-4-end-to-end-parametric-study"></a><a id="example-5-using-model-and-calculator-aliases"></a><a id="example-6-interrupt-and-resume"></a><a id="fzd---run-design-of-experiments"></a><a id="environment-variables-for-cli"></a>[CLI usage](doc/cli-usage.md)
- <a id="core-functions"></a><a id="input-variables-factorial-vs-non-factorial-designs"></a><a id="factorial-design-dict"></a><a id="non-factorial-design-dataframe"></a>[Python API (Core Functions)](doc/core-functions.md)
- <a id="model-definition"></a><a id="model-aliases"></a><a id="formula-evaluation"></a><a id="python-interpreter-default"></a><a id="r-interpreter"></a><a id="variable-default-values"></a><a id="old-funz-syntax-compatibility"></a>[Model definition](doc/model-definition.md)
- <a id="calculator-types"></a><a id="local-shell-execution"></a><a id="ssh-remote-execution"></a><a id="slurm-workload-manager"></a><a id="funz-server-execution"></a><a id="cache-calculator"></a><a id="calculator-aliases"></a><a id="calculator-model-compatibility"></a>[Calculator types](doc/calculators.md)
- <a id="advanced-features"></a><a id="parallel-execution"></a><a id="retry-mechanism"></a><a id="caching-strategy"></a><a id="output-type-casting"></a><a id="vector-array-outputs"></a><a id="progress-callbacks"></a>[Advanced features](doc/parallel-and-caching.md)
- <a id="complete-examples"></a><a id="interactive-jupyter-notebooks"></a><a id="example-1-perfect-gas-pressure-study"></a><a id="example-2-remote-hpc-calculation"></a><a id="example-3-multi-calculator-with-failover"></a><a id="example-4-design-of-experiments-with-adaptive-sampling"></a><a id="example-5-optimization-with-bfgs"></a>[Complete examples](doc/quick-examples.md)
- <a id="writing-custom-algorithms-for-fzd"></a><a id="algorithm-interface"></a><a id="algorithm-examples"></a><a id="1-monte-carlo-sampling"></a><a id="2-bfgs-optimization"></a><a id="3-brents-method-1d-optimization"></a><a id="algorithm-features"></a><a id="content-format-detection"></a><a id="dependency-management"></a>[Custom algorithms for fzd](doc/custom-algorithms.md)
- <a id="environment-variables"></a><a id="shell-path-configuration-fz_shell_path"></a><a id="campaign-manifest-and-ro-crate-traceability"></a><a id="timeout-configuration"></a><a id="1-environment-variable-global-default"></a><a id="2-model-configuration-per-model"></a><a id="3-fzrfzc-timeout-argument-per-call"></a><a id="priority-order-highest-to-lowest"></a><a id="python-configuration"></a><a id="directory-structure"></a>[Configuration details](doc/configuration.md)
- <a id="installing-plugins"></a><a id="installing-algorithm-plugins"></a><a id="from-github-repository-name"></a><a id="from-github-url"></a><a id="from-local-zip-file"></a><a id="using-installed-algorithms"></a><a id="installing-model-plugins"></a><a id="from-github-repository-name-1"></a><a id="from-github-url-or-local-zip"></a><a id="listing-installed-plugins"></a><a id="uninstalling-plugins"></a><a id="plugin-priority"></a><a id="creating-algorithm-plugins"></a>[Installing plugins](doc/installing-models.md)
- <a id="interrupt-handling"></a><a id="how-to-interrupt"></a><a id="what-happens"></a><a id="resuming-after-interrupt"></a><a id="example-with-interrupt-handling"></a>[Interrupt handling](doc/interrupt-handling.md)
- <a id="output-file-structure"></a><a id="logtxt---execution-metadata"></a><a id="fz_hash---input-file-checksums"></a>[Output file structure](doc/overview.md)
- <a id="breaking-changes"></a><a id="version-091"></a><a id="fzr-directory-structure-change"></a>[Breaking changes](doc/breaking-changes.md)
- <a id="development"></a><a id="running-tests"></a><a id="project-structure"></a><a id="testing-your-own-models"></a>[Development](doc/development.md)
- <a id="troubleshooting"></a><a id="common-issues"></a><a id="windows--cross-platform"></a><a id="debug-mode"></a>[Troubleshooting](doc/troubleshooting.md)
- <a id="performance-tips"></a>[Performance tips](doc/parallel-and-caching.md)
- <a id="core-capabilities"></a><a id="six-core-functions"></a>[Features (full)](doc/overview.md)
- <a id="using-pip"></a><a id="using-pipx-recommended-for-cli-tools"></a><a id="from-source"></a><a id="dependencies"></a>[Installation (full)](doc/installation.md)
- <a id="1-create-an-input-template"></a><a id="2-create-a-calculation-script"></a><a id="3-run-parametric-study"></a>[Quick Start (full)](doc/quick-start.md)
- [AI coding agents (full)](doc/ai-agents.md)
- [MCP server (full)](doc/mcp-server.md)
- <a id="main-documentation"></a><a id="context-documentation"></a><a id="examples"></a><a id="test-examples"></a>[Resources](doc/resources.md)

## Development and contributing

```bash
pip install -e ".[dev]"
pytest tests/ -x
```

See [Development](doc/development.md) for the test layout and CI. Contributions
welcome: fork, create a feature branch, add tests, make sure they pass, open a pull request.

## Citation

If you use FZ in your research, please cite it (see [`CITATION.cff`](CITATION.cff)):

```bibtex
@software{fz,
  title = {FZ: Parametric Scientific Computing Framework},
  designers = {[Yann Richet]},
  authors = {[Claude Sonnet, Yann Richet]},
  year = {2025},
  url = {https://github.com/Funz/fz}
}
```

## License and support

<a id="support"></a><a id="license"></a><a id="contributing"></a>BSD 3-Clause License, see [`LICENSE`](LICENSE). Issues: https://github.com/Funz/fz/issues ·
Repository: https://github.com/Funz/fz
