physioblocks 1.0.2__py3-none-any.whl → 1.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- physioblocks/__init__.py +1 -1
- physioblocks/computing/models.py +313 -1
- physioblocks/configuration/constants.py +2 -5
- physioblocks/configuration/simulation/simulations.py +11 -7
- physioblocks/library/blocks/capacitances.py +28 -80
- physioblocks/library/blocks/cavity.py +6 -24
- physioblocks/library/blocks/valves.py +10 -37
- physioblocks/library/model_components/active_law.py +37 -37
- physioblocks/library/model_components/dynamics.py +4 -6
- physioblocks/simulation/runtime.py +1 -35
- physioblocks/simulation/solvers.py +10 -40
- physioblocks/simulation/state.py +67 -4
- physioblocks/utils/gradient_test_utils.py +11 -31
- {physioblocks-1.0.2.dist-info → physioblocks-1.1.0.dist-info}/METADATA +1 -1
- {physioblocks-1.0.2.dist-info → physioblocks-1.1.0.dist-info}/RECORD +18 -18
- {physioblocks-1.0.2.dist-info → physioblocks-1.1.0.dist-info}/WHEEL +0 -0
- {physioblocks-1.0.2.dist-info → physioblocks-1.1.0.dist-info}/licenses/licenses/GPL-3.0-only.txt +0 -0
- {physioblocks-1.0.2.dist-info → physioblocks-1.1.0.dist-info}/licenses/licenses/LGPL-3.0-only.txt +0 -0
physioblocks/__init__.py
CHANGED
physioblocks/computing/models.py
CHANGED
|
@@ -32,6 +32,7 @@ functions.
|
|
|
32
32
|
|
|
33
33
|
from __future__ import annotations
|
|
34
34
|
|
|
35
|
+
import functools
|
|
35
36
|
from collections.abc import Callable
|
|
36
37
|
from dataclasses import dataclass, field
|
|
37
38
|
from inspect import get_annotations
|
|
@@ -46,7 +47,7 @@ SystemFunction: TypeAlias = Callable[..., np.float64 | NDArray[np.float64]]
|
|
|
46
47
|
"""Type alias for functions composing the system"""
|
|
47
48
|
|
|
48
49
|
|
|
49
|
-
@dataclass
|
|
50
|
+
@dataclass
|
|
50
51
|
class Expression:
|
|
51
52
|
"""Expression(size:int, expr_func: SystemFunction, expr_gradients: Mapping[str, SystemFunction] = {})
|
|
52
53
|
Store function computing numerical values for terms in the models with the function
|
|
@@ -102,6 +103,223 @@ class Expression:
|
|
|
102
103
|
)
|
|
103
104
|
|
|
104
105
|
|
|
106
|
+
class ExpressionDecorator:
|
|
107
|
+
"""
|
|
108
|
+
Base class for expression decorators.
|
|
109
|
+
|
|
110
|
+
This is a helper that defines expressions decorating methods in a model or block
|
|
111
|
+
class.
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
expression: Expression
|
|
115
|
+
"""The expression resulting from decorators declarations"""
|
|
116
|
+
|
|
117
|
+
def __init__(
|
|
118
|
+
self,
|
|
119
|
+
wrapped_function: Callable[..., Any],
|
|
120
|
+
):
|
|
121
|
+
"""
|
|
122
|
+
:param wrapped_function: The decorated expression function
|
|
123
|
+
:type wrapped_function: Callable
|
|
124
|
+
"""
|
|
125
|
+
self.expression = Expression(0, wrapped_function)
|
|
126
|
+
self._terms: list[tuple[str, int, int]] = []
|
|
127
|
+
functools.update_wrapper(self, wrapped_function)
|
|
128
|
+
|
|
129
|
+
def register_term(
|
|
130
|
+
self,
|
|
131
|
+
term_name: str,
|
|
132
|
+
term_size: int,
|
|
133
|
+
term_index: int,
|
|
134
|
+
) -> None:
|
|
135
|
+
"""
|
|
136
|
+
Register a new term to the expression decorator
|
|
137
|
+
|
|
138
|
+
:param term_name: the term local name.
|
|
139
|
+
:type term_name: str
|
|
140
|
+
|
|
141
|
+
:param term_size: The size of the term
|
|
142
|
+
:type term_size: int
|
|
143
|
+
|
|
144
|
+
:param term_index: The start index of the term in the expression
|
|
145
|
+
:type term_index: int
|
|
146
|
+
"""
|
|
147
|
+
self.expression.size += term_size
|
|
148
|
+
self._terms.append((term_name, term_size, term_index))
|
|
149
|
+
|
|
150
|
+
@property
|
|
151
|
+
def terms(self) -> list[tuple[str, int, int]]:
|
|
152
|
+
"""
|
|
153
|
+
Get the terms described by the expression.
|
|
154
|
+
|
|
155
|
+
:return: list of terms description
|
|
156
|
+
:rtype: list[[tuple[str, int, int]]]
|
|
157
|
+
"""
|
|
158
|
+
return self._terms.copy()
|
|
159
|
+
|
|
160
|
+
def __call__(self, *args: Any, **kwargs: Any) -> Any:
|
|
161
|
+
return self.expression.expr_func(*args, **kwargs)
|
|
162
|
+
|
|
163
|
+
def partial_derivative(
|
|
164
|
+
self, variable_name: str
|
|
165
|
+
) -> Callable[..., Callable[..., Any]]:
|
|
166
|
+
"""
|
|
167
|
+
Declares a flux partial derivative.
|
|
168
|
+
|
|
169
|
+
:param variable_name: the variable local name.
|
|
170
|
+
:type variable_name: str
|
|
171
|
+
"""
|
|
172
|
+
|
|
173
|
+
def _register(wrapped: Callable[..., Any]) -> Callable[..., Any]:
|
|
174
|
+
self.expression.expr_gradients[variable_name] = wrapped
|
|
175
|
+
return wrapped
|
|
176
|
+
|
|
177
|
+
return _register
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def _check_expression_decorator_type(
|
|
181
|
+
wrapped_function: Any, new_decorator_type: type[ExpressionDecorator]
|
|
182
|
+
) -> None:
|
|
183
|
+
if (
|
|
184
|
+
isinstance(wrapped_function, ExpressionDecorator) is True
|
|
185
|
+
and isinstance(wrapped_function, new_decorator_type) is False
|
|
186
|
+
):
|
|
187
|
+
raise ValueError(
|
|
188
|
+
str.format(
|
|
189
|
+
"Can not decorate a function of an other type. "
|
|
190
|
+
"Current type is {0}, new type is {1}.",
|
|
191
|
+
type(wrapped_function),
|
|
192
|
+
new_decorator_type,
|
|
193
|
+
)
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
class InternalEquationDecorator(ExpressionDecorator):
|
|
198
|
+
"""
|
|
199
|
+
Define a decorator that identifies internal equation expressions.
|
|
200
|
+
"""
|
|
201
|
+
|
|
202
|
+
pass
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def declares_internal_equation(
|
|
206
|
+
variable_name: str, size: int = 1, starting_index: int = 0
|
|
207
|
+
) -> Callable[..., InternalEquationDecorator]:
|
|
208
|
+
"""
|
|
209
|
+
Declares a internal equation expression.
|
|
210
|
+
|
|
211
|
+
Once the internal equation function is declared, partial derivatives can be added
|
|
212
|
+
using the function name and the local variable name for the partial derivative.
|
|
213
|
+
|
|
214
|
+
:param variable_name: the variable name on which the expression provides a dynamic.
|
|
215
|
+
:type variable_name: str
|
|
216
|
+
|
|
217
|
+
:param size: the size of the equation. Default is 1
|
|
218
|
+
:type size: int
|
|
219
|
+
|
|
220
|
+
:param starting_index: the starting index of the equation line matching the
|
|
221
|
+
variable. Default is 0
|
|
222
|
+
:type starting_index: int
|
|
223
|
+
|
|
224
|
+
:raises ValueError: Raises a ValueError if the function is already decorated with
|
|
225
|
+
an expression decorator of an other type.
|
|
226
|
+
|
|
227
|
+
Example
|
|
228
|
+
^^^^^^^
|
|
229
|
+
|
|
230
|
+
.. code:: python
|
|
231
|
+
|
|
232
|
+
@dataclass
|
|
233
|
+
class SimpleModel(ModelComponent):
|
|
234
|
+
|
|
235
|
+
x: Quantity
|
|
236
|
+
a: Quantity
|
|
237
|
+
|
|
238
|
+
@declares_internal_equation("x")
|
|
239
|
+
def residual(self):
|
|
240
|
+
return x.new**2 - a.current
|
|
241
|
+
|
|
242
|
+
@flux_1.partial_derivative("x")
|
|
243
|
+
def dresidual_dx(self):
|
|
244
|
+
return 2.0 * x.new
|
|
245
|
+
"""
|
|
246
|
+
|
|
247
|
+
def _create_internal_equation_decorator(
|
|
248
|
+
wrapped: Callable[..., Any],
|
|
249
|
+
) -> InternalEquationDecorator:
|
|
250
|
+
_check_expression_decorator_type(wrapped, InternalEquationDecorator)
|
|
251
|
+
|
|
252
|
+
decorated = (
|
|
253
|
+
wrapped
|
|
254
|
+
if isinstance(wrapped, InternalEquationDecorator)
|
|
255
|
+
else InternalEquationDecorator(wrapped)
|
|
256
|
+
)
|
|
257
|
+
decorated.register_term(variable_name, size, starting_index)
|
|
258
|
+
return decorated
|
|
259
|
+
|
|
260
|
+
return _create_internal_equation_decorator
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
class SavedQuantityDecorator(ExpressionDecorator):
|
|
264
|
+
"""
|
|
265
|
+
Define a decorator that identifies saved quantities expressions.
|
|
266
|
+
"""
|
|
267
|
+
|
|
268
|
+
pass
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
def declares_saved_quantity(
|
|
272
|
+
quantity_name: str, size: int = 1, starting_index: int = 0
|
|
273
|
+
) -> Callable[..., SavedQuantityDecorator]:
|
|
274
|
+
"""
|
|
275
|
+
Declares a saved quantity expression.
|
|
276
|
+
|
|
277
|
+
:param quantity_name: the local quantity name.
|
|
278
|
+
:type quantity_name: str
|
|
279
|
+
|
|
280
|
+
:param size: the size of the expression. Default is 1
|
|
281
|
+
:type size: int
|
|
282
|
+
|
|
283
|
+
:param starting_index: the starting index of the expression in the function.
|
|
284
|
+
Default is 0
|
|
285
|
+
:type starting_index: int
|
|
286
|
+
|
|
287
|
+
:raises ValueError: Raises a ValueError if the function is already decorated with
|
|
288
|
+
an expression decorator of an other type.
|
|
289
|
+
|
|
290
|
+
Example
|
|
291
|
+
^^^^^^^
|
|
292
|
+
|
|
293
|
+
.. code:: python
|
|
294
|
+
|
|
295
|
+
@dataclass
|
|
296
|
+
class SimpleModel(ModelComponent):
|
|
297
|
+
|
|
298
|
+
a: Quantity
|
|
299
|
+
b: Quantity
|
|
300
|
+
|
|
301
|
+
@declares_saved_quantity("a + b")
|
|
302
|
+
def sum(self):
|
|
303
|
+
return a.current + b.current
|
|
304
|
+
"""
|
|
305
|
+
|
|
306
|
+
def _create_saved_quantity_decorator(
|
|
307
|
+
wrapped: Callable[..., Any],
|
|
308
|
+
) -> SavedQuantityDecorator:
|
|
309
|
+
_check_expression_decorator_type(wrapped, SavedQuantityDecorator)
|
|
310
|
+
|
|
311
|
+
decorator = (
|
|
312
|
+
wrapped
|
|
313
|
+
if isinstance(wrapped, SavedQuantityDecorator)
|
|
314
|
+
else SavedQuantityDecorator(wrapped)
|
|
315
|
+
)
|
|
316
|
+
decorator.register_term(quantity_name, size, starting_index)
|
|
317
|
+
|
|
318
|
+
return decorator
|
|
319
|
+
|
|
320
|
+
return _create_saved_quantity_decorator
|
|
321
|
+
|
|
322
|
+
|
|
105
323
|
@dataclass(frozen=True)
|
|
106
324
|
class TermDefinition:
|
|
107
325
|
"""Describe Terms defined in an :class:`~physioblocks.computing.models.Expression`.
|
|
@@ -303,6 +521,23 @@ class ModelComponentMetaClass(type):
|
|
|
303
521
|
cls.__INTERNAL_EXPRESSION_KEY: [],
|
|
304
522
|
cls.__SAVED_QUANTITIES_EXPRESSION_KEY: [],
|
|
305
523
|
}
|
|
524
|
+
for attr in cls.__dict__.values():
|
|
525
|
+
if isinstance(attr, InternalEquationDecorator):
|
|
526
|
+
for term_name, term_size, term_index in attr.terms:
|
|
527
|
+
cls.declares_internal_expression(
|
|
528
|
+
term_name,
|
|
529
|
+
attr.expression,
|
|
530
|
+
term_size,
|
|
531
|
+
term_index,
|
|
532
|
+
)
|
|
533
|
+
elif isinstance(attr, SavedQuantityDecorator):
|
|
534
|
+
for term_name, term_size, term_index in attr.terms:
|
|
535
|
+
cls.declares_saved_quantity_expression(
|
|
536
|
+
term_name,
|
|
537
|
+
attr.expression,
|
|
538
|
+
term_size,
|
|
539
|
+
term_index,
|
|
540
|
+
)
|
|
306
541
|
|
|
307
542
|
@staticmethod
|
|
308
543
|
def __is_quantity_type(type_to_test: Any) -> bool:
|
|
@@ -481,6 +716,7 @@ class ModelComponentMetaClass(type):
|
|
|
481
716
|
|
|
482
717
|
# Add the term definition to the expression definition
|
|
483
718
|
expression_def.terms.append(TermDefinition(term_id, size, index))
|
|
719
|
+
expression_def.terms.sort(key=lambda term: term.index)
|
|
484
720
|
|
|
485
721
|
def declares_internal_expression(
|
|
486
722
|
cls,
|
|
@@ -690,6 +926,78 @@ class ModelComponent(metaclass=ModelComponentMetaClass):
|
|
|
690
926
|
"""Override this method to define specific for model initialization."""
|
|
691
927
|
|
|
692
928
|
|
|
929
|
+
class FluxDecorator(ExpressionDecorator):
|
|
930
|
+
"""
|
|
931
|
+
Define a decorator that identifies flux functions
|
|
932
|
+
"""
|
|
933
|
+
|
|
934
|
+
pass
|
|
935
|
+
|
|
936
|
+
|
|
937
|
+
def declares_flux(
|
|
938
|
+
index: int, dof_name: str, size: int = 1
|
|
939
|
+
) -> Callable[..., FluxDecorator]:
|
|
940
|
+
"""
|
|
941
|
+
Declares a flux function.
|
|
942
|
+
|
|
943
|
+
Once the flux expression is declared, partial derivatives can be added using the
|
|
944
|
+
flux function name and the local variable name for the partial derivative.
|
|
945
|
+
|
|
946
|
+
:param index: the index of the flux in the block.
|
|
947
|
+
:type index: int
|
|
948
|
+
|
|
949
|
+
:param dof_name: the matching dof local name
|
|
950
|
+
:type dof_name: str
|
|
951
|
+
|
|
952
|
+
:param size: the size of the flux returned by the function
|
|
953
|
+
:type size: int
|
|
954
|
+
|
|
955
|
+
:raises ValueError: Raises a ValueError if the function is already decorated with
|
|
956
|
+
an expression decorator of an other type.
|
|
957
|
+
|
|
958
|
+
|
|
959
|
+
Example
|
|
960
|
+
^^^^^^^
|
|
961
|
+
|
|
962
|
+
.. code:: python
|
|
963
|
+
|
|
964
|
+
@dataclass
|
|
965
|
+
class SimpleBlock(Block):
|
|
966
|
+
|
|
967
|
+
q_1: Quantity
|
|
968
|
+
|
|
969
|
+
# declares a flux shared at local node 1, where the associated dof has the
|
|
970
|
+
# local name "potential_1"
|
|
971
|
+
@declares_flux(1, "potential_1")
|
|
972
|
+
def flux_1(self):
|
|
973
|
+
return q_1.new
|
|
974
|
+
|
|
975
|
+
# associate the following function as the partial derivative of "flux_1" for
|
|
976
|
+
# variable "q_1"
|
|
977
|
+
@flux_1.partial_derivative("q_1")
|
|
978
|
+
def dflux_1_dq_1(self):
|
|
979
|
+
return 1.0
|
|
980
|
+
|
|
981
|
+
"""
|
|
982
|
+
|
|
983
|
+
def _create_flux_decorator(wrapped: Callable[..., Any]) -> FluxDecorator:
|
|
984
|
+
if isinstance(wrapped, ExpressionDecorator) is True:
|
|
985
|
+
raise ValueError(
|
|
986
|
+
str.format(
|
|
987
|
+
"Function already declares an expression, it can not be a flux."
|
|
988
|
+
)
|
|
989
|
+
)
|
|
990
|
+
|
|
991
|
+
decorator = (
|
|
992
|
+
wrapped if isinstance(wrapped, FluxDecorator) else FluxDecorator(wrapped)
|
|
993
|
+
)
|
|
994
|
+
decorator.register_term(dof_name, size, index)
|
|
995
|
+
|
|
996
|
+
return decorator
|
|
997
|
+
|
|
998
|
+
return _create_flux_decorator
|
|
999
|
+
|
|
1000
|
+
|
|
693
1001
|
class BlockMetaClass(ModelComponentMetaClass):
|
|
694
1002
|
"""Meta-class for :class:`~physioblocks.computing.models.Block`.
|
|
695
1003
|
|
|
@@ -711,6 +1019,10 @@ class BlockMetaClass(ModelComponentMetaClass):
|
|
|
711
1019
|
def __init__(cls, *args: Any, **kwargs: Any) -> None:
|
|
712
1020
|
super().__init__(*args, **kwargs)
|
|
713
1021
|
cls._fluxes = {}
|
|
1022
|
+
for attr in cls.__dict__.values():
|
|
1023
|
+
if isinstance(attr, FluxDecorator):
|
|
1024
|
+
for term_name, _term_size, term_index in attr.terms:
|
|
1025
|
+
cls.declares_flux_expression(term_index, term_name, attr.expression)
|
|
714
1026
|
|
|
715
1027
|
def declares_flux_expression(
|
|
716
1028
|
cls, node_index: int, variable_id: str, expr: Expression
|
|
@@ -38,11 +38,8 @@ PARAMETERS_ID = "parameters"
|
|
|
38
38
|
# Definition of the flux-dof types couples
|
|
39
39
|
FLUX_DOF_DEFINITION_ID = "flux_dof_definitions"
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
# The variable magnitude item label in the configuration
|
|
45
|
-
MAGNITUDES = "magnitudes"
|
|
41
|
+
# Options label for specific simulation types
|
|
42
|
+
SIMULATION_OPTIONS = "simulation_options"
|
|
46
43
|
|
|
47
44
|
# The variable magnitude item label in the configuration
|
|
48
45
|
VARIABLES_MAGNITUDES = "variables_magnitudes"
|
|
@@ -35,10 +35,10 @@ from typing import Any
|
|
|
35
35
|
from physioblocks.configuration.base import Configuration, ConfigurationError
|
|
36
36
|
from physioblocks.configuration.constants import (
|
|
37
37
|
INIT_VARIABLES_ID,
|
|
38
|
-
MAGNITUDES,
|
|
39
38
|
NET_ID,
|
|
40
39
|
OUTPUTS_FUNCTIONS_ID,
|
|
41
40
|
PARAMETERS_ID,
|
|
41
|
+
SIMULATION_OPTIONS,
|
|
42
42
|
SOLVER_ID,
|
|
43
43
|
TIME_MANAGER_ID,
|
|
44
44
|
VARIABLES_MAGNITUDES,
|
|
@@ -86,16 +86,15 @@ def load_simulation_config(
|
|
|
86
86
|
if SOLVER_ID in config:
|
|
87
87
|
solver = load(config[SOLVER_ID])
|
|
88
88
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
magnitudes = load(config[VARIABLES_MAGNITUDES])
|
|
89
|
+
simulation_options = None
|
|
90
|
+
if SIMULATION_OPTIONS in config:
|
|
91
|
+
simulation_options = load(config[SIMULATION_OPTIONS])
|
|
93
92
|
|
|
94
93
|
sim_factory = SimulationFactory(
|
|
95
94
|
configuration_type,
|
|
96
95
|
solver,
|
|
97
96
|
net,
|
|
98
|
-
simulation_options=
|
|
97
|
+
simulation_options=simulation_options,
|
|
99
98
|
)
|
|
100
99
|
|
|
101
100
|
configuration_object = sim_factory.create_simulation()
|
|
@@ -147,7 +146,7 @@ def save_simulation_config(
|
|
|
147
146
|
type(variable_init_values).__name__,
|
|
148
147
|
)
|
|
149
148
|
)
|
|
150
|
-
sim_config[VARIABLES_MAGNITUDES] = save(simulation.magnitudes)
|
|
149
|
+
sim_config[VARIABLES_MAGNITUDES] = save(simulation.state.magnitudes)
|
|
151
150
|
|
|
152
151
|
# Parameters
|
|
153
152
|
# Get quantities
|
|
@@ -226,6 +225,11 @@ def _configure_simulation(
|
|
|
226
225
|
configuration_references=simulation.quantities,
|
|
227
226
|
)
|
|
228
227
|
|
|
228
|
+
# magnitudes
|
|
229
|
+
if VARIABLES_MAGNITUDES in config:
|
|
230
|
+
magnitudes = load(config[VARIABLES_MAGNITUDES])
|
|
231
|
+
simulation.state.set_variables_magnitudes(magnitudes)
|
|
232
|
+
|
|
229
233
|
references.update(simulation.quantities)
|
|
230
234
|
references.update(simulation.models)
|
|
231
235
|
|
|
@@ -31,7 +31,12 @@ from typing import Any
|
|
|
31
31
|
|
|
32
32
|
import numpy as np
|
|
33
33
|
|
|
34
|
-
from physioblocks.computing import Block,
|
|
34
|
+
from physioblocks.computing import Block, Quantity, diff, mid_point
|
|
35
|
+
from physioblocks.computing.models import (
|
|
36
|
+
declares_flux,
|
|
37
|
+
declares_internal_equation,
|
|
38
|
+
declares_saved_quantity,
|
|
39
|
+
)
|
|
35
40
|
from physioblocks.registers import register_type
|
|
36
41
|
from physioblocks.simulation import Time
|
|
37
42
|
|
|
@@ -41,8 +46,8 @@ from physioblocks.simulation import Time
|
|
|
41
46
|
# Constant for the c block type id
|
|
42
47
|
C_BLOCK_TYPE_ID = "c_block"
|
|
43
48
|
|
|
44
|
-
# Constant for the c block
|
|
45
|
-
|
|
49
|
+
# Constant for the c block pressure local id
|
|
50
|
+
C_BLOCK_PRESSURE_ID = "pressure"
|
|
46
51
|
|
|
47
52
|
|
|
48
53
|
@register_type(C_BLOCK_TYPE_ID)
|
|
@@ -77,6 +82,7 @@ class CBlock(Block):
|
|
|
77
82
|
time: Time
|
|
78
83
|
"""Simulation time"""
|
|
79
84
|
|
|
85
|
+
@declares_flux(1, C_BLOCK_PRESSURE_ID)
|
|
80
86
|
def flux(self) -> Any:
|
|
81
87
|
"""
|
|
82
88
|
Compute the flux at local node 1
|
|
@@ -86,6 +92,7 @@ class CBlock(Block):
|
|
|
86
92
|
"""
|
|
87
93
|
return -self.capacitance.current * diff(self.pressure) * self.time.inv_dt
|
|
88
94
|
|
|
95
|
+
@flux.partial_derivative(C_BLOCK_PRESSURE_ID)
|
|
89
96
|
def dflux_dpressure(self) -> Any:
|
|
90
97
|
"""
|
|
91
98
|
Compute the flux at local node 1 partial derivative for pressure
|
|
@@ -96,12 +103,6 @@ class CBlock(Block):
|
|
|
96
103
|
return -self.capacitance.current * self.time.inv_dt
|
|
97
104
|
|
|
98
105
|
|
|
99
|
-
_c_block_flux_expression = Expression(
|
|
100
|
-
1, CBlock.flux, {C_BLOCK_PRESSURE_DOF_ID: CBlock.dflux_dpressure}
|
|
101
|
-
)
|
|
102
|
-
CBlock.declares_flux_expression(1, C_BLOCK_PRESSURE_DOF_ID, _c_block_flux_expression)
|
|
103
|
-
|
|
104
|
-
|
|
105
106
|
# RC BLOCK Definition
|
|
106
107
|
|
|
107
108
|
# Constant for the rc block type id
|
|
@@ -164,6 +165,7 @@ class RCBlock(Block):
|
|
|
164
165
|
time: Time
|
|
165
166
|
"""The simulation time"""
|
|
166
167
|
|
|
168
|
+
@declares_flux(1, RC_BLOCK_PRESSURE_1_DOF_ID)
|
|
167
169
|
def flux_1(self) -> Any:
|
|
168
170
|
"""
|
|
169
171
|
Computes the outlet flux at local node 1.
|
|
@@ -175,6 +177,7 @@ class RCBlock(Block):
|
|
|
175
177
|
pressure_2 = mid_point(self.pressure_2)
|
|
176
178
|
return (pressure_2 - pressure_1) / self.resistance.current
|
|
177
179
|
|
|
180
|
+
@flux_1.partial_derivative(RC_BLOCK_PRESSURE_1_DOF_ID)
|
|
178
181
|
def dflux_1_dpressure_1(self) -> Any:
|
|
179
182
|
"""
|
|
180
183
|
Computes the outlet flux at node 1 derivative for pressure_1.
|
|
@@ -184,6 +187,7 @@ class RCBlock(Block):
|
|
|
184
187
|
"""
|
|
185
188
|
return -0.5 / self.resistance.current
|
|
186
189
|
|
|
190
|
+
@flux_1.partial_derivative(RC_BLOCK_PRESSURE_2_DOF_ID)
|
|
187
191
|
def dflux_1_dpressure_2(self) -> Any:
|
|
188
192
|
"""
|
|
189
193
|
Computes the outlet flux at node 1 derivative for pressure_2.
|
|
@@ -193,6 +197,7 @@ class RCBlock(Block):
|
|
|
193
197
|
"""
|
|
194
198
|
return 0.5 / self.resistance.current
|
|
195
199
|
|
|
200
|
+
@declares_flux(2, RC_BLOCK_PRESSURE_2_DOF_ID)
|
|
196
201
|
def flux_2(self) -> Any:
|
|
197
202
|
"""
|
|
198
203
|
Computes the outlet flux at node 2.
|
|
@@ -208,6 +213,7 @@ class RCBlock(Block):
|
|
|
208
213
|
- self.capacitance.current * self.time.inv_dt * dpressure_2
|
|
209
214
|
)
|
|
210
215
|
|
|
216
|
+
@flux_2.partial_derivative(RC_BLOCK_PRESSURE_1_DOF_ID)
|
|
211
217
|
def dflux_2_dpressure_1(self) -> Any:
|
|
212
218
|
"""
|
|
213
219
|
Computes the outlet flux at node 2 derivative for pressure_1.
|
|
@@ -217,6 +223,7 @@ class RCBlock(Block):
|
|
|
217
223
|
"""
|
|
218
224
|
return 0.5 / self.resistance.current
|
|
219
225
|
|
|
226
|
+
@flux_2.partial_derivative(RC_BLOCK_PRESSURE_2_DOF_ID)
|
|
220
227
|
def dflux_2_dpressure_2(self) -> Any:
|
|
221
228
|
"""
|
|
222
229
|
Computes the outlet flux at node 2 derivative for pressure_2.
|
|
@@ -229,29 +236,6 @@ class RCBlock(Block):
|
|
|
229
236
|
)
|
|
230
237
|
|
|
231
238
|
|
|
232
|
-
# Define the flux expression going in the input node for rc_block
|
|
233
|
-
_rc_block_flux_1_expr = Expression(
|
|
234
|
-
1,
|
|
235
|
-
RCBlock.flux_1,
|
|
236
|
-
{
|
|
237
|
-
RC_BLOCK_PRESSURE_1_DOF_ID: RCBlock.dflux_1_dpressure_1,
|
|
238
|
-
RC_BLOCK_PRESSURE_2_DOF_ID: RCBlock.dflux_1_dpressure_2,
|
|
239
|
-
},
|
|
240
|
-
)
|
|
241
|
-
|
|
242
|
-
# Define the flux expression going in the output node for rc_block
|
|
243
|
-
_rc_block_flux_2_expr = Expression(
|
|
244
|
-
1,
|
|
245
|
-
RCBlock.flux_2,
|
|
246
|
-
{
|
|
247
|
-
RC_BLOCK_PRESSURE_1_DOF_ID: RCBlock.dflux_2_dpressure_1,
|
|
248
|
-
RC_BLOCK_PRESSURE_2_DOF_ID: RCBlock.dflux_2_dpressure_2,
|
|
249
|
-
},
|
|
250
|
-
)
|
|
251
|
-
|
|
252
|
-
RCBlock.declares_flux_expression(1, RC_BLOCK_PRESSURE_1_DOF_ID, _rc_block_flux_1_expr)
|
|
253
|
-
RCBlock.declares_flux_expression(2, RC_BLOCK_PRESSURE_2_DOF_ID, _rc_block_flux_2_expr)
|
|
254
|
-
|
|
255
239
|
# RCR BLOCK Definition
|
|
256
240
|
|
|
257
241
|
# Constant for the rcr block type id
|
|
@@ -300,7 +284,7 @@ class RCRBlock(Block):
|
|
|
300
284
|
|
|
301
285
|
\frac{P_1 - P_{mid}}{R_1} + \frac{P_2 - P_{mid}}{R_2} - C\dot{P}_{mid} = 0
|
|
302
286
|
|
|
303
|
-
**
|
|
287
|
+
**Discretization:**
|
|
304
288
|
|
|
305
289
|
.. math::
|
|
306
290
|
|
|
@@ -341,6 +325,7 @@ class RCRBlock(Block):
|
|
|
341
325
|
time: Time
|
|
342
326
|
"""The simulation time"""
|
|
343
327
|
|
|
328
|
+
@declares_flux(1, RCR_BLOCK_PRESSURE_1_ID)
|
|
344
329
|
def flux_1(self) -> Any:
|
|
345
330
|
"""
|
|
346
331
|
Computes the outlet flux at node 1.
|
|
@@ -354,6 +339,7 @@ class RCRBlock(Block):
|
|
|
354
339
|
|
|
355
340
|
return (pressure_mid_discr - pressure_1_discr) / self.resistance_1.current
|
|
356
341
|
|
|
342
|
+
@flux_1.partial_derivative(RCR_BLOCK_PRESSURE_1_ID)
|
|
357
343
|
def dflux_1_dp_1(self) -> Any:
|
|
358
344
|
"""
|
|
359
345
|
Computes the outlet flux at node 1 derivative for pressure_1.
|
|
@@ -364,6 +350,7 @@ class RCRBlock(Block):
|
|
|
364
350
|
|
|
365
351
|
return -0.5 / self.resistance_1.current
|
|
366
352
|
|
|
353
|
+
@flux_1.partial_derivative(RCR_BLOCK_PRESSURE_MID_ID)
|
|
367
354
|
def dflux_1_dp_mid(self) -> Any:
|
|
368
355
|
"""
|
|
369
356
|
Computes the outlet flux at node 1 derivative for pressure_mid.
|
|
@@ -374,6 +361,7 @@ class RCRBlock(Block):
|
|
|
374
361
|
|
|
375
362
|
return 0.5 / self.resistance_1.current
|
|
376
363
|
|
|
364
|
+
@declares_flux(2, RCR_BLOCK_PRESSURE_2_ID)
|
|
377
365
|
def flux_2(self) -> Any:
|
|
378
366
|
"""
|
|
379
367
|
Computes the flux at node 2.
|
|
@@ -386,6 +374,7 @@ class RCRBlock(Block):
|
|
|
386
374
|
|
|
387
375
|
return (pressure_mid_discr - pressure_2_discr) / self.resistance_2.current
|
|
388
376
|
|
|
377
|
+
@flux_2.partial_derivative(RCR_BLOCK_PRESSURE_MID_ID)
|
|
389
378
|
def dflux_2_dp_mid(self) -> Any:
|
|
390
379
|
"""
|
|
391
380
|
Computes the outlet flux at node 2 derivative for pressure_mid.
|
|
@@ -396,6 +385,7 @@ class RCRBlock(Block):
|
|
|
396
385
|
|
|
397
386
|
return 0.5 / self.resistance_2.current
|
|
398
387
|
|
|
388
|
+
@flux_2.partial_derivative(RCR_BLOCK_PRESSURE_2_ID)
|
|
399
389
|
def dflux_2_dp_2(self) -> Any:
|
|
400
390
|
"""
|
|
401
391
|
Computes the outlet flux at node 2 derivative for pressure_2.
|
|
@@ -406,6 +396,7 @@ class RCRBlock(Block):
|
|
|
406
396
|
|
|
407
397
|
return -0.5 / self.resistance_2.current
|
|
408
398
|
|
|
399
|
+
@declares_internal_equation(RCR_BLOCK_PRESSURE_MID_ID)
|
|
409
400
|
def pressure_mid_residual(self) -> Any:
|
|
410
401
|
"""
|
|
411
402
|
Compute the residual representing dynamics of the mid node pressure.
|
|
@@ -424,6 +415,7 @@ class RCRBlock(Block):
|
|
|
424
415
|
- self.capacitance.current * self.time.inv_dt * diff(self.pressure_mid)
|
|
425
416
|
)
|
|
426
417
|
|
|
418
|
+
@pressure_mid_residual.partial_derivative(RCR_BLOCK_PRESSURE_1_ID)
|
|
427
419
|
def pressure_mid_residual_dp_1(self) -> Any:
|
|
428
420
|
"""
|
|
429
421
|
Compute the residual derivative for pressure_1
|
|
@@ -434,6 +426,7 @@ class RCRBlock(Block):
|
|
|
434
426
|
|
|
435
427
|
return 0.5 / self.resistance_1.current
|
|
436
428
|
|
|
429
|
+
@pressure_mid_residual.partial_derivative(RCR_BLOCK_PRESSURE_2_ID)
|
|
437
430
|
def pressure_mid_residual_dp_2(self) -> Any:
|
|
438
431
|
"""
|
|
439
432
|
Compute the residual derivative for pressure_2
|
|
@@ -444,6 +437,7 @@ class RCRBlock(Block):
|
|
|
444
437
|
|
|
445
438
|
return 0.5 / self.resistance_2.current
|
|
446
439
|
|
|
440
|
+
@pressure_mid_residual.partial_derivative(RCR_BLOCK_PRESSURE_MID_ID)
|
|
447
441
|
def pressure_mid_residual_dp_mid(self) -> Any:
|
|
448
442
|
"""
|
|
449
443
|
Compute the residual derivative for pressure_mid
|
|
@@ -458,6 +452,7 @@ class RCRBlock(Block):
|
|
|
458
452
|
- 0.5 / self.resistance_2.current
|
|
459
453
|
)
|
|
460
454
|
|
|
455
|
+
@declares_saved_quantity("volume")
|
|
461
456
|
def compute_volume_stored(self) -> Any:
|
|
462
457
|
"""
|
|
463
458
|
Computes volume stored in the capacitance.
|
|
@@ -467,50 +462,3 @@ class RCRBlock(Block):
|
|
|
467
462
|
"""
|
|
468
463
|
|
|
469
464
|
return self.capacitance.current * self.pressure_mid.current
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
# Define the flux expression going in node 1 for rcr block
|
|
473
|
-
_rcr_block_flux_1_expr = Expression(
|
|
474
|
-
1,
|
|
475
|
-
RCRBlock.flux_1,
|
|
476
|
-
{
|
|
477
|
-
RCR_BLOCK_PRESSURE_1_ID: RCRBlock.dflux_1_dp_1,
|
|
478
|
-
RCR_BLOCK_PRESSURE_MID_ID: RCRBlock.dflux_1_dp_mid,
|
|
479
|
-
},
|
|
480
|
-
)
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
# Define the flux expression going in node 2 for rcr block
|
|
484
|
-
_rcr_block_flux_2_expr = Expression(
|
|
485
|
-
1,
|
|
486
|
-
RCRBlock.flux_2,
|
|
487
|
-
{
|
|
488
|
-
RCR_BLOCK_PRESSURE_MID_ID: RCRBlock.dflux_2_dp_mid,
|
|
489
|
-
RCR_BLOCK_PRESSURE_2_ID: RCRBlock.dflux_2_dp_2,
|
|
490
|
-
},
|
|
491
|
-
)
|
|
492
|
-
|
|
493
|
-
# Define the residual expression giving the pressure at the mid node
|
|
494
|
-
_rcr_block_pressure_mid_residual_expr = Expression(
|
|
495
|
-
1,
|
|
496
|
-
RCRBlock.pressure_mid_residual,
|
|
497
|
-
{
|
|
498
|
-
RCR_BLOCK_PRESSURE_1_ID: RCRBlock.pressure_mid_residual_dp_1,
|
|
499
|
-
RCR_BLOCK_PRESSURE_MID_ID: RCRBlock.pressure_mid_residual_dp_mid,
|
|
500
|
-
RCR_BLOCK_PRESSURE_2_ID: RCRBlock.pressure_mid_residual_dp_2,
|
|
501
|
-
},
|
|
502
|
-
)
|
|
503
|
-
|
|
504
|
-
# Derfine the stored volume saved quantity expression.
|
|
505
|
-
_rcr_volume_stored_expr = Expression(1, RCRBlock.compute_volume_stored)
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
RCRBlock.declares_internal_expression(
|
|
509
|
-
RCR_BLOCK_PRESSURE_MID_ID, _rcr_block_pressure_mid_residual_expr
|
|
510
|
-
)
|
|
511
|
-
|
|
512
|
-
RCRBlock.declares_flux_expression(1, RCR_BLOCK_PRESSURE_1_ID, _rcr_block_flux_1_expr)
|
|
513
|
-
RCRBlock.declares_flux_expression(2, RCR_BLOCK_PRESSURE_2_ID, _rcr_block_flux_2_expr)
|
|
514
|
-
RCRBlock.declares_saved_quantity_expression(
|
|
515
|
-
RCR_BLOCK_VOLUME_OUTPUT_ID, _rcr_volume_stored_expr
|
|
516
|
-
)
|