CAD integration#
Objectives
Learn how to run CAD-based simulations.
Convert a mesh from SALOME to XDMF using
meshioRun a 3D simulation
Our example case will be a 3D ITER-like monoblock made of three different materials (tungsten, cucrzr, and copper).
For this example, the mesh was created with SALOME but other meshing software can be used like GMSH.
Using meshio, the mesh file (here a .med file) can be converted to .xdmf format, readable by FESTIM.
We wrote the following function convert_med_to_xdmf to convert .med files to .xdmf.
import meshio
def convert_med_to_xdmf(
med_file,
cell_file="mesh_domains.xdmf",
facet_file="mesh_boundaries.xdmf",
cell_type="tetra",
facet_type="triangle",
):
"""Converts a MED mesh to XDMF
Args:
med_file (str): the name of the MED file
cell_file (str, optional): the name of the file containing the
volume markers. Defaults to "mesh_domains.xdmf".
facet_file (str, optional): the name of the file containing the
surface markers.. Defaults to "mesh_boundaries.xdmf".
cell_type (str, optional): The topology of the cells. Defaults to "tetra".
facet_type (str, optional): The topology of the facets. Defaults to "triangle".
Returns:
dict, dict: the correspondance dict, the cell types
"""
msh = meshio.read(med_file)
correspondance_dict = msh.cell_tags
cell_data_types = msh.cell_data_dict["cell_tags"].keys()
for mesh_block in msh.cells:
if mesh_block.type == cell_type:
meshio.write_points_cells(
cell_file,
msh.points,
[mesh_block],
cell_data={"f": [-1 * msh.cell_data_dict["cell_tags"][cell_type]]},
)
elif mesh_block.type == facet_type:
meshio.write_points_cells(
facet_file,
msh.points,
[mesh_block],
cell_data={"f": [-1 * msh.cell_data_dict["cell_tags"][facet_type]]},
)
return correspondance_dict, cell_data_types
The subdomains (volumes and surfaces) in the .med file were given tags.
This is very important to be able to assign materials properties and boundary conditions to these subdomains.
The correspondance between tags and subdomains is returned by convert_med_to_xdmf.
Here for example, the volume corresponding to tungsten is the tag 6.
correspondance_dict, cell_data_types = convert_med_to_xdmf("task08/mesh.med", cell_file="task08/mesh_domains.xdmf", facet_file="task08/mesh_boundaries.xdmf")
print(correspondance_dict)
{np.int64(-6): ['tungsten'], np.int64(-7): ['cu'], np.int64(-8): ['cucrzr'], np.int64(-9): ['top_surface'], np.int64(-10): ['cooling_surface'], np.int64(-11): ['poloidal_gap'], np.int64(-12): ['toroidal_gap'], np.int64(-13): ['bottom']}
The converted .xdmf files can then be imported in FESTIM using the MeshFromXDMF class:
import festim as F
my_model = F.Simulation()
my_model.mesh = F.MeshFromXDMF(volume_file="task08/mesh_domains.xdmf", boundary_file="task08/mesh_boundaries.xdmf")
Succesfully load mesh with 106966 cells
Using the tags provided by correspondance_dict, we can create materials and assign them to the simulation:
tungsten = F.Material(
id=6,
D_0=4.1e-7,
E_D=0.39,
S_0=1.87e24,
E_S=1.04,
thermal_cond=100,
)
copper = F.Material(
id=7,
D_0=6.6e-7,
E_D=0.387,
S_0=3.14e24,
E_S=0.572,
thermal_cond=350,
)
cucrzr = F.Material(
id=8,
D_0=3.92e-7,
E_D=0.418,
S_0=4.28e23,
E_S=0.387,
thermal_cond=350
)
my_model.materials = [tungsten, copper, cucrzr]
Similarily, the surface tags are used to create boundary conditions:
heat_flux_top = F.FluxBC(surfaces=9, value=10e6, field="T")
convective_flux_coolant = F.ConvectiveFlux(surfaces=10, h_coeff=7e04, T_ext=323)
implantation_flux_top = F.ImplantationDirichlet(surfaces=9, phi=1.61e22, R_p=9.52e-10, D_0=tungsten.D_0, E_D=tungsten.E_D)
recombination_flux = F.DirichletBC(surfaces=[10, 11, 12, 13], value=0, field=0)
my_model.boundary_conditions = [heat_flux_top, convective_flux_coolant, implantation_flux_top, recombination_flux]
We will solve a steady state heat transfer problem:
my_model.T = F.HeatTransferProblem(transient=False)
Finally, we add the settings (with chemical_pot=True to account for conservation of chemical potential) and we export the temperature and mobile concentration to XDMF.
my_model.settings = F.Settings(
absolute_tolerance=1e10,
relative_tolerance=1e-10,
transient=False,
chemical_pot=True
)
results_folder = "task08"
my_model.exports = [F.XDMFExport("T", folder=results_folder), F.XDMFExport("solute", folder=results_folder)]
my_model.initialise()
my_model.run()
Post processing#
The recommended way of plotting 3D fields is to export them to XDMF using XDMFExport, download the .xdmf file and open it in Paraview.
This is what the fields look like in Paraview: