simcardemsx 0.1.0__tar.gz

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.
Files changed (65) hide show
  1. simcardemsx-0.1.0/LICENSE +7 -0
  2. simcardemsx-0.1.0/PKG-INFO +213 -0
  3. simcardemsx-0.1.0/README.md +148 -0
  4. simcardemsx-0.1.0/pyproject.toml +236 -0
  5. simcardemsx-0.1.0/setup.cfg +4 -0
  6. simcardemsx-0.1.0/src/simcardemsx/__init__.py +18 -0
  7. simcardemsx-0.1.0/src/simcardemsx/averaging.py +112 -0
  8. simcardemsx-0.1.0/src/simcardemsx/backends/__init__.py +37 -0
  9. simcardemsx-0.1.0/src/simcardemsx/backends/base.py +120 -0
  10. simcardemsx-0.1.0/src/simcardemsx/backends/generated.py +660 -0
  11. simcardemsx-0.1.0/src/simcardemsx/backends/segregated.py +565 -0
  12. simcardemsx-0.1.0/src/simcardemsx/backends/zeta_split.py +415 -0
  13. simcardemsx-0.1.0/src/simcardemsx/checkpoint.py +727 -0
  14. simcardemsx-0.1.0/src/simcardemsx/config.py +43 -0
  15. simcardemsx-0.1.0/src/simcardemsx/controller.py +323 -0
  16. simcardemsx-0.1.0/src/simcardemsx/datacollector.py +503 -0
  17. simcardemsx-0.1.0/src/simcardemsx/interpolation.py +41 -0
  18. simcardemsx-0.1.0/src/simcardemsx/mechanics.py +219 -0
  19. simcardemsx-0.1.0/src/simcardemsx/ode_model.py +137 -0
  20. simcardemsx-0.1.0/src/simcardemsx/provenance.py +68 -0
  21. simcardemsx-0.1.0/src/simcardemsx/py.typed +0 -0
  22. simcardemsx-0.1.0/src/simcardemsx/results.py +324 -0
  23. simcardemsx-0.1.0/src/simcardemsx/transfer_plan.py +362 -0
  24. simcardemsx-0.1.0/src/simcardemsx/units.py +101 -0
  25. simcardemsx-0.1.0/src/simcardemsx/utils.py +12 -0
  26. simcardemsx-0.1.0/src/simcardemsx/zero_d.py +294 -0
  27. simcardemsx-0.1.0/src/simcardemsx.egg-info/PKG-INFO +213 -0
  28. simcardemsx-0.1.0/src/simcardemsx.egg-info/SOURCES.txt +63 -0
  29. simcardemsx-0.1.0/src/simcardemsx.egg-info/dependency_links.txt +1 -0
  30. simcardemsx-0.1.0/src/simcardemsx.egg-info/requires.txt +51 -0
  31. simcardemsx-0.1.0/src/simcardemsx.egg-info/top_level.txt +1 -0
  32. simcardemsx-0.1.0/tests/test_averaging.py +151 -0
  33. simcardemsx-0.1.0/tests/test_backends.py +363 -0
  34. simcardemsx-0.1.0/tests/test_biv_example.py +187 -0
  35. simcardemsx-0.1.0/tests/test_checkpoint.py +577 -0
  36. simcardemsx-0.1.0/tests/test_checkpoint_backends.py +268 -0
  37. simcardemsx-0.1.0/tests/test_checkpoint_circulation.py +200 -0
  38. simcardemsx-0.1.0/tests/test_circulation.py +290 -0
  39. simcardemsx-0.1.0/tests/test_coupled_backend.py +223 -0
  40. simcardemsx-0.1.0/tests/test_coupled_system.py +107 -0
  41. simcardemsx-0.1.0/tests/test_crossbridge_coupling.py +345 -0
  42. simcardemsx-0.1.0/tests/test_cycle_coupling.py +248 -0
  43. simcardemsx-0.1.0/tests/test_datacollector.py +111 -0
  44. simcardemsx-0.1.0/tests/test_demo_io.py +171 -0
  45. simcardemsx-0.1.0/tests/test_dynamic_coupling.py +127 -0
  46. simcardemsx-0.1.0/tests/test_generated_activation.py +836 -0
  47. simcardemsx-0.1.0/tests/test_interpolation.py +69 -0
  48. simcardemsx-0.1.0/tests/test_isolated_ep.py +77 -0
  49. simcardemsx-0.1.0/tests/test_isolated_mechanics.py +198 -0
  50. simcardemsx-0.1.0/tests/test_mechanics_drivers.py +112 -0
  51. simcardemsx-0.1.0/tests/test_monolithic_coupling.py +140 -0
  52. simcardemsx-0.1.0/tests/test_ode_model.py +216 -0
  53. simcardemsx-0.1.0/tests/test_provenance.py +65 -0
  54. simcardemsx-0.1.0/tests/test_results.py +225 -0
  55. simcardemsx-0.1.0/tests/test_rodero_case.py +161 -0
  56. simcardemsx-0.1.0/tests/test_rodero_example.py +419 -0
  57. simcardemsx-0.1.0/tests/test_rollback.py +492 -0
  58. simcardemsx-0.1.0/tests/test_round_trip.py +106 -0
  59. simcardemsx-0.1.0/tests/test_scheme_comparison.py +589 -0
  60. simcardemsx-0.1.0/tests/test_scheme_report.py +557 -0
  61. simcardemsx-0.1.0/tests/test_segregated_backend.py +816 -0
  62. simcardemsx-0.1.0/tests/test_slab_example.py +478 -0
  63. simcardemsx-0.1.0/tests/test_stability.py +148 -0
  64. simcardemsx-0.1.0/tests/test_transfer_plan.py +155 -0
  65. simcardemsx-0.1.0/tests/test_zero_d_coupling.py +180 -0
