Computing Module

The computing module declares functions and classes to:

  • Hold numerical values for model quantities.

  • Declare Expressions to define the Blocks and ModelComponents Flux, InternalExpressions and SavedQuantities

  • Assemble the global System from those declaration.

Quantities

Define Quantities to represent discretized numeric values along with some convenience functions to handle them.

class Quantity(value: Any)

Represent discretized values by holding their current and new numeric values.

Examples

>>> scalar = Quantity(0.5)
>>> scalar.current == scalar.new  # 0.5
>>> vector = Quantity([0.1, 0.2, 0.3])
>>> vector.current == vector.new  # [0.1, 0.2, 0.3]

It can also be initialized with numpy arrays

>>> Quantity(np.ones(3))  # [1, 1, 1]

Matrixes are flattened when initializing a quantity: it can only be a scalar or vector.

>>> Quantity(np.ones((2, 2)))  # [1, 1, 1, 1]
property current: T

Get the current value (at step n) of the quantity

Returns:

The current value

Return type:

np.float64 | NDArray[np.float64]

property new: T

Get the new value (at step n + 1) of the quantity

Returns:

The new value

Return type:

np.float64 | NDArray[np.float64]

property size: int

Get the vector size of the quantity value (or 1 for scalars)

Returns:

The vector size of the quantity

Return type:

int

update(new: Any) None

Set the new value (at step n + 1) of the quantity

Parameters:

new (Any) – The new value

Raises:

ValueError – Exception raised if the new value and the quantity value are not the same size

Example

>>> q = Quantity(0.5)
>>> q.current  # 0.5
>>> q.new  # 0.5

>>> q.update(0.6)
>>> q.current  # 0.5
>>> q.new  # 0.6
initialize(value: Any) None

Set the current and new value of the quantity

Parameters:

value (Any) – The value to set

Example

>>> q = Quantity(0.5)
>>> q.update(0.6)
>>> q.current  # 0.5
>>> q.new  # 0.6

>>> q.initialize(0.1)
>>> q.current  # 0.1
>>> q.new  # 0.1
property operation_value: T

Value used with base operators.

Direct operation are allowed and performed on the current value of the quantity.

Returns:

the current value

Return type:

Any

Example

>>> q1 = Quantity(1.0)
>>> q2 = Quantity(2.0)
>>> q1.update(1.5)

# Quantity sum is performed on current value:
>>> q1 + q2  # 3.0

>>> q1.initialise(1.5)
>>> q1 + q2  # 3.5

In place operators call initialise on the Quantity

Example

>>> q1 = Quantity(1.0)
>>> q1 += 0.5
>>> q1.current  # 1.5
>>> q1.new  # 1.5
diff(q: Quantity[T]) T

Compute the difference between the new and the current value of the given Quantity

Parameters:

q (Quantity) – The quantity

Returns:

The difference betwen new and current for the quantity

Return type:

np.float64 | NDArray[np.float64]

Examples

>>> q = Quantity(1.0)
>>> diff(q)  # 0.0

>>> q.update(1.1)
>>> diff(q)  # 0.1
mid_alpha(q: Quantity[Any], scheme_time_shift: Any) Any

Compute the discretized value of the Quantity for a shifted time scheme.

\[x^{n+\alpha} = (\frac{1}{2} - \alpha) x^{n} + (\frac{1}{2} + \alpha) x^{n + 1}\]
Parameters:
  • q – The quantity

  • scheme_time_shift (float) – the time shift of the scheme.

Raises:

ValueError – If scheme_time_shift is not a scalar, exception raised if scheme_time_shift and q are not the same size.

Returns:

the discretized value of the quantity

Return type:

np.float64 | NDArray[np.float64]

Example

>>> q = Quantity(1.0)
>>> q.update(2.0)
>>> mid_alpha(q, 0.25)  # 1.75
mid_point(q: Quantity[Any]) Any

Compute the discretized value of the Quantity for a mid point time scheme

\[x^{n + \frac{1}{2}} = \frac{1}{2} (x^{n} + x^{n + 1})\]
Parameters:

q (Quantity) – Quantity

Returns:

Discretized value of the quantity

Return type:

np.float64 | NDArray[np.float64]

Example

>>> q = Quantity(1.0)
>>> q.update(2.0)
>>> mid_point(q)  # 1.5
sign(q: Quantity[float64]) float

Get 1 if the new value is superior to current value, -1 othwerwise

Parameters:

q (Quantity) – the quantity

Returns:

1 or -1

Return type:

np.float64

Models

Declares the ModelComponents and the Block base classes along with objects to hold the Flux, Internal Expressions and Saved Quantities functions.

SystemFunction

Type alias for functions composing the system

class Expression(size: int, expr_func: SystemFunction, expr_gradients: Mapping[str, SystemFunction] = {})

Store function computing numerical values for terms in the models with the function result size.

Optionally, it can define a set of function to compute the partial derivatives for a set of variables.

Example

def f1(x1, x2):
    return 0.5 * x1 + 0.8 * x2

def df1_dx1(x1, x2):
    return 0.5

def df1_dx2(x1, x2):
    return 0.8

