Skip to content

Commit 13509dc

Browse files
authored
Merge pull request #12 from LIBRA-project/profiles
merge profiles into paper
2 parents 090a896 + 917bde3 commit 13509dc

17 files changed

Lines changed: 1184 additions & 992 deletions

data_processing/sensitivity.ipynb

Lines changed: 466 additions & 466 deletions
Large diffs are not rendered by default.

examples/sensitivity.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,16 +82,16 @@ def _forward(self, x: torch.Tensor) -> torch.Tensor:
8282
self.counter += 1
8383

8484
residual_fraction = pp.get_residual_fraction(
85-
sim_output.inventories_T2_salt,
85+
sim_output.n_T2_salt_series,
8686
sim_output.times,
8787
t_irr,
8888
t_irr + t_sparging,
8989
)
9090
tau_real = pp.get_tau_real(
91-
sim_output.inventories_T2_salt, sim_output.times, t_0=t_irr
91+
sim_output.n_T2_salt_series, sim_output.times, t_0=t_irr
9292
)
9393
(tau_exp, _), _ = pp.fit_exp(
94-
sim_output.inventories_T2_salt,
94+
sim_output.n_T2_salt_series,
9595
sim_output.times,
9696
t_0=t_irr,
9797
t_end=t_irr + t_sparging,

examples/sparging101.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,19 +48,18 @@ def profile_source_T(z: pint.Quantity | list[float], height: pint.Quantity = Non
4848
my_simulation = Simulation(
4949
my_input,
5050
t_final=t_final,
51-
profile_pressure_hydrostatic=True,
5251
)
5352

5453
if __name__ == "__main__":
5554
# my_simulation.sim_input.E_g *= 1e5
5655
# my_simulation.sim_input.E_l *= 1e-5
5756
output = my_simulation.solve(fast_solve=True)
5857
popt, pcov = pp.fit_exp(
59-
output.inventories_T2_salt, output.times, 0 * ureg.s, t_irr, phase="rampup"
58+
output.n_T2_salt_series, output.times, 0 * ureg.s, t_irr, phase="rampup"
6059
)
6160
print(f"Fitted parameters: n0 = {popt[1]}, tau = {popt[0].to('h')}")
6261
popt, pcov = pp.fit_exp(
63-
output.inventories_T2_salt, output.times, t_irr, t_final, phase="decay"
62+
output.n_T2_salt_series, output.times, t_irr, t_final, phase="decay"
6463
)
6564
print(f"Fitted parameters: n0 = {popt[1]}, tau = {popt[0].to('h')}")
6665
animation.create_animation(output, show_activity=False)

examples/sparging_LIBRA1L.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
my_simulation = Simulation(
1717
my_input,
1818
t_final=2 * ureg.days,
19-
profile_pressure_hydrostatic=False,
19+
constant_profiles=True,
2020
)
2121

2222
if __name__ == "__main__":

examples/sparging_LIBRA_Pi.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
my_simulation = Simulation(
3333
my_input,
3434
t_final=4 * ureg.days,
35-
profile_pressure_hydrostatic=True,
3635
)
3736

3837
if __name__ == "__main__":

examples/sparging_standard.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,20 +31,21 @@
3131
# standard_input.signal_irr = lambda t: 1 if t <= 24 * ureg.hours else 0
3232
standard_input.signal_irr = lambda t: 1
3333
# standard_input.profile_source_T = lambda z: 1 - z * ureg.m / standard_input.height
34-
standard_input.c_T2_0 = 3e-11 * ureg.molT2 / ureg.m**3
34+
standard_input.c_T2_init = 3e-11 * ureg.molT2 / ureg.m**3
3535

3636
my_simulation = Simulation(
3737
standard_input,
3838
t_final=6 * ureg.days,
39-
profile_pressure_hydrostatic=True,
4039
dispersion_on=True,
40+
constant_profiles=False,
4141
)
4242

4343
standard_input.to_json(FOLDER / "intermediate_params.json")
4444
breakpoint()
4545
if __name__ == "__main__":
46-
# my_simulation.exports = ["pressure", "J_T2"]
46+
my_simulation.exports = ["P_g", "a", "aJ_T2"]
4747
output = my_simulation.solve(fast_solve=True)
48+
output.exports_to_csv(FOLDER)
4849
# save output to file
4950
output.to_json(FOLDER / "params.json")
5051

src/sparging/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
from .input_examples import (
2323
get_sim_input_LIBRA1L,
2424
get_sim_input_standard,
25+
get_sim_input_malara,
2526
LIBRA_PI_GEOM,
2627
LIBRA_PI_MAT,
2728
LIBRA_PI_OPERATING_PARAMS,

src/sparging/animation.py

Lines changed: 54 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -37,42 +37,42 @@ def __init__(
3737
Vertical spacing between subplots
3838
"""
3939
self.times_hr = results.times.to("hour").magnitude
40-
self.c_T2_solutions = results.c_T2_solutions.to("molT2/m^3").magnitude
41-
self.y_T2_solutions = results.y_T2_solutions.to("dimensionless").magnitude
40+
self.c_T2_profiles = results.c_T2_profiles.to("molT2/m^3").magnitude
41+
self.y_T2_profiles = results.y_T2_profiles.to("dimensionless").magnitude
4242
self.x_ct = results.x_ct.to("m").magnitude
4343
self.x_y = results.x_y.to("m").magnitude
44-
self.inventories_T2_salt = results.inventories_T2_salt.to("molT2").magnitude
45-
self.source_T2 = (
44+
self.n_T2_salt_series = results.n_T2_salt_series.to("molT2").magnitude
45+
self.source_T2_series = (
4646
None
47-
if results.sources_T2 is None
48-
else results.sources_T2.to("molT2/s").magnitude
47+
if results.sources_T2_series is None
48+
else results.sources_T2_series.to("molT2/s").magnitude
4949
)
50-
self.fluxes_T2 = (
50+
self.ndot_T2_series = (
5151
None
52-
if results.fluxes_T2 is None
53-
else results.fluxes_T2.to("molT2/s").magnitude
52+
if results.ndot_T2_series is None
53+
else results.ndot_T2_series.to("molT2/s").magnitude
5454
)
5555
self.show_activity = show_activity
5656
self.figsize = figsize
5757
self.hspace = hspace
5858

59-
if self.inventories_T2_salt is not None and self.show_activity:
60-
self.inventories_T2_salt_display = (
61-
np.array(self.inventories_T2_salt) * molT2_to_activity
59+
if self.n_T2_salt_series is not None and self.show_activity:
60+
self.n_T2_salt_series_display = (
61+
np.array(self.n_T2_salt_series) * molT2_to_activity
6262
)
6363
else:
64-
self.inventories_T2_salt_display = self.inventories_T2_salt
64+
self.n_T2_salt_series_display = self.n_T2_salt_series
6565

6666
if (
67-
self.source_T2 is not None
68-
and self.source_T2.shape[0] != self.times_hr.shape[0]
67+
self.source_T2_series is not None
68+
and self.source_T2_series.shape[0] != self.times_hr.shape[0]
6969
):
70-
raise ValueError("source_T2 must have the same length as times")
70+
raise ValueError("source_T2_series must have the same length as times")
7171
if (
72-
self.fluxes_T2 is not None
73-
and self.fluxes_T2.shape[0] != self.times_hr.shape[0]
72+
self.ndot_T2_series is not None
73+
and self.ndot_T2_series.shape[0] != self.times_hr.shape[0]
7474
):
75-
raise ValueError("fluxes_T2 must have the same length as times")
75+
raise ValueError("ndot_T2_series must have the same length as times")
7676

7777
# Animation state
7878
self.is_animating = False
@@ -84,7 +84,7 @@ def __init__(
8484

8585
def _setup_plot(self):
8686
"""Setup the initial plot with subplots."""
87-
nrows = 3 if self.inventories_T2_salt is not None else 2
87+
nrows = 3 if self.n_T2_salt_series is not None else 2
8888
default_figsize = (11, 8) if nrows == 3 else (11, 6.3)
8989
self.fig = plt.figure(figsize=self.figsize or default_figsize)
9090
gs = gridspec.GridSpec(nrows, 1, figure=self.fig, hspace=self.hspace)
@@ -93,7 +93,7 @@ def _setup_plot(self):
9393
ax2 = self.fig.add_subplot(gs[1], sharex=ax1)
9494
self.axs = [ax1, ax2]
9595

96-
if self.inventories_T2_salt is not None:
96+
if self.n_T2_salt_series is not None:
9797
# Third axis intentionally has an independent x-scale (time).
9898
ax3 = self.fig.add_subplot(gs[2])
9999
self.axs.append(ax3)
@@ -103,18 +103,18 @@ def _setup_plot(self):
103103

104104
# Create initial plots
105105
(self.line1,) = self.axs[0].plot(
106-
self.x_ct, self.c_T2_solutions[0], "b-", linewidth=2
106+
self.x_ct, self.c_T2_profiles[0], "b-", linewidth=2
107107
)
108108
(self.line2,) = self.axs[1].plot(
109-
self.x_y, self.y_T2_solutions[0], "r-", linewidth=2
109+
self.x_y, self.y_T2_profiles[0], "r-", linewidth=2
110110
)
111-
if self.inventories_T2_salt is not None:
111+
if self.n_T2_salt_series is not None:
112112
(self.line3,) = self.axs[2].plot(
113-
self.times_hr, self.inventories_T2_salt_display, "g-", linewidth=2
113+
self.times_hr, self.n_T2_salt_series_display, "g-", linewidth=2
114114
)
115115
(self.time_marker,) = self.axs[2].plot(
116116
[self.times_hr[0]],
117-
[self.inventories_T2_salt_display[0]],
117+
[self.n_T2_salt_series_display[0]],
118118
"ko",
119119
markersize=6,
120120
)
@@ -126,37 +126,37 @@ def _setup_plot(self):
126126
self.flux_marker = None
127127
secondary_lines = []
128128
secondary_labels = []
129-
if self.source_T2 is not None or self.fluxes_T2 is not None:
129+
if self.source_T2_series is not None or self.ndot_T2_series is not None:
130130
self.ax3_secondary = self.axs[2].twinx()
131-
if self.source_T2 is not None:
131+
if self.source_T2_series is not None:
132132
(self.source_line,) = self.ax3_secondary.plot(
133133
self.times_hr,
134-
self.source_T2,
134+
self.source_T2_series,
135135
color="tab:orange",
136136
linestyle=":",
137137
linewidth=1.8,
138138
)
139139
(self.source_marker,) = self.ax3_secondary.plot(
140140
[self.times_hr[0]],
141-
[self.source_T2[0]],
141+
[self.source_T2_series[0]],
142142
marker="o",
143143
color="tab:orange",
144144
markersize=5,
145145
linestyle="None",
146146
)
147147
secondary_lines.append(self.source_line)
148148
secondary_labels.append(r"$S_{T_2}$")
149-
if self.fluxes_T2 is not None:
149+
if self.ndot_T2_series is not None:
150150
(self.flux_line,) = self.ax3_secondary.plot(
151151
self.times_hr,
152-
self.fluxes_T2,
152+
self.ndot_T2_series,
153153
color="magenta",
154154
linestyle="dashdot",
155155
linewidth=1.8,
156156
)
157157
(self.flux_marker,) = self.ax3_secondary.plot(
158158
[self.times_hr[0]],
159-
[self.fluxes_T2[0]],
159+
[self.ndot_T2_series[0]],
160160
marker="s",
161161
color="magenta",
162162
markersize=5,
@@ -169,10 +169,10 @@ def _setup_plot(self):
169169
self.ax3_secondary.grid(False)
170170

171171
sec_vals = []
172-
if self.source_T2 is not None:
173-
sec_vals.append(self.source_T2)
174-
if self.fluxes_T2 is not None:
175-
sec_vals.append(self.fluxes_T2)
172+
if self.source_T2_series is not None:
173+
sec_vals.append(self.source_T2_series)
174+
if self.ndot_T2_series is not None:
175+
sec_vals.append(self.ndot_T2_series)
176176
sec_vals = np.concatenate(sec_vals)
177177
sec_min = np.min(sec_vals)
178178
sec_max = np.max(sec_vals)
@@ -195,8 +195,8 @@ def _setup_plot(self):
195195
)
196196
self.axs[0].grid(True, alpha=0.3)
197197
self.axs[0].set_ylim(
198-
(self.c_T2_solutions.min() - EPS) * 0.9,
199-
(self.c_T2_solutions.max() + EPS) * 1.1,
198+
(self.c_T2_profiles.min() - EPS) * 0.9,
199+
(self.c_T2_profiles.max() + EPS) * 1.1,
200200
)
201201

202202
self.axs[1].set_ylabel(r"$y_{T_2} \: [-]$")
@@ -206,11 +206,11 @@ def _setup_plot(self):
206206
)
207207
self.axs[1].grid(True, alpha=0.3)
208208
self.axs[1].set_ylim(
209-
(self.y_T2_solutions.min() - EPS) * 0.9,
210-
(self.y_T2_solutions.max() + EPS) * 1.1,
209+
(self.y_T2_profiles.min() - EPS) * 0.9,
210+
(self.y_T2_profiles.max() + EPS) * 1.1,
211211
)
212212

213-
if self.inventories_T2_salt is not None:
213+
if self.n_T2_salt_series is not None:
214214
if self.show_activity:
215215
self.axs[2].set_ylabel(r"$A_{T} \: [Bq]$")
216216
self.axs[2].set_title("Total T activity in breeder [Bq]")
@@ -220,8 +220,8 @@ def _setup_plot(self):
220220
self.axs[2].set_xlabel("Time [hours]")
221221
self.axs[2].grid(True, alpha=0.3)
222222
self.axs[2].set_ylim(
223-
(self.inventories_T2_salt_display.min() - EPS) * 0.9,
224-
(self.inventories_T2_salt_display.max() + EPS) * 1.1,
223+
(self.n_T2_salt_series_display.min() - EPS) * 0.9,
224+
(self.n_T2_salt_series_display.max() + EPS) * 1.1,
225225
)
226226

227227
def _setup_slider(self):
@@ -250,8 +250,8 @@ def _update_plot(self, val):
250250
idx = np.argmin(np.abs(self.times_hr - current_time))
251251

252252
# Update the plots
253-
self.line1.set_ydata(self.c_T2_solutions[idx])
254-
self.line2.set_ydata(self.y_T2_solutions[idx])
253+
self.line1.set_ydata(self.c_T2_profiles[idx])
254+
self.line2.set_ydata(self.y_T2_profiles[idx])
255255

256256
# Update titles
257257
self.axs[0].set_title(
@@ -260,14 +260,18 @@ def _update_plot(self, val):
260260
self.axs[1].set_title(
261261
f"$T_2$ fraction in sparging gas at t={self.times_hr[idx]:.1f} hr"
262262
)
263-
if self.inventories_T2_salt is not None:
263+
if self.n_T2_salt_series is not None:
264264
self.time_marker.set_data(
265-
[self.times_hr[idx]], [self.inventories_T2_salt_display[idx]]
265+
[self.times_hr[idx]], [self.n_T2_salt_series_display[idx]]
266266
)
267267
if self.source_marker is not None:
268-
self.source_marker.set_data([self.times_hr[idx]], [self.source_T2[idx]])
268+
self.source_marker.set_data(
269+
[self.times_hr[idx]], [self.source_T2_series[idx]]
270+
)
269271
if self.flux_marker is not None:
270-
self.flux_marker.set_data([self.times_hr[idx]], [self.fluxes_T2[idx]])
272+
self.flux_marker.set_data(
273+
[self.times_hr[idx]], [self.ndot_T2_series[idx]]
274+
)
271275

272276
self.fig.canvas.draw_idle()
273277

src/sparging/config.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,24 @@
22
import scipy.constants as const
33
import logging
44

5+
"""
6+
Naming convention (paper symbol <-> code)
7+
=========================================
8+
Core rule: <quantity>_<species> mirrors the paper symbol, e.g.
9+
c_T2 -> c_{T2} ndot_T2 -> \\dot n_{T2} P_g/P_l -> P_g/P_l
10+
11+
Collections are named by the AXIS they vary along:
12+
_profile : varies in space z (1D array)
13+
_profiles : space x time (2D array, leading axis = time)
14+
_series : varies in time (1D array)
15+
16+
Fixed suffix vocabulary:
17+
Xdot : time derivative / rate (\\dot X) -> ndot_T2, Vdot_g0
18+
X_ave : spatial/quantity average (\\bar X) -> gen_T2_ave
19+
X_0 : tank bottom / gas inlet
20+
X_init : initial condition (t=0)
21+
"""
22+
523
molar_mass_T2 = 3.016 * 2 # g/mol T2
624
specific_activity_tritium = 3.57e14 # Bq/g
725
molT2_to_activity = molar_mass_T2 * specific_activity_tritium # Bq/mol T2

0 commit comments

Comments
 (0)