Materials in OpenMC

Understanding Materials

Materials in OpenMC represent the physical substances in your reactor model. Each material needs a composition (what nuclides it contains) and a density. OpenMC uses this information to calculate how neutrons interact with the material.

The basic workflow is simple: create a material object, set its density, add nuclides or elements, and optionally add thermal scattering data. Temperature is set on cells, not on materials.

python
import openmc

# Basic UO2 fuel - the essential components
fuel = openmc.Material(name='UO2 Fuel')
fuel.set_density('g/cm3', 10.4)
fuel.add_nuclide('U235', 0.045)        # 4.5% enriched uranium
fuel.add_nuclide('U238', 0.955)        # Depleted uranium  
fuel.add_element('O', 2.0)             # Stoichiometric oxygen

# Light water with thermal scattering
water = openmc.Material(name='Light Water')
water.set_density('g/cm3', 1.0)
water.add_nuclide('H1', 2.0)
water.add_element('O', 1.0)
water.add_s_alpha_beta('c_H_in_H2O')   # Critical for neutron thermalization

# Structural material
zirc = openmc.Material(name='Zircaloy-4')
zirc.set_density('g/cm3', 6.55)
zirc.add_element('Zr', 0.982)
zirc.add_element('Sn', 0.015)
zirc.add_element('Fe', 0.002)
zirc.add_element('Cr', 0.001)

print(f"Fuel density: {fuel.density} g/cm³")
print(f"Water contains {len(water.nuclides)} nuclides")

Tutorial snippet — no separate file in examples repo

Practical Material Examples

PWR Materials

python
# Standard PWR UO2 fuel pellet
fuel = openmc.Material(name='PWR UO2 Fuel')
fuel.set_density('g/cm3', 10.4)
fuel.add_nuclide('U235', 0.04)         # 4% enrichment
fuel.add_nuclide('U238', 0.96)
fuel.add_element('O', 2.0)
# Temperature is set via cell.temperature, not on materials

# Zircaloy-4 cladding with realistic composition
clad = openmc.Material(name='Zircaloy-4 Cladding')
clad.set_density('g/cm3', 6.55)
clad.add_element('Zr', 0.982)
clad.add_element('Sn', 0.015)
clad.add_element('Fe', 0.002)
clad.add_element('Cr', 0.001)

# Borated water moderator (typical PWR conditions)
moderator = openmc.Material(name='Borated Water')
moderator.set_density('g/cm3', 0.7)    # Hot, pressurized water
moderator.add_nuclide('H1', 2.0)
moderator.add_element('O', 1.0)
moderator.add_nuclide('B10', 0.00002)  # 1000 ppm boron
moderator.add_nuclide('B11', 0.00008)
moderator.add_s_alpha_beta('c_H_in_H2O')
# Temperature is set via cell.temperature, not on materials

# Structural steel (for reactor internals)
steel = openmc.Material(name='Stainless Steel 316')
steel.set_density('g/cm3', 8.0)
steel.add_element('Fe', 0.68, 'wo')     # Weight fractions
steel.add_element('Ni', 0.12, 'wo')
steel.add_element('Cr', 0.17, 'wo')
steel.add_element('Mo', 0.025, 'wo')
steel.add_element('Mn', 0.02, 'wo')

Tutorial snippet — no separate file in examples repo

Advanced Fuel Types

python
# MOX fuel (mixed oxide with plutonium)
mox_fuel = openmc.Material(name='MOX Fuel')
mox_fuel.set_density('g/cm3', 10.8)
mox_fuel.add_nuclide('U235', 0.002)    # Depleted uranium
mox_fuel.add_nuclide('U238', 0.948)
mox_fuel.add_nuclide('Pu239', 0.04)    # 4% fissile Pu-239
mox_fuel.add_nuclide('Pu240', 0.01)
mox_fuel.add_element('O', 2.0)

# TRISO fuel particles (for advanced reactors)
triso_fuel = openmc.Material(name='TRISO Fuel Kernel')
triso_fuel.set_density('g/cm3', 10.5)
triso_fuel.add_nuclide('U235', 0.15)   # Highly enriched
triso_fuel.add_nuclide('U238', 0.85)
triso_fuel.add_element('C', 1.0)       # UC kernel
# Temperature is set via cell.temperature, not on materials

