This IPython Notebook introduces the use of the openmc.mgxs module to calculate multi-group cross sections for an infinite homogeneous medium. In particular, this Notebook introduces the the following features:

  • General equations for scalar-flux averaged multi-group cross sections
  • Creation of multi-group cross sections for an infinite homogeneous medium
  • Use of tally arithmetic to manipulate multi-group cross sections

Note: This Notebook illustrates the use of Pandas DataFrames to containerize multi-group cross section data. We recommend using Pandas >v0.15.0 or later since OpenMC's Python API leverages the multi-indexing feature included in the most recent releases of Pandas.

Introduction to Multi-Group Cross Sections (MGXS)

Many Monte Carlo particle transport codes, including OpenMC, use continuous-energy nuclear cross section data. However, most deterministic neutron transport codes use multi-group cross sections defined over discretized energy bins or energy groups. An example of U-235's continuous-energy fission cross section along with a 16-group cross section computed for a light water reactor spectrum is displayed below.


In [1]:
from IPython.display import Image
Image(filename='images/mgxs.png', width=350)


Out[1]:

A variety of tools employing different methodologies have been developed over the years to compute multi-group cross sections for certain applications, including NJOY (LANL), MC$^2$-3 (ANL), and Serpent (VTT). The openmc.mgxs Python module is designed to leverage OpenMC's tally system to calculate multi-group cross sections with arbitrary energy discretizations for fine-mesh heterogeneous deterministic neutron transport applications.

Before proceeding to illustrate how one may use the openmc.mgxs module, it is worthwhile to define the general equations used to calculate multi-group cross sections. This is only intended as a brief overview of the methodology used by openmc.mgxs - we refer the interested reader to the large body of literature on the subject for a more comprehensive understanding of this complex topic.

Introductory Notation

The continuous real-valued microscopic cross section may be denoted $\sigma_{n,x}(\mathbf{r}, E)$ for position vector $\mathbf{r}$, energy $E$, nuclide $n$ and interaction type $x$. Similarly, the scalar neutron flux may be denoted by $\Phi(\mathbf{r},E)$ for position $\mathbf{r}$ and energy $E$. Note: Although nuclear cross sections are dependent on the temperature $T$ of the interacting medium, the temperature variable is neglected here for brevity.

Spatial and Energy Discretization

The energy domain for critical systems such as thermal reactors spans more than 10 orders of magnitude of neutron energies from 10$^{-5}$ - 10$^7$ eV. The multi-group approximation discretization divides this energy range into one or more energy groups. In particular, for $G$ total groups, we denote an energy group index $g$ such that $g \in \{1, 2, ..., G\}$. The energy group indices are defined such that the smaller group the higher the energy, and vice versa. The integration over neutron energies across a discrete energy group is commonly referred to as energy condensation.

Multi-group cross sections are computed for discretized spatial zones in the geometry of interest. The spatial zones may be defined on a structured and regular fuel assembly or pin cell mesh, an arbitrary unstructured mesh or the constructive solid geometry used by OpenMC. For a geometry with $K$ distinct spatial zones, we designate each spatial zone an index $k$ such that $k \in \{1, 2, ..., K\}$. The volume of each spatial zone is denoted by $V_{k}$. The integration over discrete spatial zones is commonly referred to as spatial homogenization.

General Scalar-Flux Weighted MGXS

The multi-group cross sections computed by openmc.mgxs are defined as a scalar flux-weighted average of the microscopic cross sections across each discrete energy group. This formulation is employed in order to preserve the reaction rates within each energy group and spatial zone. In particular, spatial homogenization and energy condensation are used to compute the general multi-group cross section $\sigma_{n,x,k,g}$ as follows:

$$\sigma_{n,x,k,g} = \frac{\int_{E_{g}}^{E_{g-1}}\mathrm{d}E'\int_{\mathbf{r} \in V_{k}}\mathrm{d}\mathbf{r}\sigma_{n,x}(\mathbf{r},E')\Phi(\mathbf{r},E')}{\int_{E_{g}}^{E_{g-1}}\mathrm{d}E'\int_{\mathbf{r} \in V_{k}}\mathrm{d}\mathbf{r}\Phi(\mathbf{r},E')}$$

This scalar flux-weighted average microscopic cross section is computed by openmc.mgxs for most multi-group cross sections, including total, absorption, and fission reaction types. These double integrals are stochastically computed with OpenMC's tally system - in particular, filters on the energy range and spatial zone (material, cell or universe) define the bounds of integration for both numerator and denominator.

Multi-Group Scattering Matrices

The general multi-group cross section $\sigma_{n,x,k,g}$ is a vector of $G$ values for each energy group $g$. The equation presented above only discretizes the energy of the incoming neutron and neglects the outgoing energy of the neutron (if any). Hence, this formulation must be extended to account for the outgoing energy of neutrons in the discretized scattering matrix cross section used by deterministic neutron transport codes.

We denote the incoming and outgoing neutron energy groups as $g$ and $g'$ for the microscopic scattering matrix cross section $\sigma_{n,s}(\mathbf{r},E)$. As before, spatial homogenization and energy condensation are used to find the multi-group scattering matrix cross section $\sigma_{n,s,k,g \to g'}$ as follows:

$$\sigma_{n,s,k,g\rightarrow g'} = \frac{\int_{E_{g'}}^{E_{g'-1}}\mathrm{d}E''\int_{E_{g}}^{E_{g-1}}\mathrm{d}E'\int_{\mathbf{r} \in V_{k}}\mathrm{d}\mathbf{r}\sigma_{n,s}(\mathbf{r},E'\rightarrow E'')\Phi(\mathbf{r},E')}{\int_{E_{g}}^{E_{g-1}}\mathrm{d}E'\int_{\mathbf{r} \in V_{k}}\mathrm{d}\mathbf{r}\Phi(\mathbf{r},E')}$$

This scalar flux-weighted multi-group microscopic scattering matrix is computed using OpenMC tallies with both energy in and energy out filters.

Multi-Group Fission Spectrum

The energy spectrum of neutrons emitted from fission is denoted by $\chi_{n}(\mathbf{r},E' \rightarrow E'')$ for incoming and outgoing energies $E'$ and $E''$, respectively. Unlike the multi-group cross sections $\sigma_{n,x,k,g}$ considered up to this point, the fission spectrum is a probability distribution and must sum to unity. The outgoing energy is typically much less dependent on the incoming energy for fission than for scattering interactions. As a result, it is common practice to integrate over the incoming neutron energy when computing the multi-group fission spectrum. The fission spectrum may be simplified as $\chi_{n}(\mathbf{r},E)$ with outgoing energy $E$.

Unlike the multi-group cross sections defined up to this point, the multi-group fission spectrum is weighted by the fission production rate rather than the scalar flux. This formulation is intended to preserve the total fission production rate in the multi-group deterministic calculation. In order to mathematically define the multi-group fission spectrum, we denote the microscopic fission cross section as $\sigma_{n,f}(\mathbf{r},E)$ and the average number of neutrons emitted from fission interactions with nuclide $n$ as $\nu_{n}(\mathbf{r},E)$. The multi-group fission spectrum $\chi_{n,k,g}$ is then the probability of fission neutrons emitted into energy group $g$.

Similar to before, spatial homogenization and energy condensation are used to find the multi-group fission spectrum $\chi_{n,k,g}$ as follows:

$$\chi_{n,k,g'} = \frac{\int_{E_{g'}}^{E_{g'-1}}\mathrm{d}E''\int_{0}^{\infty}\mathrm{d}E'\int_{\mathbf{r} \in V_{k}}\mathrm{d}\mathbf{r}\chi_{n}(\mathbf{r},E'\rightarrow E'')\nu_{n}(\mathbf{r},E')\sigma_{n,f}(\mathbf{r},E')\Phi(\mathbf{r},E')}{\int_{0}^{\infty}\mathrm{d}E'\int_{\mathbf{r} \in V_{k}}\mathrm{d}\mathbf{r}\nu_{n}(\mathbf{r},E')\sigma_{n,f}(\mathbf{r},E')\Phi(\mathbf{r},E')}$$

The fission production-weighted multi-group fission spectrum is computed using OpenMC tallies with both energy in and energy out filters.

This concludes our brief overview on the methodology to compute multi-group cross sections. The following sections detail more concretely how users may employ the openmc.mgxs module to power simulation workflows requiring multi-group cross sections for downstream deterministic calculations.

Generate Input Files


In [2]:
import numpy as np
import matplotlib.pyplot as plt

import openmc
import openmc.mgxs as mgxs
from openmc.source import Source
from openmc.stats import Box

%matplotlib inline

First we need to define materials that will be used in the problem. Before defining a material, we must create nuclides that are used in the material.


In [3]:
# Instantiate some Nuclides
h1 = openmc.Nuclide('H-1')
o16 = openmc.Nuclide('O-16')
u235 = openmc.Nuclide('U-235')
u238 = openmc.Nuclide('U-238')
zr90 = openmc.Nuclide('Zr-90')

