Tallies in OpenMC

Understanding Tallies

Now that we understand how to create geometry and run simulations, we need to extract useful information from our model. Tallies are OpenMC's way of scoring quantities of interest during the simulation.

Key Concepts

  • Filters: Define where to collect data (cells, materials, energy ranges)
  • Scores: Specify what to measure (flux, reaction rates, energy deposition)
  • Estimators: Determine how to collect data (track-length, collision, analog)

Basic Tally Setup

Let's start with a simple example using the geometry and materials we created earlier:

Example: Fuel Pin Flux

python
# Create a basic tally
tally = openmc.Tally(name='fuel_flux')

# Where to tally (in the fuel cell we created)
fuel_filter = openmc.CellFilter([fuel_cell])
tally.filters = [fuel_filter]

# What to tally (neutron flux)
tally.scores = ['flux']

# Add to tallies collection
tallies = openmc.Tallies([tally])

# Export with your model
model = openmc.Model(geometry, materials, settings, tallies)

Note: Tallies don't affect the physics of your simulation - they just collect data as particles travel through your geometry.

Tally Basics

Components

  • Filters: Where to tally
  • Scores: What to tally
  • Nuclides: Which isotopes
  • Estimator: How to tally

Common Scores

  • flux: Particle flux
  • fission: Fission rate
  • absorption: Absorption rate
  • scatter: Scattering rate
  • heating: Energy deposition

Basic Example

python
# Create a basic tally
tally = openmc.Tally(name='fuel_tally')

# Add filters (where to tally)
tally.filters = [
    openmc.CellFilter([fuel_cell]),      # In fuel cell
    openmc.EnergyFilter([0.0, 20.0e6])   # Full energy range
]

# Add scores (what to tally)
tally.scores = ['flux', 'fission']

# Add to collection
tallies = openmc.Tallies([tally])
tallies.export_to_xml()

Filter Types

Spatial Filters

python
# Cell and material filters
cell_filter = openmc.CellFilter([fuel_cell])
mat_filter = openmc.MaterialFilter([fuel_mat])

# Mesh filter
mesh = openmc.RegularMesh()
mesh.dimension = [10, 10, 10]
mesh.lower_left = [-50, -50, -50]
mesh.upper_right = [50, 50, 50]
mesh_filter = openmc.MeshFilter(mesh)

Energy and Time Filters

python
# Energy groups
energies = [0.0, 0.625, 1e6, 20e6]  # eV
energy_filter = openmc.EnergyFilter(energies)

# Time bins
times = [0.0, 1e-6, 1e-5]  # seconds
time_filter = openmc.TimeFilter(times)

Angular Filters

python
import numpy as np

# Polar angles (5 bins)
polar_bins = np.linspace(0.0, np.pi, 6)
polar = openmc.PolarFilter(polar_bins)

# Azimuthal angles (8 bins)
azimuthal_bins = np.linspace(-np.pi, np.pi, 9)
azimuthal = openmc.AzimuthalFilter(azimuthal_bins)

Note: Each filter adds a dimension to the tally results. Use only the filters you need to avoid memory issues and slow convergence.

Advanced Features

Specific Reactions

python
# Common MT numbers
tally.scores = [
    'elastic',     # MT2
    '(n,gamma)',   # MT102
    '(n,p)',      # MT103
    '(n,alpha)',   # MT107
]

Nuclide Tallies

python
# Tally by nuclide
tally.nuclides = ['U235', 'U238']
tally.scores = ['fission', 'absorption']

# All nuclides
tally.nuclides = ['total']

Derived Tallies

python
# Reaction rate ratio (conversion ratio)
tally1 = openmc.Tally(name='u238_capture')
tally1.filters = [openmc.CellFilter([fuel_cell])]
tally1.nuclides = ['U238']
tally1.scores = ['(n,gamma)']

tally2 = openmc.Tally(name='u235_fission')
tally2.filters = [openmc.CellFilter([fuel_cell])]
tally2.nuclides = ['U235']
tally2.scores = ['fission']

# After running:
sp = openmc.StatePoint('statepoint.h5')
t1 = sp.get_tally(name='u238_capture')
t2 = sp.get_tally(name='u235_fission')
ratio = t1.mean / t2.mean

Results Analysis

After your simulation runs, you can analyze tally results using the same StatePoint interface we learned about in the Results section:

Processing Results

python
# Load results (from previous section)
sp = openmc.StatePoint('statepoint.h5')
tally = sp.get_tally(name='fuel_flux')

# Basic statistics
mean_flux = tally.mean           # Average flux
rel_error = tally.std_dev / tally.mean  # Relative uncertainty

# Convert to pandas DataFrame for analysis
df = tally.get_pandas_dataframe()

# Example analysis
import matplotlib.pyplot as plt
plt.figure()
plt.errorbar(df.index, df['mean'], 
            yerr=df['std. dev.'],
            fmt='o', capsize=5)
plt.xlabel('Tally bin')
plt.ylabel('Flux (n/cm²/src)')
plt.grid(True)
plt.show()

Additional Resources