expression_f1 = Expression(
    1, # size
    f1, # expression function
    {
        "x1": df1_dx1,
        "x2": df1_dx2,
    } # expressions partial derivatives
)
size: int

Size of the result of the function

expr_func: SystemFunction

Function to compute the numerical value

expr_gradients: dict[str, SystemFunction]

Collection of functions to compute the derivatives of the expression for variables

class TermDefinition(term_id: str, size: int, index: int = 0)

Describe Terms defined in an Expression.

An Expression object can define several Terms.

Example

def vector_3d(x1, x2, x3):
    return [x1, x2, x3]

expression_vector = Expression(
    3, # size
    vector_3d # expression function
)

x1_term = Term(
    "x1", # id
    1, # term size
    0 # starting index in vector expression
)

x2_term = Term(
    "x2", # id
    1, # term size
    1 # starting index in vector expression
)

x3_term = Term(
    "x3", # id
    1, # term size
    2 # starting index in vector expression
)
term_id: str

Term id

size: int

Term size

index: int = 0

Starting line of the term index in its expression

class ExpressionDefinition(expression: Expression, terms: list[TermDefinition] = [])

Holds an Expression and the TermDefinition couple.

Example

# Expression Definition for the example above:
>>> definition = ExpressionDefinition(
    expression_vector,
    [
        x1_term,
        x2_term,
        x3_term
    ]
)
expression: Expression

The expression

terms: list[TermDefinition]

The expressed Terms

property valid: bool

Check if the definition is complete, meaning a term is associated with each line of the expression and terms do not overlap.

Returns:

True if the definition is valid, False otherwise

Return type:

bool

# From example above
>>> definition = ExpressionDefinition(
    expression_vector,
    [
        x1_term,
        x2_term,
        x3_term
    ]
)
>>> definition.valid  # True

>>> overlapping_definition = ExpressionDefinition(
    expression_vector,
    [
        x1_term,
        x2_term,
        x3_term,
        x1_term # overlapping term on index 0
    ]
)
>>> overlapping_definition.valid  # False

>>> incomplete_definition = ExpressionDefinition(
    expression_vector,
    [
        x1_term,
        # missing index 1 term
        x3_term
    ]
)
>>> incomplete_definition.valid  # False
get_term(index: int) TermDefinition

Get term starting in expression at the given index

Parameters:

index (int) – the first index of the term in the expression.

Returns:

the term definition

Return type:

TermDefinition

# From example above
>>> definition = ExpressionDefinition(
    expression_vector,
    [
        x1_term,
        x2_term,
        x3_term
    ]
)
>>> definition.get_term(0)  # x1_term
>>> definition.get_term(1)  # x2_term
>>> definition.get_term(2)  # x3_term
ExpressionsCollection

Type alias for a collection of expressions. Keys are the expression types as strings. Values are a tuple defining the actual expression and a list of Term Definitions it expresses.

class ModelComponentMetaClass(*args: Any, **kwargs: Any)

Meta-class for ModelComponent.

Defines the model Internal Equations and Saved Quantities using Expression objects.

  • Internal Equations are expressing Internal Variables with a residual equation.

  • Saved Quantities are given with a direct relation

property local_ids: list[str]

Get local parameters ids of the model.

Every member of the ModelComponent annotated with Quantity type has a local id.

Returns:

the local ids of the parameters

Return type:

list[str]

Example

@dataclass
class SimpleModel(metaclass=ModelComponentMetaClass):

    x1: Quantity
    x2: Quantity

SimpleModel.local_ids # ["x1", "x2"]
declares_internal_expression(variable_id: str, expr: Expression, size: int | None = None, index: int = 0) None

Declares a Expression object for an Internal Equation of the model.

Parameters:
  • term_id (str) – the local id of the variable associated with the expression

  • expr (Expression) – the associated expression

  • size (int) – the term size

  • index (str) – the starting line index of the term in the expression.

Example

@dataclass
class SimpleModel(metaclass=ModelComponentMetaClass):

    x1: Quantity
    a: Quantity
    b: Quantity

    def x1_residual(self):
        return self.a.current * self.x1.new - b.current

    def dx1_residual_dx1(self):
        return self.a

x1_expression = Expression(
    1,
    SimpleModel.x1_residual,
    {
        "x1": SimpleModel.dx1_residual_dx1
    }
)
SimpleModel.declare_internal_expression(
    "x1", # term id
    x1_expression, # term expression
    1, # term size
    0 # Term index in the expression
)
property internal_variables: list[TermDefinition]

Get the TermDefinition object describing internal Variables

Returns:

the internal variables term definitions

Return type:

list[TermDefinition]

property internal_expressions: list[ExpressionDefinition]

Get the all Expression object describing Internal Equations of the model component.

Returns:

the internal equation expressions

Return type:

list[ExpressionDefinition]

get_internal_variable_expression(term_id: str) tuple[Expression, int, int]

Get the Expression for the given Internal Variable local name.

Parameters:

term_id (str) – the term id

Returns:

the expression, its size and the starting index of the term in the expression.

Return type:

tuple[Expression, int, int]

