From 3418f442f7a6ec8316eb2cf0f855a35698ed7b15 Mon Sep 17 00:00:00 2001 From: yannrichet Date: Mon, 22 Jun 2026 22:42:26 +0200 Subject: [PATCH 1/2] Fix CRAN review remarks: donttest, commented examples, reference, vignette - Replace \dontrun{} with \donttest{} in all examples (except fz_install which installs a Python package and must stay \dontrun{}) - Remove commented-out code lines from fzi, fzo, fzr examples - Fix fzo example to create temp dir/file instead of referencing a fake path - Add framework URL reference to DESCRIPTION - Pre-build vignette into inst/doc/ to resolve missing vignette index warning Co-Authored-By: Claude Sonnet 4.6 --- .Rbuildignore | 2 + .gitignore | 2 + DESCRIPTION | 1 + R/config.R | 30 +- R/core-functions.R | 44 +-- R/install.R | 22 +- inst/doc/modelica-examples.R | 103 ++++++ inst/doc/modelica-examples.Rmd | 239 +++++++++++++ inst/doc/modelica-examples.html | 568 +++++++++++++++++++++++++++++++ man/fz-package.Rd | 2 +- man/fz_available.Rd | 2 +- man/fzc.Rd | 5 +- man/fzd.Rd | 3 +- man/fzi.Rd | 7 +- man/fzl.Rd | 10 +- man/fzo.Rd | 11 +- man/fzr.Rd | 8 +- man/get_config.Rd | 2 +- man/get_interpreter.Rd | 4 +- man/get_log_level.Rd | 4 +- man/install.Rd | 2 +- man/install_algorithm.Rd | 2 +- man/install_model.Rd | 2 +- man/list_installed_algorithms.Rd | 2 +- man/list_installed_models.Rd | 4 +- man/list_models.Rd | 2 +- man/print_config.Rd | 2 +- man/reload_config.Rd | 4 +- man/set_interpreter.Rd | 6 +- man/set_log_level.Rd | 8 +- man/uninstall.Rd | 2 +- man/uninstall_algorithm.Rd | 2 +- man/uninstall_model.Rd | 2 +- vignettes/modelica-examples.R | 103 ++++++ 34 files changed, 1093 insertions(+), 119 deletions(-) create mode 100644 inst/doc/modelica-examples.R create mode 100644 inst/doc/modelica-examples.Rmd create mode 100644 inst/doc/modelica-examples.html create mode 100644 vignettes/modelica-examples.R diff --git a/.Rbuildignore b/.Rbuildignore index f4fe100..3aee868 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -10,3 +10,5 @@ ^\.claude$ ^cran-comments\.md$ ^tests/testthat/\.fz$ +^doc$ +^Meta$ diff --git a/.gitignore b/.gitignore index af9340b..59ee8ae 100644 --- a/.gitignore +++ b/.gitignore @@ -56,3 +56,5 @@ __pycache__/ .Python venv/ env/ +/doc/ +/Meta/ diff --git a/DESCRIPTION b/DESCRIPTION index a8890e1..ed87e57 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -12,6 +12,7 @@ Description: Provides R bindings to the 'funz-fz' Python package using 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 for the underlying framework. License: BSD_3_clause + file LICENSE Encoding: UTF-8 Language: en-US diff --git a/R/config.R b/R/config.R index 36ed1ee..ffa2f3c 100644 --- a/R/config.R +++ b/R/config.R @@ -7,9 +7,9 @@ #' @export #' #' @examples -#' \dontrun{ +#' \donttest{ #' if (fz_available()) { -#' get_interpreter() # e.g. "python" +#' get_interpreter() #' } #' } get_interpreter <- function() { @@ -27,10 +27,10 @@ get_interpreter <- function() { #' @export #' #' @examples -#' \dontrun{ +#' \donttest{ #' if (fz_available()) { -#' set_interpreter("R") # evaluate formulas with R -#' set_interpreter("python") # evaluate formulas with Python (default) +#' set_interpreter("R") +#' set_interpreter("python") #' } #' } set_interpreter <- function(interpreter) { @@ -46,9 +46,9 @@ set_interpreter <- function(interpreter) { #' @export #' #' @examples -#' \dontrun{ +#' \donttest{ #' if (fz_available()) { -#' as.character(get_log_level()) # e.g. "WARNING" +#' as.character(get_log_level()) #' } #' } get_log_level <- function() { @@ -66,11 +66,11 @@ get_log_level <- function() { #' @export #' #' @examples -#' \dontrun{ +#' \donttest{ #' if (fz_available()) { -#' set_log_level("DEBUG") # maximum verbosity -#' set_log_level("WARNING") # default -#' set_log_level("ERROR") # errors only +#' set_log_level("DEBUG") +#' set_log_level("WARNING") +#' set_log_level("ERROR") #' } #' } set_log_level <- function(level) { @@ -88,7 +88,7 @@ set_log_level <- function(level) { #' @export #' #' @examples -#' \dontrun{ +#' \donttest{ #' if (fz_available()) { #' cfg <- get_config() #' cfg$max_workers @@ -108,7 +108,7 @@ get_config <- function() { #' @export #' #' @examples -#' \dontrun{ +#' \donttest{ #' if (fz_available()) { #' print_config() #' } @@ -127,11 +127,11 @@ print_config <- function() { #' @export #' #' @examples -#' \dontrun{ +#' \donttest{ #' if (fz_available()) { #' Sys.setenv(FZ_MAX_WORKERS = "8") #' reload_config() -#' get_config()$max_workers # now 8 +#' get_config()$max_workers #' } #' } reload_config <- function() { diff --git a/R/core-functions.R b/R/core-functions.R index 44a781e..ac919fc 100644 --- a/R/core-functions.R +++ b/R/core-functions.R @@ -9,9 +9,8 @@ #' @export #' #' @examples -#' \dontrun{ +#' \donttest{ #' if (fz_available()) { -#' # Write a template with two variables and their defaults #' tf <- tempfile(fileext = ".txt") #' writeLines(c("pressure = ${P~1.013}", "volume = ${V~22.4}"), tf) #' @@ -19,10 +18,6 @@ #' commentline = "#") #' #' vars <- fzi(tf, model) -#' # vars$P == 1.013, vars$V == 22.4 -#' -#' # Using an installed model alias instead of an inline dict: -#' # vars <- fzi(tf, "PerfectGas") #' } #' } fzi <- function(input_path, model) { @@ -46,7 +41,7 @@ fzi <- function(input_path, model) { #' @export #' #' @examples -#' \dontrun{ +#' \donttest{ #' if (fz_available()) { #' tf <- tempfile(fileext = ".txt") #' writeLines(c("P = ${P~1.013}", "V = ${V~22.4}"), tf) @@ -55,10 +50,7 @@ fzi <- function(input_path, model) { #' commentline = "#") #' out <- tempfile() #' -#' # Single case: one compiled directory P=2,V=11.2 #' fzc(tf, list(P = 2.0, V = 11.2), model, out) -#' -#' # Grid: 2 x 2 = 4 compiled directories #' fzc(tf, list(P = c(1.0, 2.0), V = c(11.2, 22.4)), model, out) #' } #' } @@ -81,10 +73,11 @@ fzc <- function(input_path, input_variables, model, output_dir = "output") { #' @export #' #' @examples -#' \dontrun{ +#' \donttest{ #' if (fz_available()) { -#' # After running a simulation that wrote "result = 42" to output.txt: -#' out_dir <- "my_results/P=2,V=11.2" +#' 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 = "#", @@ -92,10 +85,6 @@ fzc <- function(input_path, input_variables, model, output_dir = "output") { #' ) #' #' values <- fzo(out_dir, model) -#' # values$result == "42" -#' -#' # Glob to read all cases at once: -#' # values <- fzo("my_results/*", model) #' } #' } fzo <- function(output_path, model) { @@ -128,9 +117,8 @@ fzo <- function(output_path, model) { #' @export #' #' @examples -#' \dontrun{ +#' \donttest{ #' if (fz_available()) { -#' # Template: shell script that writes sum of x and y #' tf <- tempfile(fileext = ".sh") #' writeLines(c( #' "#!/bin/sh", @@ -142,13 +130,8 @@ fzo <- function(output_path, model) { #' output = list(result = "grep result output.txt | cut -d= -f2") #' ) #' -#' # Two values of x, one value of y -> 2 cases #' results <- fzr(tf, list(x = c(1L, 2L), y = 3L), model, #' calculators = "sh://bash input.sh") -#' # results is a data frame with columns x, y, result -#' -#' # Using an installed model alias: -#' # results <- fzr("input.txt", list(P = c(1, 2, 3)), "PerfectGas") #' } #' } fzr <- function(input_path, input_variables, model, @@ -180,17 +163,13 @@ fzr <- function(input_path, input_variables, model, #' @export #' #' @examples -#' \dontrun{ +#' \donttest{ #' if (fz_available()) { -#' # List everything #' info <- fzl() -#' names(info$models) # e.g. c("PerfectGas", "Moret") -#' names(info$calculators) # e.g. c("sh://") +#' names(info$models) +#' names(info$calculators) #' -#' # Check only models whose name starts with "Perfect" #' info <- fzl(models = "Perfect*") -#' -#' # Probe calculators to verify they are reachable #' info <- fzl(check = TRUE) #' } #' } @@ -225,7 +204,7 @@ fzl <- function(models = "*", calculators = "*", check = FALSE) { #' @export #' #' @examples -#' \dontrun{ +#' \donttest{ #' if (fz_available()) { #' tf <- tempfile(fileext = ".txt") #' writeLines(c("x = ${x~0}", "y = ${y~0}"), tf) @@ -235,7 +214,6 @@ fzl <- function(models = "*", calculators = "*", check = FALSE) { #' output = list(z = "grep z output.txt | cut -d= -f2") #' ) #' -#' # Run 30 Monte Carlo samples over x in [0,1] and y in [-5,5] #' result <- fzd( #' tf, #' list(x = "[0;1]", y = "[-5;5]"), diff --git a/R/install.R b/R/install.R index 9a2b725..249b56c 100644 --- a/R/install.R +++ b/R/install.R @@ -36,7 +36,7 @@ fz_install <- function(method = "auto", conda = "auto", pip = TRUE, ...) { #' @importFrom reticulate py_module_available #' #' @examples -#' \dontrun{ +#' \donttest{ #' if (fz_available()) { #' message("fz is available!") #' } else { @@ -65,7 +65,7 @@ fz_available <- function() { #' @export #' #' @examples -#' \dontrun{ +#' \donttest{ #' if (fz_available()) { #' install_model("Funz/Model-PerfectGas") #' } @@ -90,7 +90,7 @@ install_model <- function(source, global = FALSE) { #' @export #' #' @examples -#' \dontrun{ +#' \donttest{ #' if (fz_available()) { #' install_algorithm("Funz/Algorithm-MonteCarlo") #' } @@ -111,7 +111,7 @@ install_algorithm <- function(source, global = FALSE) { #' @export #' #' @examples -#' \dontrun{ +#' \donttest{ #' if (fz_available()) { #' uninstall_model("PerfectGas") #' } @@ -132,7 +132,7 @@ uninstall_model <- function(model_name, global = FALSE) { #' @export #' #' @examples -#' \dontrun{ +#' \donttest{ #' if (fz_available()) { #' uninstall_algorithm("MonteCarlo") #' } @@ -152,10 +152,10 @@ uninstall_algorithm <- function(algorithm_name, global = FALSE) { #' @export #' #' @examples -#' \dontrun{ +#' \donttest{ #' if (fz_available()) { #' models <- list_installed_models() -#' names(models) # e.g. c("PerfectGas") +#' names(models) #' } #' } list_installed_models <- function(global = FALSE) { @@ -173,7 +173,7 @@ list_installed_models <- function(global = FALSE) { #' @export #' #' @examples -#' \dontrun{ +#' \donttest{ #' if (fz_available()) { #' algos <- list_installed_algorithms() #' names(algos) @@ -193,7 +193,7 @@ list_installed_algorithms <- function(global = FALSE) { #' @export #' #' @examples -#' \dontrun{ +#' \donttest{ #' if (fz_available()) { #' names(list_models()) #' } @@ -212,7 +212,7 @@ list_models <- function(global = FALSE) { #' @export #' #' @examples -#' \dontrun{ +#' \donttest{ #' if (fz_available()) { #' install("Funz/Model-PerfectGas") #' } @@ -232,7 +232,7 @@ install <- function(source, global = FALSE) { #' @export #' #' @examples -#' \dontrun{ +#' \donttest{ #' if (fz_available()) { #' uninstall("PerfectGas") #' } diff --git a/inst/doc/modelica-examples.R b/inst/doc/modelica-examples.R new file mode 100644 index 0000000..1e878ec --- /dev/null +++ b/inst/doc/modelica-examples.R @@ -0,0 +1,103 @@ +## ----include = FALSE---------------------------------------------------------- +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>", + eval = FALSE # requires funz-fz Python package and a configured calculator +) + +## ----setup-------------------------------------------------------------------- +# library(fz) + +## ----install------------------------------------------------------------------ +# # Install the funz-fz Python package into the active reticulate environment +# fz_install() +# +# # Verify +# fz_available() + +## ----model_dict--------------------------------------------------------------- +# model <- list( +# varprefix = "$", +# delim = "{}", +# formulaprefix = "@", +# commentline = "#", +# output = list( +# pressure = "grep 'pressure =' output.txt | cut -d= -f2" +# ) +# ) + +## ----model_alias-------------------------------------------------------------- +# fzl()$models # lists installed aliases, e.g. "PerfectGas" + +## ----fzi---------------------------------------------------------------------- +# vars <- fzi("input.txt", model) +# # $P [1] 1.013 +# # $V [1] 22.4 +# # $n [1] 1.0 + +## ----fzc_single--------------------------------------------------------------- +# # Single case +# fzc("input.txt", list(P = 2.0, V = 11.2), model, output_dir = "compiled") +# # writes: compiled/P=2,V=11.2/input.txt (placeholder replaced with 2.0 / 11.2) + +## ----fzc_grid----------------------------------------------------------------- +# # 2 x 3 = 6 cases +# fzc("input.txt", +# list(P = c(1.0, 2.0), V = c(10.0, 20.0, 30.0)), +# model, +# output_dir = "compiled") + +## ----fzr---------------------------------------------------------------------- +# results <- fzr( +# "input.txt", +# list(P = c(1.0, 2.0, 3.0), V = 22.4), # 3 cases (V fixed) +# model, +# results_dir = "results", +# calculators = "sh://bash run.sh" # run.sh executes the simulator +# ) +# +# # results is a data frame: +# # P V pressure +# # 1 1.0 22.4 ... +# # 2 2.0 22.4 ... +# # 3 3.0 22.4 ... + +## ----fzo---------------------------------------------------------------------- +# values <- fzo("results/P=2,V=22.4", model) +# # $pressure [1] "2.026" +# +# # Glob to read all cases at once: +# all_values <- fzo("results/*", model) + +## ----fzd---------------------------------------------------------------------- +# result <- fzd( +# "input.txt", +# list(P = "[1;5]", V = "[10;30]"), +# model, +# output_expression = "pressure", +# algorithm = "algorithms/montecarlo_uniform.py", +# algorithm_options = "batch_sample_size=10;max_iterations=5;seed=42" +# ) + +## ----fzl---------------------------------------------------------------------- +# info <- fzl() +# names(info$models) # e.g. c("PerfectGas", "Moret") +# names(info$calculators) # e.g. c("sh://") +# +# # Filter by pattern +# fzl(models = "Perfect*") +# +# # Probe calculators to verify they are reachable +# fzl(check = TRUE) + +## ----save_results------------------------------------------------------------- +# saveRDS(results, "fz_results.rds") +# write.csv(results, "fz_results.csv", row.names = FALSE) + +## ----troubleshoot_install----------------------------------------------------- +# fz_install() # install funz-fz into the reticulate environment +# fz_available() # should return TRUE afterwards + +## ----session_info------------------------------------------------------------- +# sessionInfo() + diff --git a/inst/doc/modelica-examples.Rmd b/inst/doc/modelica-examples.Rmd new file mode 100644 index 0000000..49759ff --- /dev/null +++ b/inst/doc/modelica-examples.Rmd @@ -0,0 +1,239 @@ +--- +title: "Using fz for parametric studies" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{Using fz for parametric studies} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r, include = FALSE} +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>", + eval = FALSE # requires funz-fz Python package and a configured calculator +) +``` + +```{r setup} +library(fz) +``` + +## Introduction + +The `fz` package provides R bindings to the +[funz-fz](https://pypi.org/project/funz-fz/) Python package. It lets you: + +- run **parameter sweeps** over any simulation code, +- drive **design of experiments** with adaptive algorithms, +- read and collect **output files** into data frames. + +fz works with any simulation code that reads text input files and writes text +output files. You describe the model in a small dict (or install it as a named +alias with `fz install`). + +## Installation + +```{r install} +# Install the funz-fz Python package into the active reticulate environment +fz_install() + +# Verify +fz_available() +``` + +## Concepts + +### Template files + +A **template** is an ordinary input file for your simulator with variable +placeholders, e.g.: + +``` +# Perfect Gas parameters +pressure = ${P~1.013} # variable P, default 1.013 +volume = ${V~22.4} # variable V, default 22.4 +moles = ${n~1.0} +``` + +The placeholder syntax (`$`, `{}`) is defined by the **model** dict. + +### Model dict + +The model dict tells fz how to: + +1. find variable placeholders (`varprefix`, `delim`), +2. extract output values from the result files (`output`). + +```{r model_dict} +model <- list( + varprefix = "$", + delim = "{}", + formulaprefix = "@", + commentline = "#", + output = list( + pressure = "grep 'pressure =' output.txt | cut -d= -f2" + ) +) +``` + +You can also use an installed model alias (a string) instead of an inline dict: + +```{r model_alias} +fzl()$models # lists installed aliases, e.g. "PerfectGas" +``` + +## Basic workflow + +The typical fz workflow has four steps. + +### Step 1 — Inspect the template + +`fzi` parses the template and returns the variable names together with their +default values: + +```{r fzi} +vars <- fzi("input.txt", model) +# $P [1] 1.013 +# $V [1] 22.4 +# $n [1] 1.0 +``` + +### Step 2 — Compile (substitute values) + +`fzc` writes one copy of the input file per parameter combination into +`output_dir`. Each copy goes into a subdirectory named +`var1=val1,var2=val2,...`: + +```{r fzc_single} +# Single case +fzc("input.txt", list(P = 2.0, V = 11.2), model, output_dir = "compiled") +# writes: compiled/P=2,V=11.2/input.txt (placeholder replaced with 2.0 / 11.2) +``` + +Supply vectors to generate a full-factorial grid: + +```{r fzc_grid} +# 2 x 3 = 6 cases +fzc("input.txt", + list(P = c(1.0, 2.0), V = c(10.0, 20.0, 30.0)), + model, + output_dir = "compiled") +``` + +### Step 3 — Run the model and collect outputs + +`fzr` wraps steps 1–3 and output collection into a single call. It compiles +the template, runs the calculator for every case, and returns a data frame: + +```{r fzr} +results <- fzr( + "input.txt", + list(P = c(1.0, 2.0, 3.0), V = 22.4), # 3 cases (V fixed) + model, + results_dir = "results", + calculators = "sh://bash run.sh" # run.sh executes the simulator +) + +# results is a data frame: +# P V pressure +# 1 1.0 22.4 ... +# 2 2.0 22.4 ... +# 3 3.0 22.4 ... +``` + +The `calculators` argument accepts: + +- `"sh://bash run.sh"` — run a local shell command +- `"sh://"` — execute the input file directly as a shell script +- `"ssh://user@host"` — run over SSH + +### Step 4 — Read outputs from existing directories + +If you already ran the simulator externally, `fzo` reads the output files: + +```{r fzo} +values <- fzo("results/P=2,V=22.4", model) +# $pressure [1] "2.026" + +# Glob to read all cases at once: +all_values <- fzo("results/*", model) +``` + +## Algorithm-driven design of experiments + +`fzd` runs an adaptive experiment: the algorithm decides which parameter +combinations to evaluate based on previous results. Input variable ranges use +`"[min;max]"` strings: + +```{r fzd} +result <- fzd( + "input.txt", + list(P = "[1;5]", V = "[10;30]"), + model, + output_expression = "pressure", + algorithm = "algorithms/montecarlo_uniform.py", + algorithm_options = "batch_sample_size=10;max_iterations=5;seed=42" +) +``` + +Algorithms are Python files; `fz` ships several in `algorithms/` (Monte Carlo, +surrogate-based optimization, …). You can also write your own. + +## Listing installed models + +`fzl` shows which model aliases and calculators are installed in `~/.fz/`: + +```{r fzl} +info <- fzl() +names(info$models) # e.g. c("PerfectGas", "Moret") +names(info$calculators) # e.g. c("sh://") + +# Filter by pattern +fzl(models = "Perfect*") + +# Probe calculators to verify they are reachable +fzl(check = TRUE) +``` + +## Best practices + +1. **Test with `fzi` first** — verify the correct variable names are found + before running anything. +2. **Use `fzc` for a dry run** — inspect compiled files to confirm placeholder + substitution is correct. +3. **Start small** — run a handful of cases before launching a large sweep. +4. **Save results** — persist the data frame for reproducibility. + +```{r save_results} +saveRDS(results, "fz_results.rds") +write.csv(results, "fz_results.csv", row.names = FALSE) +``` + +## Troubleshooting + +**`fz` Python package not found:** + +```{r troubleshoot_install} +fz_install() # install funz-fz into the reticulate environment +fz_available() # should return TRUE afterwards +``` + +**Variables not found in template:** +Check that `varprefix` and `delim` in your model dict match the syntax used in +your template file. Run `fzi` and inspect the returned list. + +**Calculator errors:** +Run the simulator manually on one compiled directory to confirm it works before +using `fzr`. + +## Further reading + +- funz-fz documentation: +- reticulate: + +## Session info + +```{r session_info} +sessionInfo() +``` diff --git a/inst/doc/modelica-examples.html b/inst/doc/modelica-examples.html new file mode 100644 index 0000000..985c634 --- /dev/null +++ b/inst/doc/modelica-examples.html @@ -0,0 +1,568 @@ + + + + + + + + + + + + + + +Using fz for parametric studies + + + + + + + + + + + + + + + + + + + + + + + + + + +

