Skip to content

Commit 1cd5a6f

Browse files
MilanMilan
authored andcommitted
migrated tests for tritium module
1 parent 2825b17 commit 1cd5a6f

6 files changed

Lines changed: 350 additions & 0 deletions

File tree

.DS_Store

2 KB
Binary file not shown.

tests/.DS_Store

6 KB
Binary file not shown.

tests/tritium/__init__.py

Whitespace-only changes.

tests/tritium/test_bubbler.py

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
########################################################################################
2+
##
3+
## TESTS FOR
4+
## 'tritium.bubbler.py'
5+
##
6+
########################################################################################
7+
8+
# IMPORTS ==============================================================================
9+
10+
import unittest
11+
import numpy as np
12+
13+
from pathsim_chem.tritium import Bubbler4
14+
15+
from pathsim.solvers import EUF
16+
from pathsim.events.schedule import ScheduleList
17+
18+
19+
# TESTS ================================================================================
20+
21+
class TestFusionBubbler4(unittest.TestCase):
22+
"""
23+
Test the implementation of the 'Bubbler4' block class from the fusion toolbox.
24+
The block inherits from `ODE` and models a 4-vial tritium collection system.
25+
"""
26+
27+
def test_init(self):
28+
"""Test initialization with various parameter combinations"""
29+
30+
# Default initialization
31+
B = Bubbler4()
32+
self.assertEqual(B.conversion_efficiency, 0.9)
33+
self.assertEqual(B.vial_efficiency, 0.9)
34+
self.assertEqual(B.replacement_times, None)
35+
self.assertEqual(len(B.events), 0) # No events when replacement_times is None
36+
37+
# Specific initialization
38+
B = Bubbler4(conversion_efficiency=0.8, vial_efficiency=0.7, replacement_times=[100, 200])
39+
self.assertEqual(B.conversion_efficiency, 0.8)
40+
self.assertEqual(B.vial_efficiency, 0.7)
41+
self.assertEqual(B.replacement_times, [100, 200])
42+
43+
# Set solver to check internal solver instance
44+
B.set_solver(EUF, parent=None)
45+
self.assertTrue(B.engine)
46+
np.testing.assert_array_equal(B.engine.initial_value, np.zeros(4))
47+
48+
49+
def test_init_replacement_times(self):
50+
"""Test different replacement_times configurations"""
51+
52+
# Single list - should replicate for all vials
53+
B = Bubbler4(replacement_times=[100, 200, 300])
54+
B.set_solver(EUF, parent=None)
55+
self.assertEqual(len(B.events), 4)
56+
57+
# List of lists - one per vial
58+
times = [[100, 200], [150, 250], [120, 220], [180, 280]]
59+
B = Bubbler4(replacement_times=times)
60+
B.set_solver(EUF, parent=None)
61+
self.assertEqual(len(B.events), 4)
62+
for event in B.events:
63+
self.assertIsInstance(event, ScheduleList)
64+
65+
# NumPy array
66+
B = Bubbler4(replacement_times=np.array([100, 200, 300]))
67+
B.set_solver(EUF, parent=None)
68+
self.assertEqual(len(B.events), 4)
69+
70+
# Invalid case - wrong length
71+
with self.assertRaises(ValueError):
72+
B = Bubbler4(replacement_times=[[100], [200], [300]]) # Only 3 vials
73+
74+
75+
def test_update_outputs(self):
76+
"""Test the update method and output calculations"""
77+
78+
# Test with default parameters
79+
B = Bubbler4()
80+
B.set_solver(EUF, parent=None)
81+
82+
# Set some test inputs
83+
B.inputs[0] = 10.0 # soluble input
84+
B.inputs[1] = 5.0 # insoluble input
85+
86+
B.update(0.0)
87+
88+
# Check that outputs are set (initial state is zero)
89+
self.assertEqual(B.outputs[0], 0.0) # vial 1
90+
self.assertEqual(B.outputs[1], 0.0) # vial 2
91+
self.assertEqual(B.outputs[2], 0.0) # vial 3
92+
self.assertEqual(B.outputs[3], 0.0) # vial 4
93+
94+
# Calculate expected sample_out with default parameters (ve=0.9, ce=0.9)
95+
ve, ce = 0.9, 0.9
96+
sol, ins = 10.0, 5.0
97+
expected_sample_out = (1-ce)*ins + (1-ve)**2 * (ce*ins + (1-ve)**2 * sol)
98+
self.assertAlmostEqual(B.outputs[4], expected_sample_out, places=10)
99+
100+
101+
def test_mass_conservation(self):
102+
"""Test that mass is conserved in the system"""
103+
104+
B = Bubbler4(conversion_efficiency=0.8, vial_efficiency=0.7)
105+
B.set_solver(EUF, parent=None)
106+
107+
# Set test inputs
108+
sol_in, ins_in = 10.0, 5.0
109+
B.inputs[0] = sol_in
110+
B.inputs[1] = ins_in
111+
112+
# Get rates and sample_out
113+
u = np.array([sol_in, ins_in])
114+
x = np.zeros(4)
115+
rates = B.func_dyn(x, u, 0.0)
116+
117+
B.update(0.0)
118+
sample_out = B.outputs[4]
119+
120+
# Total input rate
121+
total_in = sol_in + ins_in
122+
123+
# Total accumulation rate in vials
124+
total_vial_rates = np.sum(rates)
125+
126+
# Mass conservation: input = vial accumulation + sample output
127+
total_out = total_vial_rates + sample_out
128+
129+
self.assertAlmostEqual(total_in, total_out, places=10)
130+
131+
132+
def test_vial_reset_functionality(self):
133+
"""Test that vial reset events work correctly"""
134+
135+
B = Bubbler4(replacement_times=[10.0])
136+
B.set_solver(EUF, parent=None)
137+
138+
# Manually set some vial inventories
139+
x = np.array([1.0, 2.0, 3.0, 4.0])
140+
B.engine.set(x)
141+
142+
# Test reset function for vial 0
143+
reset_event = B.events[0]
144+
reset_func = reset_event.func_act
145+
146+
# Execute reset
147+
reset_func(None)
148+
149+
# Check that vial 0 was reset but others remain
150+
x_after = B.engine.get()
151+
self.assertEqual(x_after[0], 0.0)
152+
self.assertEqual(x_after[1], 2.0)
153+
self.assertEqual(x_after[2], 3.0)
154+
self.assertEqual(x_after[3], 4.0)
155+
156+
# Test reset function for vial 3
157+
reset_event = B.events[3]
158+
reset_func = reset_event.func_act
159+
160+
# Execute reset
161+
reset_func(None)
162+
163+
# Check that vial 0 was reset but others remain
164+
x_after = B.engine.get()
165+
self.assertEqual(x_after[0], 0.0)
166+
self.assertEqual(x_after[1], 2.0)
167+
self.assertEqual(x_after[2], 3.0)
168+
self.assertEqual(x_after[3], 0.0)
169+
170+
171+
# RUN TESTS LOCALLY ====================================================================
172+
173+
if __name__ == '__main__':
174+
unittest.main(verbosity=2)
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
########################################################################################
2+
##
3+
## TESTS FOR
4+
## 'tritium.residencetime.py'
5+
##
6+
########################################################################################
7+
8+
# IMPORTS ==============================================================================
9+
10+
import unittest
11+
import numpy as np
12+
13+
from pathsim_chem.tritium import ResidenceTime, Process
14+
15+
from pathsim.solvers import EUF
16+
17+
18+
# TESTS ================================================================================
19+
20+
class TestTritiumResidenceTime(unittest.TestCase):
21+
"""
22+
Test the implementation of the 'ResidenceTime' block class from the fusion toolbox
23+
24+
The block inherits from `ODE`
25+
"""
26+
27+
def test_init(self):
28+
29+
#default initialization
30+
R = ResidenceTime()
31+
32+
self.assertEqual(R.tau, 1)
33+
self.assertEqual(R.betas, 1)
34+
self.assertEqual(R.gammas, 1)
35+
self.assertEqual(R.source_term, 0)
36+
37+
#input validation
38+
with self.assertRaises(ValueError):
39+
R = ResidenceTime(tau=0)
40+
41+
#specific initialization
42+
R = ResidenceTime(tau=0.1, betas=[1, 3, 5], gammas=[2, 4], initial_value=10, source_term=11)
43+
44+
self.assertEqual(R.tau,0.1)
45+
self.assertTrue(np.allclose(R.betas, np.array([1, 3, 5])))
46+
self.assertTrue(np.allclose(R.gammas, np.array([2, 4])))
47+
48+
#set solver to check internal solver instance
49+
R.set_solver(EUF, parent=None)
50+
51+
self.assertTrue(R.engine)
52+
self.assertEqual(R.engine.initial_value, 10)
53+
54+
55+
def test_update(self):
56+
57+
#default
58+
R = ResidenceTime()
59+
R.set_solver(EUF, parent=None)
60+
61+
R.update(None)
62+
63+
self.assertEqual(R.outputs[0], 0)
64+
65+
#specific
66+
R = ResidenceTime(tau=0.1, betas=[1, 3, 5], gammas=[2, 4], initial_value=11, source_term=12)
67+
R.set_solver(EUF, parent=None)
68+
69+
R.update(None)
70+
71+
self.assertEqual(R.outputs[0], 22) # initial_value * gammas[0]
72+
self.assertEqual(R.outputs[1], 44) # initial_value * gammas[1]
73+
74+
75+
76+
class TestTritiumProcess(unittest.TestCase):
77+
"""
78+
Test the implementation of the 'Process' block class from the fusion toolbox.
79+
80+
This block inherits from `ResidenceTime`, just testing the initialization.
81+
"""
82+
83+
def test_init(self):
84+
85+
#default initialization
86+
P = Process()
87+
88+
self.assertEqual(P.tau, 1)
89+
self.assertEqual(P.betas, 1)
90+
self.assertTrue(np.allclose(P.gammas, [1, 1])) # 1, 1/tau
91+
self.assertEqual(P.source_term, 0)
92+
93+
#specific initialization
94+
P = Process(tau=0.1, source_term=33, initial_value=44)
95+
96+
self.assertEqual(P.tau,0.1)
97+
self.assertEqual(P.betas, 1)
98+
self.assertTrue(np.allclose(P.gammas, np.array([1, 10])))
99+
self.assertEqual(P.source_term, 33)
100+
101+
#set solver to check internal solver instance
102+
P.set_solver(EUF, parent=None)
103+
104+
self.assertTrue(P.engine)
105+
self.assertEqual(P.engine.initial_value, 44)
106+
107+
108+
109+
110+
111+
112+
# RUN TESTS LOCALLY ====================================================================
113+
114+
if __name__ == '__main__':
115+
unittest.main(verbosity=2)

