Skip to content

Commit 2c2a3a8

Browse files
committed
pulsed mb with ion, atom fluxes, temp; scenario.txt file. integration with DINA dummy data
1 parent 7aa5166 commit 2c2a3a8

File tree

2 files changed

+229
-30
lines changed

2 files changed

+229
-30
lines changed

scenario.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# PULSE TYPE, NUMBER OF PULSES, RAMP UP, RAMP DOWN, STEADY STATE, WAITING
2+
FP 2 455 455 650 1000
3+
ICWC 2 36 36 180 1000
4+
RISP 2 0 0 0 0
5+
GDC 1 1 1 86398 1000
6+
FP 2 455 455 650 1000
7+
ICWC 2 36 36 180 1000
8+
RISP 2 0 0 0 0
9+
GDC 1 1 1 86398 1000
10+
FP 2 455 455 650 1000
11+
ICWC 2 36 36 180 1000
12+
RISP 2 0 0 0 0
13+
GDC 1 1 1 86398 1000
14+
BAKE 1 151200 151200 907200 100

simple_mb.py

Lines changed: 215 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,72 @@
11
# simple monoblock simulation in festim
2-
32
import festim as F
43
import numpy as np
54
import h_transport_materials as htm
6-
5+
import ufl
6+
from dolfinx.fem.function import Constant
7+
from scipy import constants
8+
import dolfinx.fem as fem
9+
import dolfinx
10+
11+
# dolfinx.log.set_log_level(dolfinx.log.LogLevel.INFO)
12+
13+
############# CUSTOM CLASSES FOR PULSED FLUXES & RECOMBO BC #############
14+
15+
class PulsedSource(F.ParticleSource):
16+
def __init__(self, flux, distribution, volume, species):
17+
self.flux = flux
18+
self.distribution = distribution
19+
super().__init__(None, volume, species)
20+
21+
@property
22+
def time_dependent(self):
23+
return True
24+
25+
def create_value_fenics(self, mesh, temperature, t: Constant):
26+
self.flux_fenics = Constant(mesh, float(self.flux(t)))
27+
x = ufl.SpatialCoordinate(mesh)
28+
self.distribution_fenics = self.distribution(x)
29+
30+
self.value_fenics = self.flux_fenics * self.distribution_fenics
31+
32+
def update(self, t: float):
33+
self.flux_fenics.value = self.flux(t)
34+
35+
class FluxFromSurfaceReaction(F.SurfaceFlux):
36+
def __init__(self, reaction: F.SurfaceReactionBC):
37+
super().__init__(
38+
F.Species(), # just a dummy species here
39+
reaction.subdomain,
40+
)
41+
self.reaction = reaction.flux_bcs[0]
42+
43+
def compute(self, ds):
44+
self.value = fem.assemble_scalar(
45+
fem.form(self.reaction.value_fenics * ds(self.surface.id))
46+
)
47+
self.data.append(self.value)
48+
49+
# TODO: ADJUST TO HANDLE ANY STRAIGHT W 6MM SIMU
50+
mb = 50
51+
52+
############# Input Flux, Heat Data #############
53+
with open('scenario.txt', 'r') as file:
54+
lines = []
55+
for line in file:
56+
lines.append(line.split())
57+
lines = lines[1:]
58+
59+
DINA_data = np.loadtxt('Binned_Flux_Data.dat', skiprows=1)
60+
ion_flux = DINA_data[:,2][mb-1]
61+
atom_flux = DINA_data[:,3][mb-1]
62+
heat = DINA_data[:,-2][mb-1]
763

864
my_model = F.HydrogenTransportProblem()
965

10-
# building 1D mesh, W mb
66+
############# Material Parameters #############
1167