# Graphite moderator (for HTGR)
graphite = openmc.Material(name='Nuclear Graphite')
graphite.set_density('g/cm3', 1.7)
graphite.add_element('C', 1.0)
graphite.add_s_alpha_beta('c_Graphite')
# Temperature is set via cell.temperature, not on materials

Tutorial snippet — no separate file in examples repo

Working with Material Collections

OpenMC requires all materials to be collected into a Materials object before running a simulation. This collection also provides useful methods for validation and manipulation.

python
# Create a complete materials collection
materials = openmc.Materials([fuel, clad, moderator, steel])

# Useful material collection methods
print(f"Total materials: {len(materials)}")
print(f"Material names: {[mat.name for mat in materials]}")

# Find materials by name
fuel_mat = next(m for m in materials if m.name == 'PWR UO2 Fuel')
print(f"Found material: {fuel_mat.name}")

# Export for use in OpenMC (performs validation)
materials.export_to_xml()

# You can also modify materials after creation
fuel.add_nuclide('Gd155', 0.001)      # Add burnable absorber
print("Added gadolinium to fuel")

Tutorial snippet — no separate file in examples repo

Advanced Material Features

Material Mixtures

python
# Control rod material (B4C with steel cladding)
b4c = openmc.Material(name='Boron Carbide')
b4c.set_density('g/cm3', 2.5)
b4c.add_nuclide('B10', 0.8)
b4c.add_nuclide('B11', 0.2)
b4c.add_element('C', 1.0)

# Create control rod mixture
control_rod = openmc.Material.mix_materials(
    materials=[b4c, steel],
    fracs=[0.8, 0.2],
    percent_type='vo'              # 'vo' = volume, 'wo' = weight
)
control_rod.name = 'Control Rod'

# Note: mix_materials does not support materials that
# contain S(alpha,beta) thermal scattering data.
# To mix a moderator with fuel, omit add_s_alpha_beta
# from the moderator before mixing, or model the
# regions with separate cells instead.

Tutorial snippet — no separate file in examples repo

Depletion Setup

python
# Temperature is a cell property, not a material property.
# Set it when creating cells:
#   fuel_cell = openmc.Cell(fill=fuel, region=region)
#   fuel_cell.temperature = 900  # Kelvin

# Material set up for depletion calculations
depleting_fuel = openmc.Material(name='Depleting Fuel')
depleting_fuel.set_density('g/cm3', 10.4)
depleting_fuel.add_nuclide('U235', 0.045)
depleting_fuel.add_nuclide('U238', 0.955)
depleting_fuel.add_element('O', 2.0)
depleting_fuel.depletable = True         # Enable depletion tracking
depleting_fuel.volume = 100.0            # cm³ (required for depletion)

print(f"Material can be depleted: {depleting_fuel.depletable}")
print(f"Material volume: {depleting_fuel.volume} cm³")

Tutorial snippet — no separate file in examples repo

Common Mistakes and Tips

Here are the most common material definition errors and how to avoid them:

Don't Forget to Set Density

python
# Wrong - missing density entirely
material = openmc.Material()
material.add_nuclide('U235', 0.05)
# No density set — OpenMC will raise an error at export/runtime

# Correct - always set density (order doesn't matter at the Python level)
material = openmc.Material()
material.add_nuclide('U235', 0.05)
material.set_density('g/cm3', 10.4)

Tutorial snippet — no separate file in examples repo

Use Realistic Values

python
# Check your material densities against references
# UO2 fuel: 10.4 g/cm³ (theoretical density)
# Zircaloy: 6.55 g/cm³
# Water (20°C): 1.0 g/cm³, (300°C): ~0.7 g/cm³
# Steel: 7.8-8.0 g/cm³

# Always add thermal scattering for light materials
water.add_s_alpha_beta('c_H_in_H2O')     # Essential for water
# Available S(α,β) tables: c_H_in_H2O, c_Graphite, c_Be, etc.

# Set temperatures on cells, not materials (in Kelvin)
# cell.temperature = 600  # 327°C
# Room temperature = 293 K, PWR operating = 580 K

Tutorial snippet — no separate file in examples repo

Use well-established reference values and validate your materials collection before running calculations.