physioblocks 1.0.3__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 CHANGED
@@ -26,7 +26,7 @@
26
26
 
27
27
  """Physioblocks package definition"""
28
28
 
29
- __version__ = "1.0.3"
29
+ __version__ = "1.1.0"
30
30
  __copyright__ = "INRIA"
31
31
  __license__ = "LGPL-3.0-only"
32
32
  __authors__ = [
@@ -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(frozen=True)
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
@@ -31,7 +31,12 @@ from typing import Any
31
31
 
32
32
  import numpy as np
33
33
 
34
- from physioblocks.computing import Block, Expression, Quantity, diff, mid_point
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 dof id
45
- C_BLOCK_PRESSURE_DOF_ID = "pressure"
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
- **Discretisation:**
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
- )
@@ -33,7 +33,8 @@ from typing import Any
33
33
 
34
34
  import numpy as np
35
35
 
36
- from physioblocks.computing import Block, Expression, Quantity
36
+ from physioblocks.computing import Block, Quantity
37
+ from physioblocks.computing.models import declares_flux
37
38
  from physioblocks.registers import register_type
38
39
  from physioblocks.simulation import Time
39
40
 
@@ -74,7 +75,7 @@ class SphericalCavityBlock(Block):
74
75
 
75
76
  :math:`Q = - \frac {dV(y)}{dt}`
76
77
 
77
- **Discretised:**
78
+ **Discretized:**
78
79
 
79
80
  :math:`Q^{n + \frac{1}{2}} = - \frac {V(y^{n + 1}) - V(y^{n})}{\Delta t^n}`
80
81
 
@@ -135,9 +136,10 @@ class SphericalCavityBlock(Block):
135
136
  3,
136
137
  )
137
138
 
139
+ @declares_flux(1, CAVITY_PRESSURE_LOCAL_ID)
138
140
  def cavity_flux(self) -> Any:
139
141
  """
140
- Compute the ventricule flux at local node 1.
142
+ Compute the cavity flux at local node 1.
141
143
 
142
144
  :return: the flux
143
145
  :rtype: np.float64
@@ -149,6 +151,7 @@ class SphericalCavityBlock(Block):
149
151
 
150
152
  return cavity_flux
151
153
 
154
+ @cavity_flux.partial_derivative(CAVITY_DISP_LOCAL_ID)
152
155
  def dcavity_flux_ddisp(self) -> Any:
153
156
  """
154
157
  Compute the partial derivative of the cavity flux for ``disp``
@@ -169,24 +172,3 @@ class SphericalCavityBlock(Block):
169
172
  )
170
173
  * (1.0 + np.pow(disp_new_ratio, -3) * self.thickness_radius_ratio)
171
174
  )
172
-
173
-
174
- # Define the cavity block flux expression.
175
- _cavity_block_flux_expr = Expression(
176
- 1,
177
- SphericalCavityBlock.cavity_flux,
178
- {CAVITY_DISP_LOCAL_ID: SphericalCavityBlock.dcavity_flux_ddisp},
179
- )
180
-
181
- SphericalCavityBlock.declares_flux_expression(
182
- 1, CAVITY_PRESSURE_LOCAL_ID, _cavity_block_flux_expr
183
- )
184
-
185
-
186
- # Define the cavity block volume of fluid expression.
187
- _cavity_block_fluid_volume_expr = Expression(
188
- 1, SphericalCavityBlock.fluid_volume_current
189
- )
190
- SphericalCavityBlock.declares_saved_quantity_expression(
191
- CAVITY_VOLUME_LOCAL_ID, _cavity_block_fluid_volume_expr
192
- )
@@ -35,12 +35,12 @@ import numpy as np
35
35
 
36
36
  from physioblocks.computing import (
37
37
  Block,
38
- Expression,
39
38
  Quantity,
40
39
  diff,
41
40
  mid_alpha,
42
41
  mid_point,
43
42
  )
43
+ from physioblocks.computing.models import declares_flux, declares_internal_equation
44
44
  from physioblocks.registers import register_type
45
45
  from physioblocks.simulation import Time
46
46
 
@@ -96,7 +96,7 @@ class ValveRLBlock(Block):
96
96
  R_{\text{back}}Q \text{ else }
97
97
  \end{cases} = 0
98
98
 
99
- **Discretisation:**
99
+ **Discretization:**
100
100
 
