Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
Background,
useNodesState,
useEdgesState,
addEdge,

Check failure on line 9 in src/App.jsx

View workflow job for this annotation

GitHub Actions / test (20.x, 3.11)

'addEdge' is defined but never used. Allowed unused vars must match /^[A-Z_]/u

Check failure on line 9 in src/App.jsx

View workflow job for this annotation

GitHub Actions / test (20.x, 3.10)

'addEdge' is defined but never used. Allowed unused vars must match /^[A-Z_]/u
} from '@xyflow/react';
import '@xyflow/react/dist/style.css';
import './App.css';
Expand Down Expand Up @@ -50,6 +50,9 @@
splitter2: Splitter2Node,
splitter3: Splitter3Node,
bubbler: BubblerNode,
white_noise: SourceNode,
pink_noise: SourceNode,

};

// Defining initial nodes and edges. In the data section, we have label, but also parameters specific to the node.
Expand Down Expand Up @@ -608,6 +611,13 @@
break;
case 'bubbler':
nodeData = { ...nodeData, conversion_efficiency: '0.95', vial_efficiency: '0.9', replacement_times: '' };
break;
case 'white_noise':
nodeData = { ...nodeData, spectral_density: '1', sampling_rate: '' };
break;
case 'pink_noise':
nodeData = { ...nodeData, spectral_density: '1', num_octaves: '16', sampling_rate: '' };
break;
default:
// For any other types, just use basic data
break;
Expand Down Expand Up @@ -768,7 +778,7 @@
return () => {
document.removeEventListener('keydown', handleKeyDown);
};
}, [selectedEdge, selectedNode, copiedNode, duplicateNode, setCopyFeedback]);

Check warning on line 781 in src/App.jsx

View workflow job for this annotation

GitHub Actions / test (20.x, 3.11)

React Hook useEffect has missing dependencies: 'deleteSelectedEdge' and 'deleteSelectedNode'. Either include them or remove the dependency array

Check warning on line 781 in src/App.jsx

View workflow job for this annotation

GitHub Actions / test (20.x, 3.10)

React Hook useEffect has missing dependencies: 'deleteSelectedEdge' and 'deleteSelectedNode'. Either include them or remove the dependency array

return (
<div style={{ width: '100vw', height: '100vh', position: 'relative' }}>
Expand Down
25 changes: 21 additions & 4 deletions src/custom_pathsim_blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@


class Process(ODE):
def __init__(self, residence_time=0, ic=0, gen=0):
def __init__(self, residence_time=0, initial_value=0, source_term=0):
alpha = -1 / residence_time if residence_time != 0 else 0
super().__init__(
func=lambda x, u, t: x * alpha + sum(u) + gen, initial_value=ic
func=lambda x, u, t: x * alpha + sum(u) + source_term,
initial_value=initial_value,
)
self.residence_time = residence_time
self.ic = ic
self.gen = gen
self.initial_value = initial_value
self.source_term = source_term

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


class Splitter2(Splitter):
def __init__(self, f1, f2):
"""
Splitter with two outputs, fractions are f1 and f2.
"""
super().__init__(n=2, fractions=[f1, f2])


class Splitter3(Splitter):
def __init__(self, f1, f2, f3):
"""
Splitter with three outputs, fractions are f1, f2 and f3.
"""
super().__init__(n=3, fractions=[f1, f2, f3])


# BUBBLER SYSTEM


Expand Down
55 changes: 32 additions & 23 deletions src/pathsim_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@
PID,
Schedule,
)
from .custom_pathsim_blocks import Process, Splitter, Bubbler
from pathsim.blocks.noise import WhiteNoise, PinkNoise
from .custom_pathsim_blocks import Process, Splitter, Splitter2, Splitter3, Bubbler
from flask import jsonify
import inspect

NAME_TO_SOLVER = {
"SSPRK22": pathsim.solvers.SSPRK22,
Expand All @@ -34,8 +36,8 @@
"amplifier": Amplifier,
"amplifier_reverse": Amplifier,
"scope": Scope,
"splitter2": Splitter,
"splitter3": Splitter,
"splitter2": Splitter2,
"splitter3": Splitter3,
"adder": Adder,
"adder_reverse": Adder,
"multiplier": Multiplier,
Expand All @@ -47,6 +49,8 @@
"function": Function,
"delay": Delay,
"bubbler": Bubbler,
"white_noise": WhiteNoise,
"pink_noise": PinkNoise,
}


Expand Down Expand Up @@ -296,14 +300,25 @@ def auto_block_construction(node: dict, eval_namespace: dict = None) -> Block:

block_class = map_str_to_object[block_type]

