Skip to content

Commit fc9acd4

Browse files
Merge pull request #196 from festim-dev/replace-by-pathsim-chem
integrated pathsim-chem
2 parents 359c6b9 + 22fb502 commit fc9acd4

File tree

7 files changed

+17
-173
lines changed

7 files changed

+17
-173
lines changed

example_graphs/festim_two_walls.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
"n_vertices": "10",
1919
"surface_area": "",
2020
"temperature": "300",
21+
"T": "0.1",
22+
"tau": "0",
2123
"thickness": "2",
2224
"nodeColor": "#DDE6ED"
2325
},
@@ -63,6 +65,8 @@
6365
"surface_area": "",
6466
"temperature": "300",
6567
"thickness": "2",
68+
"T": "0.1",
69+
"tau": "0",
6670
"nodeColor": "#DDE6ED"
6771
},
6872
"measured": {

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ classifiers = [
2525
requires-python = ">=3.8"
2626
dependencies = [
2727
"pathsim>=0.8.2",
28+
"pathsim-chem",
2829
"matplotlib>=3.7.0",
2930
"numpy>=1.24.0",
3031
"plotly>=6.0",

src/python/custom_pathsim_blocks.py

Lines changed: 4 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
from pathsim.blocks import Block, ODE, Wrapper
1+
from pathsim.blocks import ODE, Wrapper
2+
from pathsim_chem import Splitter
23
import pathsim.blocks
34
import pathsim.events
4-
from pathsim import Subsystem, Interface, Connection
55
import numpy as np
66

77

@@ -41,33 +41,14 @@ def update(self, t):
4141
self.outputs.update_from_array(outputs)
4242

4343

44-
class Splitter(Block):
45-
"""Splitter block that splits the input signal into multiple outputs based on specified fractions."""
46-
47-
def __init__(self, n=2, fractions=None):
48-
super().__init__()
49-
self.n = n # number of splits
50-
self.fractions = np.ones(n) / n if fractions is None else np.array(fractions)
51-
assert len(self.fractions) == n, "Fractions must match number of outputs"
52-
assert np.isclose(np.sum(self.fractions), 1), (
53-
f"Fractions must sum to 1, not {np.sum(self.fractions)}"
54-
)
55-
56-
def update(self, t):
57-
# get the input from port '0'
58-
u = self.inputs[0]
59-
# mult by fractions and update outputs
60-
self.outputs.update_from_array(self.fractions * u)
61-
62-
6344
class Splitter2(Splitter):
6445
_port_map_out = {"source1": 0, "source2": 1}
6546

6647
def __init__(self, f1=0.5, f2=0.5):
6748
"""
6849
Splitter with two outputs, fractions are f1 and f2.
6950
"""
70-
super().__init__(n=2, fractions=[f1, f2])
51+
super().__init__(fractions=[f1, f2])
7152

7253

7354
class Splitter3(Splitter):
@@ -77,7 +58,7 @@ def __init__(self, f1=1 / 3, f2=1 / 3, f3=1 / 3):
7758
"""
7859
Splitter with three outputs, fractions are f1, f2 and f3.
7960
"""
80-
super().__init__(n=3, fractions=[f1, f2, f3])
61+
super().__init__(fractions=[f1, f2, f3])
8162

8263

8364
class Integrator(pathsim.blocks.Integrator):
@@ -154,147 +135,6 @@ def func_act(_):
154135
return [event]
155136

156137

157-
# BUBBLER SYSTEM
158-
159-
160-
class Bubbler(Subsystem):
161-
"""
162-
Subsystem representing a tritium bubbling system with 4 vials.
163-
164-
Args:
165-
conversion_efficiency: Conversion efficiency from insoluble to soluble (between 0 and 1).
166-
vial_efficiency: collection efficiency of each vial (between 0 and 1).
167-
replacement_times: List of times at which each vial is replaced. If None, no replacement
168-
events are created. If a single value is provided, it is used for all vials.
169-
If a single list of floats is provided, it will be used for all vials.
170-
If a list of lists is provided, each sublist corresponds to the replacement times for each vial.
171-
"""
172-
173-
vial_efficiency: float
174-
conversion_efficiency: float
175-
n_soluble_vials: float
176-
n_insoluble_vials: float
177-
178-
_port_map_out = {
179-
"vial1": 0,
180-
"vial2": 1,
181-
"vial3": 2,
182-
"vial4": 3,
183-
"sample_out": 4,
184-
}
185-
_port_map_in = {
186-
"sample_in_soluble": 0,
187-
"sample_in_insoluble": 1,
188-
}
189-
190-
def __init__(
191-
self,
192-
conversion_efficiency=0.9,
193-
vial_efficiency=0.9,
194-
replacement_times=None,
195-
):
196-
self.reset_times = replacement_times
197-
self.n_soluble_vials = 2
198-
self.n_insoluble_vials = 2
199-
self.vial_efficiency = vial_efficiency
200-
col_eff1 = Splitter(n=2, fractions=[vial_efficiency, 1 - vial_efficiency])
201-
vial_1 = pathsim.blocks.Integrator()
202-
col_eff2 = Splitter(n=2, fractions=[vial_efficiency, 1 - vial_efficiency])
203-
vial_2 = pathsim.blocks.Integrator()
204-
205-
conversion_eff = Splitter(
206-
n=2, fractions=[conversion_efficiency, 1 - conversion_efficiency]
207-
)
208-
209-
col_eff3 = Splitter(n=2, fractions=[vial_efficiency, 1 - vial_efficiency])
210-
vial_3 = pathsim.blocks.Integrator()
211-
col_eff4 = Splitter(n=2, fractions=[vial_efficiency, 1 - vial_efficiency])
212-
vial_4 = pathsim.blocks.Integrator()
213-
214-
add1 = pathsim.blocks.Adder()
215-
add2 = pathsim.blocks.Adder()
216-
interface = Interface()
217-
218-
self.vials = [vial_1, vial_2, vial_3, vial_4]
219-
220-
blocks = [
221-
vial_1,
222-
col_eff1,
223-
vial_2,
224-
col_eff2,
225-
conversion_eff,
226-
vial_3,
227-
col_eff3,
228-
vial_4,
229-
col_eff4,
230-
add1,
231-
add2,
232-
interface,
233-
]
234-
connections = [
235-
Connection(interface[0], col_eff1),
236-
Connection(col_eff1[0], vial_1),
237-
Connection(col_eff1[1], col_eff2),
238-
Connection(col_eff2[0], vial_2),
239-
Connection(col_eff2[1], conversion_eff),
240-
Connection(conversion_eff[0], add1[0]),
241-
Connection(conversion_eff[1], add2[0]),
242-
Connection(interface[1], add1[1]),
243-
Connection(add1, col_eff3),
244-
Connection(col_eff3[0], vial_3),
245-
Connection(col_eff3[1], col_eff4),
246-
Connection(col_eff4[0], vial_4),
247-
Connection(col_eff4[1], add2[1]),
248-
Connection(vial_1, interface[0]),
249-
Connection(vial_2, interface[1]),
250-
Connection(vial_3, interface[2]),
251-
Connection(vial_4, interface[3]),
252-
Connection(add2, interface[4]),
253-
]
254-
super().__init__(blocks, connections)
255-
256-
def _create_reset_events_one_vial(
257-
self, block, reset_times
258-
) -> pathsim.events.ScheduleList:
259-
def reset_itg(_):
260-
block.reset()
261-
262-
event = pathsim.events.ScheduleList(times_evt=reset_times, func_act=reset_itg)
263-
return event
264-
265-
def create_reset_events(self) -> list[pathsim.events.ScheduleList]:
266-
"""Create reset events for all vials based on the replacement times.
267-
268-
Raises:
269-
ValueError: If reset_times is not valid.
270-
271-
Returns:
272-
list of reset events.
273-
"""
274-
reset_times = self.reset_times
275-
events = []
276-
# if reset_times is a single list use it for all vials
277-
if reset_times is None:
278-
return events
279-
if isinstance(reset_times, (int, float)):
280-
reset_times = [reset_times]
281-
# if it's a flat list use it for all vials
282-
elif isinstance(reset_times, list) and all(
283-
isinstance(t, (int, float)) for t in reset_times
284-
):
285-
reset_times = [reset_times] * len(self.vials)
286-
elif isinstance(reset_times, np.ndarray) and reset_times.ndim == 1:
287-
reset_times = [reset_times.tolist()] * len(self.vials)
288-
elif isinstance(reset_times, list) and len(reset_times) != len(self.vials):
289-
raise ValueError(
290-
"reset_times must be a single value or a list with the same length as the number of vials"
291-
)
292-
for i, vial in enumerate(self.vials):
293-
events.append(self._create_reset_events_one_vial(vial, reset_times[i]))
294-
295-
return events
296-
297-
298138
# FESTIM wall
299139
from pathsim.utils.register import Register
300140

src/python/pathsim_utils.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,12 @@
4747
from pathsim.blocks.noise import WhiteNoise, PinkNoise
4848
from .custom_pathsim_blocks import (
4949
Process,
50-
Splitter,
5150
Splitter2,
5251
Splitter3,
53-
Bubbler,
5452
FestimWall,
5553
Integrator,
5654
)
55+
from pathsim_chem import Bubbler4, Splitter
5756
import inspect
5857

5958
NAME_TO_SOLVER = {
@@ -119,7 +118,7 @@
119118
"function2to2": Function,
120119
"delay": Delay,
121120
"ode": ODE,
122-
"bubbler": Bubbler,
121+
"bubbler": Bubbler4,
123122
"wall": FestimWall,
124123
"white_noise": WhiteNoise,
125124
"pink_noise": PinkNoise,

src/python/templates/template_with_macros.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import numpy as np
44
import matplotlib.pyplot as plt
55
import pathview
6+
import pathsim_chem
67
{# Import macros #}
78
{% from 'block_macros.py' import create_block, create_integrator_block, create_bubbler_block, create_connections, create_event -%}
89

test/test_backend.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
Process,
44
Splitter2,
55
Splitter3,
6-
Bubbler,
76
Integrator,
87
)
8+
from pathsim_chem import Bubbler4
99

1010
import pathsim.blocks
1111

@@ -137,7 +137,7 @@ def _create_node(block_type: str, id: str = "1", data_overrides: dict = None):
137137
("splitter3", Splitter3),
138138
("white_noise", pathsim.blocks.noise.WhiteNoise),
139139
("pink_noise", pathsim.blocks.noise.PinkNoise),
140-
("bubbler", Bubbler),
140+
("bubbler", Bubbler4),
141141
("integrator", Integrator),
142142
("scope", pathsim.blocks.Scope),
143143
],
@@ -163,7 +163,7 @@ def test_auto_block_construction(node_factory, block_type, expected_class):
163163
("process", Process),
164164
("white_noise", pathsim.blocks.noise.WhiteNoise),
165165
("pink_noise", pathsim.blocks.noise.PinkNoise),
166-
("bubbler", Bubbler),
166+
("bubbler", Bubbler4),
167167
("integrator", Integrator),
168168
],
169169
)

test/test_custom_blocks.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
import pathsim.blocks
22
from pathsim import Simulation, Connection
3-
from pathview.custom_pathsim_blocks import Bubbler
3+
from pathsim_chem import Bubbler4
44

55

66
def test_bubbler():
7-
my_bubbler = Bubbler()
8-
7+
my_bubbler = Bubbler4()
98
source_soluble = pathsim.blocks.Constant(1)
109
source_insoluble = pathsim.blocks.Constant(0.5)
1110
environment = pathsim.blocks.Integrator()

0 commit comments

Comments
 (0)