Using fz for parametric studies

+ + + +
library(fz)
+

/home/richet/Sync/Open/Funz/github/fz.R/vignettes/modelica-examples.R

+
+

Introduction

+

The fz package provides R bindings to the funz-fz Python package. It +lets you:

+
    +
  • run parameter sweeps over any simulation code,
  • +
  • drive design of experiments with adaptive +algorithms,
  • +
  • read and collect output files into data +frames.
  • +
+

fz works with any simulation code that reads text input files and +writes text output files. You describe the model in a small dict (or +install it as a named alias with fz install).

+
+
+

Installation

+
# Install the funz-fz Python package into the active reticulate environment
+fz_install()
+
+# Verify
+fz_available()
+

/home/richet/Sync/Open/Funz/github/fz.R/vignettes/modelica-examples.R

+
+
+

Concepts

+
+

Template files

+

A template is an ordinary input file for your +simulator with variable placeholders, e.g.:

+
# Perfect Gas parameters
+pressure = ${P~1.013}    # variable P, default 1.013
+volume   = ${V~22.4}     # variable V, default 22.4
+moles    = ${n~1.0}
+

The placeholder syntax ($, {}) is defined +by the model dict.

+
+
+

Model dict

+

The model dict tells fz how to:

+
    +
  1. find variable placeholders (varprefix, +delim),
  2. +
  3. extract output values from the result files +(output).
  4. +