With the nuclides we defined, we will now create a material for the homogeneous medium.


In [4]:
# Instantiate a Material and register the Nuclides
inf_medium = openmc.Material(name='moderator')
inf_medium.set_density('g/cc', 5.)
inf_medium.add_nuclide(h1,  0.028999667)
inf_medium.add_nuclide(o16, 0.01450188)
inf_medium.add_nuclide(u235, 0.000114142)
inf_medium.add_nuclide(u238, 0.006886019)
inf_medium.add_nuclide(zr90, 0.002116053)

With our material, we can now create a MaterialsFile object that can be exported to an actual XML file.


In [5]:
# Instantiate a MaterialsFile, register all Materials, and export to XML
materials_file = openmc.MaterialsFile()
materials_file.default_xs = '71c'
materials_file.add_material(inf_medium)
materials_file.export_to_xml()

Now let's move on to the geometry. This problem will be a simple square cell with reflective boundary conditions to simulate an infinite homogeneous medium. The first step is to create the outer bounding surfaces of the problem.


In [6]:
# Instantiate boundary Planes
min_x = openmc.XPlane(boundary_type='reflective', x0=-0.63)
max_x = openmc.XPlane(boundary_type='reflective', x0=0.63)
min_y = openmc.YPlane(boundary_type='reflective', y0=-0.63)
max_y = openmc.YPlane(boundary_type='reflective', y0=0.63)

With the surfaces defined, we can now create a cell that is defined by intersections of half-spaces created by the surfaces.


In [7]:
# Instantiate a Cell
cell = openmc.Cell(cell_id=1, name='cell')

# Register bounding Surfaces with the Cell
cell.region = +min_x & -max_x & +min_y & -max_y

# Fill the Cell with the Material
cell.fill = inf_medium

OpenMC requires that there is a "root" universe. Let us create a root universe and add our square cell to it.


In [8]:
# Instantiate Universe
root_universe = openmc.Universe(universe_id=0, name='root universe')
root_universe.add_cell(cell)

We now must create a geometry that is assigned a root universe, put the geometry into a GeometryFile object, and export it to XML.


In [9]:
# Create Geometry and set root Universe
openmc_geometry = openmc.Geometry()
openmc_geometry.root_universe = root_universe

# Instantiate a GeometryFile
geometry_file = openmc.GeometryFile()
geometry_file.geometry = openmc_geometry

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

Next, we must define simulation parameters. In this case, we will use 10 inactive batches and 40 active batches each with 2500 particles.


In [10]:
# OpenMC simulation parameters
batches = 50
inactive = 10
particles = 2500

# Instantiate a SettingsFile
settings_file = openmc.SettingsFile()
settings_file.batches = batches
settings_file.inactive = inactive
settings_file.particles = particles
settings_file.output = {'tallies': True, 'summary': True}
bounds = [-0.63, -0.63, -0.63, 0.63, 0.63, 0.63]
settings_file.source = Source(space=Box(
    bounds[:3], bounds[3:], only_fissionable=True))

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

Now we are ready to generate multi-group cross sections! First, let's define a 2-group structure using the built-in EnergyGroups class.


In [11]:
# Instantiate a 2-group EnergyGroups object
groups = mgxs.EnergyGroups()
groups.group_edges = np.array([0., 0.625e-6, 20.])

We can now use the EnergyGroups object, along with our previously created materials and geometry, to instantiate some MGXS objects from the openmc.mgxs module. In particular, the following are subclasses of the generic and abstract MGXS class:

  • TotalXS
  • TransportXS
  • AbsorptionXS
  • CaptureXS
  • FissionXS
  • NuFissionXS
  • ScatterXS
  • NuScatterXS
  • ScatterMatrixXS
  • NuScatterMatrixXS
  • Chi

These classes provide us with an interface to generate the tally inputs as well as perform post-processing of OpenMC's tally data to compute the respective multi-group cross sections. In this case, let's create the multi-group total, absorption and scattering cross sections with our 2-group structure.


In [12]:
# Instantiate a few different sections
total = mgxs.TotalXS(domain=cell, domain_type='cell', groups=groups)
absorption = mgxs.AbsorptionXS(domain=cell, domain_type='cell', groups=groups)
scattering = mgxs.ScatterXS(domain=cell, domain_type='cell', groups=groups)

