Mathematical Notations and Capabilities in param()

The param() class, located in pizza.private.mstruct is an essential low-level class for 🍕 Pizza³. It used as parent class for data containers used by script, pipescript, dscript, scriptobject, forcefield, dforcefield. Its methods offer scripting capabilities between Pythonic and LAMMPS syntaxes.

The param class extends the struct class (located in the same module) and allows dynamic evaluation of expressions, implicit calculations, and NumPy-style operations. Instances of this class are iterable and can be managed using a Matlab-like syntax(*).

The syntax evolved between versions towards more flexibility and robustness. The capacity to perform calculations matrix/nd-operations is vital for building LAMMPS codelets/blocks with complex displacements and boundary conditions.

(*)note: Matlab inputs are also enabled as shorthands.


Manage dependencies

note: It is mandatory to import NumPy as np (internal convention) if NumPy arrays are defined in param text expressions.

The following snippet also shows how to check the current working directory (if needed)

note: If your notebook is showing an empty figure above, it is normal at at the initialization of Pizza. The code is testing the graphical capabilities.


1 | Overview

param and paramauto are sibling classes with similar features, offering MATLAB-like syntax, variable interpolation, and mathematical evaluation. Additionally, paramauto implements an internal mechanism to reorder expressions into a feasible execution sequence. This feature allows users to define expressions before their inputs or linked expressions, regardless of their order of definition. Such functionality is handy in multiscale modeling, where physical properties, discretization, and simulation parameters are interdependent. As a result, rescaling or imposing a physical property does not require rewriting the corresponding 🍕 Pizza³ template.

For conciseness, this document focuses on the param class. The same syntax applies to paramauto, with the only difference being the instance initialization: p = paramauto() instead of p = param().


1.1 | Variable Definition & Assignment

✍️ The param() class stores values and expressions as fields/attributes. Variables are referenced using the syntax ${var}. For example, if an instance is created as p = param(var=value, ...), then:

🗑️ To delete a variable, use either:


1.2 | param Expressions

🟰 param expressions are stored as strings. They can represent either mathematical expressions or template strings. Unlike Python’s built-in eval(), the evaluation result depends on the context—returning either a numerical value or a processed string.

📏 Matrix operations are supported using @{matrix} instead of ${matrix}.

Valid expression components:


1.3 | Interpolation & Evaluation

🧮 Interpolation (substitution) and 🚀 evaluation occur in this order:

🤔 If a full evaluation is not feasible, the result is stored with 4 significant digits by default (configurable).

Errors during evaluation return an error message. For example, accessing a variable that has not been evaluated will raise an error.

🚨 Enable debug messages on error evaluation with:

🔄 Alternative Syntax:
For simple variable substitutions, Pythonic {variable} notation is also supported alongside ${variable} for more flexible evaluation.

🔁 Nested vs. forced Evaluation:
Nested evaluation is implemented. 🌀 The best interpolation/local/global/evaluation scenario will be followed according to the context. 🔧 Full evaluation can be forced by prefixing the param expression with a ❗ like var = "! ...".


1.4 | Native vs. param Text Expressions

🔢 Variables can be stored as strings ("1.0") or numbers (1.0). Scalars and complex numbers are supported.

📐 Defining matrices & arrays using different param notations:

⚠️ Evaluation Order

🔄 Convert a dynamic param instance to a static structure with:

or equivalently

Variables can be specified


1.5 | Iterable Instances, Indexing & Slicing

🤝 param instances behave like lists or collections:

Auto-assigning Undefined Variables
If ${var} appears in an expression but isn’t defined, assign it automatically as:

Use p.check() to validate all variable assignments.


1.6 | Updating, Inheritance & Merging

📦 Batch updating variables within a param instance:

or via dictionary:

🔗 Merging multiple param instances using the + operator:


1.7 | Conversions

➡️ Convert param instances (p) to various formats:

ConversionMethod
param ➡️ Static struct (non-evaluated)s = p.tostatic()
param ➡️ Evaluated structse = p.tostruct() or se = p()
param ➡️ Dictionaryd = p.todict()
param ➡️ paramautopa = p.paramauto() or pa = paramauto(**p)
struct ➡️ paramp = s.struct2param()
struct ➡️ Dictionaryd = s.struct2dict()
dict ➡️ structs = struct(**d)
dict ➡️ paramp = param(**d)
dict ➡️ paramautopa = paramauto(**d)

1.8 | File Operations

💾 Save and load param instances:
📥 Save to disk

📤 Load from disk


2 | Define variables

2.1 | Overview


2.2 | Literal expressions

For legacy support, literal expressions can be defined either by:

note: The latest versions of param() can automatically detect literals that cannot be evaluated.

Literal Expressions Example

This example demonstrates how to use literal expressions with param():

The evaluated static structure is obtained by calling l().

 

 

 


2.3 | Inheritance of Missing Variables/Parameters, paramauto altenative and variable reordering