101
101
 
102
102
  .. math:: Q_1^{{n + \frac{1}{2}}} = - Q^{{n + \frac{1}{2}}}
@@ -145,6 +145,7 @@ class ValveRLBlock(Block):
145
145
  / (self.conductance.current + self.backward_conductance.current)
146
146
  )
147
147
 
148
+ @declares_internal_equation(VALVE_RL_BLOCK_FLUX_VAR_ID)
148
149
  def flux_residual(self) -> Any:
149
150
  """
150
151
  Compute the residual giving the dynamics on the flux in the valve.
@@ -168,6 +169,7 @@ class ValveRLBlock(Block):
168
169
  + q_mid_alpha / conductance
169
170
  )
170
171
 
172
+ @flux_residual.partial_derivative(VALVE_RL_BLOCK_FLUX_VAR_ID)
171
173
  def flux_residual_dflux(self) -> Any:
172
174
  """
173
175
  Compute the residual partial derivative for ``flux``
@@ -187,6 +189,7 @@ class ValveRLBlock(Block):
187
189
  + (0.5 + self.scheme_ts_flux.current) / conductance
188
190
  )
189
191
 
192
+ @flux_residual.partial_derivative(VALVE_RL_BLOCK_PRESSURE_1_DOF_ID)
190
193
  def flux_residual_dp1(self) -> Any:
191
194
  """
192
195
  Compute the residual partial derivative for ``pressure_1``
@@ -197,6 +200,7 @@ class ValveRLBlock(Block):
197
200
 
198
201
  return -0.5
199
202
 
203
+ @flux_residual.partial_derivative(VALVE_RL_BLOCK_PRESSURE_2_DOF_ID)
200
204
  def flux_residual_dp2(self) -> Any:
201
205
  """
202
206
  Compute the residual partial derivative for ``pressure_2``
@@ -207,6 +211,7 @@ class ValveRLBlock(Block):
207
211
 
208
212
  return 0.5
209
213
 
214
+ @declares_flux(1, VALVE_RL_BLOCK_PRESSURE_1_DOF_ID)
210
215
  def flux_1(self) -> Any:
211
216
  """
212
217
  Compute the block flux at node 1
@@ -217,6 +222,7 @@ class ValveRLBlock(Block):
217
222
  """
218
223
  return -mid_point(self.flux)
219
224
 
225
+ @flux_1.partial_derivative(VALVE_RL_BLOCK_FLUX_VAR_ID)
220
226
  def dflux_1_dflux(self) -> Any:
221
227
  """
222
228
  Compute the block flux at node 1 partial derivative for ``flux``
@@ -227,6 +233,7 @@ class ValveRLBlock(Block):
227
233
  """
228
234
  return -0.5
229
235
 
236
+ @declares_flux(2, VALVE_RL_BLOCK_PRESSURE_2_DOF_ID)
230
237
  def flux_2(self) -> Any:
231
238
  """
232
239
  Compute the block flux at node 2
@@ -236,6 +243,7 @@ class ValveRLBlock(Block):
236
243
  """
237
244
  return mid_point(self.flux)
238
245
 
246
+ @flux_2.partial_derivative(VALVE_RL_BLOCK_FLUX_VAR_ID)
239
247
  def dflux_2_dflux(self) -> Any:
240
248
  """
241
249
  Compute the block flux at node 2 partial derivative for ``flux``
@@ -244,38 +252,3 @@ class ValveRLBlock(Block):
244
252
  :rtype: np.float64
245
253
  """
246
254
  return 0.5