Each multi-group cross section object stores its tallies in a Python dictionary called tallies. We can inspect the tallies in the dictionary for our Absorption object as follows.


In [13]:
absorption.tallies


Out[13]:
OrderedDict([('flux', Tally
              	ID             =	10000
              	Name           =	
              	Filters        =	
                              		cell	[1]
                              		energy	[  0.00000000e+00   6.25000000e-07   2.00000000e+01]
              	Nuclides       =	total 
              	Scores         =	['flux']
              	Estimator      =	tracklength), ('absorption', Tally
              	ID             =	10001
              	Name           =	
              	Filters        =	
                              		cell	[1]
                              		energy	[  0.00000000e+00   6.25000000e-07   2.00000000e+01]
              	Nuclides       =	total 
              	Scores         =	['absorption']
              	Estimator      =	tracklength)])

The Absorption object includes tracklength tallies for the 'absorption' and 'flux' scores in the 2-group structure in cell 1. Now that each MGXS object contains the tallies that it needs, we must add these tallies to a TalliesFile object to generate the "tallies.xml" input file for OpenMC.


In [14]:
# Instantiate an empty TalliesFile
tallies_file = openmc.TalliesFile()

# Add total tallies to the tallies file
for tally in total.tallies.values():
    tallies_file.add_tally(tally)

# Add absorption tallies to the tallies file
for tally in absorption.tallies.values():
    tallies_file.add_tally(tally)

# Add scattering tallies to the tallies file
for tally in scattering.tallies.values():
    tallies_file.add_tally(tally)
                
# Export to "tallies.xml"
tallies_file.export_to_xml()

Now we a have a complete set of inputs, so we can go ahead and run our simulation.


In [15]:
# Run OpenMC
executor = openmc.Executor()
executor.run_simulation()


       .d88888b.                             888b     d888  .d8888b.
      d88P" "Y88b                            8888b   d8888 d88P  Y88b
      888     888                            88888b.d88888 888    888
      888     888 88888b.   .d88b.  88888b.  888Y88888P888 888       
      888     888 888 "88b d8P  Y8b 888 "88b 888 Y888P 888 888       
      888     888 888  888 88888888 888  888 888  Y8P  888 888    888
      Y88b. .d88P 888 d88P Y8b.     888  888 888   "   888 Y88b  d88P
       "Y88888P"  88888P"   "Y8888  888  888 888       888  "Y8888P"