12-
L = 6e-3 # m
13-
vertices = np.concatenate(
68+
L = 6e-3 # m
69+
vertices = np.concatenate( # 1D mesh with extra refinement
1470
[
1571
np.linspace(0, 30e-9, num=200),
1672
np.linspace(30e-9, 3e-6, num=300),
@@ -20,17 +76,17 @@
2076
)
2177
my_model.mesh = F.Mesh1D(vertices)
2278

23-
24-
# W material parameters
79+
# W material parameters
80+
# TODO integrate with htm
2581
w_density = 6.3382e28 # atoms/m3
26-
tungsten_diff = htm.diffusivities.filter(material=htm.TUNGSTEN).mean()
82+
# tungsten_diff = htm.diffusivities.filter(material=htm.TUNGSTEN).mean()
2783
tungsten = F.Material(
28-
D_0=tungsten_diff.pre_exp.magnitude,
29-
E_D=tungsten_diff.act_energy.magnitude,
84+
D_0=4.1e-7, # Hodille 2015 paper pg 426
85+
E_D=0.39,
3086
name="tungsten",
3187
)
3288

33-
# subdomains
89+
# mb subdomains
3490
w_subdomain = F.VolumeSubdomain1D(id=1, borders=[0, L], material=tungsten)
3591
inlet = F.SurfaceSubdomain1D(id=1, x=0)
3692
outlet = F.SurfaceSubdomain1D(id=2, x=L)
@@ -52,7 +108,6 @@
52108
trap3_D = F.Species("trap3_D", mobile=False)
53109
trap3_T = F.Species("trap3_T", mobile=False)
54110

55-
56111
# traps
57112
empty_trap1 = F.ImplicitSpecies( # implicit trap 1
58113
n=6.338e24, # 1e-4 at.fr.
@@ -66,8 +121,9 @@
66121
name="empty_trap2",
67122
)
68123

124+
# density_func =
69125
empty_trap3 = F.ImplicitSpecies( # fermi-dirac-like trap 3
70-
n=6.338e27, # 1e-1 at.fr.
126+
n=6.338e27, # density_func # 1e-1 at.fr.
71127
others=[trap3_T, trap3_D],
72128
name="empty_trap3",
73129
)
@@ -141,25 +197,153 @@
141197
),
142198
]
143199

144-
# temperature
145-
# my_model.temperature = 1000 - (1000-350)/L*x
146-
my_model.temperature = 1000
200+
############# Pulse Parameters (s) #############
201+
pulses_per_day = 13
202+
203+
flat_top_duration = 50*pulses_per_day
204+
ramp_up_duration = 33*pulses_per_day
205+
ramp_down_duration = 35*pulses_per_day
206+
dwelling_time = 72000 # 20 hours
207+
208+
total_time_pulse = flat_top_duration + ramp_up_duration + ramp_down_duration
209+
total_time_cycle = total_time_pulse + dwelling_time
210+
211+
isotope_split = 0.5
212+
213+
############# Temperature Parameters (K) #############
214+
T_coolant = 343 # 70 degree C cooling water
215+
216+
def T_surface(t): # plasma-facing side
217+
return 1.1e-4*heat+T_coolant
218+
219+
def T_rear(t): # coolant facing side
220+
return 2.2e-5*heat+T_coolant
221+
222+
def T_function(x, t: Constant):
223+
a = (T_rear(t) - T_surface(t)) / L
224+
b = T_surface(t)
225+
flat_top_value = a * x[0] + b
226+
resting_value = T_coolant
227+
return (
228+
flat_top_value
229+
if float(t) % total_time_cycle < total_time_pulse
230+
else resting_value
231+
)
232+
233+
my_model.temperature = T_function
234+
235+
############# Flux Parameters #############
236+
237+
def gaussian_distribution(x):
238+
depth = 3e-9
239+
width = 1e-9
240+
return ufl.exp(-((x[0] - depth) ** 2) / (2 * width**2))
241+
242+
def deuterium_ion_flux(t: Constant):
243+
flat_top_value = ion_flux*isotope_split
244+
resting_value = 0
245+
return (
246+
flat_top_value
247+
if float(t) % total_time_cycle < total_time_pulse
248+
else resting_value
249+
)
250+
251+
def tritium_ion_flux(t: Constant):
252+
flat_top_value = ion_flux*isotope_split
253+
resting_value = 0
254+
return (
255+
flat_top_value
256+
if float(t) % total_time_cycle < total_time_pulse
257+
else resting_value
258+
)
259+
260+
def deuterium_atom_flux(t: Constant):
261+
flat_top_value = atom_flux*isotope_split
262+
resting_value = 0
263+
return (
264+
flat_top_value
265+
if float(t) % total_time_cycle < total_time_pulse
266+
else resting_value
267+
)
268+
269+
def tritium_atom_flux(t: Constant):
270+
flat_top_value = atom_flux*isotope_split
271+
resting_value = 0
272+
return (
273+
flat_top_value
274+
if float(t) % total_time_cycle < total_time_pulse
275+
else resting_value
276+
)
277+
278+
279+
my_model.sources = [
280+
PulsedSource(
281+
flux=deuterium_ion_flux,
282+
distribution=gaussian_distribution,
283+
species=mobile_D,
284+
volume=w_subdomain,
285+
),
286+
PulsedSource(
287+
flux=tritium_ion_flux,
288+
distribution=gaussian_distribution,
289+
species=mobile_T,
290+
volume=w_subdomain
291+
),
292+
PulsedSource(
293+
flux=deuterium_atom_flux,
294+
distribution=gaussian_distribution,
295+
species=mobile_D,
296+
volume=w_subdomain,
297+
),
298+
PulsedSource(
299+
flux=tritium_atom_flux,
300+
distribution=gaussian_distribution,
301+
species=mobile_T,
302+
volume=w_subdomain
303+
)
304+
305+
]
306+
307+
############# Boundary Conditions #############
308+
surface_reaction_dd = F.SurfaceReactionBC(
309+
reactant=[mobile_D, mobile_D],
310+
gas_pressure=0,
311+
k_r0=7.94e-17,
312+
E_kr=-2,
313+
k_d0=0,
314+
E_kd=0,
315+
subdomain=inlet,
316+
)
317+
318+
surface_reaction_tt = F.SurfaceReactionBC(
319+
reactant=[mobile_T, mobile_T],
320+
gas_pressure=0,
321+
k_r0=7.94e-17,
322+
E_kr=-2,
323+
k_d0=0,
324+
E_kd=0,
325+
subdomain=inlet,
326+
)
147327