+
model <- list(
+  varprefix    = "$",
+  delim        = "{}",
+  formulaprefix = "@",
+  commentline  = "#",
+  output = list(
+    pressure = "grep 'pressure =' output.txt | cut -d= -f2"
+  )
+)
+

/home/richet/Sync/Open/Funz/github/fz.R/vignettes/modelica-examples.R

+

You can also use an installed model alias (a string) instead of an +inline dict:

+
fzl()$models  # lists installed aliases, e.g. "PerfectGas"
+

/home/richet/Sync/Open/Funz/github/fz.R/vignettes/modelica-examples.R

+
+
+
+

Basic workflow

+

The typical fz workflow has four steps.

+
+

Step 1 — Inspect the template

+

fzi parses the template and returns the variable names +together with their default values:

+
vars <- fzi("input.txt", model)
+# $P [1] 1.013
+# $V [1] 22.4
+# $n [1] 1.0
+

/home/richet/Sync/Open/Funz/github/fz.R/vignettes/modelica-examples.R

+
+
+

Step 2 — Compile (substitute values)

+

fzc writes one copy of the input file per parameter +combination into output_dir. Each copy goes into a +subdirectory named var1=val1,var2=val2,...:

+
# Single case
+fzc("input.txt", list(P = 2.0, V = 11.2), model, output_dir = "compiled")
+# writes: compiled/P=2,V=11.2/input.txt  (placeholder replaced with 2.0 / 11.2)
+

