Fuel pin-cell simulation

This notebook shows how ONIX can be used to run a coupled simulation of a simple fuel pin-cell. Since this model uses coupling with OpenMC, it is necessary to have OpenMC installed.

OpenMC input part

ONIX python input commands should be located just after OpenMC python commands in the same python input file. The OpenMC part of the input file is the same as the one you would use to launch an OpenMC simulation. Users should refer to OpenMC documentation for the corresponding Python API. In this example, however, the OpenMC part of the input file is included to better explain the articulation of ONIX with OpenMC.

[1]:
import openmc
import onix
---------------------------------------------------------------------------
ModuleNotFoundError                       Traceback (most recent call last)
<ipython-input-1-51377a570dec> in <module>
----> 1 import openmc
      2 import onix

ModuleNotFoundError: No module named 'openmc'

This part of the OpenMC input commands create the materials that will fill the OpenMC cells.

Important to note: since ONIX cannot handle elements but only isotopes, users should only use the command “add_nuclide” for materials that are going to be depleted by ONIX. Other materials not depleted by ONIX can use “add_element”.

[ ]:
MOX_mat = openmc.Material()
MOX_mat.set_density('atom/b-cm', density = 0.06987922652 )
MOX_mat.add_nuclide('U234', 2.5952E-7)
MOX_mat.add_nuclide('U235', 5.4287E-5)
MOX_mat.add_nuclide('U238', 2.1387E-2)
MOX_mat.add_nuclide('Pu238', 4.6610E-5)
MOX_mat.add_nuclide('Pu239', 1.0156E-3)
MOX_mat.add_nuclide('Pu240', 4.8255E-4)
MOX_mat.add_nuclide('Pu241', 1.7491E-4)
MOX_mat.add_nuclide('Pu242', 1.3201E-4)
MOX_mat.add_nuclide('O16', 4.6586E-2)

clad_mat = openmc.Material()
clad_mat.set_density('atom/b-cm', density = 0.038858703999999994 )
clad_mat.add_element('Zr',3.8657E-2)
clad_mat.add_element('Fe',1.3345E-4)
clad_mat.add_element('Cr',6.8254E-5)

mod_mat = openmc.Material()
mod_mat.set_density('atom/b-cm', density = 0.0726512136)
mod_mat.add_element('H',4.8414E-2)
mod_mat.add_nuclide('O16',2.4213E-2)
mod_mat.add_nuclide('B10', 4.7896E-6)
mod_mat.add_nuclide('B11', 1.9424E-5)
mod_mat.add_s_alpha_beta('c_H_in_H2O')

# Instantiate a Materials collection
materials_file = openmc.Materials([MOX_mat, clad_mat, mod_mat])
materials_file.cross_sections = '/home/julien/cross-sections/mcnp_endfb70/cross_sections.xml'

# Export to "materials.xml"
materials_file.export_to_xml()

The following commands define the geometry and the cells.

Important to note: ONIX requires the user to define a root cell that is named “root cell”. This root cell will be used to fill the root universe.

[ ]:
# Create cylinders for the fuel and clad
fuel_outer_radius = openmc.ZCylinder(x0=0.0, y0=0.0, R=0.410)
clad_outer_radius = openmc.ZCylinder(x0=0.0, y0=0.0, R=0.475)

# Create boundary planes to surround the geometry
min_x = openmc.XPlane(x0=-0.65635, boundary_type='reflective')
max_x = openmc.XPlane(x0=+0.65635, boundary_type='reflective')
min_y = openmc.YPlane(y0=-0.65635, boundary_type='reflective')
max_y = openmc.YPlane(y0=+0.65635, boundary_type='reflective')
min_z = openmc.ZPlane(z0=-0.65635, boundary_type='reflective')
max_z = openmc.ZPlane(z0=+0.65635, boundary_type='reflective')

# Create a Universe to encapsulate the fuel pin
pin_cell_universe = openmc.Universe(name='MOX Fuel Pin')

# Create fuel Cell
MOX_cell = openmc.Cell(name='MOX fuel')
MOX_cell.fill = MOX_mat
MOX_cell.region = -fuel_outer_radius
MOX_cell.temperature = 900
pin_cell_universe.add_cell(MOX_cell)

# Create a clad Cell
clad_cell = openmc.Cell(name='Clad')
clad_cell.fill = clad_mat
clad_cell.region = +fuel_outer_radius & -clad_outer_radius
clad_cell.temperature = 600
pin_cell_universe.add_cell(clad_cell)

# Create a moderator Cell
mod_cell = openmc.Cell(name='Mod')
mod_cell.fill = mod_mat
mod_cell.region = +clad_outer_radius
mod_cell.temperature = 600
pin_cell_universe.add_cell(mod_cell)

# Create root Cell
root_cell = openmc.Cell(name='root cell')
root_cell.fill = pin_cell_universe
root_cell.region = +min_x & -max_x & +min_y & -max_y & +min_z & -max_z

# Create root Universe
root_universe = openmc.Universe(universe_id=0, name='root universe')
root_universe.add_cell(root_cell)

# Create Geometry and set root Universe
openmc_geometry = openmc.Geometry(root_universe)

# Export to "geometry.xml"
openmc_geometry.export_to_xml()

The following commands are for the simulations settings of OpenMC.

There are no particular requirements from ONIX here so users can input these commands as they would for a normal OpenMC simulation.

