Solution#

Here you will find the solution for the challenge B.

Two traps are needed to reproduce the TDS spectra and the NRA profiles.

The first peak on the TDS correspond to an intrinsic trap (homogeneously distributed) while the second peak correspond to a trap induced by the heavy ion damaged, only present in the first micron.

For this TDS, we used the diffusivity obtained by Frauenfelder but the one from Holzner could be used too.

import festim as F
import sympy as sp
import numpy as np
import h_transport_materials as htm

implantation_time = 2000  # s
temperature_ramp = 4  # K/s
storage_time = 50  # s
storage_temp = 300  # K
start_tds = implantation_time + storage_time  # s

exposure_temps = [300, 400, 500]


def festim_model(T_exp):
    """Runs a festim model and returns the derived quantities

    Args:
        T_exp (float): exposure temperature in K

    Returns:
        F.DerivedQuantities: the derived quantities
    """
    my_model = F.Simulation()

    vertices = np.concatenate(
        [
            np.linspace(0, 30e-9, num=100),
            np.linspace(30e-9, 3e-6, num=200),
            np.linspace(3e-6, 5e-6, num=200),
            np.linspace(5e-6, 20e-6, num=200),
        ]
    )

    my_model.mesh = F.MeshFromVertices(vertices)


    frauenfelder_diff = htm.diffusivities.filter(material=htm.TUNGSTEN, author="frauenfelder")[0]
    tungsten = F.Material(
        id=1,
        D_0=frauenfelder_diff.pre_exp.magnitude,  # m2/s
        E_D=frauenfelder_diff.act_energy.magnitude,  # eV
    )

    my_model.materials = tungsten

    incident_flux = 5e19  # H/m2/s
    reflection_coeff = 0.5
    implanted_flux = incident_flux * (1 - reflection_coeff)
    ion_flux = sp.Piecewise((implanted_flux, F.t <= implantation_time), (0, True))

    source_term = F.ImplantationFlux(
        flux=ion_flux, imp_depth=5e-9, width=2.1e-9, volume=1  # H/m2/s  # m  # m
    )

    my_model.sources = [source_term]

    w_atom_density = 6.3e28  # atom/m3

    trap_1 = F.Trap(
        k_0=tungsten.D_0 / (1.1e-10**2 * 6 * w_atom_density),
        E_k=tungsten.E_D,
        p_0=1e13,
        E_p=0.87,
        density=1e-3 * w_atom_density,
        materials=tungsten,
    )

    trap_2_distrib = sp.Piecewise((1, F.x < 1e-6), (0, True))
    trap_2 = F.Trap(
        k_0=tungsten.D_0 / (1.1e-10**2 * 6 * w_atom_density),
        E_k=tungsten.E_D,
        p_0=1e13,
        E_p=1.2,
        density=4e-4 * w_atom_density * trap_2_distrib,
        materials=tungsten,
    )

    my_model.traps = [trap_1, trap_2]

    my_model.boundary_conditions = [F.DirichletBC(surfaces=[1, 2], value=0, field=0)]

    my_model.T = F.Temperature(
        value=sp.Piecewise(
            (T_exp, F.t <= implantation_time),
            (storage_temp, F.t <= start_tds),
            (storage_temp + temperature_ramp * (F.t - start_tds), True),
        )
    )

    my_model.settings = F.Settings(
        absolute_tolerance=1e10,
        relative_tolerance=1e-10,
        final_time=implantation_time + storage_time + 100,
        traps_element_type="DG",
    )

    list_of_derived_quantities = [
        F.TotalVolume("solute", volume=1),
        F.TotalVolume("retention", volume=1),
        F.TotalVolume("1", volume=1),
        F.TotalVolume("2", volume=1),
        F.AverageVolume("T", volume=1),
        F.HydrogenFlux(surface=1),
        F.HydrogenFlux(surface=2),
    ]

    derived_quantities = F.DerivedQuantities(
        list_of_derived_quantities,
        show_units=True,
        filename=f"{T_exp}_K/derived_quantities.csv",
    )

    txt_exports = [
        F.TXTExport(
            filename=f"{T_exp}_K/retention.txt", field="retention", times=[start_tds]
        ),
        F.TXTExport(filename=f"{T_exp}_K/trap_1.txt", field="1", times=[start_tds]),
        F.TXTExport(filename=f"{T_exp}_K/trap_2.txt", field="2", times=[start_tds]),
    ]

    my_model.exports = [derived_quantities] + txt_exports

    def max_stepsize(t):
        if t >= start_tds:
            return 1
        elif implantation_time <= t <= start_tds:
            return 10
        else:
            return None

    my_model.dt = F.Stepsize(
        initial_value=0.5,
        stepsize_change_ratio=1.1,
        max_stepsize=max_stepsize,
        dt_min=1e-05,
        milestones=[implantation_time, start_tds],
    )

    my_model.initialise()
    my_model.run()
    return derived_quantities
---------------------------------------------------------------------------
ModuleNotFoundError                       Traceback (most recent call last)
Cell In[1], line 4
      1 import festim as F
      2 import sympy as sp
      3 import numpy as np
----> 4 import h_transport_materials as htm
      5 
      6 implantation_time = 2000  # s
      7 temperature_ramp = 4  # K/s

File ~/checkouts/readthedocs.org/user_builds/festim-workshop/conda/festim1/lib/python3.11/site-packages/h_transport_materials/__init__.py:25
     22 Rg = 8.314 * ureg.Pa * ureg.m**3 * ureg.mol**-1 * ureg.K**-1
     23 avogadro_nb = 6.022e23 * ureg.particle * ureg.mol**-1
---> 25 from pybtex.database import parse_file
     26 from pathlib import Path
     28 bib_database = parse_file(str(Path(__file__).parent) + "/references.bib")

File ~/checkouts/readthedocs.org/user_builds/festim-workshop/conda/festim1/lib/python3.11/site-packages/pybtex/database/__init__.py:44
     42 from pybtex.errors import report_error
     43 from pybtex.py3compat import fix_unicode_literals_in_doctest, python_2_unicode_compatible
---> 44 from pybtex.plugin import find_plugin
     47 # for python2 compatibility
     48 def indent(text, prefix):

File ~/checkouts/readthedocs.org/user_builds/festim-workshop/conda/festim1/lib/python3.11/site-packages/pybtex/plugin/__init__.py:26
      2 # Copyright (c) 2006-2021  Andrey Golovizin
      3 # Copyright (c) 2014  Matthias C. M. Troffaes
      4 #
   (...)     21 # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     22 # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     25 import os.path  # splitext
---> 26 import pkg_resources
     28 from pybtex.exceptions import PybtexError
     31 class Plugin(object):

ModuleNotFoundError: No module named 'pkg_resources'

Results#

Note: we have to change the filepath here because we are now in a child directory.

import numpy as np
import matplotlib.pyplot as plt


def plot_experimental_tds(T_exp, **kwargs):
    data = np.genfromtxt(
        f"../challenge_B/{T_exp}_K/tds.txt", skip_header=1, delimiter=","
    )
    flux = data[:, -1]
    tds_T = data[:, 1]
    return plt.plot(tds_T, flux, **kwargs)


def plot_nra_profile(T_exp, **kwargs):
    data = np.genfromtxt(
        f"../challenge_B/{T_exp}_K/retention_profile.txt", skip_header=1, delimiter=","
    )
    depth = data[:, 0]
    nra = data[:, 1]
    return plt.step(depth, nra, **kwargs)

def plot_simulated_tds(derived_quantities, **kwargs):
    """Function to plot a simulated TDS spectrum

    Args:
        derived_quantities (festim.DerivedQuantities): the derived quantities object from the simulation.
            Assumes we have an AverageVolume(field="T") and two SurfaceFluxe(fields="solute") for surfaces 1 and 2.
        **kwargs: keyword arguments to be passed to the plot function.
    """
    if derived_quantities == []:

        return
    t = np.array(derived_quantities.t)
    indexes = np.where(t >= start_tds)[0]
    temp = np.array(derived_quantities.filter(fields="T").data)
    flux_left = np.array(derived_quantities.filter(fields="solute", surfaces=1).data)
    flux_right = np.array(derived_quantities.filter(fields="solute", surfaces=2).data)

    flux_total = -flux_left - flux_right

    temp = temp[indexes]
    flux_total = flux_total[indexes]
    t = t[indexes]

    return plt.plot(temp, flux_total, **kwargs)


def plot_simulated_profile(filename: str = "", **kwargs):
    if filename == "":
        return
    data_retention = np.genfromtxt(filename, delimiter=",", skip_header=1)
    return plt.plot(data_retention[:, 0], data_retention[:, 1], **kwargs)