/home/richet/Sync/Open/Funz/github/fz.R/vignettes/modelica-examples.R

+

Supply vectors to generate a full-factorial grid:

+
# 2 x 3 = 6 cases
+fzc("input.txt",
+    list(P = c(1.0, 2.0), V = c(10.0, 20.0, 30.0)),
+    model,
+    output_dir = "compiled")
+

/home/richet/Sync/Open/Funz/github/fz.R/vignettes/modelica-examples.R

+
+
+

Step 3 — Run the model and collect outputs

+

fzr wraps steps 1–3 and output collection into a single +call. It compiles the template, runs the calculator for every case, and +returns a data frame:

+
results <- fzr(
+  "input.txt",
+  list(P = c(1.0, 2.0, 3.0), V = 22.4),   # 3 cases (V fixed)
+  model,
+  results_dir = "results",
+  calculators = "sh://bash run.sh"           # run.sh executes the simulator
+)
+
+# results is a data frame:
+#     P    V  pressure
+# 1  1.0  22.4   ...
+# 2  2.0  22.4   ...
+# 3  3.0  22.4   ...
+

/home/richet/Sync/Open/Funz/github/fz.R/vignettes/modelica-examples.R

+

The calculators argument accepts:

+
    +
  • "sh://bash run.sh" — run a local shell command
  • +
  • "sh://" — execute the input file directly as a shell +script
  • +
  • "ssh://user@host" — run over SSH
  • +