148-
# boundary conditions
328+
surface_reaction_dt = F.SurfaceReactionBC(
329+
reactant=[mobile_D, mobile_T],
330+
gas_pressure=0,
331+
k_r0=7.94e-17,
332+
E_kr=-2,
333+
k_d0=0,
334+
E_kd=0,
335+
subdomain=inlet,
336+
)
149337

150338
my_model.boundary_conditions = [
151-
F.DirichletBC(subdomain=inlet, value=1e20, species=mobile_T),
152-
F.DirichletBC(subdomain=inlet, value=1e19, species=mobile_D),
153-
F.DirichletBC(subdomain=outlet, value=0, species=mobile_T),
154-
F.DirichletBC(subdomain=outlet, value=0, species=mobile_D),
339+
surface_reaction_dd,
340+
surface_reaction_dt,
341+
surface_reaction_tt
155342
]
156343

157-
# exports
344+
############# Exports #############
158345

159-
left_flux = F.SurfaceFlux(field=mobile_T, surface=inlet)
160-
right_flux = F.SurfaceFlux(field=mobile_T, surface=outlet)
161-
162-
folder = "multi_isotope_trapping_example"
346+
folder = f'mb{mb}_results'
163347

164348
my_model.exports = [
165349
F.VTXExport(f"{folder}/mobile_concentration_t.bp", field=mobile_T),
@@ -178,19 +362,20 @@
178362
my_model.exports.append(quantity)
179363
quantities[species.name] = quantity
180364

181-
# settings
365+
############# Settings #############
182366

183367
my_model.settings = F.Settings(
184-
atol=1e-10, rtol=1e-10, max_iterations=30, final_time=3000
368+
atol=1e-15, rtol=1e-15, max_iterations=1000, final_time=3000
185369
)
186370

187371
my_model.settings.stepsize = F.Stepsize(initial_value=20)
188372

189-
# run simu
373+
############# Run Simu #############
190374

191375
my_model.initialise()
192376
my_model.run()
193377

378+
############# Results Plotting #############
194379

195380
import matplotlib.pyplot as plt
196381

@@ -217,4 +402,4 @@
217402
plt.xlabel("Time (s)")
218403
plt.ylabel("Total quantity (atoms/m2)")
219404
plt.legend()
220-
plt.show()
405+
plt.show()

0 commit comments

Comments
 (0)