| Title: | R Wrapper for the 'funz-fz' Parametric Simulation Framework |
|---|---|
| Description: | Provides R bindings to the 'funz-fz' Python package using 'reticulate'. The 'fz' framework wraps arbitrary simulation codes to run parameter sweeps, design-of-experiments studies, and iterative algorithm-driven analyses by substituting variable placeholders in text input files and collecting outputs into data frames. Calculators can run locally (shell), over SSH, or on 'SLURM' clusters. See <https://github.com/Funz/fz> for the underlying framework. |
| Authors: | Yann Richet [aut, cre] (ORCID: <https://orcid.org/0000-0002-5677-8458>) |
| Maintainer: | Yann Richet <[email protected]> |
| License: | BSD_3_clause + file LICENSE |
| Version: | 1.2.0 |
| Built: | 2026-10-04 11:05:15 UTC |
| Source: | https://github.com/funz/fz.r |
Checks whether the fz Python package is available in the current Python environment.
fz_available()fz_available()
The importable module name of the funz-fz package is fz. This
function returns TRUE only when a module named fz imports
and exposes the expected API (fzi/fzc/fzo/
fzr), so that an unrelated Python package that also happens to be
importable as fz is not mistaken for funz-fz. All examples
and tests are guarded with if (fz_available()) and therefore skip
(rather than error) when the Python side is missing or misconfigured.
Logical; TRUE if fz is available, FALSE otherwise.
if (fz_available()) { message("fz is available!") } else { message("Please install fz with fz_install()") }if (fz_available()) { message("fz is available!") } else { message("Please install fz with fz_install()") }
This function installs the fz Python package into a virtual environment or conda environment managed by reticulate.
fz_install( packages = "funz-fz", method = "auto", conda = "auto", pip = TRUE, ... )fz_install( packages = "funz-fz", method = "auto", conda = "auto", pip = TRUE, ... )
packages |
Package specification passed to |
method |
Installation method. Either "auto", "virtualenv", or "conda". |
conda |
Path to conda executable. Only used when method is "conda". |
pip |
Logical; use pip for installation? Default is TRUE. |
... |
Additional arguments passed to |
NULL (invisibly). Called for side effects.
## Not run: # Install fz in a virtual environment fz_install() # Install in a conda environment fz_install(method = "conda") # Track the latest main branch on GitHub (unreleased features) fz_install(packages = "git+https://github.com/Funz/fz.git") ## End(Not run)## Not run: # Install fz in a virtual environment fz_install() # Install in a conda environment fz_install(method = "conda") # Track the latest main branch on GitHub (unreleased features) fz_install(packages = "git+https://github.com/Funz/fz.git") ## End(Not run)
Compiles input file(s) by replacing variable placeholders with values.
Each unique combination of values is written to its own subdirectory inside
output_dir, named var1=val1,var2=val2,....
fzc( input_path, input_variables, model, output_dir = "output", input_static = NULL )fzc( input_path, input_variables, model, output_dir = "output", input_static = NULL )
input_path |
Path to input file or directory. |
input_variables |
Named list of variable values. Supply a vector of values to generate a full-factorial grid across variables. |
model |
Model definition dict or alias string. |
output_dir |
Output directory for compiled files. Default |
input_static |
Optional character vector of files that are identical
across every case (see |
NULL (invisibly). Called for side effects.
if (fz_available()) { tf <- tempfile(fileext = ".txt") writeLines(c("P = ${P~1.013}", "V = ${V~22.4}"), tf) model <- list(varprefix = "$", delim = "{}", formulaprefix = "@", commentline = "#") out <- tempfile() fzc(tf, list(P = 2.0, V = 11.2), model, out) fzc(tf, list(P = c(1.0, 2.0), V = c(11.2, 22.4)), model, out) }if (fz_available()) { tf <- tempfile(fileext = ".txt") writeLines(c("P = ${P~1.013}", "V = ${V~22.4}"), tf) model <- list(varprefix = "$", delim = "{}", formulaprefix = "@", commentline = "#") out <- tempfile() fzc(tf, list(P = 2.0, V = 11.2), model, out) fzc(tf, list(P = c(1.0, 2.0), V = c(11.2, 22.4)), model, out) }
Runs an iterative design of experiments driven by an algorithm.
Unlike fzr (which evaluates a fixed grid), fzd lets an
algorithm adaptively choose which parameter combinations to evaluate, which
is useful for sensitivity analysis, surrogate-model fitting, or optimization.
fzd( input_path, input_variables, model, output_expression = NULL, algorithm, calculators = NULL, algorithm_options = NULL, analysis_dir = "analysis", input_static = NULL )fzd( input_path, input_variables, model, output_expression = NULL, algorithm, calculators = NULL, algorithm_options = NULL, analysis_dir = "analysis", input_static = NULL )
input_path |
Path to input file or directory. Must be |
input_variables |
Named list of variable range strings of the form
|
model |
Model definition dict or alias string, or an R function (see "Direct function model" below). |
output_expression |
Expression evaluated on the model outputs to
produce the quantity the algorithm optimizes or analyses, e.g.
|
algorithm |
Path to the algorithm Python file, e.g.
|
calculators |
Calculator specification(s). Default |
algorithm_options |
Algorithm options as a named list, a JSON string,
or a path to a JSON file. Default |
analysis_dir |
Analysis directory. Default |
input_static |
Optional character vector of files identical across every
case (see |
Named list with the analysis results produced by the algorithm.
Instead of a file-based model, model can be an R function. This
requires funz-fz >= 1.2 (earlier releases do not support callable
models); a development build can be installed with
fz_install(packages = "git+https://github.com/Funz/fz.git"). In
this mode:
input_path must be NULL – there are no input files.
input_variables names must match the function's arguments.
output_expression may be NULL; the value used is then
the first element of the function's return value (its return value
directly if scalar, the first element if a vector/list, or the first
entry's value if a named list).
calculators must be a single integer, but is always forced
to 1 here – regardless of the value passed in – before being
forwarded to fz. On the fz (Python) side,
calculators > 1 now evaluates a Python-function model
concurrently in a worker-thread pool (Funz/fz#73);
that is unsafe here because R functions are called back into the R
session via reticulate, which is only safe from the main
thread – invoking the function from any other thread crashes the R
session. Passing a value other than 1 therefore emits a
warning explaining that it is being forced back to 1, and the
call always proceeds with calculators = 1 (strictly
sequential, one call at a time, in the calling thread).
each iteration's directory (iterNNN/) only contains a
values.csv of that iteration's function inputs/outputs, since
there is no file-based execution.
if (fz_available()) { # run inside a throwaway directory: fz writes analysis/ and .fz/ under cwd ex_dir <- file.path(tempdir(), "fz-fzd-example") dir.create(ex_dir, showWarnings = FALSE) owd <- setwd(ex_dir) tf <- tempfile(fileext = ".txt") writeLines(c("x = ${x~0}", "y = ${y~0}"), tf) model <- list( varprefix = "$", delim = "{}", formulaprefix = "@", commentline = "#", output = list(z = "grep z output.txt | cut -d= -f2") ) # A minimal self-contained random-sampling algorithm (see # https://github.com/Funz/fz for ready-made algorithms to install) algo <- tempfile(fileext = ".py") writeLines(c( "import random", "class RandomSampler:", " def __init__(self, **options):", " self.batch = int(options.get('batch_sample_size', 5))", " self.max_iterations = int(options.get('max_iterations', 3))", " self.iteration = 0", " self.input_vars = {}", " def get_initial_design(self, input_vars, output_vars):", " self.input_vars = input_vars", " self.iteration = 1", " return [{k: random.uniform(*v) for k, v in input_vars.items()}", " for _ in range(self.batch)]", " def get_next_design(self, previous_input_vars, previous_output_values):", " self.iteration += 1", " if self.iteration > self.max_iterations:", " return []", " return [{k: random.uniform(*v) for k, v in self.input_vars.items()}", " for _ in range(self.batch)]", " def get_analysis(self, input_vars, output_values):", " valid = [v for v in output_values if v is not None]", " mean = sum(valid) / len(valid) if valid else None", " return {'text': f'mean={mean}', 'data': {'mean': mean}}" ), algo) result <- fzd( tf, list(x = "[0;1]", y = "[-5;5]"), model, output_expression = "z", algorithm = algo, algorithm_options = list(batch_sample_size = 10, max_iterations = 3) ) setwd(owd) unlink(ex_dir, recursive = TRUE) } ## Not run: # Direct function model (requires funz-fz >= 1.2) rosenbrock <- function(x, y) { list(result = (1 - x)^2 + 100 * (y - x^2)^2) } result <- fzd( input_path = NULL, input_variables = list(x = "[-2;2]", y = "[-2;2]"), model = rosenbrock, output_expression = "result", algorithm = "examples/algorithms/bfgs.py", calculators = 1L, # forced to 1L anyway for R functions -- see "Direct function model" algorithm_options = list(max_iter = 20, tol = 1e-4) ) ## End(Not run)if (fz_available()) { # run inside a throwaway directory: fz writes analysis/ and .fz/ under cwd ex_dir <- file.path(tempdir(), "fz-fzd-example") dir.create(ex_dir, showWarnings = FALSE) owd <- setwd(ex_dir) tf <- tempfile(fileext = ".txt") writeLines(c("x = ${x~0}", "y = ${y~0}"), tf) model <- list( varprefix = "$", delim = "{}", formulaprefix = "@", commentline = "#", output = list(z = "grep z output.txt | cut -d= -f2") ) # A minimal self-contained random-sampling algorithm (see # https://github.com/Funz/fz for ready-made algorithms to install) algo <- tempfile(fileext = ".py") writeLines(c( "import random", "class RandomSampler:", " def __init__(self, **options):", " self.batch = int(options.get('batch_sample_size', 5))", " self.max_iterations = int(options.get('max_iterations', 3))", " self.iteration = 0", " self.input_vars = {}", " def get_initial_design(self, input_vars, output_vars):", " self.input_vars = input_vars", " self.iteration = 1", " return [{k: random.uniform(*v) for k, v in input_vars.items()}", " for _ in range(self.batch)]", " def get_next_design(self, previous_input_vars, previous_output_values):", " self.iteration += 1", " if self.iteration > self.max_iterations:", " return []", " return [{k: random.uniform(*v) for k, v in self.input_vars.items()}", " for _ in range(self.batch)]", " def get_analysis(self, input_vars, output_values):", " valid = [v for v in output_values if v is not None]", " mean = sum(valid) / len(valid) if valid else None", " return {'text': f'mean={mean}', 'data': {'mean': mean}}" ), algo) result <- fzd( tf, list(x = "[0;1]", y = "[-5;5]"), model, output_expression = "z", algorithm = algo, algorithm_options = list(batch_sample_size = 10, max_iterations = 3) ) setwd(owd) unlink(ex_dir, recursive = TRUE) } ## Not run: # Direct function model (requires funz-fz >= 1.2) rosenbrock <- function(x, y) { list(result = (1 - x)^2 + 100 * (y - x^2)^2) } result <- fzd( input_path = NULL, input_variables = list(x = "[-2;2]", y = "[-2;2]"), model = rosenbrock, output_expression = "result", algorithm = "examples/algorithms/bfgs.py", calculators = 1L, # forced to 1L anyway for R functions -- see "Direct function model" algorithm_options = list(max_iter = 20, tol = 1e-4) ) ## End(Not run)
Parses input file(s) to find variables, formulas, and static objects.
fzi(input_path, model, input_static = NULL)fzi(input_path, model, input_static = NULL)
input_path |
Path to input file or directory. |
model |
Model definition dict or alias string. |
input_static |
Optional character vector of files that are identical
across every case (see |
Named list keyed by the discovered static objects, variable names,
and formula expressions, mapped to their values (or NULL for
variables with no default).
if (fz_available()) { tf <- tempfile(fileext = ".txt") writeLines(c("pressure = ${P~1.013}", "volume = ${V~22.4}"), tf) model <- list(varprefix = "$", delim = "{}", formulaprefix = "@", commentline = "#") vars <- fzi(tf, model) }if (fz_available()) { tf <- tempfile(fileext = ".txt") writeLines(c("pressure = ${P~1.013}", "volume = ${V~22.4}"), tf) model <- list(varprefix = "$", delim = "{}", formulaprefix = "@", commentline = "#") vars <- fzi(tf, model) }
Lists installed models and available calculators.
fzl(models = "*", calculators = "*", check = FALSE)fzl(models = "*", calculators = "*", check = FALSE)
models |
Pattern to match models. Default |
calculators |
Pattern to match calculators. Default |
check |
Logical; probe each calculator to verify it is reachable.
Default |
Named list with two entries:
Named list of installed model definitions.
Named list of available calculators.
if (fz_available()) { info <- fzl() names(info$models) names(info$calculators) info <- fzl(models = "Perfect*") info <- fzl(check = TRUE) }if (fz_available()) { info <- fzl() names(info$models) names(info$calculators) info <- fzl(models = "Perfect*") info <- fzl(check = TRUE) }
Reads and parses output file(s) according to the model's output commands. Each matched directory is processed independently; the results are combined into a single list or data frame.
fzo(output_path, model)fzo(output_path, model)
output_path |
Path or glob pattern matching one or more output directories. Subdirectories within matched directories are not processed. |
model |
Model definition dict or alias string. |
Named list or data frame of parsed output values. An output entry may resolve to a vector (list) - e.g. a time series or spectrum - which is stored per case unmodified (no flattening, padding, or truncation).
Each entry of the model's output list is a string describing how to
extract that value from the case directory. Besides the default shell
command (optionally marked "bash://..."), funz-fz >= 1.2
supports shell-free extractors, portable on Windows without a bash install:
"python://<expr>" - a Python expression evaluated in the case
directory with helpers such as grep(), read(),
lines(), json_file(), csv_file(),
hdf5_file() and the re/json/math/
statistics/np/pd modules.
"jq://<filter> <file>" - JSON extraction via the jq
executable.
"yq://<filter> <file>" - YAML/JSON/XML/TOML extraction via
mikefarah/yq.
"xpath://<expr> <file>" - XML extraction via
xmllint --xpath.
The python://, jq://, yq:// and xpath:// forms
preserve list results as vectors; a plain shell command simplifies a
single-element result to a scalar.
if (fz_available()) { out_dir <- file.path(tempdir(), "P=2,V=11.2") dir.create(out_dir, recursive = TRUE) writeLines("result = 42", file.path(out_dir, "output.txt")) model <- list( varprefix = "$", delim = "{}", formulaprefix = "@", commentline = "#", output = list(result = "grep 'result' output.txt | cut -d= -f2") ) values <- fzo(out_dir, model) }if (fz_available()) { out_dir <- file.path(tempdir(), "P=2,V=11.2") dir.create(out_dir, recursive = TRUE) writeLines("result = 42", file.path(out_dir, "output.txt")) model <- list( varprefix = "$", delim = "{}", formulaprefix = "@", commentline = "#", output = list(result = "grep 'result' output.txt | cut -d= -f2") ) values <- fzo(out_dir, model) }
Runs full parametric calculations over an input template.
fzr combines fzc, calculator execution, and
fzo into a single call: it compiles the template for every
parameter combination, runs the model via the calculator(s), and collects
all outputs into a data frame.
fzr( input_path, input_variables, model, results_dir = "results", calculators = NULL, callbacks = NULL, timeout = NULL, case_naming = NULL, input_static = NULL )fzr( input_path, input_variables, model, results_dir = "results", calculators = NULL, callbacks = NULL, timeout = NULL, case_naming = NULL, input_static = NULL )
input_path |
Path to input file or directory. |
input_variables |
Named list of variable values (or vectors of values for a full-factorial grid), or a data frame where each row is one case. |
model |
Model definition dict or alias string. |
results_dir |
Results directory. Default |
calculators |
Calculator specification(s). Strings of the form
|
callbacks |
Optional named list of callback functions. |
timeout |
Timeout in seconds per case. Default |
case_naming |
How each case's result/temp subdirectory is named:
|
input_static |
Optional character vector of files identical across
every case (e.g. a shared reference dataset): never templated, never
re-hashed per case, and - for relative paths - symlinked into each case
directory instead of duplicated (and transferred to remote calculators).
Absolute paths are assumed already present calculator-side. Default
|
Data frame (or named list) with one row per case and columns for each input variable and output quantity.
if (fz_available()) { # run inside a throwaway directory: fz writes results/ and .fz/ under cwd ex_dir <- file.path(tempdir(), "fz-fzr-example") dir.create(ex_dir, showWarnings = FALSE) owd <- setwd(ex_dir) tf <- tempfile(fileext = ".sh") writeLines(c( "#!/bin/sh", "echo result = $(( ${x~0} + ${y~0} )) > output.txt" ), tf) model <- list( varprefix = "$", delim = "{}", formulaprefix = "@", commentline = "#", output = list(result = "grep result output.txt | cut -d= -f2") ) results <- fzr(tf, list(x = c(1L, 2L), y = 3L), model, calculators = "sh://bash input.sh") setwd(owd) unlink(ex_dir, recursive = TRUE) }if (fz_available()) { # run inside a throwaway directory: fz writes results/ and .fz/ under cwd ex_dir <- file.path(tempdir(), "fz-fzr-example") dir.create(ex_dir, showWarnings = FALSE) owd <- setwd(ex_dir) tf <- tempfile(fileext = ".sh") writeLines(c( "#!/bin/sh", "echo result = $(( ${x~0} + ${y~0} )) > output.txt" ), tf) model <- list( varprefix = "$", delim = "{}", formulaprefix = "@", commentline = "#", output = list(result = "grep result output.txt | cut -d= -f2") ) results <- fzr(tf, list(x = c(1L, 2L), y = 3L), model, calculators = "sh://bash input.sh") setwd(owd) unlink(ex_dir, recursive = TRUE) }
Returns the fz configuration object. Values are controlled by environment
variables such as FZ_LOG_LEVEL, FZ_MAX_WORKERS,
FZ_MAX_RETRIES, and FZ_SHELL_PATH.
get_config()get_config()
A Python Config object. Access fields with $, e.g.
get_config()$max_workers.
if (fz_available()) { cfg <- get_config() cfg$max_workers cfg$max_retries }if (fz_available()) { cfg <- get_config() cfg$max_workers cfg$max_retries }
Returns the global formula interpreter used when evaluating formula
expressions inside template files (e.g. "python" or "R").
get_interpreter()get_interpreter()
Character string naming the current interpreter.
if (fz_available()) { get_interpreter() }if (fz_available()) { get_interpreter() }
Returns the current logging verbosity level.
get_log_level()get_log_level()
A log-level value (use as.character() to convert to a string
such as "DEBUG", "INFO", "WARNING", "ERROR").
if (fz_available()) { as.character(get_log_level()) }if (fz_available()) { as.character(get_log_level()) }
Generic alias: installs a model from a GitHub name, URL, or local zip file.
Equivalent to install_model.
install(source, global = FALSE)install(source, global = FALSE)
source |
GitHub name (e.g. |
global |
Logical; install system-wide instead of user-level.
Default |
Named list with installation details.
## Not run: # Requires the named GitHub repository to exist and network access; # not run automatically since neither is guaranteed in all environments. install("Funz/Model-PerfectGas") ## End(Not run)## Not run: # Requires the named GitHub repository to exist and network access; # not run automatically since neither is guaranteed in all environments. install("Funz/Model-PerfectGas") ## End(Not run)
Installs an algorithm from a GitHub repository name, URL, or local zip file
into the user-level ~/.fz/algorithms/ directory (or system-level when
global = TRUE).
install_algorithm(source, global = FALSE)install_algorithm(source, global = FALSE)
source |
GitHub name (e.g. |
global |
Logical; install system-wide instead of user-level.
Default |
Named list with installation details (path, name, ...).
## Not run: # Requires the named GitHub repository to exist and network access; # not run automatically since neither is guaranteed in all environments. install_algorithm("Funz/Algorithm-MonteCarlo") ## End(Not run)## Not run: # Requires the named GitHub repository to exist and network access; # not run automatically since neither is guaranteed in all environments. install_algorithm("Funz/Algorithm-MonteCarlo") ## End(Not run)
Installs a model from a GitHub repository name, URL, or local zip file into
the user-level ~/.fz/models/ directory (or system-level when
global = TRUE).
install_model(source, global = FALSE)install_model(source, global = FALSE)
source |
GitHub name (e.g. |
global |
Logical; install system-wide instead of user-level.
Default |
Named list with installation details (path, id, ...).
## Not run: # Requires the named GitHub repository to exist and network access; # not run automatically since neither is guaranteed in all environments. install_model("Funz/Model-PerfectGas") ## End(Not run)## Not run: # Requires the named GitHub repository to exist and network access; # not run automatically since neither is guaranteed in all environments. install_model("Funz/Model-PerfectGas") ## End(Not run)
Returns details of all algorithms installed in ~/.fz/algorithms/.
list_installed_algorithms(global = FALSE)list_installed_algorithms(global = FALSE)
global |
Logical; list system-level installs. Default |
Named list of installed algorithm definitions.
if (fz_available()) { algos <- list_installed_algorithms() names(algos) }if (fz_available()) { algos <- list_installed_algorithms() names(algos) }
Returns details of all models installed in ~/.fz/models/.
list_installed_models(global = FALSE)list_installed_models(global = FALSE)
global |
Logical; list system-level installs. Default |
Named list of installed model definitions.
if (fz_available()) { models <- list_installed_models() names(models) }if (fz_available()) { models <- list_installed_models() names(models) }
Alias for list_installed_models.
list_models(global = FALSE)list_models(global = FALSE)
global |
Logical; list system-level installs. Default |
Named list of installed model definitions.
if (fz_available()) { names(list_models()) }if (fz_available()) { names(list_models()) }
Prints all fz configuration values in a human-readable format, including which settings come from environment variables.
print_config()print_config()
NULL (invisibly). Called for side effects.
if (fz_available()) { print_config() }if (fz_available()) { print_config() }
Re-reads all FZ_* environment variables and updates the live
configuration. Useful after changing environment variables within the
session.
reload_config()reload_config()
NULL (invisibly). Called for side effects.
if (fz_available()) { Sys.setenv(FZ_MAX_WORKERS = "8") reload_config() get_config()$max_workers }if (fz_available()) { Sys.setenv(FZ_MAX_WORKERS = "8") reload_config() get_config()$max_workers }
Sets the global formula interpreter for evaluating expressions inside template files.
set_interpreter(interpreter)set_interpreter(interpreter)
interpreter |
Character string: |
NULL (invisibly). Called for side effects.
if (fz_available()) { set_interpreter("R") set_interpreter("python") }if (fz_available()) { set_interpreter("R") set_interpreter("python") }
Controls how much output fz emits during execution.
set_log_level(level)set_log_level(level)
level |
Character string or log-level object: one of |
NULL (invisibly). Called for side effects.
if (fz_available()) { set_log_level("DEBUG") set_log_level("WARNING") set_log_level("ERROR") }if (fz_available()) { set_log_level("DEBUG") set_log_level("WARNING") set_log_level("ERROR") }
Generic alias: removes a model by name.
Equivalent to uninstall_model.
uninstall(model_name, global = FALSE)uninstall(model_name, global = FALSE)
model_name |
Name of the model to remove. |
global |
Logical; remove from system-level install. Default |
TRUE if removed, FALSE otherwise.
if (fz_available()) { uninstall("PerfectGas") }if (fz_available()) { uninstall("PerfectGas") }
Removes a previously installed algorithm from ~/.fz/algorithms/.
uninstall_algorithm(algorithm_name, global = FALSE)uninstall_algorithm(algorithm_name, global = FALSE)
algorithm_name |
Name of the algorithm to remove. |
global |
Logical; remove from system-level install. Default |
TRUE if the algorithm was removed, FALSE otherwise.
if (fz_available()) { uninstall_algorithm("MonteCarlo") }if (fz_available()) { uninstall_algorithm("MonteCarlo") }
Removes a previously installed model from ~/.fz/models/.
uninstall_model(model_name, global = FALSE)uninstall_model(model_name, global = FALSE)
model_name |
Name of the model to remove (e.g. |
global |
Logical; remove from system-level install. Default |
TRUE if the model was removed, FALSE otherwise.
if (fz_available()) { uninstall_model("PerfectGas") }if (fz_available()) { uninstall_model("PerfectGas") }