+
+
+

Step 4 — Read outputs from existing directories

+

If you already ran the simulator externally, fzo reads +the output files:

+
values <- fzo("results/P=2,V=22.4", model)
+# $pressure [1] "2.026"
+
+# Glob to read all cases at once:
+all_values <- fzo("results/*", model)
+

/home/richet/Sync/Open/Funz/github/fz.R/vignettes/modelica-examples.R

+
+
+
+

Algorithm-driven design of experiments

+

fzd runs an adaptive experiment: the algorithm decides +which parameter combinations to evaluate based on previous results. +Input variable ranges use "[min;max]" strings:

+
result <- fzd(
+  "input.txt",
+  list(P = "[1;5]", V = "[10;30]"),
+  model,
+  output_expression = "pressure",
+  algorithm         = "algorithms/montecarlo_uniform.py",
+  algorithm_options = "batch_sample_size=10;max_iterations=5;seed=42"
+)
+

/home/richet/Sync/Open/Funz/github/fz.R/vignettes/modelica-examples.R

+

Algorithms are Python files; fz ships several in +algorithms/ (Monte Carlo, surrogate-based optimization, …). +You can also write your own.

+
+
+

Listing installed models

+

fzl shows which model aliases and calculators are +installed in ~/.fz/:

+
info <- fzl()
+names(info$models)       # e.g. c("PerfectGas", "Moret")
+names(info$calculators)  # e.g. c("sh://")
+
+# Filter by pattern
+fzl(models = "Perfect*")
+
+# Probe calculators to verify they are reachable
+fzl(check = TRUE)
+

/home/richet/Sync/Open/Funz/github/fz.R/vignettes/modelica-examples.R

+
+
+

Best practices

+
    +
  1. Test with fzi first — verify the +correct variable names are found before running anything.
  2. +
  3. Use fzc for a dry run — inspect +compiled files to confirm placeholder substitution is correct.
  4. +
  5. Start small — run a handful of cases before +launching a large sweep.
  6. +
  7. Save results — persist the data frame for +reproducibility.
  8. +
+
saveRDS(results, "fz_results.rds")
+write.csv(results, "fz_results.csv", row.names = FALSE)
+

/home/richet/Sync/Open/Funz/github/fz.R/vignettes/modelica-examples.R

+
+
+

Troubleshooting

+

fz Python package not found:

+
fz_install()         # install funz-fz into the reticulate environment
+fz_available()       # should return TRUE afterwards
+

/home/richet/Sync/Open/Funz/github/fz.R/vignettes/modelica-examples.R

+

Variables not found in template: Check that +varprefix and delim in your model dict match +the syntax used in your template file. Run fzi and inspect +the returned list.

+

Calculator errors: Run the simulator manually on one +compiled directory to confirm it works before using +fzr.

+
+
+

Further reading

+ +
+
+

Session info

+
sessionInfo()
+

/home/richet/Sync/Open/Funz/github/fz.R/vignettes/modelica-examples.R

