Skip to content

Commit 5fdb733

Browse files
wenfengyepyansys-ci-botmhoeijm
authored
feat: closed system (#1021)
Co-authored-by: pyansys-ci-bot <[email protected]> Co-authored-by: mhoeijm <[email protected]>
1 parent e484b66 commit 5fdb733

File tree

5 files changed

+362
-269
lines changed

5 files changed

+362
-269
lines changed

doc/source/changelog/1021.added.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
closed system

src/ansys/health/heart/settings/defaults/mechanics.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@
150150
"scale_factor": {"normal": 0.5, "radial": 1.0},
151151
},
152152
"end_diastolic_cavity_pressure": {
153-
## https://doi.org/10.3389/fphys.2018.00539
153+
# https://doi.org/10.3389/fphys.2018.00539
154154
"left_ventricle": Quantity(15, "mmHg"),
155155
"left_atrial": Quantity(15, "mmHg"),
156156
"right_ventricle": Quantity(8, "mmHg"),
@@ -173,7 +173,7 @@
173173
rv = ra
174174

175175
system_model = {
176-
"name": "ConstantPreloadWindkesselAfterload",
176+
"name": "open-loop",
177177
"left_ventricle": {
178178
"constants": {
179179
# preload resistance
Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
# Copyright (C) 2023 - 2025 ANSYS, Inc. and/or its affiliates.
2+
# SPDX-License-Identifier: MIT
3+
#
4+
#
5+
# Permission is hereby granted, free of charge, to any person obtaining a copy
6+
# of this software and associated documentation files (the "Software"), to deal
7+
# in the Software without restriction, including without limitation the rights
8+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
# copies of the Software, and to permit persons to whom the Software is
10+
# furnished to do so, subject to the following conditions:
11+
#
12+
# The above copyright notice and this permission notice shall be included in all
13+
# copies or substantial portions of the Software.
14+
#
15+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
# SOFTWARE.
22+
"""Module to system model."""
23+
24+
from dataclasses import dataclass
25+
26+
from ansys.health.heart.models import BiVentricle, FourChamber, HeartModel, LeftVentricle
27+
from ansys.health.heart.objects import Part
28+
from ansys.health.heart.writer.define_function_templates import _define_function_0d_system
29+
30+
31+
@dataclass
32+
class CVInteraction:
33+
"""Template to define control volume interaction."""
34+
35+
id: int
36+
cvid1: int
37+
cvid2: int
38+
lcid: int
39+
flow_name: str
40+
parameters: dict
41+
42+
def _define_function_keyword(self):
43+
if self.flow_name == "closed-loop":
44+
return ""
45+
else:
46+
return _define_function_0d_system(self.lcid, self.flow_name, self.parameters)
47+
48+
49+
@dataclass
50+
class ControlVolume:
51+
"""Template to define control volume."""
52+
53+
part: Part
54+
id: int
55+
Interactions: list[CVInteraction]
56+
57+
58+
def _create_open_loop(id_offset: int, model: HeartModel, settings) -> list[ControlVolume]:
59+
"""Create open loop system model.
60+
61+
Parameters
62+
----------
63+
id_offset : int
64+
ID of the first control volume
65+
model : HeartModel
66+
Heart model
67+
settings : _type_
68+
parameters for the control volume
69+
70+
Returns
71+
-------
72+
list[ControlVolume]
73+
list of control volumes
74+
"""
75+
if isinstance(model, LeftVentricle):
76+
system_map = [
77+
ControlVolume(
78+
part=model.left_ventricle,
79+
id=1,
80+
Interactions=[
81+
CVInteraction(
82+
id=1,
83+
cvid1=1,
84+
cvid2=0,
85+
lcid=id_offset,
86+
flow_name="constant_preload_windkessel_afterload_left",
87+
parameters=settings.left_ventricle,
88+
)
89+
],
90+
)
91+
]
92+
elif isinstance(model, BiVentricle):
93+
system_map = [
94+
ControlVolume(
95+
part=model.left_ventricle,
96+
id=1,
97+
Interactions=[
98+
CVInteraction(
99+
id=1,
100+
cvid1=1,
101+
cvid2=0,
102+
lcid=id_offset,
103+
flow_name="constant_preload_windkessel_afterload_left",
104+
parameters=settings.left_ventricle,
105+
)
106+
],
107+
),
108+
ControlVolume(
109+
part=model.right_ventricle,
110+
id=2,
111+
Interactions=[
112+
CVInteraction(
113+
id=2,
114+
cvid1=2,
115+
cvid2=0,
116+
lcid=id_offset + 1,
117+
flow_name="constant_preload_windkessel_afterload_right",
118+
parameters=settings.right_ventricle,
119+
)
120+
],
121+
),
122+
]
123+
elif isinstance(model, FourChamber):
124+
system_map = [
125+
ControlVolume(
126+
part=model.left_ventricle,
127+
id=1,
128+
Interactions=[
129+
CVInteraction(
130+
id=1,
131+
cvid1=1,
132+
cvid2=0,
133+
lcid=id_offset,
134+
flow_name="afterload_windkessel_left",
135+
parameters=settings.left_ventricle,
136+
),
137+
],
138+
),
139+
ControlVolume(
140+
part=model.right_ventricle,
141+
id=2,
142+
Interactions=[
143+
CVInteraction(
144+
id=2,
145+
cvid1=2,
146+
cvid2=0,
147+
lcid=id_offset + 1,
148+
flow_name="afterload_windkessel_right",
149+
parameters=settings.right_ventricle,
150+
),
151+
],
152+
),
153+
ControlVolume(
154+
part=model.left_atrium,
155+
id=3,
156+
Interactions=[
157+
CVInteraction(
158+
id=3,
159+
cvid1=3,
160+
cvid2=0,
161+
lcid=id_offset + 2,
162+
flow_name="constant_flow_left_atrium",
163+
parameters={"flow": -83.0}, # ~5 L/min
164+
),
165+
CVInteraction(
166+
id=4,
167+
cvid1=3,
168+
cvid2=1,
169+
lcid=id_offset + 3,
170+
flow_name="valve_mitral",
171+
parameters={"Rv": 1e-6},
172+
),
173+
],
174+
),
175+
ControlVolume(
176+
part=model.right_atrium,
177+
id=4,
178+
Interactions=[
179+
CVInteraction(
180+
id=5,
181+
cvid1=4,
182+
cvid2=0,
183+
lcid=id_offset + 4,
184+
flow_name="constant_flow_right_atrium",
185+
parameters={"flow": -83.0}, # ~5 L/min
186+
),
187+
CVInteraction(
188+
id=6,
189+
cvid1=4,
190+
cvid2=2,
191+
lcid=id_offset + 5,
192+
flow_name="valve_tricuspid",
193+
parameters={"Rv": 1e-6},
194+
),
195+
],
196+
),
197+
]
198+
199+
return system_map
200+
201+
202+
def _create_closed_loop(model: HeartModel) -> list[ControlVolume]:
203+
"""Create close loop system model.
204+
205+
Parameters
206+
----------
207+
model : HeartModel
208+
Heart model
209+
210+
Returns
211+
-------
212+
list[ControlVolume]
213+
list of control volumes
214+
"""
215+
interaction_id = [-1, -2, -3, -4]
216+
217+
if isinstance(model, LeftVentricle):
218+
control_volumes = [model.left_ventricle]
219+
elif isinstance(model, BiVentricle):
220+
control_volumes = [model.left_ventricle, model.right_ventricle]
221+
elif isinstance(model, FourChamber):
222+
control_volumes = [
223+
model.left_ventricle,
224+
model.right_ventricle,
225+
model.left_atrium,
226+
model.right_atrium,
227+
]
228+
229+
system_map = []
230+
for i, part in enumerate(control_volumes):
231+
system_map.append(
232+
ControlVolume(
233+
part=part,
234+
id=i + 1,
235+
Interactions=[
236+
CVInteraction(
237+
id=i + 1,
238+
cvid1=i + 1,
239+
cvid2=0,
240+
lcid=interaction_id[i],
241+
flow_name="closed-loop",
242+
parameters={},
243+
)
244+
],
245+
)
246+
)
247+
return system_map

0 commit comments

Comments
 (0)