[ ]:
# OpenMC simulation parameters
batches = 100
inactive = 10
particles = 10000

# Instantiate a Settings object
settings_file = openmc.Settings()
settings_file.batches = batches
settings_file.inactive = inactive
settings_file.particles = particles

# Create an initial uniform spatial source distribution over fissionable zones
bounds = [-0.65635, -0.65635, -0.65635, 0.65635, 0.65635, 0.65635]
uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:], only_fissionable=True)
settings_file.source = openmc.source.Source(space=uniform_dist)

#settings_file.temperature = {'method':'interpolation'}

# Export to "settings.xml"
settings_file.export_to_xml()

ONIX input part

This section describes the input commands for ONIX.

Defning a sequence

The first thing to define is the sequence of burnup points or time points that ONIX should follow when iterating between OpenMC simulations and depletion calculations.

We first define the macrostep vector in burnup units (MWd/kg) or time units (“s” for seconds, “m” for minutes, “d” for days, “y” for years). These points defines when OpenMC simulations update the neutron flux and reaction rates.

There is no need to define the initial point (which would be 0 in burnup or time units).

[ ]:
macrostep_vector = [0.1, 0.5, 2.5, 7.5, 15, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330, 360, 390, 420]
macrostep_unit = 'd'

We then define a vector for power of flux normalization. This vector indicates what is the value or the flux or power density to use for each macrostep. The user choose between flux and power density by defining the unit of the vector, “flux” or “power”.

The flux should be in units of \(cm^{-2}\cdot s^{-1}\), the power should be in units of \(kW/l\).

Important to note: the power density is the total power of the system divided by the total volume of the system, including non-nuclear elements such as moderator, cladding etc.

[ ]:
norma_vector = [108.93]*len(macrostep_vector)
norma_unit = 'power'

The last element of the sequence object that we need to define is the number of microsteps within each macrostep. Below, we indicate to ONIX that there should be 3 microsteps that divide each and every macrosteps.

[ ]:
microstep_vector = [3]*len(macrostep_vector)

We then instantiate a sequence object and fill it with the vectors we defined above.

Important to note: since ONIX enables the user to define multiple sequence objects within one input file, the user needs to associate each sequence object with a number id as below.

[ ]:
sequence1 = onix.Sequence(1)
sequence1.set_macrostep(macrostep_vector, macrostep_unit)
sequence1.set_norma(norma_vector, norma_unit)
sequence1.microstep_vector = microstep_vector

Finally, we need to define the way ONIX approximate the neutron flux for each microstep. In the current version, the only option is to take the initial value (‘iv’) of the flux for the microstep.

[ ]:
sequence1.flux_approximation ='iv'

Coupling with OpenMC

Once the sequence objects are defined, we can import parameters from OpenMC to construct ONIX depletion systems

We first need to instantiate a couple object. This object will operate all communication between OpenMC and ONIX.

[ ]:
couple = onix.couple.Couple_openmc()

ONIX will run a dummy OpenMC volume simulation. Because this “pre run” simulation calculates volumes, it is necessary to provide a bounding box to ONIX.

Important to note: ONIX can use the volume provided by this simulation for the burnup regions that the user wants to deplete. However, due to non-negligible errors in the stochastic volume calculation of OpenMC, it is recommended

[ ]:
couple.set_bounding_box([-0.65635, -0.65635, -0.65635], [0.65635, 0.65635, 0.65635])

[Optional]: simulations on HPC clusters require to explicitly define the path to the OpenMC executable in the openmc.run() command. The user should indicate the path to OpenMC executable to ONIX with the following command:

[ ]:
couple.openmc_bin_path = '/home/julien/virtualenvs/py3/bin/openmc'

The user can select which OpenMC cells will be depleted by adding the names of the cell objects defined above in the command below. Cells that are selected for depletion are called BUCells in ONIX.

[ ]:
couple.select_bucells([MOX_cell])

The following command indicate to ONIX which OpenMC cell is the root cell. ONIX will use this cell to extract information on OpenMC materials and cells.

[ ]:
couple.import_openmc(root_cell)

[Optional] By default, ONIX will use ENDF/B-VIII.0 libraries for decay and fission yields data. If users want to use other libraries, they can use the following commands:

Important to note: if users want to complement the fission yield data library they are defining with the data from ENDF/B-VIII.0, they should set the complete parameter to True in the set_user_fy_lib command.

[ ]:
couple.set_decay_lib('/home/julien/ONIX/ONIX/onix/data/other_libs/origen2.2/decay_lib')
couple.set_user_fy_lib('/home/julien/ONIX/ONIX/onix/data/other_libs/origen2.2/fy_lib', complete=True)

As explained above, OpenMC volume calculations are not always reliable, especially for complex geometry. The user can dedice to manually set volumes for each BUCell.

[ ]:
vol_dict = {'MOX fuel': 0.69323, 'total volume':2.26197}
couple.set_vol(vol_dict)

Now we can indicate to the couple object which sequence it should use for the simulation.

[ ]:
couple.set_sequence(sequence1)

We can finally ask ONIX to burn the system and launch the coupled simulation

[ ]:
couple.burn()

Output results are going to be located in two types of folder. Per step folders include densities, power, neutron flux, burnup, one-group cross sections and burnup matrices for each macrostep, separately. The output summary folder contains aggregated output results for the whole simulation and for every macrostep.