247
-
248
-
249
- # define the Valve RL internal variable residual expression
250
- # giving the dynamics on the flux in the valve
251
- _valve_rl_flux_residual_expr = Expression(
252
- 1,
253
- ValveRLBlock.flux_residual,
254
- {
255
- VALVE_RL_BLOCK_FLUX_VAR_ID: ValveRLBlock.flux_residual_dflux,
256
- VALVE_RL_BLOCK_PRESSURE_1_DOF_ID: ValveRLBlock.flux_residual_dp1,
257
- VALVE_RL_BLOCK_PRESSURE_2_DOF_ID: ValveRLBlock.flux_residual_dp2,
258
- },
259
- )
260
-
261
- # define the ValveRL flux expression at node 1.
262
- _valve_rl_flux_1_expr = Expression(
263
- 1, ValveRLBlock.flux_1, {VALVE_RL_BLOCK_FLUX_VAR_ID: ValveRLBlock.dflux_1_dflux}
264
- )
265
-
266
- # define the ValveRL flux expression at node 2.
267
- _valve_rl_flux_2_expr = Expression(
268
- 1,
269
- ValveRLBlock.flux_2,
270
- {VALVE_RL_BLOCK_FLUX_VAR_ID: ValveRLBlock.dflux_2_dflux},
271
- )
272
-
273
- ValveRLBlock.declares_internal_expression(
274
- VALVE_RL_BLOCK_FLUX_VAR_ID, _valve_rl_flux_residual_expr
275
- )
276
- ValveRLBlock.declares_flux_expression(
277
- 1, VALVE_RL_BLOCK_PRESSURE_1_DOF_ID, _valve_rl_flux_1_expr
278
- )
279
- ValveRLBlock.declares_flux_expression(
280
- 2, VALVE_RL_BLOCK_PRESSURE_2_DOF_ID, _valve_rl_flux_2_expr
281
- )
@@ -31,24 +31,36 @@ import numpy as np
31
31
  from numpy.typing import NDArray
32
32
 
33
33
  from physioblocks.computing import (
34
- Expression,
35
34
  ModelComponent,
36
35
  Quantity,
37
36
  diff,
38
37
  mid_point,
39
38
  )
39
+ from physioblocks.computing.models import declares_internal_equation
40
40
  from physioblocks.registers import register_type
41
41
  from physioblocks.simulation import Time
42
42
 
43
43
  # Constant for the active law type id
44
44
  ACTIVE_LAW_MACRO_HUXLEY_TWO_MOMENTS_TYPE_ID = "active_law_macro_huxley_two_moments"
45
45
 
46
+ # Constant for the active stiffness local id
47
+ ACTIVE_LAW_MACRO_HUXLEY_TWO_MOMENTS_ACTIVE_STIFFNESS = "active_stiffness"
48
+
49
+ # Constant for the active energy sqrt local id
50
+ ACTIVE_LAW_MACRO_HUXLEY_TWO_MOMENTS_ACTIVE_ENERGY_SQRT = "active_energy_sqrt"
51
+
52
+ # Constant for the active tension discretization local id
53
+ ACTIVE_LAW_MACRO_HUXLEY_TWO_MOMENTS_ACTIVE_TENSION_DISCR = "active_tension_discr"
54
+
55
+ # Constant for the fiber deformation local id
56
+ ACTIVE_LAW_MACRO_HUXLEY_TWO_MOMENTS_FIB_DEFORM = "fib_deform"
57
+
46
58
 
47
59
  @register_type(ACTIVE_LAW_MACRO_HUXLEY_TWO_MOMENTS_TYPE_ID)
48
60
  @dataclass
49
61
  class ActiveLawMacroscopicHuxleyTwoMoment(ModelComponent):
50
62
  r"""
51
- Describes the Macroscopic Huxley Two Moment implementation of the ative law.
63
+ Describes the Macroscopic Huxley Two Moment implementation of the active law.
52
64
 
53
65
  **Internal Equations:**
54
66
 
@@ -65,7 +77,7 @@ class ActiveLawMacroscopicHuxleyTwoMoment(ModelComponent):
65
77
 
66
78
  \lambda_c - T_c/\sqrt{K_c} = 0
67
79
 
68
- **Discretised:**
80
+ **Discretized:**
69
81
 
70
82
  .. math::
71
83
 
@@ -90,7 +102,7 @@ class ActiveLawMacroscopicHuxleyTwoMoment(ModelComponent):
90
102
  """:math:`\\lambda_c` the active energy sqrt"""
91
103
 
92
104
  active_tension_discr: Quantity[np.float64]
93
- """:math:`T_c^{n + \\frac{1}{2}\\sharp}` the active tension discretisation"""
105
+ """:math:`T_c^{n + \\frac{1}{2}\\sharp}` the active tension discretization"""
94
106
 
95
107
  starling_abscissas: Quantity[NDArray[np.float64]]
96
108
  """Abscissas of :math:`n_0` the discretized starling function"""
@@ -113,6 +125,15 @@ class ActiveLawMacroscopicHuxleyTwoMoment(ModelComponent):
113
125
  time: Time
114
126
  """:math:`t` the simulation time"""
115
127
 
128
+ @declares_internal_equation(
129
+ ACTIVE_LAW_MACRO_HUXLEY_TWO_MOMENTS_ACTIVE_STIFFNESS, 1, 0
130
+ )
131
+ @declares_internal_equation(
132
+ ACTIVE_LAW_MACRO_HUXLEY_TWO_MOMENTS_ACTIVE_ENERGY_SQRT, 1, 1
133
+ )
134
+ @declares_internal_equation(
135
+ ACTIVE_LAW_MACRO_HUXLEY_TWO_MOMENTS_ACTIVE_TENSION_DISCR, 1, 2
136
+ )
116
137
  def active_law_residual(self) -> Any:
117
138
  """
