Python¶
The package is bijective-gamut on PyPI, imported as gamut
(installing). This page is generated from its
docstrings, which help() shows in Python, and every
example has a Python tab. Positions count from 0,
and a refusal raises GamutError naming the rule. gamut.FORMAT is the
format the package writes, gamut/1, and gamut.__version__ the
package's own version.
Files¶
create ¶
create(
path: str,
*,
writer: str,
parameters: Mapping[str, Any] | None = None,
labels: Mapping[str, Any] | None = None,
scalars: Mapping[str, Any] | None = None,
fields: Mapping[str, Any] | None = None,
mesh_labels: Mapping[str, Any] | None = None,
constants: Mapping[str, Any] | None = None,
mesh: str | None = None,
per: str | None = None,
coordinates: Mapping[str, Any] | None = None,
precision: Mapping[str, Any] | None = None,
round_bits: Mapping[str, int] | None = None,
title: str | None = None,
license: str | None = None,
references: str | None = None,
source: str | None = None,
portion_marking: str | None = None,
generalisation_group: str | None = None,
compression: bool = True,
) -> Study
Creates a data file and returns it open to add runs: use it in a
with block, or call close(). Everything the file holds is declared
here by name. The destination must not exist; a refused declaration
removes only the new file, leaving any existing destination unchanged.
parameters: inputs that place a run, as{"alpha": {"units": "degree", "role": "condition"}}. Role "design" (the default), "condition" or "time"; optional "lower", "upper". float64 whatever the values given, or"dtype": "int64"for whole numbers such as a count or a seed.labels: names rather than numbers, as{"status": {"role": "status", "categories": ["converged", "failed"]}}. Role "categorical" (the default), "group", "status" or "split". Only the status "converged" marks a run as usable. A name not yet in "categories" is added to them.booldeclares a false/true label.scalars: one number per run, as{"cl": "1"}(its units), or a mapping with "units" and a relation ("of" with "statistic" and "q", or "with_respect_to").fields: one number per node or cell, as{"p": {"units": "Pa", "at": "node"}}; needs a mesh.constants: one number for the whole study, as{"area": (12.5, "m2")}.mesh,per: no mesh (a run table); "shared" (one mesh for every run) with per "fixed", "run" or"group:<label>"; or "changing" (a mesh per run) with per "run" or"group:<label>". With a mesh,coordinates={"units": "m", "axes": 2}.mesh_labels: zones or patches, as{"surface": {"at": "node", "categories": ["field", "wall"]}}.generalisation_group: the group label a fair test holds out whole.title,license,references,source: describe the file.portion_marking: a marking the author set, as free text;evaluatecopies it into every answer,extractandwrite_copykeep it.precision,round_bits,compression: storage; the defaults suit most studies.
Units use the UDUNITS grammar: "1", "degree", "m s-1", "W m-2".
open ¶
open(path: str, mode: str = 'r', threads: int = 1) -> Study
Opens a file to read (mode "r") or to add runs in place (mode "a"),
as a Study; use it in a with block, or call close(). threads
decompresses large field reads in that many threads.
create_model ¶
create_model(
path: str,
*,
writer: str,
parameters: Mapping[str, Any] | None = None,
labels: Mapping[str, Any] | None = None,
scalars: Mapping[str, Any] | None = None,
fields: Mapping[str, Any] | None = None,
constants: Mapping[str, Any] | None = None,
mesh: str | None = None,
per: str = "fixed",
coordinates: Mapping[str, Any] | None = None,
trained_on: Sequence[str] | None = None,
title: str | None = None,
license: str | None = None,
references: str | None = None,
source: str | None = None,
portion_marking: str | None = None,
) -> ModelFile
Creates a model file and returns it open to add models: use it in a
with block, or call close(). The destination must not exist.
A model file holds no runs. It is
declared as create declares a data file (labels, constants, mesh,
per, coordinates, title, license, references, source,
portion_marking), except:
parameters: each needs "lower" and "upper", the range the model was fitted on, as{"alpha": {"units": "degree", "lower": 0.0, "upper": 10.0}}.evaluatewarns (W4) of an input outside it, and evaluates it.scalars,fields: each names the model and the output that computes it, as{"cl": {"units": "1", "model": "fit", "output": "cl"}}. A spread or a derivative is declared as increate("of", "statistic", "with_respect_to"), and the model'scallis asked for it.trained_on: the file_id (study.describe()["file_id"]) of each study the model was fitted on.portion_marking: a marking the model's author set, as free text;evaluatecopies it into every answer file.
Then add_model(id, model, inputs) stores each model: an object of a
type registered with register_model_type, or the built-in Nearest.
The file keeps the numbers its save returns, never code; a program
that evaluates the file registers the type first. Closing refuses a
file with no model, or a result whose model was never added.
The whole pattern, with a model type of one's own:
import numpy as np
import gamut
@gamut.register_model_type
class Polynomial:
type = "example.polynomial" # the name the file records
def __init__(self, coefficients):
self.coefficients = np.asarray(coefficients, dtype=float)
@classmethod
def load(cls, numbers): # numbers: the dictionary save returned
return cls(numbers["coefficients"])
def save(self): # numbers, text, booleans, arrays, dictionaries
return {"coefficients": self.coefficients}
def call(self, inputs, wanted): # an array per input, a value per row
(x,) = inputs.values()
return {output: {"values": np.polyval(self.coefficients, x)}
for output, *_ in wanted}
alpha = np.array([0.0, 2.0, 4.0, 6.0])
with gamut.create_model("lift.gamut", writer="my fit",
parameters={"alpha": {"units": "degree", "lower": 0.0, "upper": 6.0}},
scalars={"cl": {"units": "1", "model": "fit", "output": "cl"}}) as model:
model.add_model("fit", Polynomial(np.polyfit(alpha, 0.11 * alpha, 2)), inputs=["alpha"])
with gamut.evaluate("lift.gamut", {"alpha": [1.0, 5.0]}) as answer: # an ordinary data file
print(answer.get_scalar("cl"))
The study¶
Study ¶
A study file open to write (from create) or to read (from open).
Writing: add_run, add_runs, set_mesh, notes, set_private.
Reading: row_count, names, describe, select, get_parameter,
get_label, get_scalar, get_constant, get_field, get_points,
get_cells, get_mesh_label, categories, table, related,
outside.
Rows are positions counted from 0; a rows argument takes a position,
a list of them, a slice, or None for every row.
Arrays it returns are the caller's own; it is a context manager, and
close() releases the file.
addons
property
¶
addons: list[str]
What the file holds beyond its type: "time", "uncertainty", "gradients".
notes
property
¶
notes: Any
Free-form public notes: a dict when reading; assign items when
writing (study.notes["solver"] = "OpenFOAM v2406").
close ¶
close() -> None
Finishes the file. A refused close (a shared mesh never set, a model file without a model) keeps it open to fix and close again.
set_mesh ¶
set_mesh(
points: Any = None,
cells: Any = None,
labels: Mapping[str, Any] | None = None,
n_nodes: int | None = None,
) -> None
A shared mesh: its cells (types, offsets, connectivity), its fixed
mesh labels, and its points when the geometry is fixed. When the
coordinates come with the runs, give n_nodes instead of points.
add_run ¶
add_run(
values: Mapping[str, Any],
*,
fields: Mapping[str, Any] | None = None,
points: Any = None,
cells: Any = None,
mesh_labels: Mapping[str, Any] | None = None,
) -> int
Adds one run; returns its id. values gives each parameter, label
(by name) and scalar; fields one value per node or cell.
add_runs ¶
add_runs(
columns: Mapping[str, Any],
*,
fields: Mapping[str, Any] | None = None,
points: Sequence[Any] | None = None,
cells: Sequence[Any] | None = None,
mesh_labels: Sequence[Mapping[str, Any]] | None = None,
) -> list[int]
Adds many runs at once: columns maps each name to one value per
run, as a dict of arrays or a pandas DataFrame does; fields to runs
x sites (a changing mesh: every run's values end to end); points,
cells, mesh_labels one per run (or per new group member) when the
geometry changes.
names ¶
names(group: str) -> list[str]
The names in a group: "parameters", "labels", "scalars", "constants", "node_fields", "cell_fields", "node_labels", "cell_labels", "tables" or "models".
describe ¶
describe(name: str | None = None) -> dict[str, str]
A concept's attributes as text, or with no name the file's own.
model_numbers ¶
model_numbers(id: str) -> dict[str, Any]
A model's stored numbers (spec section 12), as the dictionary its
save gave; its type need not be registered.
get_row_ids ¶
get_row_ids(rows: Any = None) -> np.ndarray
Each row's id, unique in the file and kept when runs are extracted to another; not its position.
get_parameter ¶
get_parameter(
name: str, rows: Any = None, units: str | None = None
) -> np.ndarray
A parameter's value in each row, in units if given (which needs
the units extra, pint).
outside ¶
outside(name: str, rows: Any = None) -> np.ndarray
How far each row's value of the parameter name lies outside the
bounds the file declares for it, in the parameter's units: 0 inside
or on a bound, value - lower (negative) below, value - upper
(positive) above, NaN where the value is missing. A parameter with
no bounds is refused. The answer of evaluate keeps the model's
bounds, so this says which of its rows lie outside the range the
model was fitted on, and how far.
get_label ¶
get_label(name: str, rows: Any = None) -> np.ndarray
A label's category name in each row.
get_label_codes ¶
get_label_codes(name: str, rows: Any = None) -> np.ndarray
A label's code in each row; categories(name)[code] is its name.
get_scalar ¶
get_scalar(name: str, rows: Any = None, units: str | None = None) -> np.ndarray
A scalar result in each row, NaN where a run has none.
get_constant ¶
get_constant(name: str, units: str | None = None) -> Any
A constant's one value for the whole study.
get_cells ¶
get_cells(row: int | None = None) -> tuple[np.ndarray, np.ndarray, np.ndarray]
The cells as VTK gives them: a type per cell, offsets (one more
than the cells), node numbers. A changing mesh needs the row.
get_points ¶
get_points(row: int | None = None, units: str | None = None) -> np.ndarray
Node coordinates, nodes x axes. A geometry that changes with the
run (per run or per group member) needs the row.
get_field ¶
get_field(
name: str,
rows: Any = None,
nodes: Any = None,
cells: Any = None,
units: str | None = None,
) -> np.ndarray
A field: runs x nodes (or cells) on a shared mesh, one row's
values on a changing mesh. nodes or cells choose sites by
position, as rows chooses rows.
get_mesh_label ¶
get_mesh_label(name: str, row: int | None = None) -> np.ndarray
A mesh label's code per node or cell; categories(name) names
the codes (a zone, a boundary patch).
categories ¶
categories(name: str) -> list[str]
The category table of a label or mesh label: code c names entry c.
table ¶
table(
names: Sequence[str] | None = None, rows: Any = None
) -> dict[str, np.ndarray]
The run table as columns: parameters, labels (as names), scalars.
set_private ¶
set_private(name: str, data: bytes) -> None
A producer's own record: bytes no other reader interprets.
get_private ¶
get_private(name: str) -> bytes
A producer's own record, the bytes set_private stored.
select ¶
select(where: str) -> np.ndarray
The positions of the rows where selects, e.g.
"mach > 0.5 and status == converged" (docs/reference/selecting.md).
related ¶
related(name: str) -> dict[str, Any]
What describes name (spec section 6): its std, its quantiles by
q, its derivatives by what they are taken with respect to
("coordinates:x" for node position along x), and the parts of its
vector, itself among them.
Models¶
evaluate ¶
evaluate(
model_path: str,
inputs: Mapping[str, Any],
path: str | None = None,
coordinates: Any = None,
) -> Study
Evaluates a model file on a table of inputs (spec section 7.4) and
returns the resulting data file, open to read. An explicit path must
not exist. inputs maps each
parameter to values and each label to names from the model file's
table, all of one length; coordinates (rows x nodes x axes) when a
model reads geometry the file does not store. Each model's type must
be registered (register_model_type; Nearest is built in). An
input outside a parameter's bounds is evaluated, with a warning (W4),
and the answer's outside(name) says how far each row lies outside.
Without path the data file is temporary and removed when closed:
read it in a with block, or give path to keep it.
register_model_type ¶
register_model_type(cls: type) -> type
Registers a model type, so that evaluate runs the files that name
it; usable as a decorator. A file records the type's name and its
numbers, never its code, so every program that evaluates the file
registers the type first. create_model shows the whole pattern.
The class has (SPEC.md section 7.3):
type its name in files; name it after your project:
"mylab.polynomial".
load(numbers) a classmethod: the model from the dictionary save
returned.
save() the model's numbers: a dictionary of numbers, text,
booleans, NumPy arrays of booleans, int32, int64 or
float64, and dictionaries of those.
call(inputs, wanted) inputs maps each input the model reads to an
array with a value per row. wanted lists what to return,
each item one of (output, "values"), (output, "std"),
(output, "quantile", q) or (output, "derivative", name).
Returns {output: {"values": ..., "std": ...,
"quantiles": {q: ...}, "derivatives": {name: ...}}} with
what was wanted: a value per row for a scalar, rows x
nodes (or cells) for a field.
Nearest ¶
The built-in model: for each input row, the outputs of the closest stored point (spec section 7.5). Evaluated by the core, so every language gets the same answers.
Copies¶
append ¶
append(dst: str, src: str) -> int
Adds the rows of src to dst in place and returns how many. The
rows get new ids continuing dst's; category tables merge by name. Both
files need the same declarations (bounds may differ), the same mesh,
and one geometry for a group member found in both.
extract ¶
extract(src: str, dst: str, rows: Any) -> None
Writes the selected rows of src (positions, a slice, or a strictly
increasing array) as a new file dst (which must not exist): ids kept, every table whole, a
changing mesh's instances reduced to those the rows use.
write_copy ¶
write_copy(src: str, dst: str) -> None
Rewrites src as dst with the default layout (chunks and
compression), as for a file another writer chunked finely; the copy
keeps the file's identity (file_id, created). The destination must not exist.
Checking¶
Report
dataclass
¶
Every finding of one validation.
Finding
dataclass
¶
One finding: rule ("E7", "W2"), severity ("error" | "warning"),
path (a concept path such as "node_fields/p", "" for the file) and a
message saying what is wrong and what to do.
Errors and the library¶
GamutError ¶
The one error: rule is the spec's rule id ("E7") or empty, path
a concept path or empty, message what went wrong and how to fix it.
library_path ¶
library_path() -> str
The core library this package loaded. MATLAB and Julia can use the same file (it carries its own HDF5 in a wheel).