tests/tritium/test_splitter.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
########################################################################################
2+
##
3+
## TESTS FOR
4+
## 'tritium.splitter.py'
5+
##
6+
########################################################################################
7+
8+
# IMPORTS ==============================================================================
9+
10+
import unittest
11+
import numpy as np
12+
13+
from pathsim_chem.tritium import Splitter
14+
15+
16+
# TESTS ================================================================================
17+
18+
class TestTritiumSplitter(unittest.TestCase):
19+
"""
20+
Test the implementation of the 'Splitter' block class from the fusion toolbox
21+
"""
22+
23+
def test_init(self):
24+
25+
#default initialization
26+
S = Splitter()
27+
self.assertEqual(S.fractions, np.ones(1))
28+
29+
#input validation
30+
for fracs in [[1, 3], [0.4, 0.6, 0.001], [0.33, 0.33, 0.33]]:
31+
with self.assertRaises(ValueError):
32+
S = Splitter(fracs)
33+
34+
#special initialization
35+
S = Splitter([0.4, 0.5, 0.1])
36+
self.assertEqual(sum(S.fractions - np.array([0.4, 0.5, 0.1])), 0)
37+
38+
#test the automatic port maps
39+
self.assertEqual(S._port_map_out, {"out 0.4":0, "out 0.5":1, "out 0.1":2})
40+
41+
42+
def test_update(self):
43+
44+
S = Splitter([0.4, 0.5, 0.1])
45+
46+
#set block inputs
47+
S.inputs[0] = 2
48+
49+
#update block
50+
S.update(None)
51+
52+
#test if update was correct
53+
self.assertEqual(S.outputs[0], 0.8)
54+
self.assertEqual(S.outputs[1], 1)
55+
self.assertEqual(S.outputs[2], 0.2)
56+
57+
58+
# RUN TESTS LOCALLY ====================================================================
59+
60+
if __name__ == '__main__':
61+
unittest.main(verbosity=2)

0 commit comments

Comments
 (0)