118
139
  Compute the residual of the active law.
@@ -166,6 +187,9 @@ class ActiveLawMacroscopicHuxleyTwoMoment(ModelComponent):
166
187
  ],
167
188
  )
168
189
 
190
+ @active_law_residual.partial_derivative(
191
+ ACTIVE_LAW_MACRO_HUXLEY_TWO_MOMENTS_ACTIVE_STIFFNESS
192
+ )
169
193
  def active_law_residual_dactive_stiffness(self) -> Any:
170
194
  """
171
195
  Compute the residual partial derivative for the active stiffness
@@ -219,6 +243,9 @@ class ActiveLawMacroscopicHuxleyTwoMoment(ModelComponent):
219
243
  ],
220
244
  )
221
245
 
246
+ @active_law_residual.partial_derivative(
247
+ ACTIVE_LAW_MACRO_HUXLEY_TWO_MOMENTS_ACTIVE_ENERGY_SQRT
248
+ )
222
249
  def active_law_residual_dactive_energy_sqrt(self) -> Any:
223
250
  """
224
251
  Compute the residual partial derivative for the active energy sqrt
@@ -264,6 +291,9 @@ class ActiveLawMacroscopicHuxleyTwoMoment(ModelComponent):
264
291
  ],
265
292
  )
266
293
 
294
+ @active_law_residual.partial_derivative(
295
+ ACTIVE_LAW_MACRO_HUXLEY_TWO_MOMENTS_FIB_DEFORM
296
+ )
267
297
  def active_law_residual_dfib_deform(self) -> Any:
268
298
  """
269
299
  Compute the residual partial derivative for the fiber deformation
@@ -293,6 +323,9 @@ class ActiveLawMacroscopicHuxleyTwoMoment(ModelComponent):
293
323
  ],
294
324
  )
295
325
 
326
+ @active_law_residual.partial_derivative(
327
+ ACTIVE_LAW_MACRO_HUXLEY_TWO_MOMENTS_ACTIVE_TENSION_DISCR
328
+ )
296
329
  def active_law_residual_dactive_tension(self) -> Any:
297
330
  """
298
331
  Compute the residual partial derivative for the active tension
@@ -310,36 +343,3 @@ class ActiveLawMacroscopicHuxleyTwoMoment(ModelComponent):
310
343
  * np.fabs(diff(self.fib_deform))
311
344
  * self.time.inv_dt
312
345
  )
313
-
314
-
315
- # Define the expression for the residual of the ActiveLawMacroscopicHuxleyTwoMoment and
316
- # its partial derivatives.
317
- _active_law_macroscopic_huxley_two_moment_residual_expression = Expression(
318
- 3,
319
- ActiveLawMacroscopicHuxleyTwoMoment.active_law_residual,
320
- {
321
- "active_stiffness": ActiveLawMacroscopicHuxleyTwoMoment.active_law_residual_dactive_stiffness, # noqa: E501
322
- "active_energy_sqrt": ActiveLawMacroscopicHuxleyTwoMoment.active_law_residual_dactive_energy_sqrt, # noqa: E501
323
- "active_tension_discr": ActiveLawMacroscopicHuxleyTwoMoment.active_law_residual_dactive_tension, # noqa: E501
324
- "fib_deform": ActiveLawMacroscopicHuxleyTwoMoment.active_law_residual_dfib_deform, # noqa: E501
325
- },
326
- )
327
-
328
- ActiveLawMacroscopicHuxleyTwoMoment.declares_internal_expression(
329
- "active_stiffness",
330
- _active_law_macroscopic_huxley_two_moment_residual_expression,
331
- 1,
332
- 0,
333
- )
334
- ActiveLawMacroscopicHuxleyTwoMoment.declares_internal_expression(
335
- "active_energy_sqrt",
336
- _active_law_macroscopic_huxley_two_moment_residual_expression,
337
- 1,
338
- 1,
339
- )
340
- ActiveLawMacroscopicHuxleyTwoMoment.declares_internal_expression(
341
- "active_tension_discr",
342
- _active_law_macroscopic_huxley_two_moment_residual_expression,
343
- 1,
344
- 2,
345
- )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: physioblocks
3
- Version: 1.0.3
3
+ Version: 1.1.0
4
4
  Dynamic: Author