__________________888______________________________________________________
                  888
                  888

      Copyright:      2011-2015 Massachusetts Institute of Technology
      License:        http://mit-crpg.github.io/openmc/license.html
      Version:        0.7.1
      Git SHA1:       ea9fb637f63f9374c7436456141afa850b84acf9
      Date/Time:      2016-01-14 07:16:05

 ===========================================================================
 ========================>     INITIALIZATION     <=========================
 ===========================================================================

 Reading settings XML file...
 Reading cross sections XML file...
 Reading geometry XML file...
 Reading materials XML file...
 Reading tallies XML file...
 Building neighboring cells lists for each surface...
 Loading ACE cross section table: 1001.71c
 Loading ACE cross section table: 8016.71c
 Loading ACE cross section table: 92235.71c
 Loading ACE cross section table: 92238.71c
 Loading ACE cross section table: 40090.71c
 Maximum neutron transport energy: 20.0000 MeV for 1001.71c
 Initializing source particles...

 ===========================================================================
 ====================>     K EIGENVALUE SIMULATION     <====================
 ===========================================================================

  Bat./Gen.      k            Average k         
  =========   ========   ====================   
        1/1    1.19804                       
        2/1    1.12945                       
        3/1    1.15573                       
        4/1    1.13929                       
        5/1    1.16300                       
        6/1    1.22117                       
        7/1    1.19012                       
        8/1    1.11299                       
        9/1    1.16066                       
       10/1    1.12566                       
       11/1    1.20854                       
       12/1    1.14691    1.17773 +/- 0.03082
       13/1    1.17204    1.17583 +/- 0.01789
       14/1    1.14148    1.16724 +/- 0.01529
       15/1    1.17272    1.16834 +/- 0.01189
       16/1    1.18575    1.17124 +/- 0.01014
       17/1    1.20498    1.17606 +/- 0.00983
       18/1    1.14754    1.17249 +/- 0.00923
       19/1    1.18141    1.17348 +/- 0.00820
       20/1    1.15074    1.17121 +/- 0.00768
       21/1    1.15914    1.17011 +/- 0.00703
       22/1    1.14586    1.16809 +/- 0.00673
       23/1    1.18999    1.16978 +/- 0.00642
       24/1    1.15101    1.16844 +/- 0.00609
       25/1    1.13791    1.16640 +/- 0.00602
       26/1    1.19791    1.16837 +/- 0.00597
       27/1    1.19818    1.17012 +/- 0.00587
       28/1    1.14160    1.16854 +/- 0.00576
       29/1    1.11487    1.16571 +/- 0.00614
       30/1    1.17538    1.16620 +/- 0.00584
       31/1    1.20210    1.16791 +/- 0.00581
       32/1    1.20078    1.16940 +/- 0.00574
       33/1    1.14624    1.16839 +/- 0.00558
       34/1    1.14618    1.16747 +/- 0.00542
       35/1    1.16866    1.16752 +/- 0.00520
       36/1    1.18565    1.16821 +/- 0.00504
       37/1    1.16824    1.16821 +/- 0.00485
       38/1    1.18299    1.16874 +/- 0.00471
       39/1    1.21418    1.17031 +/- 0.00480
       40/1    1.11167    1.16835 +/- 0.00504
       41/1    1.11545    1.16665 +/- 0.00516
       42/1    1.11114    1.16491 +/- 0.00529
       43/1    1.14227    1.16423 +/- 0.00517
       44/1    1.14104    1.16355 +/- 0.00506
       45/1    1.16756    1.16366 +/- 0.00492
       46/1    1.13065    1.16274 +/- 0.00487
       47/1    1.11251    1.16139 +/- 0.00492
       48/1    1.14731    1.16101 +/- 0.00481
       49/1    1.16691    1.16117 +/- 0.00469
       50/1    1.19679    1.16206 +/- 0.00465
 Creating state point statepoint.50.h5...

 ===========================================================================
 ======================>     SIMULATION FINISHED     <======================
 ===========================================================================


 =======================>     TIMING STATISTICS     <=======================

 Total time for initialization     =  1.1720E+00 seconds
   Reading cross sections          =  9.0300E-01 seconds
 Total time in simulation          =  1.7319E+01 seconds
   Time in transport only          =  1.7310E+01 seconds
   Time in inactive batches        =  1.9120E+00 seconds
   Time in active batches          =  1.5407E+01 seconds
   Time synchronizing fission bank =  2.0000E-03 seconds
     Sampling source sites         =  2.0000E-03 seconds
     SEND/RECV source sites        =  0.0000E+00 seconds
   Time accumulating tallies       =  0.0000E+00 seconds
 Total time for finalization       =  1.0000E-03 seconds
 Total time elapsed                =  1.8507E+01 seconds
 Calculation Rate (inactive)       =  13075.3 neutrons/second
 Calculation Rate (active)         =  6490.56 neutrons/second

 ============================>     RESULTS     <============================

 k-effective (Collision)     =  1.16131 +/-  0.00453
 k-effective (Track-length)  =  1.16206 +/-  0.00465
 k-effective (Absorption)    =  1.16096 +/-  0.00364
 Combined k-effective        =  1.16120 +/-  0.00325
 Leakage Fraction            =  0.00000 +/-  0.00000

Out[15]:
0

Tally Data Processing

Our simulation ran successfully and created statepoint and summary output files. We begin our analysis by instantiating a StatePoint object.


In [16]:
# Load the last statepoint file
sp = openmc.StatePoint('statepoint.50.h5')

In addition to the statepoint file, our simulation also created a summary file which encapsulates information about the materials and geometry. This is necessary for the openmc.mgxs module to properly process the tally data. We first create a Summary object and link it with the statepoint.


In [17]:
# Load the summary file and link it with the statepoint
su = openmc.Summary('summary.h5')
sp.link_with_summary(su)

The statepoint is now ready to be analyzed by our multi-group cross sections. We simply have to load the tallies from the StatePoint into each object as follows and our MGXS objects will compute the cross sections for us under-the-hood.


In [18]:
# Load the tallies from the statepoint into each MGXS object
total.load_from_statepoint(sp)
absorption.load_from_statepoint(sp)
scattering.load_from_statepoint(sp)

Voila! Our multi-group cross sections are now ready to rock 'n roll!

Extracting and Storing MGXS Data

Let's first inspect our total cross section by printing it to the screen.


In [19]:
total.print_xs()


Multi-Group XS
	Reaction Type  =	total
	Domain Type    =	cell
	Domain ID      =	1
	Cross Sections [cm^-1]:
            Group 1 [6.25e-07   - 20.0      MeV]:	6.81e-01 +/- 1.88e-01%
            Group 2 [0.0        - 6.25e-07  MeV]:	1.40e+00 +/- 5.91e-01%