has_internal_variable(variable_id: str) bool

Get if the given name match an Internal Variable of the model component

Parameters:

variable_id (str) – the id to test

Returns:

True if the id defines an Internal Variable, False otherwise

Return type:

bool

declares_saved_quantity_expression(term_id: str, expr: Expression, size: int | None = None, index: int = 0) None

Add a Saved Quantity Expression object to the model definition.

Parameters:
  • term_id (str) – the local id of the term.

  • expr (Expression) – the associated expression

  • size (int) – the term size

  • index (str) – the starting line index of the term in the expression.

Example

@dataclass
class SimpleModel(metaclass=ModelComponentMetaClass):

    x1: Quantity

    def x1_squared(self):
        return x1.current * x1.current

x1_squared_expression = Expression(
    1,
    SimpleModel.x1_squared
)
SimpleModel.declares_saved_quantity_expression(
    "x1_squared", # term id
    x1_squared_expression, # term expression
    1, # term size
    0 # Term index in the expression
)
property saved_quantities: list[TermDefinition]

Get the saved quantities expressed by the model

Returns:

the saved quantities local id and size.

Return type:

list[tuple[str, int]]

has_saved_quantity(saved_quantity_id: str) bool

Get if the given id is a saved quantity

Parameters:

saved_quantity_id (str) – the id to test

Returns:

True if the id defines a saved quantity, false otherwise

Return type:

bool

property saved_quantities_expressions: list[ExpressionDefinition]

Get the all saved quantities expressions

Returns:

the saved quantities expressions

Return type:

list[ExpressionDefinition]

get_saved_quantity_expression(term_id: str) tuple[Expression, int, int]

Get the expression for the given saved quantity local id.

Parameters:

term_id (str) – the term id

Returns:

the expression, the starting index of the term in the expression and its size.

Return type:

tuple[Expression, int, int]

class ModelComponent

Holds parameters and define functions to compute Internal Equations and Saved Quantities.

initialize() None

Override this method to define specific for model initialization.

class BlockMetaClass(*args: Any, **kwargs: Any)

Meta-class for Block.

Extends ModelComponentMetaClass type adding Flux Expression to the model definition.

  • Every Flux is expressed toward the outside of the Block.

  • Every Local Nodes index of the Block defines one Flux.

Note

BlockMetaClass can also define Internal Equations and Saved Quantities

declares_flux_expression(node_index: int, variable_id: str, expr: Expression) None

Add a flux expression defining a block external relation.

Parameters:
  • node_index (int) – the local node index where the flux is shared

  • variable_id (str) – the local id of the variable associated to the node.

  • expr (Expression) – the associated expression

Example

@dataclass
class SimpleBlock(metaclass=BlockMetaClass):

    q0.new: Quantity

    def flux_0(self):
        return q0.new


    def dflux_0_dq0(self):
        return 1.0

flux_0_expression = Expression(
    1,
    SimpleBlock.flux_0,
    {
        "q0": SimpleBlock.dflux_0_dq0
    }
)

SimpleBlock.declares_flux_expression(
    0, # Local Node index,
    "potential_0", # Associated DOF id
    flux_0_expression, # flux expression
)
property nodes: list[int]

Get all the local nodes indexes.

Returns:

The list of indexes.

Return type:

list[int]

property fluxes_expressions: dict[int, ExpressionDefinition]

Get all the fluxes expressions in the block with the local node where they are shared.

Returns:

the fluxes exressions ordered by node index.

Return type:

dict[int, ExpressionDefinition]

property external_variables_ids: list[str]

Get local id of variables defined by the flux connecting to a node in the block.

Returns:

a list of all local external variables ids.

Return type:

list[str]

class Block

Extends ModelComponent and declare functions to compute Flux.

Assembling

Allows to build systems that computes residual and gradient from collections of functions.

class EqSystem(size: int)

Global Equation system

Allows to compute the numerical value of the residual and the gradient for a Net.

The system is built from a collection of System Parts. The parts are summed in a global system to compute the numerical value of the residual and the gradient.

property system_size: int

Get the system size

Returns:

the system size

Return type:

int

add_system_part(self, residual_index: int, residual_size: int, residual_func: SystemFunction, gradients_func: dict[int, SystemFunction], parameters: Any)

Add an equation system part to the global system.

Parameters:
  • residual_index (int) – the line index where to sum the function in the global system

  • residual_size (int) – the size of the result of the residual_func

  • residual_func (SystemFunction) – the function to compute the residual part

  • gradients_func – the functions to compute the gradients parts associated with the index of the variable in the state vector

  • parameters (Any) – the parameters needed to compute the SystemFunctions (both residual and gradient) (should be the same type as the argument of the residual_func and the gradients_func input type)

Raises:

ValueError – Raises a ValueError when either the size of the residual or the gradient part will exceed the global system size.

compute_residual() NDArray[np.float64]

Compute the numerical value of the residual.

Returns:

the residual

Return type:

NDArray[np.float64]

compute_gradient() NDArray[np.float64]

Compute the numerical value of the gradient.

Returns:

the gradient

Return type:

NDArray[np.float64]