fonsim.core package
Submodules
fonsim.core.component module
Class Component
2020, July 21
- class fonsim.core.component.Component(label)
Bases:
object
Components to build a system with.
TODO
States and variables The state data (e.g. amount of fluid inside actuator) is saved as 2D-array in the components themselves (and the solver always refers to these) while the argument data (e.g. pressure, flow in/out) is saved as a list of _references_ to nameless 1D-arrays created by the solver. The component object provides functionality for the solver to allocate memory for the states, but not for allocating the variables. The solver takes care of calling these functions necessary. The object property
state_history
holds the 2D-array and object propertyargument_history
holds a list with references to the 1D-arrays.- Parameters:
label – Component name.
- auto(func)
- auto_state(func)
- evaluate(values, jacobian_state, jacobian_arguments, state, arguments, elapsed_time)
Evaluates the component internal equations. This method should be static.
Note: only evaluate left-hand side (LH) of equation, equation should be structured such that RH is always zero.
- Parameters:
values – array where the equation residuals will be stored.
jacobian_state – array where the jacobian to the state will be stored.
jacobian_arguments – array where the jacobian to the arguments will be stored.
state – numerical values belonging to the state Variables.
arguments – numerical values belonging to the Variables.
elapsed_time – ? TODO.
- Returns:
None
- get(variable_key, terminal_label=None)
Same as method
self.get_all
, but returns only the first return value.
- get_all(variable_key, terminal_label=None)
Get simulation results. Supports ‘smart matching’ by comparing string distances.
- Parameters:
variable_key – key of variable, e.g. ‘pressure’
terminal_label – label of terminal, e.g. ‘a’
- Returns:
Numpy ndarray object and Terminal object
- get_state(label)
Get simulation results. Supports ‘smart matching’ by comparing string distances.
- Parameters:
label – state label, e.g. ‘volume’
- Returns:
Numpy ndarray object
- get_terminal(terminallabel=None)
Returns Terminal object. If no label given, returns the first unconnected terminal. If label given, returns terminal with that label. If no terminal found, returns None.
- Parameters:
terminallabel – Label of terminal
- Returns:
Terminal object
- set_arguments(*arguments)
Overwrite component arguments list with the provided Variable objects.
- Parameters:
arguments – one or more Variable objects
- Returns:
None
- set_states(*states)
Overwrite component states list with the provided Variable objects.
- Parameters:
states – one or more Variable objects
- Returns:
None
- set_terminals(*terminals)
Overwrite component terminals list with the provided Terminal objects and attach those terminals to the component.
- Parameters:
terminals – one or more Terminal objects
- Returns:
None
- update_state(state_new, jacobian, state, arguments, dt)
Evaluates the update to the component state. This method should be static.
- Parameters:
state_new – array where the new state values will be stored.
jacobian – array where the jacobian to the arguments will be stored.
state – numerical values belonging to the state Variables.
arguments – numerical values belonging to the Variables.
dt – time discretization timestep.
- Returns:
None
fonsim.core.node module
Class Node
2021, January 14
- class fonsim.core.node.Node(*terminals)
Bases:
object
Connection between multiple component terminals
- add_terminals(*terminals)
Connect terminals to the node
- Parameters:
terminals – Terminal object. Multiple can be provided
- Returns:
None
- contains_terminal(terminal)
Check if the node contains the requested terminal
- Parameters:
terminal – Terminal object
- Returns:
Boolean
- get_variables(orientation=None, key=None)
Get a list of all variables with the provided orientation and/or key associated with the node.
- Parameters:
orientation – optional string specifying requested variable orientation
key – optional string specifying requested variable key
- Returns:
list of Variable objects
- merge_node(node)
Connect all terminals from another node to this node
- Parameters:
node – Node object
- Returns:
None
fonsim.core.setnumpythreads module
https://gitlab.com/abaeyens/fonsim/-/issues/19
2022, June 04
- fonsim.core.setnumpythreads.setnumpythreads(nb_threads=1)
fonsim.core.simulation module
Class Simulation
2020, July 22
- class fonsim.core.simulation.Simulation(system_to_simulate, duration=10, step=None, step_min=None, step_max=None, max_steps=0, verbose=0)
Bases:
object
Class to convert network information (how the components are connected to each other) and component information (equations for each component) to a single non-linear system of equations (function vector + Jacobian) describing the whole system.
Solving this system is to be done by a solver. This object contains a solver object in the property self.solver. (Future functionality: possibility to select a solver manually etc.)
The Class Solver interacts heavily with the System class and expects the following methods to be available:
evaluate_equations()
update_state()
equation_to_string()
as well as the following properties:
system
phi
,H
andA
arguments
nb_arguments
andnb_network_equations
times
andduration
andverbose
- Parameters:
system_to_simulate – System object with components and how they are connected
duration – amount of time the system will be simulated for
step – initial time increment
step_min – minimal time increment during the simulation
step_max – maximal time increment during the simulation
max_steps – maximum amount of time increments before the simulation is terminated prematurely. A value of 0 disables this behavior (default)
verbose –
level of information printed in the console during the simulation. All messages belonging to a level with a number lower than or equal to the provided parameter will be displayed, with the possible levels being:
-1: simulation start and end messages
0 (default): simulation progress in % steps
1: system matrices on iterations with bad convergence
- check_issolvable()
Warns when number of equations doesn’t equal number of unknowns. :return: None
- equation_to_string(equation_index)
Return a string describing the equation with the provided index in a human-readable format. For a network equation, this string contains the involved variables and their coefficients. For a component equation, this string mentions the component label and the index of the equation in the list of equations of that particular component.
- Parameters:
equation_index – index of the row in the simulation equation matrix corresponding to the desired equation
- Return eq_str:
string representing the equation
- evaluate_equations(simstep, g, H, elapsed_time, dt)
Evaluate component equations to obtain evaluated function vector (equation residuals) and jacobian. This method will call the method
Component.evaluate
on each component. This method will also call the methodComponent.update_state
on each component.Note: This function does not evaluate (or update) the network equations (upper part of the jacobian ‘H’)!
- Parameters:
simstep – simulation timestep index to start from
g – numpy ndarray for the evaluated function vector
H – numpy ndarray for the evaluated jacobian
elapsed_time – time elapsed
dt – timestep (0 for explicit Euler, dt for implicit Euler)
- Returns:
None
- extend_memory(nb_extra_steps)
Increase the size of the simulation memory without overwriting previous results. This deals with the same entities as described in the documentation of initialize_memory
- Parameters:
nb_extra_steps – amount of time steps by which to increase the memory
- Returns:
None
- fill_network_matrix(A)
Fill the network matrix. The network matrix is constant over the simulation, at least supposing the network configuration does not change. It is thus sufficient to calculate it a single time.
There are two types of network equations, one for across variables and one for through variables. At each node, all across variables have to be equal. Thus for each node n-1 equations, n being the number of components attached to that node. Concerning the through variables, the sum of all through variables should be zero at each node, thus one equation for each node.
- Parameters:
A – system Jacobian matrix, numpy ndarray n x n, n=len(phi)
- Returns:
None
- init_matrixconstruction()
Create some LUT-style lists and dicts so data can be moved around quickly in the simulation loop.
- Returns:
None
- initialize_memory(nb_steps)
Initialize all arrays that will hold the simulation results through time. This includes - The vector with time values - Component argument and state histories (in Component class) - The simulation phi matrix with all arguments over time All previously stored results are overwritten. This method initializes the arrays with zeros and therefore does not use the
initial_value
attribute of the Variable objects.- Parameters:
nb_steps – estimated amount of time steps in the simulation
- Returns:
None
- map_phi_to_components(phi)
Send addresses of arguments over time to components, so one can get the data from the component without passing by the Simulation object. Furthermore, it avoids duplicating the data.
- Parameters:
phi – numpy ndarray m x n with the argument vector over time (m = nb timesteps and n = nb arguments)
- Returns:
None
- map_state_to_components(state)
Send addresses of state over time to components, so one can get the data from the component without passing by the Simulation object. Furthermore, it avoids duplicating the data.
- Parameters:
state – numpy ndarray m x n with the state vector over time (m = nb timesteps and n = nb states)
- Returns:
None
- print_equations()
Print a human-readable representation of the full system of equations to the console.
- Returns:
None
- run()
Run simulation, with the parameters specified previously.
- Returns:
None
- set_initial_values_phi(step=0)
Takes the initial values from the component argument Variable objects and writes them to the simulation memory (matrix ‘phi’).
- Parameters:
step – simulation step at which to write the initial value
- Returns:
None
- set_initial_values_state(step=0)
Takes the initial values from the component state Variable objects and writes them to the simulation memory (matrix ‘state’).
- Parameters:
step – simulation step at which to write the initial value
- Returns:
None
- slice_memory(start_step, end_step)
Decrease the size of the simulation memory by taking a slice out of it. This deals with the same entities as described in the documentation of initialize_memory
# TODO update such that takes slice as argument
- Parameters:
start_step – index of the first time step in the range to maintain
end_step – index of the first time step outside the range to maintain
- Returns:
None
- update_state(simstep, dt)
Update the state variables in all components using the arguments in self.phi at step n + 1 (n = ‘simstep’). This method will call the method
Component.update_state
on each component.- Parameters:
simstep – simulation timestep index to start from
dt – timestep
- Returns:
None
fonsim.core.solver module
Classes with available solvers
A solver takes care of solving the (non-linear) system of equations generated by the Simulation object. This object can interact with the Simulation object.
The Simulation class expects the following methods
from the solver object:
- get_nb_steps_estimate()
- run_step(simulation_step_index)
- Current solvers:
ImplicitEulerNewtonConstantTimeStep
ImplicitEulerNewtonAdaptiveTimeStep
2020, July 23
- class fonsim.core.solver.ImplicitEulerNewton(simulation)
Bases:
object
- apply_solver_bias(bias=1e-12, step=0)
Give elements in the solution vector a small positive value, to ease starting the simulation
- Parameters:
bias – bias value added to the solution vector entries
step – simulation step for which this bias is applied
- Returns:
None
- get_all_variables(simstep)
- Parameters:
simstep – simulation step at which variables are queried
- Returns:
np array with the values of all arguments and component states at the desired simulation step
- get_residual(simstep, res=None)
Evaluate the simulation system of equations at the provided timestep to get the residual vector
- Parameters:
simstep – index of simulation timestep at which the system of equations is evaluated
res – optional initialized residual vector that will be overwritten by this function in place
- Returns:
evaluated residual vector
- newton_solver(step, iterations=100, alpha=1.0)
Newton method for solving the system equations and storing the solution in the simulation phi vector at an time step
- Parameters:
step – step index for which the system will be solved and the solution will be stored. The initialization for the solver can be done externally by setting self.sim.phi[step] to the initial guess
iterations – maximum number of newton solver iterations. 100 (default) gives good results although it often converges in one step and otherwise mostly in less than ten
alpha – correction constant for damped Newton method
- Returns:
flag indicating exit status of the solver for this step: * 0: maximum amount of iterations reached without convergence * 1: solver converged quickly * 2: solver converged slowly
- print_report(simstep)
Print a report on the solver status at a certain simulation time step.
- Parameters:
simstep – index of simulation timestep for which the report is generated
- Returns:
None
- class fonsim.core.solver.ImplicitEulerNewtonAdaptiveTimeStep(simulation, step, step_min, step_max, max_attempts=200)
Bases:
ImplicitEulerNewton
- delta_in_range(delta)
Check whether a change in simulation variables (both arguments and states) during a step is within an acceptable range compared to the other simulation step results or it is abnormally large
- Parameters:
delta – vector with change in all the arguments between consecutive simulation steps
- Return in_range:
True if delta is of an acceptable magnitude and False if it represents a change which is abnormally large
- get_nb_steps_estimate()
- Returns:
number of timesteps the solver thinks it will need to finish the simulation
- run_step(simstep)
Run a single step of the solver. Note: Calling it at step n (‘simstep’ = n) results in it writing to the next step, aka step n+1
- Parameters:
simstep – index of timestep with the last simulated results
- Returns:
list with as elements: * 0: boolean showing solver convergence for the simulation step * 1: string giving more information about the exit status
- update_delta_range(nb_points, delta)
Update the average and variance of the changes of simulation variables (both arguments and states) over all simulation steps with the change at the current step
- Parameters:
nb_points – amount of steps included in the last metrics
delta – new change in simulation arguments between consecutive steps to include in the metrics
- Returns:
None
- class fonsim.core.solver.ImplicitEulerNewtonConstantTimeStep(simulation, step)
Bases:
ImplicitEulerNewton
- get_nb_steps_estimate()
- Returns:
number of timesteps the solver needs
- run_step(simstep)
Run a single step of the solver. Note: Calling it at step n (‘simstep’ = n) results in it writing to the next step, aka step n+1
- Parameters:
simstep – index of simulation timestep with the last results
- Returns:
None
fonsim.core.system module
Class System
2020, July 22
- class fonsim.core.system.System(label=None)
Bases:
object
A System is a collection of interconnected components. It contains the Component objects and keeps track of how they are connected to each other. A System with components is created by first creating the System object, then adding components to this object and finally connecting these components to each other.
- Parameters:
label – Label of the system, optional and currently not important.
- add(*components)
Add components to the system.
- Parameters:
components – Component object(s) to be added to the system
- Returns:
None
- connect(*args)
Connect two or more components together by connecting their terminals. In case terminals are not specified directly, the Component objects decide on which of their terminals to connect. The connections are made in sequential pairs using the method
System.connect_two_components
which in turn uses the methodself.connect_two_terminals
.The components and/or terminals to connect should be as specified in the method
System.get_component_and_terminal
.For instead connecting all components to a common Node, use the method
System.connect_common
.- Parameters:
args – component terminals
- Returns:
None
- connect_common(*args)
Connect two or more component terminals together. In case terminals are not specified directly, the Component objects decide on which of their terminals to connect. All Terminals are connected to each other, aka to a common Node. Making the connection is handled with the method
self.connect_two_terminals
.The components and/or terminals to connect should be as specified in the method
System.get_component_and_terminal
.For instead making sequential connections, use the method
System.connect
.- Parameters:
args – component terminals
- Returns:
None
- connect_two_components(component_a, component_b)
Connect two Components to each other. The connection is made using the method
self.connect_two_terminals
.The component arguments component_a and component_b can be as specified in the method
System.get_component_and_terminal
.- Parameters:
component_a – First component, see description
component_b – Second component, see description
- Returns:
None
- connect_two_terminals(terminal_a, terminal_b)
Connect two system terminals together in a Node. These nodes exist for the workings of the solver and have nothing to do with any nodes in the fluidic networks being simulated.
- Parameters:
terminal_a – Terminal object
terminal_b – Terminal object
- Returns:
None
- get(component_label)
- Parameters:
component_label – Label of the desired component.
- Returns:
Component object with the given label.
- get_component_and_terminal(arg)
Get a pair of a Component and a Terminal given an argument
arg
. This argument can be:a string specifying a component label present in the system
a Component object
a Terminal object
a Tuple with first the component label and then the terminal label as strings
If multiple choices are available, this method may make an undefined choice.
- Parameters:
arg – see desription
- Returns:
Component object, Terminal object
- get_connectivity_message()
Get a message describing the connectivity of the system in case not every component is connected together.
- Returns:
message string
fonsim.core.terminal module
Class Terminal
2020, July 22
- class fonsim.core.terminal.Terminal(label, variables, variable_labels={})
Bases:
object
Component connection point with local through and across variables.
Note: In any particular Terminal object, there cannot be more than one variable with the same key.
- Parameters:
label – Label to refer to the Terminal later on. Free to choose.
variables – Variable objects that will belong to the Terminal.
- get_variable(key)
Return the variable object attached to the terminal with the provided key, for example ‘pressure’. If there is no variable with the requested key, None is returned.
- Parameters:
key – key of the variable to return
- Return variable:
attached variable with the matching key
- get_variables(orientation=None)
Get list of all terminal variables with the given orientation. The orientation can be either “through” or “across”. If not provided or None, all variables regardless of orientation are returned
- Parameters:
orientation – optional string specifying desired variable orientation
- Returns:
list of Variable objects
fonsim.core.variable module
Class Variable
2020, July 21
- class fonsim.core.variable.Variable(key, orientation, initial_value=0.0, terminal=None, label='None')
Bases:
object
A
Variable
object is used to denote the presence of a yet unknown numerical value. For each Variable object, the solver will search for the optimal numerical values over time. The solver does so by solving the system of equations that connect these variables together. The variables are connected by each other by connecting the Terminal objects that contain the values to each other.The parameter ‘key’ indicates the type label. Only Variable objects with the same type label can exchange information.
The parameter ‘orientation’ should have value ‘across’ or ‘through’ or ‘free’. ‘across’ indicates that the value of the Variable will be shared with the Variable belonging to the other Terminal while ‘through’ indicates that its negative will be shared. The former is typically used with nondirectional values, such as pressure, while the latter is typically used with directional values, such as a massflow. ‘local’ indicates that it will not be shared (feature WIP).
- Parameters:
key – type label, e.g. ‘pressure’, ‘massflow’
orientation – ‘across’, ‘through’ or ‘free’.
initial_value – Initial value, default: 0
terminal – Terminal object to which Variable object get connected, default: None
- copy_and_attach(terminal)
Return a copy of the variable object attached to a given terminal. The returned variable has the same key, orientation and initial value but is otherwise unrelated to the Variable object it is called upon.
- Parameters:
terminal – Terminal object to attach the variable copy to
- Return variable:
attached copy of the variable object
- short_str(nb_var_chars=1)
Return a short string describing the variable more as a symbol than in words. This string contains the first n letters of the variable name as well as (if applicable) the port and component it is attached to.
- Parameters:
nb_var_chars – number of characters with which the variable key is abbreviated. Set to 0 to avoid abbreviation.
- Return var_str:
short string representing the variable
Module contents
2020, September 17