@@ -0,0 +1,7 @@
1
+ Copyright 2025 Simula Research Laboratory and Henrik Finsberg
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,213 @@
1
+ Metadata-Version: 2.4
2
+ Name: simcardemsx
3
+ Version: 0.1.0
4
+ Summary: Next generation cardiac electro-mechanics solver based on FEniCSx
5
+ Author-email: Henrik Finsberg <henriknf@simula.no>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://computationalphysiology.github.io/simcardemsx
8
+ Project-URL: Documentation, https://computationalphysiology.github.io/simcardemsx
9
+ Project-URL: Source, https://github.com/ComputationalPhysiology/simcardemsx
10
+ Project-URL: Issues, https://github.com/ComputationalPhysiology/simcardemsx/issues
11
+ Keywords: cardiac,electromechanics,finite element,fenicsx,electrophysiology
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: Topic :: Scientific/Engineering :: Physics
15
+ Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
16
+ Requires-Python: >=3.12.0
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Requires-Dist: fenics-dolfinx
20
+ Requires-Dist: fenicsx-pulse>=0.11.1
21
+ Requires-Dist: fenicsx-beat>=0.9.0
22
+ Requires-Dist: crossbridge>=0.3.4
23
+ Requires-Dist: io4dolfinx
24
+ Requires-Dist: scipy
25
+ Requires-Dist: gotranx>=2.2.0
26
+ Requires-Dist: toml
27
+ Requires-Dist: pydantic
28
+ Requires-Dist: pydantic_pint
29
+ Provides-Extra: test
30
+ Requires-Dist: pytest; extra == "test"
31
+ Requires-Dist: pytest-cov; extra == "test"
32
+ Requires-Dist: cardiac-geometriesx; extra == "test"
33
+ Requires-Dist: circulation>=0.4.0; extra == "test"
34
+ Provides-Extra: dev
35
+ Requires-Dist: pdbpp; extra == "dev"
36
+ Requires-Dist: ipython; extra == "dev"
37
+ Requires-Dist: bump2version; extra == "dev"
38
+ Requires-Dist: mypy; extra == "dev"
39
+ Requires-Dist: types-toml; extra == "dev"
40
+ Requires-Dist: pre-commit; extra == "dev"
41
+ Provides-Extra: demo
42
+ Requires-Dist: matplotlib; extra == "demo"
43
+ Requires-Dist: cardiac-geometriesx; extra == "demo"
44
+ Requires-Dist: fenicsx-ldrb; extra == "demo"
45
+ Requires-Dist: ukb-atlas; extra == "demo"
46
+ Requires-Dist: circulation>=0.4.0; extra == "demo"
47
+ Requires-Dist: gotranx; extra == "demo"
48
+ Requires-Dist: io4dolfinx; extra == "demo"
49
+ Provides-Extra: docs
50
+ Requires-Dist: mystmd; extra == "docs"
51
+ Requires-Dist: jupytext; extra == "docs"
52
+ Requires-Dist: ipykernel; extra == "docs"
53
+ Requires-Dist: jupyter-server; extra == "docs"
54
+ Requires-Dist: griffe>=2; extra == "docs"
55
+ Requires-Dist: simcardemsx[demo]; extra == "docs"
56
+ Provides-Extra: benchmark
57
+ Requires-Dist: pytest-codspeed; extra == "benchmark"
58
+ Requires-Dist: simcardemsx[test]; extra == "benchmark"
59
+ Provides-Extra: all
60
+ Requires-Dist: simcardemsx[test]; extra == "all"
61
+ Requires-Dist: simcardemsx[docs]; extra == "all"
62
+ Requires-Dist: simcardemsx[dev]; extra == "all"
63
+ Requires-Dist: simcardemsx[demo]; extra == "all"
64
+ Dynamic: license-file
65
+
66
+ # simcardemsx
67
+
68
+ Cardiac electro-mechanics in [FEniCSx](https://fenicsproject.org).
69
+
70
+ simcardemsx couples a model of cardiac electrophysiology (EP) to a model of tissue
71
+ mechanics, with the contraction of each cell in between. It does not solve either
72
+ physics itself. It connects two solvers that do:
73
+
74
+ - [fenicsx-beat](https://github.com/finsberg/fenicsx-beat) for EP (the monodomain
75
+ model);
76
+ - [fenicsx-pulse](https://github.com/finsberg/fenicsx-pulse) for the mechanics, from a
77
+ single element to a beating heart in a circulation model.
78
+
79
+ The cell model, EP and contraction alike, is a single
80
+ [gotranx](https://github.com/finsberg/gotranx) `.ode` file. simcardemsx splits it in two
81
+ and generates code for each half. The EP half is NumPy code for beat. The contraction
82
+ half is UFL, which the mechanics solver can differentiate through, so the contraction
83
+ model can be stepped *inside* the mechanics Newton iteration. That removes the
84
+ instability the usual staggered coupling suffers from when the tissue is soft
85
+ (Regazzoni & Quarteroni, 2021). Models that cannot be written in UFL, such as the NumPy
86
+ models of [crossbridge](https://github.com/ComputationalPhysiology/crossbridge), are
87
+ coupled with the stabilized scheme of the same paper instead.
88
+
89
+ 📖 **Documentation**: <https://computationalphysiology.github.io/simcardemsx>
90
+
91
+ ## Features
92
+
93
+ - One `.ode` file for the whole cell, split anywhere between EP and contraction.
94
+ Which variables cross between the two sides is read off the generated code, not
95
+ configured by hand.
96
+ - Separate meshes and time steps for EP and mechanics.
97
+ - Three coupling schemes: monolithic (the default), stabilized segregated, and the
98
+ naive segregated scheme for comparison.
99
+ - Static and dynamic mechanics, closed-loop circulation (Regazzoni's 0D circuit) and
100
+ open-loop cardiac cycles, through pulse.
101
+ - Rollback of a failed time step, and checkpoints that a run continues from in a new
102
+ process (bit for bit under pulse's default direct solver).
103
+
104
+ ## Installation
105
+
106
+ simcardemsx needs [DOLFINx](https://github.com/FEniCS/dolfinx), which is not
107
+ installable from PyPI on its own. The simplest way to get it is the DOLFINx container:
108
+
109
+ ```bash
110
+ docker run -ti -v $(pwd):/home/shared -w /home/shared ghcr.io/fenics/dolfinx/dolfinx:stable
111
+ ```
112
+
113
+ Inside it, install simcardemsx with pip:
114
+
115
+ ```bash
116
+ python3 -m pip install simcardemsx
117
+ ```
118
+
119
+ or from source, with the dependencies of the examples:
120
+
121
+ ```bash
122
+ git clone https://github.com/ComputationalPhysiology/simcardemsx.git
123
+ cd simcardemsx
124
+ python3 -m pip install -e ".[demo]"
125
+ ```
126
+
127
+ The extras are `demo` (the examples), `test`, `docs` and `dev`.
128
+
129
+ ## A first look
130
+
131
+ Generate the two halves of a cell model and see what crosses between them:
132
+
133
+ ```python
134
+ from pathlib import Path
135
+
136
+ from simcardemsx.ode_model import load_ode_modules
137
+
138
+ odefile = Path("examples/odefiles/ToRORd_dynCl_endo_zetasplit.ode")
139
+ modules = load_ode_modules(odefile, Path("generated_odes"))
140
+
141
+ print(modules.mechanics.missing) # what contraction needs from EP: {'XS': 0, 'XW': 1}
142
+ print(modules.ep.missing) # what EP needs back: {'Zetas': 0, 'Zetaw': 1}
143
+ ```
144
+
145
+ The contraction half becomes the active stress of a pulse model:
146
+
147
+ ```python
148
+ from simcardemsx.backends import GeneratedActivation
149
+
150
+ backend = GeneratedActivation(modules.mechanics, mesh, f0, quadrature_degree=4)
151
+ model = pulse.CardiacModel(material=material, active=backend, compressibility=compressibility)
152
+ ```
153
+
154
+ and `SimulationController` steps EP and mechanics together:
155
+
156
+ ```python
157
+ from simcardemsx.controller import SimulationController
158
+
159
+ controller = SimulationController(
160
+ mechanics=problem, # a pulse.StaticProblem or DynamicProblem using `model`
161
+ ep_solver=ep_solver, # a beat.MonodomainSplittingSolver
162
+ backend=backend,
163
+ ode_modules=modules,
164
+ dt_mech=1.0, # ms
165
+ dt_ep=0.05, # ms
166
+ )
167
+ while controller.t < 200.0:
168
+ controller.step()
169
+ ```
170
+
171
+ The [tutorials](https://github.com/ComputationalPhysiology/simcardemsx/tree/main/examples) build this up step by step, from one cell to a
172
+ coupled slab.
173
+
174
+ ## Examples
175
+
176
+ [`examples/`](https://github.com/ComputationalPhysiology/simcardemsx/tree/main/examples) holds four short tutorials and four larger
177
+ applications:
178
+
179
+ - an electro-mechanical slab, for any split, scheme or contraction model;
180
+ - a biventricular heart beating in a closed-loop circulation;
181
+ - a biventricular heart from the Rodero cohort, driven through the cardiac cycle;
182
+ - a convergence study of the coupling schemes.
183
+
184
+ ## Development
185
+
186
+ ```bash
187
+ python3 -m pip install -e ".[dev,test]"
188
+ python3 -m pytest # the test suite
189
+ python3 -m pytest -m "not slow" # the fast part of it
190
+ pre-commit run --all # ruff, mypy, cspell, …
191
+ ```
192
+
193
+ The documentation is built with [MyST](https://mystmd.org). See
194
+ [`docs/README.md`](https://github.com/ComputationalPhysiology/simcardemsx/blob/main/docs/README.md).
195
+
196
+ ## References
197
+
198
+ - F. Regazzoni and A. Quarteroni. An oscillation-free fully staggered algorithm for
199
+ velocity-dependent active models of cardiac mechanics. *Computer Methods in Applied
200
+ Mechanics and Engineering* 373, 113506 (2021).
201
+ - J. Tomek et al. Development, calibration, and validation of a novel human ventricular
202
+ myocyte model in health, disease, and drug block. *eLife* 8, e48890 (2019).
203
+ - S. Land et al. A model of cardiac contraction based on novel measurements of tension
204
+ development in human cardiomyocytes. *Journal of Molecular and Cellular Cardiology*
205
+ 106, 68–83 (2017).
206
+
207
+ ## Authors
208
+
209
+ Henrik Finsberg (<henriknf@simula.no>)
210
+
211
+ ## License
212
+
213
+ MIT. See [LICENSE](https://github.com/ComputationalPhysiology/simcardemsx/blob/main/LICENSE).
@@ -0,0 +1,148 @@
1
+ # simcardemsx
2
+
3
+ Cardiac electro-mechanics in [FEniCSx](https://fenicsproject.org).
4
+
5
+ simcardemsx couples a model of cardiac electrophysiology (EP) to a model of tissue
6
+ mechanics, with the contraction of each cell in between. It does not solve either
7
+ physics itself. It connects two solvers that do:
8
+
9
+ - [fenicsx-beat](https://github.com/finsberg/fenicsx-beat) for EP (the monodomain
10
+ model);
11
+ - [fenicsx-pulse](https://github.com/finsberg/fenicsx-pulse) for the mechanics, from a
12
+ single element to a beating heart in a circulation model.
13
+
14
+ The cell model, EP and contraction alike, is a single
15
+ [gotranx](https://github.com/finsberg/gotranx) `.ode` file. simcardemsx splits it in two
16
+ and generates code for each half. The EP half is NumPy code for beat. The contraction
17
+ half is UFL, which the mechanics solver can differentiate through, so the contraction
18
+ model can be stepped *inside* the mechanics Newton iteration. That removes the
19
+ instability the usual staggered coupling suffers from when the tissue is soft
20
+ (Regazzoni & Quarteroni, 2021). Models that cannot be written in UFL, such as the NumPy
21
+ models of [crossbridge](https://github.com/ComputationalPhysiology/crossbridge), are
22
+ coupled with the stabilized scheme of the same paper instead.
23
+
24
+ 📖 **Documentation**: <https://computationalphysiology.github.io/simcardemsx>
25
+
26
+ ## Features
27
+
28
+ - One `.ode` file for the whole cell, split anywhere between EP and contraction.
29
+ Which variables cross between the two sides is read off the generated code, not
30
+ configured by hand.
31
+ - Separate meshes and time steps for EP and mechanics.
32
+ - Three coupling schemes: monolithic (the default), stabilized segregated, and the
33
+ naive segregated scheme for comparison.
34
+ - Static and dynamic mechanics, closed-loop circulation (Regazzoni's 0D circuit) and
35
+ open-loop cardiac cycles, through pulse.
36
+ - Rollback of a failed time step, and checkpoints that a run continues from in a new
37
+ process (bit for bit under pulse's default direct solver).
38
+
39
+ ## Installation
40
+
41
+ simcardemsx needs [DOLFINx](https://github.com/FEniCS/dolfinx), which is not
42
+ installable from PyPI on its own. The simplest way to get it is the DOLFINx container:
43
+
44
+ ```bash
45
+ docker run -ti -v $(pwd):/home/shared -w /home/shared ghcr.io/fenics/dolfinx/dolfinx:stable
46
+ ```
47
+
48
+ Inside it, install simcardemsx with pip:
49
+
50
+ ```bash
51
+ python3 -m pip install simcardemsx
52
+ ```
53
+
54
+ or from source, with the dependencies of the examples:
55
+
56
+ ```bash
57
+ git clone https://github.com/ComputationalPhysiology/simcardemsx.git
58
+ cd simcardemsx
59
+ python3 -m pip install -e ".[demo]"
60
+ ```
61
+
62
+ The extras are `demo` (the examples), `test`, `docs` and `dev`.
63
+
64
+ ## A first look
65
+
66
+ Generate the two halves of a cell model and see what crosses between them:
67
+
68
+ ```python
69
+ from pathlib import Path
70
+
71
+ from simcardemsx.ode_model import load_ode_modules
72
+
73
+ odefile = Path("examples/odefiles/ToRORd_dynCl_endo_zetasplit.ode")
74
+ modules = load_ode_modules(odefile, Path("generated_odes"))
75
+
76
+ print(modules.mechanics.missing) # what contraction needs from EP: {'XS': 0, 'XW': 1}
77
+ print(modules.ep.missing) # what EP needs back: {'Zetas': 0, 'Zetaw': 1}
78
+ ```
79
+
80
+ The contraction half becomes the active stress of a pulse model:
81
+
82
+ ```python
83
+ from simcardemsx.backends import GeneratedActivation
84
+
85
+ backend = GeneratedActivation(modules.mechanics, mesh, f0, quadrature_degree=4)
86
+ model = pulse.CardiacModel(material=material, active=backend, compressibility=compressibility)
87
+ ```
88
+
89
+ and `SimulationController` steps EP and mechanics together:
90
+
91
+ ```python
92
+ from simcardemsx.controller import SimulationController
93
+
94
+ controller = SimulationController(
95
+ mechanics=problem, # a pulse.StaticProblem or DynamicProblem using `model`
96
+ ep_solver=ep_solver, # a beat.MonodomainSplittingSolver
97
+ backend=backend,
98
+ ode_modules=modules,
99
+ dt_mech=1.0, # ms
100
+ dt_ep=0.05, # ms
101
+ )
102
+ while controller.t < 200.0:
103
+ controller.step()
104
+ ```
105
+
106
+ The [tutorials](https://github.com/ComputationalPhysiology/simcardemsx/tree/main/examples) build this up step by step, from one cell to a
107
+ coupled slab.
108
+
109
+ ## Examples
110
+
111
+ [`examples/`](https://github.com/ComputationalPhysiology/simcardemsx/tree/main/examples) holds four short tutorials and four larger
112
+ applications:
113
+
114
+ - an electro-mechanical slab, for any split, scheme or contraction model;
115
+ - a biventricular heart beating in a closed-loop circulation;
116
+ - a biventricular heart from the Rodero cohort, driven through the cardiac cycle;
117
+ - a convergence study of the coupling schemes.
118
+
119
+ ## Development
120
+
121
+ ```bash
122
+ python3 -m pip install -e ".[dev,test]"
123
+ python3 -m pytest # the test suite
124
+ python3 -m pytest -m "not slow" # the fast part of it
125
+ pre-commit run --all # ruff, mypy, cspell, …
126
+ ```
127
+
128
+ The documentation is built with [MyST](https://mystmd.org). See
129
+ [`docs/README.md`](https://github.com/ComputationalPhysiology/simcardemsx/blob/main/docs/README.md).
130
+
131
+ ## References
132
+
133
+ - F. Regazzoni and A. Quarteroni. An oscillation-free fully staggered algorithm for
134
+ velocity-dependent active models of cardiac mechanics. *Computer Methods in Applied
135
+ Mechanics and Engineering* 373, 113506 (2021).
136
+ - J. Tomek et al. Development, calibration, and validation of a novel human ventricular
137
+ myocyte model in health, disease, and drug block. *eLife* 8, e48890 (2019).
138
+ - S. Land et al. A model of cardiac contraction based on novel measurements of tension
139
+ development in human cardiomyocytes. *Journal of Molecular and Cellular Cardiology*
140
+ 106, 68–83 (2017).
141
+
142
+ ## Authors
143
+
144
+ Henrik Finsberg (<henriknf@simula.no>)
145
+
146
+ ## License
147
+
148
+ MIT. See [LICENSE](https://github.com/ComputationalPhysiology/simcardemsx/blob/main/LICENSE).
@@ -0,0 +1,236 @@
1
+ [build-system] # Require setuptool version due to https://github.com/pypa/setuptools/issues/2938
2
+ requires = [
3
+ "scikit-build-core[pyproject]>=0.11.0", # Ensuring license field is correctly parsed]
4
+ "nanobind>=1.3.2",
5
+ "setuptools>=77.0.3", # Ensuring license field is correctly parsed]
6
+ "packaging>=24.2", # Ensuring license field is correctly parsed]
7
+ "pkgconfig",
8
+ ]
9
+
10
+ [project]
11
+ name = "simcardemsx"
12
+ version = "0.1.0"
13
+ description = "Next generation cardiac electro-mechanics solver based on FEniCSx"
14
+ authors = [{name = "Henrik Finsberg", email = "henriknf@simula.no"}]
15
+ license = "MIT"
16
+ license-files = ["LICENSE"]
17
+ readme = "README.md"
18
+ keywords = ["cardiac", "electromechanics", "finite element", "fenicsx", "electrophysiology"]
19
+ classifiers = [
20
+ "Programming Language :: Python :: 3",
21
+ "Intended Audience :: Science/Research",
22
+ "Topic :: Scientific/Engineering :: Physics",
23
+ "Topic :: Scientific/Engineering :: Medical Science Apps.",
24
+ ]
25
+ requires-python = ">=3.12.0"
26
+ dependencies = [
27
+ "fenics-dolfinx",
28
+ # pulse 0.11.1 and beat 0.7.2 are the first releases with the restart API that
29
+ # simcardemsx.checkpoint calls (restart_functions/restart_metadata, and pulse's
30
+ # CycleController.state_dict); SimulationController.step() snapshots through it.
31
+ # beat 0.9.0 replaced beat.ecg.Leads12 with twelve_lead(), which rodero_05's post.py uses.
32
+ "fenicsx-pulse>=0.11.1",
33
+ "fenicsx-beat>=0.9.0",
34
+ # crossbridge backs the Ca_i-split activation backend and is imported at
35
+ # package import time via simcardemsx.backends. 0.3.3 is the first release whose
36
+ # RDQ20MF can take a step longer than its 25 us RU step (gate X2), and 0.3.4 the
37
+ # first with get_state/set_state, which the backend's checkpoint saves.
38
+ "crossbridge>=0.3.4",
39
+ # io4dolfinx writes and reads restart.bp and results.bp (simcardemsx.checkpoint,
40
+ # simcardemsx.results), and is imported at package import time.
41
+ "io4dolfinx",
42
+ # scipy is used by simcardemsx.zero_d for the monolithic reference solve
43
+ "scipy",
44
+ # gotranx 2.2.0 orders the generated states independently of PYTHONHASHSEED, and its
45
+ # GRL step linearizes every state, also through intermediates (1.8 advanced v, cai
46
+ # and the concentrations by forward Euler).
47
+ "gotranx>=2.2.0",
48
+ "toml",
49
+ "pydantic",
50
+ "pydantic_pint",
51
+ ]
52
+
53
+ [project.urls]
54
+ Homepage = "https://computationalphysiology.github.io/simcardemsx"
55
+ Documentation = "https://computationalphysiology.github.io/simcardemsx"
56
+ Source = "https://github.com/ComputationalPhysiology/simcardemsx"
57
+ Issues = "https://github.com/ComputationalPhysiology/simcardemsx/issues"
58
+
59
+ [project.optional-dependencies]
60
+ test = [
61
+ "pytest",
62
+ "pytest-cov",
63
+ "cardiac-geometriesx",
64
+ # Regazzoni's closed-loop circuit (its .ode file), for the circulation gates
65
+ "circulation>=0.4.0",
66
+ ]
67
+ dev = [
68
+ "pdbpp",
69
+ "ipython",
70
+ "bump2version",
71
+ "mypy",
72
+ # Stubs for mypy, which pre-commit runs from this environment (language: system).
73
+ # Not scipy-stubs: see the scipy mypy override below.
74
+ "types-toml",
75
+ "pre-commit",
76
+ ]
77
+ demo = [
78
+ "matplotlib",
79
+ "cardiac-geometriesx",
80
+ "fenicsx-ldrb",
81
+ "ukb-atlas",
82
+ "circulation>=0.4.0",
83
+ "gotranx",
84
+ "io4dolfinx",
85
+ ]
86
+ docs = [
87
+ # MyST builds the site (docs/myst.yml); jupytext turns the tutorials into the notebooks
88
+ # it executes, in the kernel ipykernel registers; griffe reads the docstrings for the
89
+ # API reference (docs/generate_api_pages.py) without importing the package.
90
+ "mystmd",
91
+ "jupytext",
92
+ "ipykernel",
93
+ "jupyter-server",
94
+ "griffe>=2",
95
+ "simcardemsx[demo]",
96
+ ]
97
+ benchmark = [
98
+ "pytest-codspeed",
99
+ "simcardemsx[test]",
100
+ ]
101
+
102
+ all = [
103
+ "simcardemsx[test]",
104
+ "simcardemsx[docs]",
105
+ "simcardemsx[dev]",
106
+ "simcardemsx[demo]",
107
+ ]
108
+
109
+ [dependency-groups]
110
+ # Keep in sync with [build-system].requires above. Needed as a group, not just
111
+ # as build-system metadata, because scifem is installed with
112
+ # `--no-build-isolation`, so the build backend has to already be present.
113
+ build = [
114
+ "scikit-build-core[pyproject]>=0.11.0",
115
+ "nanobind>=1.3.2",
116
+ "setuptools>=77.0.3",
117
+ "packaging>=24.2",
118
+ "pkgconfig",
119
+ ]
120
+
121
+ [tool.pytest.ini_options]
122
+ addopts = [
123
+ "--cov=simcardemsx",
124
+ "--cov-report=html",
125
+ "--cov-report=xml",
126
+ "--cov-report=term-missing",
127
+ "-v",
128
+ ]
129
+ testpaths = [
130
+ "tests"
131
+ ]
132
+ markers = ["slow: takes more than a few seconds"]
133
+
134
+
135
+ [[tool.mypy.overrides]]
136
+ # scipy ships no types of its own. scipy-stubs would supply them, but it installs optype, and
137
+ # pint >= 0.26 imports optype when it is present, which sends mypy <= 2.3.1 into infinite
138
+ # recursion (python/mypy#21985; fixed on mypy master by python/mypy#22036, not yet released).
139
+ module = ["scipy", "scipy.*"]
140
+ ignore_missing_imports = true
141
+
142
+ [[tool.mypy.overrides]]
143
+ # circulation (Regazzoni's circuit, for the circulation gates) ships no py.typed marker.
144
+ module = ["circulation", "circulation.*"]
145
+ ignore_missing_imports = true
146
+
147
+
148
+ [tool.ruff]
149
+ # Exclude a variety of commonly ignored directories.
150
+ exclude = [
151
+ ".bzr",
152
+ ".direnv",
153
+ ".eggs",
154
+ ".git",
155
+ ".hg",
156
+ ".mypy_cache",
157
+ ".nox",
158
+ ".pants.d",
159
+ ".pytype",
160
+ ".ruff_cache",
161
+ ".svn",
162
+ ".tox",
163
+ ".venv",
164
+ "__pypackages__",
165
+ "_build",
166
+ "buck-out",
167
+ "build",
168
+ "dist",
169
+ "node_modules",
170
+ "venv",
171
+ "third-party",
172
+ ]
173
+
174
+ # Same as Black.
175
+ line-length = 100
176
+
177
+ # Allow unused variables when underscore-prefixed.
178
+
179
+ # Assume Python 3.10.
180
+ target-version = "py312"
181
+
182
+
183
+ [tool.ruff.lint]
184
+ # Enable pycodestyle (`E`) and Pyflakes (`F`) codes by default.
185
+ select = ["E", "F", "I"]
186
+ ignore = ["E402", "E741", "E743", "E731"]
187
+
188
+ # Allow autofix for all enabled rules (when `--fix`) is provided.
189
+ fixable = ["A", "B", "C", "D", "E", "F", "I"]
190
+ unfixable = []
191
+
192
+ dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
193
+
194
+ [tool.ruff.lint.mccabe]
195
+ # Unlike Flake8, default to a complexity level of 10.
196
+ max-complexity = 10
197
+
198
+
199
+ [tool.ruff.lint.isort]
200
+ known-first-party = ["cardiac_geometries"]
201
+ known-third-party = [
202
+ "basix",
203
+ "dolfinx",
204
+ "ffcx",
205
+ "ufl",
206
+ "gmsh",
207
+ "numpy",
208
+ "pytest",
209
+ ]
210
+ section-order = [
211
+ "future",
212
+ "standard-library",
213
+ "mpi",
214
+ "third-party",
215
+ "first-party",
216
+ "local-folder",
217
+ ]
218
+ [tool.ruff.lint.isort.sections]
219
+ "mpi" = ["mpi4py", "petsc4py"]
220
+
221
+
222
+ [tool.bumpversion]
223
+ allow_dirty = false
224
+ commit = true
225
+ message = "Bump version: {current_version} → {new_version}"
226
+ tag = true
227
+ sign_tags = false
228
+ tag_name = "v{new_version}"
229
+ tag_message = "Bump version: {current_version} → {new_version}"
230
+ current_version = "0.1.0"
231
+
232
+
233
+ [[tool.bumpversion.files]]
234
+ filename = "pyproject.toml"
235
+ search = 'version = "{current_version}"'
236
+ replace = 'version = "{new_version}"'
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,18 @@
1
+ from importlib.metadata import metadata
2
+
3
+ meta = metadata("simcardemsx")
4
+ __version__ = meta.get("Version")
5
+ __author__ = meta.get("Author-email")
6
+ __license__ = meta.get("license-expression")
7
+ __email__ = meta.get("Author-email")
8
+ __program_name__ = meta.get("Name")
9
+
10
+ from . import backends, controller, interpolation, ode_model, utils
11
+
12
+ __all__ = [
13
+ "backends",
14
+ "controller",
15
+ "ode_model",
16
+ "utils",
17
+ "interpolation",
18
+ ]