Let’s run the model for the three exposure temperatures

T_exp_to_derived_quantities = {}

for T_exp in exposure_temps:
    print("---------------------")
    print(f"Running for {T_exp} K")
    derived_quantities = festim_model(T_exp)
    T_exp_to_derived_quantities[T_exp] = derived_quantities
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[3], line 3
      1 T_exp_to_derived_quantities = {}
      2 
----> 3 for T_exp in exposure_temps:
      4     print("---------------------")
      5     print(f"Running for {T_exp} K")
      6     derived_quantities = festim_model(T_exp)

NameError: name 'exposure_temps' is not defined
for T_exp in exposure_temps:

    derived_quantities = T_exp_to_derived_quantities[T_exp]

    plt.figure(1)
    (l,) = plot_experimental_tds(
        T_exp, label=f"T_exp = {T_exp} K - exp", linestyle="dashed"
    )
    plot_simulated_tds(
        derived_quantities=derived_quantities,
        color=l.get_color(),
        label=f"FESTIM",
        marker="o",
        alpha=0.3,
        linestyle="None",
    )

    plt.figure(2)
    filename = f"{T_exp}_K/retention.txt"
    (l,) = plot_nra_profile(
        T_exp, label=f"T_exp = {T_exp} K - exp", linestyle="dashed", marker="o"
    )
    plot_simulated_profile(filename, color=l.get_color(), label=f"FESTIM")

plt.figure(1)
plt.title("TDS spectra")
plt.xlabel("Temperature (K)")
plt.ylabel("Flux (D/m2/s)")
plt.legend()

plt.figure(2)
plt.title("Retention profiles")
plt.xlabel("x (m)")
plt.ylabel("Retention (H/m3)")
plt.legend()
plt.show()
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[4], line 1
----> 1 for T_exp in exposure_temps:
      2 
      3     derived_quantities = T_exp_to_derived_quantities[T_exp]
      4 

NameError: name 'exposure_temps' is not defined

Generate dummy data for challenge#

for T_exp in exposure_temps:
    data_retention = np.genfromtxt(
        f"{T_exp}_K/retention.txt", delimiter=",", skip_header=1
    )

    # sample a few points on the retention profile
    sample_points = np.linspace(0, 3e-6, num=8)
    sample_points = np.append(sample_points, 5e-6)
    sample_points_retention = np.interp(
        sample_points, data_retention[:, 0], data_retention[:, 1]
    )

    # dump sample_points and sample_points_retention to file with header
    np.savetxt(
        f"../challenge_B/{T_exp}_K/retention_profile.txt",
        np.column_stack((sample_points, sample_points_retention)),
        header="x (m), retention (H/m3)",
        comments="",
        delimiter=",",
    )
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[5], line 1
----> 1 for T_exp in exposure_temps:
      2     data_retention = np.genfromtxt(
      3         f"{T_exp}_K/retention.txt", delimiter=",", skip_header=1
      4     )

NameError: name 'exposure_temps' is not defined
def save_tds(derived_quantities, filename):
    t = np.array(derived_quantities.t)
    indexes = np.where(t >= start_tds)[0]
    temp = np.array(derived_quantities.filter(fields="T").data)
    flux_left = np.array(derived_quantities.filter(fields="solute", surfaces=1).data)
    flux_right = np.array(derived_quantities.filter(fields="solute", surfaces=2).data)

    flux_total = -flux_left - flux_right

    temp = temp[indexes]
    flux_total = flux_total[indexes]
    t = t[indexes]

    np.savetxt(
        filename,
        np.column_stack((t, temp, flux_total)),
        header="t (s), T (K), flux (H/m2/s)",
        delimiter=",",
        comments="",
    )


for T_exp in exposure_temps:
    derived_quantities = T_exp_to_derived_quantities[T_exp]
    save_tds(derived_quantities, f"../challenge_B/{T_exp}_K/tds.txt")
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[6], line 23
     19         comments="",
     20     )
     21 
     22 
---> 23 for T_exp in exposure_temps:
     24     derived_quantities = T_exp_to_derived_quantities[T_exp]
     25     save_tds(derived_quantities, f"../challenge_B/{T_exp}_K/tds.txt")

NameError: name 'exposure_temps' is not defined