Skip to content

Commit 147c4ee

Browse files
Merge branch 'main' into example-festim
2 parents db5014f + 4e7d7fe commit 147c4ee

File tree

5 files changed

+99
-36
lines changed

5 files changed

+99
-36
lines changed

src/App.jsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ const nodeTypes = {
5252
splitter3: Splitter3Node,
5353
wall: WallNode,
5454
bubbler: BubblerNode,
55+
white_noise: SourceNode,
56+
pink_noise: SourceNode,
57+
5558
};
5659

5760
// Defining initial nodes and edges. In the data section, we have label, but also parameters specific to the node.
@@ -614,6 +617,12 @@ export default function App() {
614617
case 'bubbler':
615618
nodeData = { ...nodeData, conversion_efficiency: '0.95', vial_efficiency: '0.9', replacement_times: '' };
616619
break;
620+
case 'white_noise':
621+
nodeData = { ...nodeData, spectral_density: '1', sampling_rate: '' };
622+
break;
623+
case 'pink_noise':
624+
nodeData = { ...nodeData, spectral_density: '1', num_octaves: '16', sampling_rate: '' };
625+
break;
617626
default:
618627
// For any other types, just use basic data
619628
break;

src/custom_pathsim_blocks.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@
55

66

77
class Process(ODE):
8-
def __init__(self, residence_time=0, ic=0, gen=0):
8+
def __init__(self, residence_time=0, initial_value=0, source_term=0):
99
alpha = -1 / residence_time if residence_time != 0 else 0
1010
super().__init__(
11-
func=lambda x, u, t: x * alpha + sum(u) + gen, initial_value=ic
11+
func=lambda x, u, t: x * alpha + sum(u) + source_term,
12+
initial_value=initial_value,
1213
)
1314
self.residence_time = residence_time
14-
self.ic = ic
15-
self.gen = gen
15+
self.initial_value = initial_value
16+
self.source_term = source_term
1617

1718
def update(self, t):
1819
x = self.engine.get()
@@ -39,6 +40,22 @@ def update(self, t):
3940
self.outputs.update_from_array(self.fractions * u)
4041

4142

43+
class Splitter2(Splitter):
44+
def __init__(self, f1, f2):
45+
"""
46+
Splitter with two outputs, fractions are f1 and f2.
47+
"""
48+
super().__init__(n=2, fractions=[f1, f2])
49+
50+
51+
class Splitter3(Splitter):
52+
def __init__(self, f1, f2, f3):
53+
"""
54+
Splitter with three outputs, fractions are f1, f2 and f3.
55+
"""
56+
super().__init__(n=3, fractions=[f1, f2, f3])
57+
58+
4259
# BUBBLER SYSTEM
4360

4461

src/pathsim_utils.py

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,17 @@
1919
PID,
2020
Schedule,
2121
)
22-
from .custom_pathsim_blocks import Process, Splitter, Bubbler, FestimWall
22+
from pathsim.blocks.noise import WhiteNoise, PinkNoise
23+
from .custom_pathsim_blocks import (
24+
Process,
25+
Splitter,
26+
Splitter2,
27+
Splitter3,
28+
Bubbler,
29+
FestimWall,
30+
)
2331
from flask import jsonify
32+
import inspect
2433

2534
NAME_TO_SOLVER = {
2635
"SSPRK22": pathsim.solvers.SSPRK22,
@@ -34,8 +43,8 @@
3443
"amplifier": Amplifier,
3544
"amplifier_reverse": Amplifier,
3645
"scope": Scope,
37-
"splitter2": Splitter,
38-
"splitter3": Splitter,
46+
"splitter2": Splitter2,
47+
"splitter3": Splitter3,
3948
"adder": Adder,
4049
"adder_reverse": Adder,
4150
"multiplier": Multiplier,
@@ -48,6 +57,8 @@
4857
"delay": Delay,
4958
"bubbler": Bubbler,
5059
"wall": FestimWall,
60+
"white_noise": WhiteNoise,
61+
"pink_noise": PinkNoise,
5162
}
5263

5364

@@ -297,14 +308,25 @@ def auto_block_construction(node: dict, eval_namespace: dict = None) -> Block:
297308

298309
block_class = map_str_to_object[block_type]
299310

300-
# skip 'self'
301-
parameters_for_class = block_class.__init__.__code__.co_varnames[1:]
311+
parameters_for_class = inspect.signature(block_class.__init__).parameters
312+
parameters = {}
313+
for k, value in parameters_for_class.items():
314+
if k == "self":
315+
continue
316+
# Skip 'operations' for Adder, as it is handled separately
317+
# https://github.com/festim-dev/fuel-cycle-sim/issues/73
318+
if k in ["operations"]:
319+
continue
320+
user_input = node["data"][k]
321+
if user_input == "":
322+
if value.default is inspect._empty:
323+
raise ValueError(
324+
f"expected parameter for {k} in {block_type} ({node['label']})"
325+
)
326+
parameters[k] = value.default
327+
else:
328+
parameters[k] = eval(user_input, eval_namespace)
302329