Since the openmc.mgxs module uses tally arithmetic under-the-hood, the cross section is stored as a "derived" Tally object. This means that it can be queried and manipulated using all of the same methods supported for the Tally class in the OpenMC Python API. For example, we can construct a Pandas DataFrame of the multi-group cross section data.


In [20]:
df = scattering.get_pandas_dataframe()
df.head(10)


Out[20]:
cell group in nuclide mean std. dev.
1 1 1 total 0.668323 0.001264
0 1 2 total 1.293258 0.007624

Each multi-group cross section object can be easily exported to a variety of file formats, including CSV, Excel, and LaTeX for storage or data processing.


In [21]:
absorption.export_xs_data(filename='absorption-xs', format='excel')

The following code snippet shows how to export all three MGXS to the same HDF5 binary data store.


In [22]:
total.build_hdf5_store(filename='mgxs', append=True)
absorption.build_hdf5_store(filename='mgxs', append=True)
scattering.build_hdf5_store(filename='mgxs', append=True)

Comparing MGXS with Tally Arithmetic

Finally, we illustrate how one can leverage OpenMC's tally arithmetic data processing feature with MGXS objects. The openmc.mgxs module uses tally arithmetic to compute multi-group cross sections with automated uncertainty propagation. Each MGXS object includes an xs_tally attribute which is a "derived" Tally based on the tallies needed to compute the cross section type of interest. These derived tallies can be used in subsequent tally arithmetic operations. For example, we can use tally artithmetic to confirm that the TotalXS is equal to the sum of the AbsorptionXS and ScatterXS objects.


In [23]:
# Use tally arithmetic to compute the difference between the total, absorption and scattering
difference = total.xs_tally - absorption.xs_tally - scattering.xs_tally

# The difference is a derived tally which can generate Pandas DataFrames for inspection
difference.get_pandas_dataframe()


Out[23]:
cell energy [MeV] nuclide score mean std. dev.
0 1 (0.0e+00 - 6.3e-07) total (((total / flux) - (absorption / flux)) - (sca... 4.884981e-15 0.011274
1 1 (6.3e-07 - 2.0e+01) total (((total / flux) - (absorption / flux)) - (sca... 1.221245e-15 0.001802

Similarly, we can use tally arithmetic to compute the ratio of AbsorptionXS and ScatterXS to the TotalXS.


In [24]:
# Use tally arithmetic to compute the absorption-to-total MGXS ratio
absorption_to_total = absorption.xs_tally / total.xs_tally

# The absorption-to-total ratio is a derived tally which can generate Pandas DataFrames for inspection
absorption_to_total.get_pandas_dataframe()


Out[24]:
cell energy [MeV] nuclide score mean std. dev.
0 1 (0.0e+00 - 6.3e-07) total ((absorption / flux) / (total / flux)) 0.076219 0.000651
1 1 (6.3e-07 - 2.0e+01) total ((absorption / flux) / (total / flux)) 0.019319 0.000086

In [25]:
# Use tally arithmetic to compute the scattering-to-total MGXS ratio
scattering_to_total = scattering.xs_tally / total.xs_tally

# The scattering-to-total ratio is a derived tally which can generate Pandas DataFrames for inspection
scattering_to_total.get_pandas_dataframe()


Out[25]:
cell energy [MeV] nuclide score mean std. dev.
0 1 (0.0e+00 - 6.3e-07) total ((scatter / flux) / (total / flux)) 0.923781 0.007714
1 1 (6.3e-07 - 2.0e+01) total ((scatter / flux) / (total / flux)) 0.980681 0.002617

Lastly, we sum the derived scatter-to-total and absorption-to-total ratios to confirm that they sum to unity.


In [26]:
# Use tally arithmetic to ensure that the absorption- and scattering-to-total MGXS ratios sum to unity
sum_ratio = absorption_to_total + scattering_to_total

# The scattering-to-total ratio is a derived tally which can generate Pandas DataFrames for inspection
sum_ratio.get_pandas_dataframe()


Out[26]:
cell energy [MeV] nuclide score mean std. dev.
0 1 (0.0e+00 - 6.3e-07) total (((absorption / flux) / (total / flux)) + ((sc... 1 0.007741
1 1 (6.3e-07 - 2.0e+01) total (((absorption / flux) / (total / flux)) + ((sc... 1 0.002619