The missing parameter x can be supplied :

Solution 1: operator +

 

 

 

Solution 2: Altenatively, the missing parameter can be appended to l and l can be converted to a paramauto instance. The instance paramauto shows eventually order errors, but it tries to reorder the fields at runtime to remove errors.

 

 

 

Solution 3: Reordering fields using slicing and +.

 

 

 

note: param and struct instances can be indexed with lists [idx1,idx2,key1,key2...]:

 

 

 

 

 

 

 

 

 


2.4 | Numeric examples

This example demonstrates basic numeric assignments:

 

 

 


3 | Interpolation and Local Evaluation

3.1 | General Rules

This section demonstrates the interpolation and local evaluation capabilities:

Supported Operations

Supported Mathematical Functions


3.2 | Scalar evaluations Example

The following examples show scalar evaluations:

note: ` It is recommended not to mix global and local expressions (especially for indexing with NumPy arrays).

 

 

 

Evaluation and Display of Scalar Evaluations The following code evaluates all expressions (using p()) and displays:


3.3 | Nested Interpolations

Nested interpolation enables the use of a variable as an index or key:

note: Nested interpolation is not enabled for NumPy arrays defined in param text expressions. Tuples can be indexed

The following examples show the principles:

 

 

 

note: Lists and dictionaries defined in param text expressions can be also indexed.

These features are exemplified by replacing Python expressions with text ones.

 

 

 


3.4 | List and Nested Evaluations

This section demonstrates that variables can hold multiple values and that results are stored in lists:

note: The special character ! can be placed in front of expressions using lists as results (e.g., "!["${myvar}",${sum(myvar)+offset}]" to force recursive execution if it is not guessed internally.

param Text Example

In the following example, q.units is a literal string (with the $ prefix).

 

 

 

Text/Numeric Evaluation Example This example mixes text and numeric evaluations:

 

 

 

Additional Numeric Example

This example defines a param instance t with parameters o and p. Then:

 

 

 


3.5 | Support of dict (dictionnaries)

By design, instances of struct (and, by extension, param()) are intended to serve as flexible containers that can hold any type of data—including class instances. However, evaluating advanced types, such as nested lists or dictionaries, is more challenging. At this stage, only minimal support is provided for these advanced types in param().

note: Dictionary fields can be defined either as native Python dictionaries or as strings representing dictionaries. One limitation is that nesting strings for key names (i.e., defining keys as strings within string representations) remains an open issue. This is because, according to PEP 3101 (the guidelines for Python's advanced string formatting), quoted keys are not accepted in formatted strings. Consequently, a compromise approach is currently implemented.

Example Demonstrating Dictionary Support in param()

note: The definition of a dict within a param expression `${}' imposes fields to be used without quotes (adherence to PEP 3101)

 

 

 


4 | Mathematical shorthands for vectors, matrices, 3D and 4D arrays

Lists cannot be directly used as vectors and must be converted into NumPy arrays before performing vectorized operations.

Note:This section separate non-mathematical syntaxes leading to list instances from mathematical ones generating NumPy instances.


4.1 | Non-Mathematical Syntaxes for Lists

Numeric lists and lists of strings are non-mathematical containers. They accept à la Matlab and Pythonic shorthands for rapid prototyping and definitions. They cannot be used directly in NumPy operations, and only their scalar values can be used.

These syntaxes are used without $[] and operates only with a minimum of interpolation. Their use is limited to simple expressions and constants (float, int, str):

The following example illustrates rapid syntaxes applicable to lists

 

 

 


4.2 | Mathematical/NumPy Syntax

The param() class offers several shorthands to seamlessly manipulate NumPy arrays using param text expressions:

Variable References:

Transpose:

Function Application:

Slicing:

Matlab Notations Supported:

Examples:


4.3 | Simple Definitions Example

This example demonstrates simple definitions using Matlab-style notations:

 

 

 


4.4 | Matrix Operations Example

This example illustrates simple matrix operations:

 

 

 


4.5 | Slicing Example

This example demonstrates slicing operations:

 

 

 


4.6 | Advanced Example

This advanced example demonstrates operations such as:

 

 

 


5 | Global evaluation

A global evaluation is attempted for all expressions after interpolation and local evaluations have been performed. If the global evaluation does not raise any error, the evaluated result is kept; otherwise, the original interpolated expression is preserved. Since several expressions involving matrix operations require global evaluation (i.e., outside of ${...} or @{...}), it is recommended to define mathematically valid expressions and, if needed, use separate variables to store results as text.

5.1 | Global Evaluation Example with NumPy

This example demonstrates global evaluation:

 

 

 


5.2 | Global Evaluation Example with Various Matrix and ND- Operations

This example demonstrates various matrix operations:

 

 

 


For any question, contact INRAE\olivier.vitrac@agroparistech.fr | last revision $2025-02-08$