303-
parameters = {
304-
k: eval(v, eval_namespace)
305-
for k, v in node["data"].items()
306-
if k in parameters_for_class
307-
}
308330
return block_class(**parameters)
309331

310332

@@ -330,21 +352,15 @@ def make_blocks(
330352
tau=eval(node["data"]["delay"], eval_namespace),
331353
)
332354
elif block_type == "splitter2":
333-
block = Splitter(
334-
n=2,
335-
fractions=[
336-
eval(node["data"]["f1"], eval_namespace),
337-
eval(node["data"]["f2"], eval_namespace),
338-
],
355+
block = Splitter2(
356+
f1=eval(node["data"]["f1"], eval_namespace),
357+
f2=eval(node["data"]["f2"], eval_namespace),
339358
)
340359
elif block_type == "splitter3":
341-
block = Splitter(
342-
n=3,
343-
fractions=[
344-
eval(node["data"]["f1"], eval_namespace),
345-
eval(node["data"]["f2"], eval_namespace),
346-
eval(node["data"]["f3"], eval_namespace),
347-
],
360+
block = Splitter3(
361+
f1=eval(node["data"]["f1"], eval_namespace),
362+
f2=eval(node["data"]["f2"], eval_namespace),
363+
f3=eval(node["data"]["f3"], eval_namespace),
348364
)
349365
elif block_type == "bubbler":
350366
block, events_bubbler = create_bubbler(node)

src/templates/template_with_macros.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@
4848
iterations_max={{ solverParams["iterations_max"] }},
4949
log={{ solverParams["log"].capitalize() }},
5050
tolerance_fpi={{ solverParams["tolerance_fpi"] }},
51+
{%- if solverParams["extra_params"] != '' -%}
5152
**{{ solverParams["extra_params"] }},
53+
{%- endif -%}
5254
)
5355

5456
if __name__ == "__main__":

test/test_backend.py

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
auto_block_construction,
44
create_function,
55
)
6-
from src.custom_pathsim_blocks import Process, Splitter
6+
from src.custom_pathsim_blocks import Process, Splitter2, Splitter3
77

88
import pathsim.blocks
99

@@ -33,17 +33,17 @@
3333
"data": {"expression": "3*x**2", "label": "Function"},
3434
},
3535
"delay": {"type": "delay", "data": {"tau": "1.0", "label": "Delay"}},
36-
"rng": {"type": "rng", "data": {"seed": "42", "label": "RNG"}},
36+
"rng": {"type": "rng", "data": {"sampling_rate": "2", "label": "RNG"}},
3737
"pid": {
3838
"type": "pid",
39-
"data": {"kp": "1.0", "ki": "0.0", "kd": "0.0", "label": "PID"},
39+
"data": {"Kp": "1.0", "Ki": "0.0", "Kd": "0.0", "f_max": "100", "label": "PID"},
4040
},
4141
"process": {
4242
"type": "process",
4343
"data": {
4444
"residence_time": "1.0",
45-
"ic": "0.0",
46-
"gen": "0.0",
45+
"initial_value": "0.0",
46+
"source_term": "0.0",
4747
"label": "Process",
4848
},
4949
},
@@ -56,6 +56,23 @@
5656
"data": {"f1": "1/3", "f2": "1/3", "f3": "1/3", "label": "Splitter 3"},
5757
},
5858
"scope": {"type": "scope", "data": {"label": "Scope"}},
59+
"white_noise": {
60+
"type": "white_noise",
61+
"data": {
62+
"spectral_density": "1",
63+
"sampling_rate": "2",
64+
"label": "White Noise Source",
65+
},
66+
},
67+
"pink_noise": {
68+
"type": "pink_noise",
69+
"data": {
70+
"spectral_density": "1",
71+
"num_octaves": "16",
72+
"sampling_rate": "5",
73+
"label": "Pink Noise Source",
74+
},
75+
},
5976
}
6077

6178

@@ -117,8 +134,10 @@ def test_create_integrator():
117134
("rng", pathsim.blocks.RNG),
118135
("pid", pathsim.blocks.PID),
119136
("process", Process),
120-
("splitter2", Splitter),
121-
("splitter3", Splitter),
137+
("splitter2", Splitter2),
138+
("splitter3", Splitter3),
139+
("white_noise", pathsim.blocks.noise.WhiteNoise),
140+
("pink_noise", pathsim.blocks.noise.PinkNoise),
122141
],
123142
)
124143
def test_auto_block_construction(node_factory, block_type, expected_class):
@@ -140,8 +159,8 @@ def test_auto_block_construction(node_factory, block_type, expected_class):
140159
("rng", pathsim.blocks.RNG),
141160
("pid", pathsim.blocks.PID),
142161
("process", Process),
143-
("splitter2", Splitter),
144-
("splitter3", Splitter),
162+
("white_noise", pathsim.blocks.noise.WhiteNoise),
163+
("pink_noise", pathsim.blocks.noise.PinkNoise),
145164
],
146165
)
147166
def test_auto_block_construction_with_var(node_factory, block_type, expected_class):

0 commit comments

Comments
 (0)