5
5
  Dynamic: Author-email
6
6
  Dynamic: License
@@ -1,10 +1,10 @@
1
- physioblocks/__init__.py,sha256=cISNrgJhzM89OfbdFh9adOQcp0TvpiqizNJtm-sBWEE,1169
1
+ physioblocks/__init__.py,sha256=NGE_lMcYMiJkOlsYXaUITBFVAdwOmguluAly7DLiZ2k,1169
2
2
  physioblocks/base/__init__.py,sha256=2h6bk0fe8pwQvJ15Buytg4SZzYOH-Ep7WqoD6pd1eOQ,986
3
3
  physioblocks/base/operators.py,sha256=uUfswQZsaMNd2bd7wsaxSGFIYLAr1hQCQ6SQfYawdBc,5689
4
4
  physioblocks/base/registers.py,sha256=Cd0hmy1XqojjPQgb_jn4mGeAMTyWWgDkl3qJHCVjCRU,3119
5
5
  physioblocks/computing/__init__.py,sha256=rLjuzRCA0nVAnHcYsL0jhn2KQpl6MnC3DJLf3a0i6uw,1302
6
6
  physioblocks/computing/assembling.py,sha256=2pKNA85PWJJ4fwSPRi7IitMdjlYTTiWQIgnKyhHja-8,9308
7
- physioblocks/computing/models.py,sha256=2V5Xbsoy3jK_OcubTKxmTUa7nKBag0x-T4Zivcul7So,24489
7
+ physioblocks/computing/models.py,sha256=3CbSsbvEvHg4dgHFF-I7UZSY3O9tg_SxYJcKjAAQdJs,33556
8
8
  physioblocks/computing/quantities.py,sha256=f2wU0VDylJ8nuUtOsV0FsA1mJnqNy1AvoK6-w04Fctc,8934
9
9
  physioblocks/configuration/__init__.py,sha256=XNeIev97Fc9DAy_mA3CAZ0kMif7Nkop9sCI38ZZ2wgM,1454
10
10
  physioblocks/configuration/aliases.py,sha256=o7E54IYeW0NfmCX_r3zLKURVHsQoCmTlLD5085kY0eg,6302
@@ -51,9 +51,9 @@ physioblocks/library/aliases/simulations/newton_method_solver.json,sha256=p0jgVC
51
51
  physioblocks/library/aliases/simulations/spherical_heart_forward_simulation.jsonc,sha256=CXG5m8lRftbqYUchDedA_ggO81v1M0qiqyshRCMOl4E,5664
52
52
  physioblocks/library/aliases/simulations/spherical_heart_with_respiration_forward_simulation.jsonc,sha256=kCy065DN5Cau3d7ouuzdDAaLevBuzlnZkWtROG3DgtY,1542
53
53
  physioblocks/library/blocks/__init__.py,sha256=EhnoyZYTooSd_cTfysnT-YR6Ylrn15dJsfWwALFV00I,991
54
- physioblocks/library/blocks/capacitances.py,sha256=-coa-Zb4rVHwZVM2ip3iAHKURlQ9Mzw4Q34eCc-DHKc,14175
55
- physioblocks/library/blocks/cavity.py,sha256=JODm84TYz0Zuji3QXHb-bhQZlM_QZh6lTluf_8c0GL8,6064
56
- physioblocks/library/blocks/valves.py,sha256=jMo5ZaBIONaiG-e2y-5zRnayOq7YhsG44zL6mn900Ag,7747
54
+ physioblocks/library/blocks/capacitances.py,sha256=fMd-UXv4b4ggfOn1qjPj0xxR7q4Dk4-N7NKdIS_aVjc,13011
55
+ physioblocks/library/blocks/cavity.py,sha256=SgiBs4xeuIC1pXj_ZffEleA1Aw8AAvFdMKkf_I4IkCI,5632
56
+ physioblocks/library/blocks/valves.py,sha256=S-5uZ2jRE7r7zc24Lpl2ryNutH3OxPOHHI3AlDUpkgQ,7223
57
57
  physioblocks/library/functions/__init__.py,sha256=k9cFPqrsApbeSkcnu-FbhonilTTeJS0Cp5EJCrfPeII,988