# skip 'self'
parameters_for_class = block_class.__init__.__code__.co_varnames[1:]
parameters_for_class = inspect.signature(block_class.__init__).parameters
parameters = {}
for k, value in parameters_for_class.items():
if k == "self":
continue
# Skip 'operations' for Adder, as it is handled separately
# https://github.com/festim-dev/fuel-cycle-sim/issues/73
if k in ["operations"]:
continue
user_input = node["data"][k]
if user_input == "":
if value.default is inspect._empty:
raise ValueError(
f"expected parameter for {k} in {block_type} ({node['label']})"
)
parameters[k] = value.default
else:
parameters[k] = eval(user_input, eval_namespace)

parameters = {
k: eval(v, eval_namespace)
for k, v in node["data"].items()
if k in parameters_for_class
}
return block_class(**parameters)


Expand All @@ -329,21 +344,15 @@ def make_blocks(
tau=eval(node["data"]["delay"], eval_namespace),
)
elif block_type == "splitter2":
block = Splitter(
n=2,
fractions=[
eval(node["data"]["f1"], eval_namespace),
eval(node["data"]["f2"], eval_namespace),
],
block = Splitter2(
f1=eval(node["data"]["f1"], eval_namespace),
f2=eval(node["data"]["f2"], eval_namespace),
)
elif block_type == "splitter3":
block = Splitter(
n=3,
fractions=[
eval(node["data"]["f1"], eval_namespace),
eval(node["data"]["f2"], eval_namespace),
eval(node["data"]["f3"], eval_namespace),
],
block = Splitter3(
f1=eval(node["data"]["f1"], eval_namespace),
f2=eval(node["data"]["f2"], eval_namespace),
f3=eval(node["data"]["f3"], eval_namespace),
)
elif block_type == "bubbler":
block, events_bubbler = create_bubbler(node)
Expand Down
2 changes: 2 additions & 0 deletions src/templates/template_with_macros.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@
iterations_max={{ solverParams["iterations_max"] }},
log={{ solverParams["log"].capitalize() }},
tolerance_fpi={{ solverParams["tolerance_fpi"] }},
{%- if solverParams["extra_params"] != '' -%}
**{{ solverParams["extra_params"] }},
{%- endif -%}
)

if __name__ == "__main__":
Expand Down
37 changes: 28 additions & 9 deletions test/test_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
auto_block_construction,
create_function,
)
from src.custom_pathsim_blocks import Process, Splitter
from src.custom_pathsim_blocks import Process, Splitter2, Splitter3

import pathsim.blocks

Expand Down Expand Up @@ -33,17 +33,17 @@
"data": {"expression": "3*x**2", "label": "Function"},
},
"delay": {"type": "delay", "data": {"tau": "1.0", "label": "Delay"}},
"rng": {"type": "rng", "data": {"seed": "42", "label": "RNG"}},
"rng": {"type": "rng", "data": {"sampling_rate": "2", "label": "RNG"}},
"pid": {
"type": "pid",
"data": {"kp": "1.0", "ki": "0.0", "kd": "0.0", "label": "PID"},
"data": {"Kp": "1.0", "Ki": "0.0", "Kd": "0.0", "f_max": "100", "label": "PID"},
},
"process": {
"type": "process",
"data": {
"residence_time": "1.0",
"ic": "0.0",
"gen": "0.0",
"initial_value": "0.0",
"source_term": "0.0",
"label": "Process",
},
},
Expand All @@ -56,6 +56,23 @@
"data": {"f1": "1/3", "f2": "1/3", "f3": "1/3", "label": "Splitter 3"},
},
"scope": {"type": "scope", "data": {"label": "Scope"}},
"white_noise": {
"type": "white_noise",
"data": {
"spectral_density": "1",
"sampling_rate": "2",
"label": "White Noise Source",
},
},
"pink_noise": {
"type": "pink_noise",
"data": {
"spectral_density": "1",
"num_octaves": "16",
"sampling_rate": "5",
"label": "Pink Noise Source",
},
},
}


Expand Down Expand Up @@ -117,8 +134,10 @@ def test_create_integrator():
("rng", pathsim.blocks.RNG),
("pid", pathsim.blocks.PID),
("process", Process),
("splitter2", Splitter),
("splitter3", Splitter),
("splitter2", Splitter2),
("splitter3", Splitter3),
("white_noise", pathsim.blocks.noise.WhiteNoise),
("pink_noise", pathsim.blocks.noise.PinkNoise),
],
)
def test_auto_block_construction(node_factory, block_type, expected_class):
Expand All @@ -140,8 +159,8 @@ def test_auto_block_construction(node_factory, block_type, expected_class):
("rng", pathsim.blocks.RNG),
("pid", pathsim.blocks.PID),
("process", Process),
("splitter2", Splitter),
("splitter3", Splitter),
("white_noise", pathsim.blocks.noise.WhiteNoise),
("pink_noise", pathsim.blocks.noise.PinkNoise),
],
)
def test_auto_block_construction_with_var(node_factory, block_type, expected_class):
Expand Down
Loading