+
+ + + + + + + + + + + diff --git a/man/fz-package.Rd b/man/fz-package.Rd index ce1d0e6..bbcd3ee 100644 --- a/man/fz-package.Rd +++ b/man/fz-package.Rd @@ -6,7 +6,7 @@ \alias{fz-package} \title{fz: 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. +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 \url{https://github.com/Funz/fz} for the underlying framework. } \seealso{ Useful links: diff --git a/man/fz_available.Rd b/man/fz_available.Rd index ecc6401..01436e5 100644 --- a/man/fz_available.Rd +++ b/man/fz_available.Rd @@ -14,7 +14,7 @@ Checks whether the fz Python package is available in the current Python environment. } \examples{ -\dontrun{ +\donttest{ if (fz_available()) { message("fz is available!") } else { diff --git a/man/fzc.Rd b/man/fzc.Rd index 39f00fc..a9b2963 100644 --- a/man/fzc.Rd +++ b/man/fzc.Rd @@ -25,7 +25,7 @@ Each unique combination of values is written to its own subdirectory inside \code{output_dir}, named \code{var1=val1,var2=val2,...}. } \examples{ -\dontrun{ +\donttest{ if (fz_available()) { tf <- tempfile(fileext = ".txt") writeLines(c("P = ${P~1.013}", "V = ${V~22.4}"), tf) @@ -34,10 +34,7 @@ if (fz_available()) { commentline = "#") out <- tempfile() - # Single case: one compiled directory P=2,V=11.2 fzc(tf, list(P = 2.0, V = 11.2), model, out) - - # Grid: 2 x 2 = 4 compiled directories fzc(tf, list(P = c(1.0, 2.0), V = c(11.2, 22.4)), model, out) } } diff --git a/man/fzd.Rd b/man/fzd.Rd index d978c14..95cb7f1 100644 --- a/man/fzd.Rd +++ b/man/fzd.Rd @@ -48,7 +48,7 @@ algorithm adaptively choose which parameter combinations to evaluate, which is useful for sensitivity analysis, surrogate-model fitting, or optimization. } \examples{ -\dontrun{ +\donttest{ if (fz_available()) { tf <- tempfile(fileext = ".txt") writeLines(c("x = ${x~0}", "y = ${y~0}"), tf) @@ -58,7 +58,6 @@ if (fz_available()) { output = list(z = "grep z output.txt | cut -d= -f2") ) - # Run 30 Monte Carlo samples over x in [0,1] and y in [-5,5] result <- fzd( tf, list(x = "[0;1]", y = "[-5;5]"), diff --git a/man/fzi.Rd b/man/fzi.Rd index a49bfe5..98a258d 100644 --- a/man/fzi.Rd +++ b/man/fzi.Rd @@ -18,9 +18,8 @@ Named list with variable names and their default values (or NULL). Parses input file(s) to find variables, formulas, and static objects. } \examples{ -\dontrun{ +\donttest{ if (fz_available()) { - # Write a template with two variables and their defaults tf <- tempfile(fileext = ".txt") writeLines(c("pressure = ${P~1.013}", "volume = ${V~22.4}"), tf) @@ -28,10 +27,6 @@ if (fz_available()) { commentline = "#") vars <- fzi(tf, model) - # vars$P == 1.013, vars$V == 22.4 - - # Using an installed model alias instead of an inline dict: - # vars <- fzi(tf, "PerfectGas") } } } diff --git a/man/fzl.Rd b/man/fzl.Rd index 7bd18a1..904c52f 100644 --- a/man/fzl.Rd +++ b/man/fzl.Rd @@ -26,17 +26,13 @@ Named list with two entries: Lists installed models and available calculators. } \examples{ -\dontrun{ +\donttest{ if (fz_available()) { - # List everything info <- fzl() - names(info$models) # e.g. c("PerfectGas", "Moret") - names(info$calculators) # e.g. c("sh://") + names(info$models) + names(info$calculators) - # Check only models whose name starts with "Perfect" info <- fzl(models = "Perfect*") - - # Probe calculators to verify they are reachable info <- fzl(check = TRUE) } } diff --git a/man/fzo.Rd b/man/fzo.Rd index 8fb7451..7093cb9 100644 --- a/man/fzo.Rd +++ b/man/fzo.Rd @@ -21,10 +21,11 @@ Each matched directory is processed independently; the results are combined into a single list or data frame. } \examples{ -\dontrun{ +\donttest{ if (fz_available()) { - # After running a simulation that wrote "result = 42" to output.txt: - out_dir <- "my_results/P=2,V=11.2" + 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 = "#", @@ -32,10 +33,6 @@ if (fz_available()) { ) values <- fzo(out_dir, model) - # values$result == "42" - - # Glob to read all cases at once: - # values <- fzo("my_results/*", model) } } } diff --git a/man/fzr.Rd b/man/fzr.Rd index c379c61..761a11d 100644 --- a/man/fzr.Rd +++ b/man/fzr.Rd @@ -45,9 +45,8 @@ parameter combination, runs the model via the calculator(s), and collects all outputs into a data frame. } \examples{ -\dontrun{ +\donttest{ if (fz_available()) { - # Template: shell script that writes sum of x and y tf <- tempfile(fileext = ".sh") writeLines(c( "#!/bin/sh", @@ -59,13 +58,8 @@ if (fz_available()) { output = list(result = "grep result output.txt | cut -d= -f2") ) - # Two values of x, one value of y -> 2 cases results <- fzr(tf, list(x = c(1L, 2L), y = 3L), model, calculators = "sh://bash input.sh") - # results is a data frame with columns x, y, result - - # Using an installed model alias: - # results <- fzr("input.txt", list(P = c(1, 2, 3)), "PerfectGas") } } } diff --git a/man/get_config.Rd b/man/get_config.Rd index 771fa61..186c2e8 100644 --- a/man/get_config.Rd +++ b/man/get_config.Rd @@ -16,7 +16,7 @@ variables such as \code{FZ_LOG_LEVEL}, \code{FZ_MAX_WORKERS}, \code{FZ_MAX_RETRIES}, and \code{FZ_SHELL_PATH}. } \examples{ -\dontrun{ +\donttest{ if (fz_available()) { cfg <- get_config() cfg$max_workers diff --git a/man/get_interpreter.Rd b/man/get_interpreter.Rd index f001ee3..5467b0b 100644 --- a/man/get_interpreter.Rd +++ b/man/get_interpreter.Rd @@ -14,9 +14,9 @@ Returns the global formula interpreter used when evaluating formula expressions inside template files (e.g. \code{"python"} or \code{"R"}). } \examples{ -\dontrun{ +\donttest{ if (fz_available()) { - get_interpreter() # e.g. "python" + get_interpreter() } } } diff --git a/man/get_log_level.Rd b/man/get_log_level.Rd index b7b5644..6b55781 100644 --- a/man/get_log_level.Rd +++ b/man/get_log_level.Rd @@ -14,9 +14,9 @@ such as \code{"DEBUG"}, \code{"INFO"}, \code{"WARNING"}, \code{"ERROR"}). Returns the current logging verbosity level. } \examples{ -\dontrun{ +\donttest{ if (fz_available()) { - as.character(get_log_level()) # e.g. "WARNING" + as.character(get_log_level()) } } } diff --git a/man/install.Rd b/man/install.Rd index ba20655..2f1268f 100644 --- a/man/install.Rd +++ b/man/install.Rd @@ -21,7 +21,7 @@ Generic alias: installs a model from a GitHub name, URL, or local zip file. Equivalent to \code{\link{install_model}}. } \examples{ -\dontrun{ +\donttest{ if (fz_available()) { install("Funz/Model-PerfectGas") } diff --git a/man/install_algorithm.Rd b/man/install_algorithm.Rd index 771560d..97a7d39 100644 --- a/man/install_algorithm.Rd +++ b/man/install_algorithm.Rd @@ -22,7 +22,7 @@ into the user-level \code{~/.fz/algorithms/} directory (or system-level when \code{global = TRUE}). } \examples{ -\dontrun{ +\donttest{ if (fz_available()) { install_algorithm("Funz/Algorithm-MonteCarlo") } diff --git a/man/install_model.Rd b/man/install_model.Rd index d1f2fc1..432ff3d 100644 --- a/man/install_model.Rd +++ b/man/install_model.Rd @@ -22,7 +22,7 @@ the user-level \code{~/.fz/models/} directory (or system-level when \code{global = TRUE}). } \examples{ -\dontrun{ +\donttest{ if (fz_available()) { install_model("Funz/Model-PerfectGas") } diff --git a/man/list_installed_algorithms.Rd b/man/list_installed_algorithms.Rd index 525b40d..7a69c8a 100644 --- a/man/list_installed_algorithms.Rd +++ b/man/list_installed_algorithms.Rd @@ -16,7 +16,7 @@ Named list of installed algorithm definitions. Returns details of all algorithms installed in \code{~/.fz/algorithms/}. } \examples{ -\dontrun{ +\donttest{ if (fz_available()) { algos <- list_installed_algorithms() names(algos) diff --git a/man/list_installed_models.Rd b/man/list_installed_models.Rd index 158e35d..629f76e 100644 --- a/man/list_installed_models.Rd +++ b/man/list_installed_models.Rd @@ -16,10 +16,10 @@ Named list of installed model definitions. Returns details of all models installed in \code{~/.fz/models/}. } \examples{ -\dontrun{ +\donttest{ if (fz_available()) { models <- list_installed_models() - names(models) # e.g. c("PerfectGas") + names(models) } } } diff --git a/man/list_models.Rd b/man/list_models.Rd index 08ffd12..eaddc4c 100644 --- a/man/list_models.Rd +++ b/man/list_models.Rd @@ -16,7 +16,7 @@ Named list of installed model definitions. Alias for \code{\link{list_installed_models}}. } \examples{ -\dontrun{ +\donttest{ if (fz_available()) { names(list_models()) } diff --git a/man/print_config.Rd b/man/print_config.Rd index dca102b..b02ac14 100644 --- a/man/print_config.Rd +++ b/man/print_config.Rd @@ -14,7 +14,7 @@ Prints all fz configuration values in a human-readable format, including which settings come from environment variables. } \examples{ -\dontrun{ +\donttest{ if (fz_available()) { print_config() } diff --git a/man/reload_config.Rd b/man/reload_config.Rd index 3666d62..8609aca 100644 --- a/man/reload_config.Rd +++ b/man/reload_config.Rd @@ -15,11 +15,11 @@ configuration. Useful after changing environment variables within the session. } \examples{ -\dontrun{ +\donttest{ if (fz_available()) { Sys.setenv(FZ_MAX_WORKERS = "8") reload_config() - get_config()$max_workers # now 8 + get_config()$max_workers } } } diff --git a/man/set_interpreter.Rd b/man/set_interpreter.Rd index ffd6f0f..d0a97a7 100644 --- a/man/set_interpreter.Rd +++ b/man/set_interpreter.Rd @@ -17,10 +17,10 @@ Sets the global formula interpreter for evaluating expressions inside template files. } \examples{ -\dontrun{ +\donttest{ if (fz_available()) { - set_interpreter("R") # evaluate formulas with R - set_interpreter("python") # evaluate formulas with Python (default) + set_interpreter("R") + set_interpreter("python") } } } diff --git a/man/set_log_level.Rd b/man/set_log_level.Rd index 63e1e25..213d074 100644 --- a/man/set_log_level.Rd +++ b/man/set_log_level.Rd @@ -17,11 +17,11 @@ NULL (invisibly). Called for side effects. Controls how much output fz emits during execution. } \examples{ -\dontrun{ +\donttest{ if (fz_available()) { - set_log_level("DEBUG") # maximum verbosity - set_log_level("WARNING") # default - set_log_level("ERROR") # errors only + set_log_level("DEBUG") + set_log_level("WARNING") + set_log_level("ERROR") } } } diff --git a/man/uninstall.Rd b/man/uninstall.Rd index 4c68d7b..1d97848 100644 --- a/man/uninstall.Rd +++ b/man/uninstall.Rd @@ -19,7 +19,7 @@ Generic alias: removes a model by name. Equivalent to \code{\link{uninstall_model}}. } \examples{ -\dontrun{ +\donttest{ if (fz_available()) { uninstall("PerfectGas") } diff --git a/man/uninstall_algorithm.Rd b/man/uninstall_algorithm.Rd index 8eda084..ba34ec1 100644 --- a/man/uninstall_algorithm.Rd +++ b/man/uninstall_algorithm.Rd @@ -18,7 +18,7 @@ uninstall_algorithm(algorithm_name, global = FALSE) Removes a previously installed algorithm from \code{~/.fz/algorithms/}. } \examples{ -\dontrun{ +\donttest{ if (fz_available()) { uninstall_algorithm("MonteCarlo") } diff --git a/man/uninstall_model.Rd b/man/uninstall_model.Rd index 769b271..0b2cf44 100644 --- a/man/uninstall_model.Rd +++ b/man/uninstall_model.Rd @@ -18,7 +18,7 @@ uninstall_model(model_name, global = FALSE) Removes a previously installed model from \code{~/.fz/models/}. } \examples{ -\dontrun{ +\donttest{ if (fz_available()) { uninstall_model("PerfectGas") } diff --git a/vignettes/modelica-examples.R b/vignettes/modelica-examples.R new file mode 100644 index 0000000..1e878ec --- /dev/null +++ b/vignettes/modelica-examples.R @@ -0,0 +1,103 @@ +## ----include = FALSE---------------------------------------------------------- +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>", + eval = FALSE # requires funz-fz Python package and a configured calculator +) + +## ----setup-------------------------------------------------------------------- +# library(fz) + +## ----install------------------------------------------------------------------ +# # Install the funz-fz Python package into the active reticulate environment +# fz_install() +# +# # Verify +# fz_available() + +## ----model_dict--------------------------------------------------------------- +# model <- list( +# varprefix = "$", +# delim = "{}", +# formulaprefix = "@", +# commentline = "#", +# output = list( +# pressure = "grep 'pressure =' output.txt | cut -d= -f2" +# ) +# ) + +## ----model_alias-------------------------------------------------------------- +# fzl()$models # lists installed aliases, e.g. "PerfectGas" + +## ----fzi---------------------------------------------------------------------- +# vars <- fzi("input.txt", model) +# # $P [1] 1.013 +# # $V [1] 22.4 +# # $n [1] 1.0 + +## ----fzc_single--------------------------------------------------------------- +# # Single case +# fzc("input.txt", list(P = 2.0, V = 11.2), model, output_dir = "compiled") +# # writes: compiled/P=2,V=11.2/input.txt (placeholder replaced with 2.0 / 11.2) + +## ----fzc_grid----------------------------------------------------------------- +# # 2 x 3 = 6 cases +# fzc("input.txt", +# list(P = c(1.0, 2.0), V = c(10.0, 20.0, 30.0)), +# model, +# output_dir = "compiled") + +## ----fzr---------------------------------------------------------------------- +# results <- fzr( +# "input.txt", +# list(P = c(1.0, 2.0, 3.0), V = 22.4), # 3 cases (V fixed) +# model, +# results_dir = "results", +# calculators = "sh://bash run.sh" # run.sh executes the simulator +# ) +# +# # results is a data frame: +# # P V pressure +# # 1 1.0 22.4 ... +# # 2 2.0 22.4 ... +# # 3 3.0 22.4 ... + +## ----fzo---------------------------------------------------------------------- +# values <- fzo("results/P=2,V=22.4", model) +# # $pressure [1] "2.026" +# +# # Glob to read all cases at once: +# all_values <- fzo("results/*", model) + +## ----fzd---------------------------------------------------------------------- +# result <- fzd( +# "input.txt", +# list(P = "[1;5]", V = "[10;30]"), +# model, +# output_expression = "pressure", +# algorithm = "algorithms/montecarlo_uniform.py", +# algorithm_options = "batch_sample_size=10;max_iterations=5;seed=42" +# ) + +## ----fzl---------------------------------------------------------------------- +# info <- fzl() +# names(info$models) # e.g. c("PerfectGas", "Moret") +# names(info$calculators) # e.g. c("sh://") +# +# # Filter by pattern +# fzl(models = "Perfect*") +# +# # Probe calculators to verify they are reachable +# fzl(check = TRUE) + +## ----save_results------------------------------------------------------------- +# saveRDS(results, "fz_results.rds") +# write.csv(results, "fz_results.csv", row.names = FALSE) + +## ----troubleshoot_install----------------------------------------------------- +# fz_install() # install funz-fz into the reticulate environment +# fz_available() # should return TRUE afterwards + +## ----session_info------------------------------------------------------------- +# sessionInfo() + From 653914fbecb678e543bd62ffc2d2d58659f4ac26 Mon Sep 17 00:00:00 2001 From: yannrichet Date: Tue, 23 Jun 2026 12:58:28 +0200 Subject: [PATCH 2/2] Use BSD 3-Clause license consistently: remove LICENSE stub, fix README Co-Authored-By: Claude Sonnet 4.6 --- LICENSE | 3 --- README.md | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) delete mode 100644 LICENSE diff --git a/LICENSE b/LICENSE deleted file mode 100644 index f9943bf..0000000 --- a/LICENSE +++ /dev/null @@ -1,3 +0,0 @@ -YEAR: 2025 -ORGANIZATION: Funz -COPYRIGHT HOLDER: Funz diff --git a/README.md b/README.md index ff28daa..462c3ef 100644 --- a/README.md +++ b/README.md @@ -139,4 +139,4 @@ Contributions are welcome. Please open a Pull Request or file an issue at ## License -MIT — see [LICENSE](LICENSE). +BSD 3-Clause — see [LICENSE](LICENSE.md).