58
58
  physioblocks/library/functions/base_operations.py,sha256=TpN7rabrX9Nojd2uu90j1Dw_7OpdjbBSuiM_HWzJH3M,3507
59
59
  physioblocks/library/functions/first_order.py,sha256=oSkFyECA7ywgQCYKt-sEZmSu84QrRere_Ee736vk2Ik,3687
@@ -61,7 +61,7 @@ physioblocks/library/functions/piecewise.py,sha256=xpR22eP0Jkfuskc737uttenbpOOMX
61
61
  physioblocks/library/functions/trigonometric.py,sha256=Y5UolXZTASEi4EH_GpLpUIxMZbXIVHc-THFEXg9vrtg,2126
62
62
  physioblocks/library/functions/watchers.py,sha256=fY1SSPn-7R9cix0VMFP69H5-pmJzl4OXs1tgvjCetvM,3212
63
63
  physioblocks/library/model_components/__init__.py,sha256=JcDL2PaPTrT9mTlDUbPjUsyFfsiGh5GgroJ7J3g2uwE,998
64
- physioblocks/library/model_components/active_law.py,sha256=97D3fC7Dmzw8jLqDALxUJgl48EZYOx39SYjZgGJx-Eo,11634
64
+ physioblocks/library/model_components/active_law.py,sha256=EWVG6C13VxUydUKebDUqeKtEra0mbFwU0wfgIAEURmw,11692
65
65
  physioblocks/library/model_components/dynamics.py,sha256=T-ZmfhTgtr1Tj6434GDYU-5XSztHx-dd6sf228c4cyo,35198
66
66
  physioblocks/library/model_components/rheology.py,sha256=7x5RrB_0DXMWlm0mIrTxdLlsjXVa1WPuFYYifW4fKeg,4724
67
67
  physioblocks/library/model_components/velocity_law.py,sha256=UYr9MywlLkRw0LszK0u_AamwThjobDMV9jYbaSbdDkU,5047
@@ -86,8 +86,8 @@ physioblocks/utils/math_utils.py,sha256=w5MDs4cP5WiTPHe8WofFuNZZ20WDNLT0XmFGlbis
86
86
  physioblocks/references/circulation_alone_sim.jsonc,sha256=qv27nzmK7jennhtCJ7wQ_f83mt9_YJSOTABjGCYMcZw,736
87
87
  physioblocks/references/spherical_heart_respiration_sim.jsonc,sha256=kKq5xf94r90O1KpkCHk1qwgy6DJ37ePo3-8buEtcu5Y,1397
88
88
  physioblocks/references/spherical_heart_sim.jsonc,sha256=kGGBqxY8dnmGKmpMv216kbneyJRGz_3VkcYn1OWavIA,1151
89
- physioblocks-1.0.3.dist-info/METADATA,sha256=-_Pm7SVFyAzY4eHI79u3CGR93C-Yo5iWGwUJzDtM6gM,4708
90
- physioblocks-1.0.3.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
91
- physioblocks-1.0.3.dist-info/licenses/licenses/GPL-3.0-only.txt,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
92
- physioblocks-1.0.3.dist-info/licenses/licenses/LGPL-3.0-only.txt,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
93
- physioblocks-1.0.3.dist-info/RECORD,,
89
+ physioblocks-1.1.0.dist-info/METADATA,sha256=d7JWdSGdkgL7dx9ExTNXLqB0O1LkIQ-qLpKeGoeHilU,4708
90
+ physioblocks-1.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
91
+ physioblocks-1.1.0.dist-info/licenses/licenses/GPL-3.0-only.txt,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
92
+ physioblocks-1.1.0.dist-info/licenses/licenses/LGPL-3.0-only.txt,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
93
+ physioblocks-1.1.0.dist-info/RECORD,,