This IPython Notebook illustrates the use of the openmc.mgxs module to calculate multi-group cross sections for a heterogeneous fuel pin cell geometry. In particular, this Notebook illustrates the following features:

  • Creation of multi-group cross sections on a heterogeneous geometry
  • Calculation of cross sections on a nuclide-by-nuclide basis
  • The use of tally precision triggers with multi-group cross sections
  • Built-in features for energy condensation in downstream data processing
  • The use of the openmc.data module to plot continuous-energy vs. multi-group cross sections
  • Validation of multi-group cross sections with OpenMOC

Note: This Notebook was created using OpenMOC to verify the multi-group cross-sections generated by OpenMC. In order to run this Notebook in its entirety, you must have OpenMOC installed on your system, along with OpenCG to convert the OpenMC geometries into OpenMOC geometries. In addition, this Notebook illustrates the use of Pandas DataFrames to containerize multi-group cross section data.

Generate Input Files


In [1]:
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

import openmoc
from openmoc.opencg_compatible import get_openmoc_geometry

import openmc
import openmc.mgxs as mgxs
import openmc.data

%matplotlib inline


/home/romano/miniconda3/envs/default/lib/python3.5/site-packages/matplotlib/__init__.py:1350: UserWarning:  This call to matplotlib.use() has no effect
because the backend has already been chosen;
matplotlib.use() must be called *before* pylab, matplotlib.pyplot,
or matplotlib.backends is imported for the first time.

  warnings.warn(_use_error_msg)

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 [2]:
# Instantiate some Nuclides
h1 = openmc.Nuclide('H1')
o16 = openmc.Nuclide('O16')
u235 = openmc.Nuclide('U235')
u238 = openmc.Nuclide('U238')
zr90 = openmc.Nuclide('Zr90')

With the nuclides we defined, we will now create three distinct materials for water, clad and fuel.


In [3]:
# 1.6% enriched fuel
fuel = openmc.Material(name='1.6% Fuel')
fuel.set_density('g/cm3', 10.31341)
fuel.add_nuclide(u235, 3.7503e-4)
fuel.add_nuclide(u238, 2.2625e-2)
fuel.add_nuclide(o16, 4.6007e-2)

# borated water
water = openmc.Material(name='Borated Water')
water.set_density('g/cm3', 0.740582)
water.add_nuclide(h1, 4.9457e-2)
water.add_nuclide(o16, 2.4732e-2)

# zircaloy
zircaloy = openmc.Material(name='Zircaloy')
zircaloy.set_density('g/cm3', 6.55)
zircaloy.add_nuclide(zr90, 7.2758e-3)

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


In [4]:
# Instantiate a Materials collection
materials_file = openmc.Materials((fuel, water, zircaloy))

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

Now let's move on to the geometry. Our problem will have three regions for the fuel, the clad, and the surrounding coolant. The first step is to create the bounding surfaces -- in this case two cylinders and six reflective planes.


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

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

With the surfaces defined, we can now create cells that are defined by intersections of half-spaces created by the surfaces.


In [6]:
# Create a Universe to encapsulate a fuel pin
pin_cell_universe = openmc.Universe(name='1.6% Fuel Pin')

# Create fuel Cell
fuel_cell = openmc.Cell(name='1.6% Fuel')
fuel_cell.fill = fuel
fuel_cell.region = -fuel_outer_radius
pin_cell_universe.add_cell(fuel_cell)

# Create a clad Cell
clad_cell = openmc.Cell(name='1.6% Clad')
clad_cell.fill = zircaloy
clad_cell.region = +fuel_outer_radius & -clad_outer_radius
pin_cell_universe.add_cell(clad_cell)

# Create a moderator Cell
moderator_cell = openmc.Cell(name='1.6% Moderator')
moderator_cell.fill = water
moderator_cell.region = +clad_outer_radius
pin_cell_universe.add_cell(moderator_cell)

OpenMC requires that there is a "root" universe. Let us create a root cell that is filled by the pin cell universe and then assign it to the root universe.


In [7]:
# Create root Cell
root_cell = openmc.Cell(name='root cell')
root_cell.region = +min_x & -max_x & +min_y & -max_y
root_cell.fill = pin_cell_universe

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

We now must create a geometry that is assigned a root universe and export it to XML.


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

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

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


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

# Instantiate a Settings object
settings_file = openmc.Settings()
settings_file.batches = batches
settings_file.inactive = inactive
settings_file.particles = particles
settings_file.output = {'tallies': True}

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

# Activate tally precision triggers
settings_file.trigger_active = True
settings_file.trigger_max_batches = settings_file.batches * 4

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

Now we are finally ready to make use of the openmc.mgxs module to generate multi-group cross sections! First, let's define "coarse" 2-group and "fine" 8-group structures using the built-in EnergyGroups class.


In [10]:
# Instantiate a "coarse" 2-group EnergyGroups object
coarse_groups = mgxs.EnergyGroups()
coarse_groups.group_edges = np.array([0., 0.625, 20.0e6])

# Instantiate a "fine" 8-group EnergyGroups object
fine_groups = mgxs.EnergyGroups()
fine_groups.group_edges = np.array([0., 0.058, 0.14, 0.28,
                                    0.625, 4.0, 5.53e3, 821.0e3, 20.0e6])

Now we will instantiate a variety of MGXS objects needed to run an OpenMOC simulation to verify the accuracy of our cross sections. In particular, we define transport, fission, nu-fission, nu-scatter and chi cross sections for each of the three cells in the fuel pin with the 8-group structure as our energy groups.


In [11]:
# Extract all Cells filled by Materials
openmc_cells = openmc_geometry.get_all_material_cells()

# Create dictionary to store multi-group cross sections for all cells
xs_library = {}

# Instantiate 8-group cross sections for each cell
for cell in openmc_cells:
    xs_library[cell.id] = {}
    xs_library[cell.id]['transport']  = mgxs.TransportXS(groups=fine_groups)
    xs_library[cell.id]['fission'] = mgxs.FissionXS(groups=fine_groups)
    xs_library[cell.id]['nu-fission'] = mgxs.NuFissionXS(groups=fine_groups)
    xs_library[cell.id]['nu-scatter'] = mgxs.NuScatterMatrixXS(groups=fine_groups)
    xs_library[cell.id]['chi'] = mgxs.Chi(groups=fine_groups)

Next, we showcase the use of OpenMC's tally precision trigger feature in conjunction with the openmc.mgxs module. In particular, we will assign a tally trigger of 1E-2 on the standard deviation for each of the tallies used to compute multi-group cross sections.


In [12]:
# Create a tally trigger for +/- 0.01 on each tally used to compute the multi-group cross sections
tally_trigger = openmc.Trigger('std_dev', 1E-2)

# Add the tally trigger to each of the multi-group cross section tallies
for cell in openmc_cells:
    for mgxs_type in xs_library[cell.id]:
        xs_library[cell.id][mgxs_type].tally_trigger = tally_trigger

Now, we must loop over all cells to set the cross section domains to the various cells - fuel, clad and moderator - included in the geometry. In addition, we will set each cross section to tally cross sections on a per-nuclide basis through the use of the MGXS class' boolean by_nuclide instance attribute.


In [13]:
# Instantiate an empty Tallies object
tallies_file = openmc.Tallies()

# Iterate over all cells and cross section types
for cell in openmc_cells:
    for rxn_type in xs_library[cell.id]:

        # Set the cross sections domain to the cell
        xs_library[cell.id][rxn_type].domain = cell
        
        # Tally cross sections by nuclide
        xs_library[cell.id][rxn_type].by_nuclide = True
                
        # Add OpenMC tallies to the tallies file for XML generation
        for tally in xs_library[cell.id][rxn_type].tallies.values():
            tallies_file.append(tally, merge=True)

# 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 [14]:
# Run OpenMC
openmc.run(output=True)


                               %%%%%%%%%%%%%%%
                          %%%%%%%%%%%%%%%%%%%%%%%%
                       %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
                     %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
                   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
                  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
                                   %%%%%%%%%%%%%%%%%%%%%%%%
                                    %%%%%%%%%%%%%%%%%%%%%%%%
                ###############      %%%%%%%%%%%%%%%%%%%%%%%%
               ##################     %%%%%%%%%%%%%%%%%%%%%%%
               ###################     %%%%%%%%%%%%%%%%%%%%%%%
               ####################     %%%%%%%%%%%%%%%%%%%%%%
               #####################     %%%%%%%%%%%%%%%%%%%%%
               ######################     %%%%%%%%%%%%%%%%%%%%
               #######################     %%%%%%%%%%%%%%%%%%
                #######################     %%%%%%%%%%%%%%%%%
                ######################     %%%%%%%%%%%%%%%%%
                 ####################     %%%%%%%%%%%%%%%%%
                   #################     %%%%%%%%%%%%%%%%%
                    ###############     %%%%%%%%%%%%%%%%
                      ############     %%%%%%%%%%%%%%%
                         ########     %%%%%%%%%%%%%%
                                     %%%%%%%%%%%

                   | The OpenMC Monte Carlo Code
         Copyright | 2011-2016 Massachusetts Institute of Technology
           License | http://openmc.readthedocs.io/en/latest/license.html
           Version | 0.8.0
          Git SHA1 | da5563eddb5f2c2d6b2c9839d518de40962b78f2
         Date/Time | 2016-10-31 12:29:16
    OpenMP Threads | 4

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

 Reading settings XML file...
 Reading geometry XML file...
 Reading materials XML file...
 Reading cross sections XML file...
 Reading U235 from /home/romano/openmc/scripts/nndc_hdf5/U235.h5
 Reading U238 from /home/romano/openmc/scripts/nndc_hdf5/U238.h5
 Reading O16 from /home/romano/openmc/scripts/nndc_hdf5/O16.h5
 Reading H1 from /home/romano/openmc/scripts/nndc_hdf5/H1.h5
 Reading Zr90 from /home/romano/openmc/scripts/nndc_hdf5/Zr90.h5
 Maximum neutron transport energy: 2.00000E+07 eV for U235
 Reading tallies XML file...
 Building neighboring cells lists for each surface...
 Initializing source particles...

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

  Bat./Gen.      k            Average k         
  =========   ========   ====================   
        1/1    1.20332                       
        2/1    1.22209                       
        3/1    1.24309                       
        4/1    1.22833                       
        5/1    1.21786                       
        6/1    1.22005                       
        7/1    1.20894                       
        8/1    1.22071                       
        9/1    1.21279                       
       10/1    1.22198                       
       11/1    1.22287                       
       12/1    1.25490    1.23888 +/- 0.01602
       13/1    1.20224    1.22667 +/- 0.01532
       14/1    1.23375    1.22844 +/- 0.01098
       15/1    1.23068    1.22889 +/- 0.00851
       16/1    1.23073    1.22920 +/- 0.00696
       17/1    1.25364    1.23269 +/- 0.00684
       18/1    1.20820    1.22963 +/- 0.00667
       19/1    1.23138    1.22982 +/- 0.00588
       20/1    1.20682    1.22752 +/- 0.00574
       21/1    1.23580    1.22827 +/- 0.00525
       22/1    1.24190    1.22941 +/- 0.00492
       23/1    1.23125    1.22955 +/- 0.00453
       24/1    1.21606    1.22859 +/- 0.00430
       25/1    1.23653    1.22912 +/- 0.00404
       26/1    1.23850    1.22970 +/- 0.00383
       27/1    1.20986    1.22853 +/- 0.00378
       28/1    1.25277    1.22988 +/- 0.00381
       29/1    1.23334    1.23006 +/- 0.00361
       30/1    1.24345    1.23073 +/- 0.00349
       31/1    1.21565    1.23001 +/- 0.00339
       32/1    1.20555    1.22890 +/- 0.00342
       33/1    1.22995    1.22895 +/- 0.00327
       34/1    1.19763    1.22764 +/- 0.00339
       35/1    1.22645    1.22760 +/- 0.00325
       36/1    1.23900    1.22803 +/- 0.00316
       37/1    1.24305    1.22859 +/- 0.00309
       38/1    1.22484    1.22846 +/- 0.00298
       39/1    1.20986    1.22782 +/- 0.00294
       40/1    1.23764    1.22814 +/- 0.00286
       41/1    1.20476    1.22739 +/- 0.00287
       42/1    1.21652    1.22705 +/- 0.00280
       43/1    1.21279    1.22662 +/- 0.00275
       44/1    1.20210    1.22590 +/- 0.00276
       45/1    1.22644    1.22591 +/- 0.00268
       46/1    1.22907    1.22600 +/- 0.00261
       47/1    1.24057    1.22639 +/- 0.00257
       48/1    1.21610    1.22612 +/- 0.00251
       49/1    1.22199    1.22602 +/- 0.00245
       50/1    1.20860    1.22558 +/- 0.00243
 Triggers unsatisfied, max unc./thresh. is 1.25496 for flux in tally 10050
 The estimated number of batches is 73
 Creating state point statepoint.050.h5...
       51/1    1.21850    1.22541 +/- 0.00237
       52/1    1.22833    1.22548 +/- 0.00232
       53/1    1.20239    1.22494 +/- 0.00233
       54/1    1.24876    1.22548 +/- 0.00234
       55/1    1.20670    1.22506 +/- 0.00232
       56/1    1.24260    1.22545 +/- 0.00230
       57/1    1.21039    1.22512 +/- 0.00228
       58/1    1.23929    1.22542 +/- 0.00225
       59/1    1.21357    1.22518 +/- 0.00221
       60/1    1.23456    1.22537 +/- 0.00218
       61/1    1.23963    1.22565 +/- 0.00215
       62/1    1.24020    1.22593 +/- 0.00213
       63/1    1.22325    1.22587 +/- 0.00209
       64/1    1.22070    1.22578 +/- 0.00205
       65/1    1.22423    1.22575 +/- 0.00201
       66/1    1.22973    1.22582 +/- 0.00198
       67/1    1.21842    1.22569 +/- 0.00195
       68/1    1.19552    1.22517 +/- 0.00198
       69/1    1.21475    1.22500 +/- 0.00196
       70/1    1.21888    1.22489 +/- 0.00193
       71/1    1.19720    1.22444 +/- 0.00195
       72/1    1.23770    1.22465 +/- 0.00193
       73/1    1.23894    1.22488 +/- 0.00191
 Triggers unsatisfied, max unc./thresh. is 1.00243 for flux in tally 10050
 The estimated number of batches is 74
       74/1    1.22437    1.22487 +/- 0.00188
 Triggers satisfied for batch 74
 Creating state point statepoint.074.h5...

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


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

 Total time for initialization     =  5.0262E-01 seconds
   Reading cross sections          =  3.4207E-01 seconds
 Total time in simulation          =  1.2843E+02 seconds
   Time in transport only          =  1.2831E+02 seconds
   Time in inactive batches        =  8.1328E+00 seconds
   Time in active batches          =  1.2030E+02 seconds
   Time synchronizing fission bank =  2.9797E-02 seconds
     Sampling source sites         =  2.1385E-02 seconds
     SEND/RECV source sites        =  8.2632E-03 seconds
   Time accumulating tallies       =  1.4577E-03 seconds
 Total time for finalization       =  1.3462E-02 seconds
 Total time elapsed                =  1.2901E+02 seconds
 Calculation Rate (inactive)       =  12295.9 neutrons/second
 Calculation Rate (active)         =  3325.12 neutrons/second

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

 k-effective (Collision)     =  1.22358 +/-  0.00179
 k-effective (Track-length)  =  1.22487 +/-  0.00188
 k-effective (Absorption)    =  1.22300 +/-  0.00114
 Combined k-effective        =  1.22347 +/-  0.00106
 Leakage Fraction            =  0.00000 +/-  0.00000

Out[14]:
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 [15]:
# Load the last statepoint file
sp = openmc.StatePoint('statepoint.074.h5')

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 [16]:
# Iterate over all cells and cross section types
for cell in openmc_cells:
    for rxn_type in xs_library[cell.id]:
        xs_library[cell.id][rxn_type].load_from_statepoint(sp)

That's it! Our multi-group cross sections are now ready for the big spotlight. This time we have cross sections in three distinct spatial zones - fuel, clad and moderator - on a per-nuclide basis.

Extracting and Storing MGXS Data

Let's first inspect one of our cross sections by printing it to the screen as a microscopic cross section in units of barns.


In [17]:
nufission = xs_library[fuel_cell.id]['nu-fission']
nufission.print_xs(xs_type='micro', nuclides=['U235', 'U238'])


Multi-Group XS
	Reaction Type  =	nu-fission
	Domain Type    =	cell
	Domain ID      =	10000
	Nuclide        =	U235
	Cross Sections [barns]:
            Group 1 [821000.0   - 20000000.0eV]:	3.30e+00 +/- 2.19e-01%
            Group 2 [5530.0     - 821000.0  eV]:	3.96e+00 +/- 1.32e-01%
            Group 3 [4.0        - 5530.0    eV]:	5.52e+01 +/- 2.31e-01%
            Group 4 [0.625      - 4.0       eV]:	8.83e+01 +/- 2.96e-01%
            Group 5 [0.28       - 0.625     eV]:	2.90e+02 +/- 4.64e-01%
            Group 6 [0.14       - 0.28      eV]:	4.49e+02 +/- 4.22e-01%
            Group 7 [0.058      - 0.14      eV]:	6.87e+02 +/- 2.97e-01%
            Group 8 [0.0        - 0.058     eV]:	1.44e+03 +/- 2.91e-01%

	Nuclide        =	U238
	Cross Sections [barns]:
            Group 1 [821000.0   - 20000000.0eV]:	1.06e+00 +/- 2.56e-01%
            Group 2 [5530.0     - 821000.0  eV]:	1.21e-03 +/- 2.55e-01%
            Group 3 [4.0        - 5530.0    eV]:	5.77e-04 +/- 3.67e+00%
            Group 4 [0.625      - 4.0       eV]:	6.54e-06 +/- 2.74e-01%
            Group 5 [0.28       - 0.625     eV]:	1.07e-05 +/- 4.55e-01%
            Group 6 [0.14       - 0.28      eV]:	1.55e-05 +/- 4.25e-01%
            Group 7 [0.058      - 0.14      eV]:	2.30e-05 +/- 2.97e-01%
            Group 8 [0.0        - 0.058     eV]:	4.24e-05 +/- 2.90e-01%



Our multi-group cross sections are capable of summing across all nuclides to provide us with macroscopic cross sections as well.


In [18]:
nufission = xs_library[fuel_cell.id]['nu-fission']
nufission.print_xs(xs_type='macro', nuclides='sum')


Multi-Group XS
	Reaction Type  =	nu-fission
	Domain Type    =	cell
	Domain ID      =	10000
	Cross Sections [cm^-1]:
            Group 1 [821000.0   - 20000000.0eV]:	2.52e-02 +/- 2.44e-01%
            Group 2 [5530.0     - 821000.0  eV]:	1.51e-03 +/- 1.30e-01%
            Group 3 [4.0        - 5530.0    eV]:	2.07e-02 +/- 2.31e-01%
            Group 4 [0.625      - 4.0       eV]:	3.31e-02 +/- 2.96e-01%
            Group 5 [0.28       - 0.625     eV]:	1.09e-01 +/- 4.64e-01%
            Group 6 [0.14       - 0.28      eV]:	1.69e-01 +/- 4.22e-01%
            Group 7 [0.058      - 0.14      eV]:	2.58e-01 +/- 2.97e-01%
            Group 8 [0.0        - 0.058     eV]:	5.40e-01 +/- 2.91e-01%



Although a printed report is nice, it is not scalable or flexible. Let's extract the microscopic cross section data for the moderator as a Pandas DataFrame .


In [19]:
nuscatter = xs_library[moderator_cell.id]['nu-scatter']
df = nuscatter.get_pandas_dataframe(xs_type='micro')
df.head(10)


Out[19]:
cell group in group out nuclide mean std. dev.
126 10002 1 1 H1 0.234115 0.003568
127 10002 1 1 O16 1.563707 0.005953
124 10002 1 2 H1 1.594129 0.002369
125 10002 1 2 O16 0.285761 0.001676
122 10002 1 3 H1 0.011089 0.000248
123 10002 1 3 O16 0.000000 0.000000
120 10002 1 4 H1 0.000000 0.000000
121 10002 1 4 O16 0.000000 0.000000
118 10002 1 5 H1 0.000000 0.000000
119 10002 1 5 O16 0.000000 0.000000

Next, we illustate how one can easily take multi-group cross sections and condense them down to a coarser energy group structure. The MGXS class includes a get_condensed_xs(...) method which takes an EnergyGroups parameter with a coarse(r) group structure and returns a new MGXS condensed to the coarse groups. We illustrate this process below using the 2-group structure created earlier.


In [20]:
# Extract the 16-group transport cross section for the fuel
fine_xs = xs_library[fuel_cell.id]['transport']

# Condense to the 2-group structure
condensed_xs = fine_xs.get_condensed_xs(coarse_groups)

Group condensation is as simple as that! We now have a new coarse 2-group TransportXS in addition to our original 16-group TransportXS. Let's inspect the 2-group TransportXS by printing it to the screen and extracting a Pandas DataFrame as we have already learned how to do.


In [21]:
condensed_xs.print_xs()


Multi-Group XS
	Reaction Type  =	transport
	Domain Type    =	cell
	Domain ID      =	10000
	Nuclide        =	U235
	Cross Sections [cm^-1]:
            Group 1 [0.625      - 20000000.0eV]:	7.73e-03 +/- 5.06e-01%
            Group 2 [0.0        - 0.625     eV]:	1.82e-01 +/- 2.05e-01%

	Nuclide        =	U238
	Cross Sections [cm^-1]:
            Group 1 [0.625      - 20000000.0eV]:	2.17e-01 +/- 1.44e-01%
            Group 2 [0.0        - 0.625     eV]:	2.53e-01 +/- 2.57e-01%

	Nuclide        =	O16
	Cross Sections [cm^-1]:
            Group 1 [0.625      - 20000000.0eV]:	1.46e-01 +/- 1.60e-01%
            Group 2 [0.0        - 0.625     eV]:	1.75e-01 +/- 2.94e-01%




In [22]:
df = condensed_xs.get_pandas_dataframe(xs_type='micro')
df


Out[22]:
cell group in nuclide mean std. dev.
3 10000 1 U235 20.611692 0.104237
4 10000 1 U238 9.585358 0.013808
5 10000 1 O16 3.164190 0.005049
0 10000 2 U235 485.413426 0.996410
1 10000 2 U238 11.190386 0.028731
2 10000 2 O16 3.794859 0.011139

Verification with OpenMOC

Now, let's verify our cross sections using OpenMOC. First, we use OpenCG construct an equivalent OpenMOC geometry.


In [23]:
# Create an OpenMOC Geometry from the OpenCG Geometry
openmoc_geometry = get_openmoc_geometry(sp.summary.opencg_geometry)

Next, we we can inject the multi-group cross sections into the equivalent fuel pin cell OpenMOC geometry.


In [24]:
# Get all OpenMOC cells in the gometry
openmoc_cells = openmoc_geometry.getRootUniverse().getAllCells()

# Inject multi-group cross sections into OpenMOC Materials
for cell_id, cell in openmoc_cells.items():
    
    # Ignore the root cell
    if cell.getName() == 'root cell':
        continue
    
    # Get a reference to the Material filling this Cell
    openmoc_material = cell.getFillMaterial()
    
    # Set the number of energy groups for the Material
    openmoc_material.setNumEnergyGroups(fine_groups.num_groups)
    
    # Extract the appropriate cross section objects for this cell
    transport = xs_library[cell_id]['transport']
    nufission = xs_library[cell_id]['nu-fission']
    nuscatter = xs_library[cell_id]['nu-scatter']
    chi = xs_library[cell_id]['chi']
    
    # Inject NumPy arrays of cross section data into the Material
    # NOTE: Sum across nuclides to get macro cross sections needed by OpenMOC
    openmoc_material.setSigmaT(transport.get_xs(nuclides='sum').flatten())
    openmoc_material.setNuSigmaF(nufission.get_xs(nuclides='sum').flatten())
    openmoc_material.setSigmaS(nuscatter.get_xs(nuclides='sum').flatten())
    openmoc_material.setChi(chi.get_xs(nuclides='sum').flatten())

We are now ready to run OpenMOC to verify our cross-sections from OpenMC.


In [25]:
# Generate tracks for OpenMOC
track_generator = openmoc.TrackGenerator(openmoc_geometry, num_azim=128, azim_spacing=0.1)
track_generator.generateTracks()

# Run OpenMOC
solver = openmoc.CPUSolver(track_generator)
solver.computeEigenvalue()


[  NORMAL ]  Importing ray tracing data from file...
[  NORMAL ]  Computing the eigenvalue...
[  NORMAL ]  Iteration 0:	k_eff = 0.574672	res = 0.000E+00
[  NORMAL ]  Iteration 1:	k_eff = 0.679815	res = 4.253E-01
[  NORMAL ]  Iteration 2:	k_eff = 0.660826	res = 1.830E-01
[  NORMAL ]  Iteration 3:	k_eff = 0.658941	res = 2.793E-02
[  NORMAL ]  Iteration 4:	k_eff = 0.643012	res = 2.852E-03
[  NORMAL ]  Iteration 5:	k_eff = 0.625810	res = 2.417E-02
[  NORMAL ]  Iteration 6:	k_eff = 0.606678	res = 2.675E-02
[  NORMAL ]  Iteration 7:	k_eff = 0.587485	res = 3.057E-02
[  NORMAL ]  Iteration 8:	k_eff = 0.569029	res = 3.164E-02
[  NORMAL ]  Iteration 9:	k_eff = 0.551707	res = 3.142E-02
[  NORMAL ]  Iteration 10:	k_eff = 0.536035	res = 3.044E-02
[  NORMAL ]  Iteration 11:	k_eff = 0.522274	res = 2.841E-02
[  NORMAL ]  Iteration 12:	k_eff = 0.510609	res = 2.567E-02
[  NORMAL ]  Iteration 13:	k_eff = 0.501106	res = 2.234E-02
[  NORMAL ]  Iteration 14:	k_eff = 0.493831	res = 1.861E-02
[  NORMAL ]  Iteration 15:	k_eff = 0.488780	res = 1.452E-02
[  NORMAL ]  Iteration 16:	k_eff = 0.485923	res = 1.023E-02
[  NORMAL ]  Iteration 17:	k_eff = 0.485210	res = 5.846E-03
[  NORMAL ]  Iteration 18:	k_eff = 0.486569	res = 1.467E-03
[  NORMAL ]  Iteration 19:	k_eff = 0.489903	res = 2.801E-03
[  NORMAL ]  Iteration 20:	k_eff = 0.495103	res = 6.852E-03
[  NORMAL ]  Iteration 21:	k_eff = 0.502053	res = 1.061E-02
[  NORMAL ]  Iteration 22:	k_eff = 0.510627	res = 1.404E-02
[  NORMAL ]  Iteration 23:	k_eff = 0.520693	res = 1.708E-02
[  NORMAL ]  Iteration 24:	k_eff = 0.532117	res = 1.971E-02
[  NORMAL ]  Iteration 25:	k_eff = 0.544764	res = 2.194E-02
[  NORMAL ]  Iteration 26:	k_eff = 0.558501	res = 2.377E-02
[  NORMAL ]  Iteration 27:	k_eff = 0.573195	res = 2.522E-02
[  NORMAL ]  Iteration 28:	k_eff = 0.588718	res = 2.631E-02
[  NORMAL ]  Iteration 29:	k_eff = 0.604946	res = 2.708E-02
[  NORMAL ]  Iteration 30:	k_eff = 0.621759	res = 2.756E-02
[  NORMAL ]  Iteration 31:	k_eff = 0.639047	res = 2.779E-02
[  NORMAL ]  Iteration 32:	k_eff = 0.656702	res = 2.780E-02
[  NORMAL ]  Iteration 33:	k_eff = 0.674624	res = 2.763E-02
[  NORMAL ]  Iteration 34:	k_eff = 0.692722	res = 2.729E-02
[  NORMAL ]  Iteration 35:	k_eff = 0.710910	res = 2.683E-02
[  NORMAL ]  Iteration 36:	k_eff = 0.729109	res = 2.625E-02
[  NORMAL ]  Iteration 37:	k_eff = 0.747248	res = 2.560E-02
[  NORMAL ]  Iteration 38:	k_eff = 0.765263	res = 2.488E-02
[  NORMAL ]  Iteration 39:	k_eff = 0.783094	res = 2.411E-02
[  NORMAL ]  Iteration 40:	k_eff = 0.800690	res = 2.330E-02
[  NORMAL ]  Iteration 41:	k_eff = 0.818005	res = 2.247E-02
[  NORMAL ]  Iteration 42:	k_eff = 0.834999	res = 2.163E-02
[  NORMAL ]  Iteration 43:	k_eff = 0.851638	res = 2.078E-02
[  NORMAL ]  Iteration 44:	k_eff = 0.867892	res = 1.993E-02
[  NORMAL ]  Iteration 45:	k_eff = 0.883736	res = 1.909E-02
[  NORMAL ]  Iteration 46:	k_eff = 0.899149	res = 1.826E-02
[  NORMAL ]  Iteration 47:	k_eff = 0.914115	res = 1.744E-02
[  NORMAL ]  Iteration 48:	k_eff = 0.928622	res = 1.664E-02
[  NORMAL ]  Iteration 49:	k_eff = 0.942659	res = 1.587E-02
[  NORMAL ]  Iteration 50:	k_eff = 0.956221	res = 1.512E-02
[  NORMAL ]  Iteration 51:	k_eff = 0.969305	res = 1.439E-02
[  NORMAL ]  Iteration 52:	k_eff = 0.981909	res = 1.368E-02
[  NORMAL ]  Iteration 53:	k_eff = 0.994035	res = 1.300E-02
[  NORMAL ]  Iteration 54:	k_eff = 1.005685	res = 1.235E-02
[  NORMAL ]  Iteration 55:	k_eff = 1.016866	res = 1.172E-02
[  NORMAL ]  Iteration 56:	k_eff = 1.027584	res = 1.112E-02
[  NORMAL ]  Iteration 57:	k_eff = 1.037846	res = 1.054E-02
[  NORMAL ]  Iteration 58:	k_eff = 1.047661	res = 9.986E-03
[  NORMAL ]  Iteration 59:	k_eff = 1.057040	res = 9.457E-03
[  NORMAL ]  Iteration 60:	k_eff = 1.065994	res = 8.953E-03
[  NORMAL ]  Iteration 61:	k_eff = 1.074533	res = 8.470E-03
[  NORMAL ]  Iteration 62:	k_eff = 1.082671	res = 8.011E-03
[  NORMAL ]  Iteration 63:	k_eff = 1.090418	res = 7.573E-03
[  NORMAL ]  Iteration 64:	k_eff = 1.097790	res = 7.156E-03
[  NORMAL ]  Iteration 65:	k_eff = 1.104797	res = 6.760E-03
[  NORMAL ]  Iteration 66:	k_eff = 1.111453	res = 6.383E-03
[  NORMAL ]  Iteration 67:	k_eff = 1.117770	res = 6.025E-03
[  NORMAL ]  Iteration 68:	k_eff = 1.123764	res = 5.684E-03
[  NORMAL ]  Iteration 69:	k_eff = 1.129446	res = 5.362E-03
[  NORMAL ]  Iteration 70:	k_eff = 1.134828	res = 5.056E-03
[  NORMAL ]  Iteration 71:	k_eff = 1.139924	res = 4.765E-03
[  NORMAL ]  Iteration 72:	k_eff = 1.144746	res = 4.491E-03
[  NORMAL ]  Iteration 73:	k_eff = 1.149306	res = 4.230E-03
[  NORMAL ]  Iteration 74:	k_eff = 1.153617	res = 3.983E-03
[  NORMAL ]  Iteration 75:	k_eff = 1.157688	res = 3.751E-03
[  NORMAL ]  Iteration 76:	k_eff = 1.161534	res = 3.530E-03
[  NORMAL ]  Iteration 77:	k_eff = 1.165163	res = 3.322E-03
[  NORMAL ]  Iteration 78:	k_eff = 1.168586	res = 3.124E-03
[  NORMAL ]  Iteration 79:	k_eff = 1.171813	res = 2.938E-03
[  NORMAL ]  Iteration 80:	k_eff = 1.174855	res = 2.762E-03
[  NORMAL ]  Iteration 81:	k_eff = 1.177721	res = 2.596E-03
[  NORMAL ]  Iteration 82:	k_eff = 1.180419	res = 2.439E-03
[  NORMAL ]  Iteration 83:	k_eff = 1.182960	res = 2.291E-03
[  NORMAL ]  Iteration 84:	k_eff = 1.185350	res = 2.152E-03
[  NORMAL ]  Iteration 85:	k_eff = 1.187599	res = 2.021E-03
[  NORMAL ]  Iteration 86:	k_eff = 1.189713	res = 1.897E-03
[  NORMAL ]  Iteration 87:	k_eff = 1.191700	res = 1.780E-03
[  NORMAL ]  Iteration 88:	k_eff = 1.193567	res = 1.670E-03
[  NORMAL ]  Iteration 89:	k_eff = 1.195321	res = 1.567E-03
[  NORMAL ]  Iteration 90:	k_eff = 1.196967	res = 1.469E-03
[  NORMAL ]  Iteration 91:	k_eff = 1.198513	res = 1.378E-03
[  NORMAL ]  Iteration 92:	k_eff = 1.199964	res = 1.291E-03
[  NORMAL ]  Iteration 93:	k_eff = 1.201326	res = 1.211E-03
[  NORMAL ]  Iteration 94:	k_eff = 1.202602	res = 1.135E-03
[  NORMAL ]  Iteration 95:	k_eff = 1.203800	res = 1.062E-03
[  NORMAL ]  Iteration 96:	k_eff = 1.204922	res = 9.959E-04
[  NORMAL ]  Iteration 97:	k_eff = 1.205974	res = 9.321E-04
[  NORMAL ]  Iteration 98:	k_eff = 1.206961	res = 8.732E-04
[  NORMAL ]  Iteration 99:	k_eff = 1.207884	res = 8.175E-04
[  NORMAL ]  Iteration 100:	k_eff = 1.208748	res = 7.646E-04
[  NORMAL ]  Iteration 101:	k_eff = 1.209558	res = 7.159E-04
[  NORMAL ]  Iteration 102:	k_eff = 1.210316	res = 6.699E-04
[  NORMAL ]  Iteration 103:	k_eff = 1.211025	res = 6.262E-04
[  NORMAL ]  Iteration 104:	k_eff = 1.211689	res = 5.864E-04
[  NORMAL ]  Iteration 105:	k_eff = 1.212310	res = 5.481E-04
[  NORMAL ]  Iteration 106:	k_eff = 1.212891	res = 5.124E-04
[  NORMAL ]  Iteration 107:	k_eff = 1.213434	res = 4.792E-04
[  NORMAL ]  Iteration 108:	k_eff = 1.213942	res = 4.477E-04
[  NORMAL ]  Iteration 109:	k_eff = 1.214416	res = 4.189E-04
[  NORMAL ]  Iteration 110:	k_eff = 1.214861	res = 3.907E-04
[  NORMAL ]  Iteration 111:	k_eff = 1.215275	res = 3.660E-04
[  NORMAL ]  Iteration 112:	k_eff = 1.215663	res = 3.414E-04
[  NORMAL ]  Iteration 113:	k_eff = 1.216025	res = 3.188E-04
[  NORMAL ]  Iteration 114:	k_eff = 1.216363	res = 2.981E-04
[  NORMAL ]  Iteration 115:	k_eff = 1.216679	res = 2.776E-04
[  NORMAL ]  Iteration 116:	k_eff = 1.216974	res = 2.599E-04
[  NORMAL ]  Iteration 117:	k_eff = 1.217250	res = 2.427E-04
[  NORMAL ]  Iteration 118:	k_eff = 1.217507	res = 2.263E-04
[  NORMAL ]  Iteration 119:	k_eff = 1.217747	res = 2.115E-04
[  NORMAL ]  Iteration 120:	k_eff = 1.217970	res = 1.970E-04
[  NORMAL ]  Iteration 121:	k_eff = 1.218180	res = 1.834E-04
[  NORMAL ]  Iteration 122:	k_eff = 1.218375	res = 1.718E-04
[  NORMAL ]  Iteration 123:	k_eff = 1.218557	res = 1.602E-04
[  NORMAL ]  Iteration 124:	k_eff = 1.218726	res = 1.496E-04
[  NORMAL ]  Iteration 125:	k_eff = 1.218885	res = 1.387E-04
[  NORMAL ]  Iteration 126:	k_eff = 1.219032	res = 1.301E-04
[  NORMAL ]  Iteration 127:	k_eff = 1.219169	res = 1.211E-04
[  NORMAL ]  Iteration 128:	k_eff = 1.219298	res = 1.127E-04
[  NORMAL ]  Iteration 129:	k_eff = 1.219418	res = 1.058E-04
[  NORMAL ]  Iteration 130:	k_eff = 1.219529	res = 9.828E-05
[  NORMAL ]  Iteration 131:	k_eff = 1.219633	res = 9.100E-05
[  NORMAL ]  Iteration 132:	k_eff = 1.219730	res = 8.530E-05
[  NORMAL ]  Iteration 133:	k_eff = 1.219820	res = 7.940E-05
[  NORMAL ]  Iteration 134:	k_eff = 1.219904	res = 7.409E-05
[  NORMAL ]  Iteration 135:	k_eff = 1.219983	res = 6.876E-05
[  NORMAL ]  Iteration 136:	k_eff = 1.220056	res = 6.455E-05
[  NORMAL ]  Iteration 137:	k_eff = 1.220124	res = 5.969E-05
[  NORMAL ]  Iteration 138:	k_eff = 1.220187	res = 5.603E-05
[  NORMAL ]  Iteration 139:	k_eff = 1.220246	res = 5.166E-05
[  NORMAL ]  Iteration 140:	k_eff = 1.220301	res = 4.829E-05
[  NORMAL ]  Iteration 141:	k_eff = 1.220352	res = 4.510E-05
[  NORMAL ]  Iteration 142:	k_eff = 1.220400	res = 4.199E-05
[  NORMAL ]  Iteration 143:	k_eff = 1.220445	res = 3.939E-05
[  NORMAL ]  Iteration 144:	k_eff = 1.220486	res = 3.630E-05
[  NORMAL ]  Iteration 145:	k_eff = 1.220525	res = 3.362E-05
[  NORMAL ]  Iteration 146:	k_eff = 1.220561	res = 3.181E-05
[  NORMAL ]  Iteration 147:	k_eff = 1.220594	res = 2.977E-05
[  NORMAL ]  Iteration 148:	k_eff = 1.220626	res = 2.745E-05
[  NORMAL ]  Iteration 149:	k_eff = 1.220655	res = 2.569E-05
[  NORMAL ]  Iteration 150:	k_eff = 1.220682	res = 2.376E-05
[  NORMAL ]  Iteration 151:	k_eff = 1.220707	res = 2.201E-05
[  NORMAL ]  Iteration 152:	k_eff = 1.220730	res = 2.071E-05
[  NORMAL ]  Iteration 153:	k_eff = 1.220752	res = 1.925E-05
[  NORMAL ]  Iteration 154:	k_eff = 1.220772	res = 1.793E-05
[  NORMAL ]  Iteration 155:	k_eff = 1.220791	res = 1.669E-05
[  NORMAL ]  Iteration 156:	k_eff = 1.220809	res = 1.554E-05
[  NORMAL ]  Iteration 157:	k_eff = 1.220826	res = 1.457E-05
[  NORMAL ]  Iteration 158:	k_eff = 1.220841	res = 1.372E-05
[  NORMAL ]  Iteration 159:	k_eff = 1.220855	res = 1.249E-05
[  NORMAL ]  Iteration 160:	k_eff = 1.220868	res = 1.138E-05
[  NORMAL ]  Iteration 161:	k_eff = 1.220881	res = 1.104E-05
[  NORMAL ]  Iteration 162:	k_eff = 1.220892	res = 1.028E-05

We report the eigenvalues computed by OpenMC and OpenMOC here together to summarize our results.


In [26]:
# Print report of keff and bias with OpenMC
openmoc_keff = solver.getKeff()
openmc_keff = sp.k_combined[0]
bias = (openmoc_keff - openmc_keff) * 1e5

print('openmc keff = {0:1.6f}'.format(openmc_keff))
print('openmoc keff = {0:1.6f}'.format(openmoc_keff))
print('bias [pcm]: {0:1.1f}'.format(bias))


openmc keff = 1.223474
openmoc keff = 1.220892
bias [pcm]: -258.1

As a sanity check, let's run a simulation with the coarse 2-group cross sections to ensure that they also produce a reasonable result.


In [27]:
openmoc_geometry = get_openmoc_geometry(sp.summary.opencg_geometry)
openmoc_cells = openmoc_geometry.getRootUniverse().getAllCells()

# Inject multi-group cross sections into OpenMOC Materials
for cell_id, cell in openmoc_cells.items():
    
    # Ignore the root cell
    if cell.getName() == 'root cell':
        continue
    
    openmoc_material = cell.getFillMaterial()
    openmoc_material.setNumEnergyGroups(coarse_groups.num_groups)
    
    # Extract the appropriate cross section objects for this cell
    transport = xs_library[cell_id]['transport']
    nufission = xs_library[cell_id]['nu-fission']
    nuscatter = xs_library[cell_id]['nu-scatter']
    chi = xs_library[cell_id]['chi']
    
    # Perform group condensation
    transport = transport.get_condensed_xs(coarse_groups)
    nufission = nufission.get_condensed_xs(coarse_groups)
    nuscatter = nuscatter.get_condensed_xs(coarse_groups)
    chi = chi.get_condensed_xs(coarse_groups)
    
    # Inject NumPy arrays of cross section data into the Material
    openmoc_material.setSigmaT(transport.get_xs(nuclides='sum').flatten())
    openmoc_material.setNuSigmaF(nufission.get_xs(nuclides='sum').flatten())
    openmoc_material.setSigmaS(nuscatter.get_xs(nuclides='sum').flatten())
    openmoc_material.setChi(chi.get_xs(nuclides='sum').flatten())

In [28]:
# Generate tracks for OpenMOC
track_generator = openmoc.TrackGenerator(openmoc_geometry, num_azim=128, azim_spacing=0.1)
track_generator.generateTracks()

# Run OpenMOC
solver = openmoc.CPUSolver(track_generator)
solver.computeEigenvalue()


[  NORMAL ]  Importing ray tracing data from file...
[  NORMAL ]  Computing the eigenvalue...
[  NORMAL ]  Iteration 0:	k_eff = 0.495816	res = 0.000E+00
[  NORMAL ]  Iteration 1:	k_eff = 0.557477	res = 5.042E-01
[  NORMAL ]  Iteration 2:	k_eff = 0.518301	res = 1.244E-01
[  NORMAL ]  Iteration 3:	k_eff = 0.509212	res = 7.027E-02
[  NORMAL ]  Iteration 4:	k_eff = 0.496490	res = 1.754E-02
[  NORMAL ]  Iteration 5:	k_eff = 0.488581	res = 2.498E-02
[  NORMAL ]  Iteration 6:	k_eff = 0.482897	res = 1.593E-02
[  NORMAL ]  Iteration 7:	k_eff = 0.479775	res = 1.163E-02
[  NORMAL ]  Iteration 8:	k_eff = 0.478834	res = 6.465E-03
[  NORMAL ]  Iteration 9:	k_eff = 0.479871	res = 1.960E-03
[  NORMAL ]  Iteration 10:	k_eff = 0.482684	res = 2.165E-03
[  NORMAL ]  Iteration 11:	k_eff = 0.487084	res = 5.860E-03
[  NORMAL ]  Iteration 12:	k_eff = 0.492900	res = 9.116E-03
[  NORMAL ]  Iteration 13:	k_eff = 0.499971	res = 1.194E-02
[  NORMAL ]  Iteration 14:	k_eff = 0.508153	res = 1.435E-02
[  NORMAL ]  Iteration 15:	k_eff = 0.517312	res = 1.637E-02
[  NORMAL ]  Iteration 16:	k_eff = 0.527325	res = 1.802E-02
[  NORMAL ]  Iteration 17:	k_eff = 0.538079	res = 1.936E-02
[  NORMAL ]  Iteration 18:	k_eff = 0.549472	res = 2.039E-02
[  NORMAL ]  Iteration 19:	k_eff = 0.561410	res = 2.117E-02
[  NORMAL ]  Iteration 20:	k_eff = 0.573807	res = 2.173E-02
[  NORMAL ]  Iteration 21:	k_eff = 0.586585	res = 2.208E-02
[  NORMAL ]  Iteration 22:	k_eff = 0.599674	res = 2.227E-02
[  NORMAL ]  Iteration 23:	k_eff = 0.613007	res = 2.231E-02
[  NORMAL ]  Iteration 24:	k_eff = 0.626528	res = 2.223E-02
[  NORMAL ]  Iteration 25:	k_eff = 0.640181	res = 2.206E-02
[  NORMAL ]  Iteration 26:	k_eff = 0.653920	res = 2.179E-02
[  NORMAL ]  Iteration 27:	k_eff = 0.667700	res = 2.146E-02
[  NORMAL ]  Iteration 28:	k_eff = 0.681483	res = 2.107E-02
[  NORMAL ]  Iteration 29:	k_eff = 0.695234	res = 2.064E-02
[  NORMAL ]  Iteration 30:	k_eff = 0.708921	res = 2.018E-02
[  NORMAL ]  Iteration 31:	k_eff = 0.722515	res = 1.969E-02
[  NORMAL ]  Iteration 32:	k_eff = 0.735993	res = 1.918E-02
[  NORMAL ]  Iteration 33:	k_eff = 0.749331	res = 1.865E-02
[  NORMAL ]  Iteration 34:	k_eff = 0.762510	res = 1.812E-02
[  NORMAL ]  Iteration 35:	k_eff = 0.775514	res = 1.759E-02
[  NORMAL ]  Iteration 36:	k_eff = 0.788326	res = 1.705E-02
[  NORMAL ]  Iteration 37:	k_eff = 0.800935	res = 1.652E-02
[  NORMAL ]  Iteration 38:	k_eff = 0.813328	res = 1.599E-02
[  NORMAL ]  Iteration 39:	k_eff = 0.825497	res = 1.547E-02
[  NORMAL ]  Iteration 40:	k_eff = 0.837433	res = 1.496E-02
[  NORMAL ]  Iteration 41:	k_eff = 0.849130	res = 1.446E-02
[  NORMAL ]  Iteration 42:	k_eff = 0.860583	res = 1.397E-02
[  NORMAL ]  Iteration 43:	k_eff = 0.871788	res = 1.349E-02
[  NORMAL ]  Iteration 44:	k_eff = 0.882742	res = 1.302E-02
[  NORMAL ]  Iteration 45:	k_eff = 0.893442	res = 1.256E-02
[  NORMAL ]  Iteration 46:	k_eff = 0.903887	res = 1.212E-02
[  NORMAL ]  Iteration 47:	k_eff = 0.914077	res = 1.169E-02
[  NORMAL ]  Iteration 48:	k_eff = 0.924012	res = 1.127E-02
[  NORMAL ]  Iteration 49:	k_eff = 0.933693	res = 1.087E-02
[  NORMAL ]  Iteration 50:	k_eff = 0.943122	res = 1.048E-02
[  NORMAL ]  Iteration 51:	k_eff = 0.952299	res = 1.010E-02
[  NORMAL ]  Iteration 52:	k_eff = 0.961228	res = 9.730E-03
[  NORMAL ]  Iteration 53:	k_eff = 0.969911	res = 9.377E-03
[  NORMAL ]  Iteration 54:	k_eff = 0.978351	res = 9.033E-03
[  NORMAL ]  Iteration 55:	k_eff = 0.986552	res = 8.702E-03
[  NORMAL ]  Iteration 56:	k_eff = 0.994517	res = 8.382E-03
[  NORMAL ]  Iteration 57:	k_eff = 1.002250	res = 8.074E-03
[  NORMAL ]  Iteration 58:	k_eff = 1.009755	res = 7.776E-03
[  NORMAL ]  Iteration 59:	k_eff = 1.017037	res = 7.488E-03
[  NORMAL ]  Iteration 60:	k_eff = 1.024099	res = 7.211E-03
[  NORMAL ]  Iteration 61:	k_eff = 1.030947	res = 6.944E-03
[  NORMAL ]  Iteration 62:	k_eff = 1.037584	res = 6.687E-03
[  NORMAL ]  Iteration 63:	k_eff = 1.044016	res = 6.438E-03
[  NORMAL ]  Iteration 64:	k_eff = 1.050247	res = 6.199E-03
[  NORMAL ]  Iteration 65:	k_eff = 1.056282	res = 5.969E-03
[  NORMAL ]  Iteration 66:	k_eff = 1.062125	res = 5.746E-03
[  NORMAL ]  Iteration 67:	k_eff = 1.067781	res = 5.531E-03
[  NORMAL ]  Iteration 68:	k_eff = 1.073255	res = 5.326E-03
[  NORMAL ]  Iteration 69:	k_eff = 1.078552	res = 5.126E-03
[  NORMAL ]  Iteration 70:	k_eff = 1.083676	res = 4.936E-03
[  NORMAL ]  Iteration 71:	k_eff = 1.088632	res = 4.751E-03
[  NORMAL ]  Iteration 72:	k_eff = 1.093425	res = 4.573E-03
[  NORMAL ]  Iteration 73:	k_eff = 1.098058	res = 4.403E-03
[  NORMAL ]  Iteration 74:	k_eff = 1.102537	res = 4.237E-03
[  NORMAL ]  Iteration 75:	k_eff = 1.106866	res = 4.079E-03
[  NORMAL ]  Iteration 76:	k_eff = 1.111049	res = 3.926E-03
[  NORMAL ]  Iteration 77:	k_eff = 1.115090	res = 3.779E-03
[  NORMAL ]  Iteration 78:	k_eff = 1.118995	res = 3.638E-03
[  NORMAL ]  Iteration 79:	k_eff = 1.122766	res = 3.501E-03
[  NORMAL ]  Iteration 80:	k_eff = 1.126408	res = 3.370E-03
[  NORMAL ]  Iteration 81:	k_eff = 1.129925	res = 3.244E-03
[  NORMAL ]  Iteration 82:	k_eff = 1.133320	res = 3.122E-03
[  NORMAL ]  Iteration 83:	k_eff = 1.136597	res = 3.005E-03
[  NORMAL ]  Iteration 84:	k_eff = 1.139761	res = 2.892E-03
[  NORMAL ]  Iteration 85:	k_eff = 1.142815	res = 2.783E-03
[  NORMAL ]  Iteration 86:	k_eff = 1.145761	res = 2.679E-03
[  NORMAL ]  Iteration 87:	k_eff = 1.148605	res = 2.579E-03
[  NORMAL ]  Iteration 88:	k_eff = 1.151348	res = 2.482E-03
[  NORMAL ]  Iteration 89:	k_eff = 1.153994	res = 2.388E-03
[  NORMAL ]  Iteration 90:	k_eff = 1.156547	res = 2.299E-03
[  NORMAL ]  Iteration 91:	k_eff = 1.159009	res = 2.212E-03
[  NORMAL ]  Iteration 92:	k_eff = 1.161384	res = 2.129E-03
[  NORMAL ]  Iteration 93:	k_eff = 1.163674	res = 2.049E-03
[  NORMAL ]  Iteration 94:	k_eff = 1.165882	res = 1.972E-03
[  NORMAL ]  Iteration 95:	k_eff = 1.168012	res = 1.898E-03
[  NORMAL ]  Iteration 96:	k_eff = 1.170064	res = 1.827E-03
[  NORMAL ]  Iteration 97:	k_eff = 1.172043	res = 1.757E-03
[  NORMAL ]  Iteration 98:	k_eff = 1.173951	res = 1.692E-03
[  NORMAL ]  Iteration 99:	k_eff = 1.175790	res = 1.628E-03
[  NORMAL ]  Iteration 100:	k_eff = 1.177562	res = 1.566E-03
[  NORMAL ]  Iteration 101:	k_eff = 1.179269	res = 1.507E-03
[  NORMAL ]  Iteration 102:	k_eff = 1.180916	res = 1.450E-03
[  NORMAL ]  Iteration 103:	k_eff = 1.182502	res = 1.396E-03
[  NORMAL ]  Iteration 104:	k_eff = 1.184030	res = 1.343E-03
[  NORMAL ]  Iteration 105:	k_eff = 1.185503	res = 1.292E-03
[  NORMAL ]  Iteration 106:	k_eff = 1.186922	res = 1.244E-03
[  NORMAL ]  Iteration 107:	k_eff = 1.188288	res = 1.197E-03
[  NORMAL ]  Iteration 108:	k_eff = 1.189606	res = 1.151E-03
[  NORMAL ]  Iteration 109:	k_eff = 1.190874	res = 1.108E-03
[  NORMAL ]  Iteration 110:	k_eff = 1.192096	res = 1.066E-03
[  NORMAL ]  Iteration 111:	k_eff = 1.193273	res = 1.026E-03
[  NORMAL ]  Iteration 112:	k_eff = 1.194407	res = 9.870E-04
[  NORMAL ]  Iteration 113:	k_eff = 1.195499	res = 9.504E-04
[  NORMAL ]  Iteration 114:	k_eff = 1.196550	res = 9.140E-04
[  NORMAL ]  Iteration 115:	k_eff = 1.197563	res = 8.792E-04
[  NORMAL ]  Iteration 116:	k_eff = 1.198538	res = 8.468E-04
[  NORMAL ]  Iteration 117:	k_eff = 1.199477	res = 8.140E-04
[  NORMAL ]  Iteration 118:	k_eff = 1.200382	res = 7.837E-04
[  NORMAL ]  Iteration 119:	k_eff = 1.201253	res = 7.539E-04
[  NORMAL ]  Iteration 120:	k_eff = 1.202091	res = 7.257E-04
[  NORMAL ]  Iteration 121:	k_eff = 1.202898	res = 6.979E-04
[  NORMAL ]  Iteration 122:	k_eff = 1.203676	res = 6.716E-04
[  NORMAL ]  Iteration 123:	k_eff = 1.204424	res = 6.465E-04
[  NORMAL ]  Iteration 124:	k_eff = 1.205144	res = 6.217E-04
[  NORMAL ]  Iteration 125:	k_eff = 1.205838	res = 5.979E-04
[  NORMAL ]  Iteration 126:	k_eff = 1.206505	res = 5.760E-04
[  NORMAL ]  Iteration 127:	k_eff = 1.207148	res = 5.532E-04
[  NORMAL ]  Iteration 128:	k_eff = 1.207767	res = 5.325E-04
[  NORMAL ]  Iteration 129:	k_eff = 1.208363	res = 5.125E-04
[  NORMAL ]  Iteration 130:	k_eff = 1.208936	res = 4.935E-04
[  NORMAL ]  Iteration 131:	k_eff = 1.209487	res = 4.744E-04
[  NORMAL ]  Iteration 132:	k_eff = 1.210018	res = 4.559E-04
[  NORMAL ]  Iteration 133:	k_eff = 1.210529	res = 4.392E-04
[  NORMAL ]  Iteration 134:	k_eff = 1.211021	res = 4.223E-04
[  NORMAL ]  Iteration 135:	k_eff = 1.211495	res = 4.060E-04
[  NORMAL ]  Iteration 136:	k_eff = 1.211951	res = 3.914E-04
[  NORMAL ]  Iteration 137:	k_eff = 1.212390	res = 3.763E-04
[  NORMAL ]  Iteration 138:	k_eff = 1.212812	res = 3.623E-04
[  NORMAL ]  Iteration 139:	k_eff = 1.213217	res = 3.480E-04
[  NORMAL ]  Iteration 140:	k_eff = 1.213608	res = 3.344E-04
[  NORMAL ]  Iteration 141:	k_eff = 1.213984	res = 3.223E-04
[  NORMAL ]  Iteration 142:	k_eff = 1.214347	res = 3.097E-04
[  NORMAL ]  Iteration 143:	k_eff = 1.214695	res = 2.985E-04
[  NORMAL ]  Iteration 144:	k_eff = 1.215031	res = 2.869E-04
[  NORMAL ]  Iteration 145:	k_eff = 1.215352	res = 2.763E-04
[  NORMAL ]  Iteration 146:	k_eff = 1.215663	res = 2.648E-04
[  NORMAL ]  Iteration 147:	k_eff = 1.215962	res = 2.552E-04
[  NORMAL ]  Iteration 148:	k_eff = 1.216249	res = 2.460E-04
[  NORMAL ]  Iteration 149:	k_eff = 1.216526	res = 2.362E-04
[  NORMAL ]  Iteration 150:	k_eff = 1.216792	res = 2.279E-04
[  NORMAL ]  Iteration 151:	k_eff = 1.217048	res = 2.188E-04
[  NORMAL ]  Iteration 152:	k_eff = 1.217294	res = 2.100E-04
[  NORMAL ]  Iteration 153:	k_eff = 1.217531	res = 2.024E-04
[  NORMAL ]  Iteration 154:	k_eff = 1.217759	res = 1.948E-04
[  NORMAL ]  Iteration 155:	k_eff = 1.217978	res = 1.872E-04
[  NORMAL ]  Iteration 156:	k_eff = 1.218189	res = 1.799E-04
[  NORMAL ]  Iteration 157:	k_eff = 1.218393	res = 1.733E-04
[  NORMAL ]  Iteration 158:	k_eff = 1.218588	res = 1.668E-04
[  NORMAL ]  Iteration 159:	k_eff = 1.218776	res = 1.600E-04
[  NORMAL ]  Iteration 160:	k_eff = 1.218957	res = 1.544E-04
[  NORMAL ]  Iteration 161:	k_eff = 1.219131	res = 1.485E-04
[  NORMAL ]  Iteration 162:	k_eff = 1.219298	res = 1.428E-04
[  NORMAL ]  Iteration 163:	k_eff = 1.219459	res = 1.374E-04
[  NORMAL ]  Iteration 164:	k_eff = 1.219614	res = 1.321E-04
[  NORMAL ]  Iteration 165:	k_eff = 1.219763	res = 1.270E-04
[  NORMAL ]  Iteration 166:	k_eff = 1.219906	res = 1.221E-04
[  NORMAL ]  Iteration 167:	k_eff = 1.220044	res = 1.175E-04
[  NORMAL ]  Iteration 168:	k_eff = 1.220177	res = 1.130E-04
[  NORMAL ]  Iteration 169:	k_eff = 1.220304	res = 1.084E-04
[  NORMAL ]  Iteration 170:	k_eff = 1.220427	res = 1.045E-04
[  NORMAL ]  Iteration 171:	k_eff = 1.220545	res = 1.007E-04
[  NORMAL ]  Iteration 172:	k_eff = 1.220659	res = 9.678E-05
[  NORMAL ]  Iteration 173:	k_eff = 1.220768	res = 9.304E-05
[  NORMAL ]  Iteration 174:	k_eff = 1.220874	res = 8.984E-05
[  NORMAL ]  Iteration 175:	k_eff = 1.220975	res = 8.640E-05
[  NORMAL ]  Iteration 176:	k_eff = 1.221073	res = 8.326E-05
[  NORMAL ]  Iteration 177:	k_eff = 1.221166	res = 7.985E-05
[  NORMAL ]  Iteration 178:	k_eff = 1.221256	res = 7.662E-05
[  NORMAL ]  Iteration 179:	k_eff = 1.221343	res = 7.371E-05
[  NORMAL ]  Iteration 180:	k_eff = 1.221426	res = 7.091E-05
[  NORMAL ]  Iteration 181:	k_eff = 1.221506	res = 6.827E-05
[  NORMAL ]  Iteration 182:	k_eff = 1.221583	res = 6.560E-05
[  NORMAL ]  Iteration 183:	k_eff = 1.221657	res = 6.320E-05
[  NORMAL ]  Iteration 184:	k_eff = 1.221729	res = 6.067E-05
[  NORMAL ]  Iteration 185:	k_eff = 1.221797	res = 5.829E-05
[  NORMAL ]  Iteration 186:	k_eff = 1.221863	res = 5.641E-05
[  NORMAL ]  Iteration 187:	k_eff = 1.221927	res = 5.382E-05
[  NORMAL ]  Iteration 188:	k_eff = 1.221987	res = 5.196E-05
[  NORMAL ]  Iteration 189:	k_eff = 1.222046	res = 4.968E-05
[  NORMAL ]  Iteration 190:	k_eff = 1.222102	res = 4.810E-05
[  NORMAL ]  Iteration 191:	k_eff = 1.222157	res = 4.617E-05
[  NORMAL ]  Iteration 192:	k_eff = 1.222209	res = 4.456E-05
[  NORMAL ]  Iteration 193:	k_eff = 1.222260	res = 4.287E-05
[  NORMAL ]  Iteration 194:	k_eff = 1.222308	res = 4.122E-05
[  NORMAL ]  Iteration 195:	k_eff = 1.222355	res = 3.971E-05
[  NORMAL ]  Iteration 196:	k_eff = 1.222399	res = 3.805E-05
[  NORMAL ]  Iteration 197:	k_eff = 1.222442	res = 3.657E-05
[  NORMAL ]  Iteration 198:	k_eff = 1.222484	res = 3.521E-05
[  NORMAL ]  Iteration 199:	k_eff = 1.222523	res = 3.381E-05
[  NORMAL ]  Iteration 200:	k_eff = 1.222561	res = 3.262E-05
[  NORMAL ]  Iteration 201:	k_eff = 1.222598	res = 3.107E-05
[  NORMAL ]  Iteration 202:	k_eff = 1.222634	res = 2.985E-05
[  NORMAL ]  Iteration 203:	k_eff = 1.222668	res = 2.902E-05
[  NORMAL ]  Iteration 204:	k_eff = 1.222700	res = 2.804E-05
[  NORMAL ]  Iteration 205:	k_eff = 1.222732	res = 2.639E-05
[  NORMAL ]  Iteration 206:	k_eff = 1.222762	res = 2.577E-05
[  NORMAL ]  Iteration 207:	k_eff = 1.222792	res = 2.487E-05
[  NORMAL ]  Iteration 208:	k_eff = 1.222820	res = 2.400E-05
[  NORMAL ]  Iteration 209:	k_eff = 1.222847	res = 2.291E-05
[  NORMAL ]  Iteration 210:	k_eff = 1.222872	res = 2.200E-05
[  NORMAL ]  Iteration 211:	k_eff = 1.222897	res = 2.121E-05
[  NORMAL ]  Iteration 212:	k_eff = 1.222921	res = 2.040E-05
[  NORMAL ]  Iteration 213:	k_eff = 1.222944	res = 1.964E-05
[  NORMAL ]  Iteration 214:	k_eff = 1.222967	res = 1.882E-05
[  NORMAL ]  Iteration 215:	k_eff = 1.222988	res = 1.821E-05
[  NORMAL ]  Iteration 216:	k_eff = 1.223009	res = 1.763E-05
[  NORMAL ]  Iteration 217:	k_eff = 1.223029	res = 1.690E-05
[  NORMAL ]  Iteration 218:	k_eff = 1.223048	res = 1.630E-05
[  NORMAL ]  Iteration 219:	k_eff = 1.223067	res = 1.572E-05
[  NORMAL ]  Iteration 220:	k_eff = 1.223084	res = 1.507E-05
[  NORMAL ]  Iteration 221:	k_eff = 1.223101	res = 1.427E-05
[  NORMAL ]  Iteration 222:	k_eff = 1.223117	res = 1.394E-05
[  NORMAL ]  Iteration 223:	k_eff = 1.223133	res = 1.330E-05
[  NORMAL ]  Iteration 224:	k_eff = 1.223148	res = 1.298E-05
[  NORMAL ]  Iteration 225:	k_eff = 1.223163	res = 1.241E-05
[  NORMAL ]  Iteration 226:	k_eff = 1.223177	res = 1.167E-05
[  NORMAL ]  Iteration 227:	k_eff = 1.223190	res = 1.151E-05
[  NORMAL ]  Iteration 228:	k_eff = 1.223203	res = 1.073E-05
[  NORMAL ]  Iteration 229:	k_eff = 1.223215	res = 1.050E-05
[  NORMAL ]  Iteration 230:	k_eff = 1.223227	res = 1.000E-05

In [29]:
# Print report of keff and bias with OpenMC
openmoc_keff = solver.getKeff()
openmc_keff = sp.k_combined[0]
bias = (openmoc_keff - openmc_keff) * 1e5

print('openmc keff = {0:1.6f}'.format(openmc_keff))
print('openmoc keff = {0:1.6f}'.format(openmoc_keff))
print('bias [pcm]: {0:1.1f}'.format(bias))


openmc keff = 1.223474
openmoc keff = 1.223227
bias [pcm]: -24.7

There is a non-trivial bias in both the 2-group and 8-group cases. In the case of a pin cell, one can show that these biases do not converge to <100 pcm with more particle histories. For heterogeneous geometries, additional measures must be taken to address the following three sources of bias:

  • Appropriate transport-corrected cross sections
  • Spatial discretization of OpenMOC's mesh
  • Constant-in-angle multi-group cross sections

Visualizing MGXS Data

It is often insightful to generate visual depictions of multi-group cross sections. There are many different types of plots which may be useful for multi-group cross section visualization, only a few of which will be shown here for enrichment and inspiration.

One particularly useful visualization is a comparison of the continuous-energy and multi-group cross sections for a particular nuclide and reaction type. We illustrate one option for generating such plots with the use of the openmc.data module to parse continuous-energy cross sections from an openly available ACE cross section library distributed by NNDC. First, we instantiate a openmc.data.IncidentNeutron object for U-235 as follows.


In [30]:
# Parse ACE data into memory
u235 = openmc.data.IncidentNeutron.from_ace('../../../../scripts/nndc/293.6K/U_235_293.6K.ace')

# Extract the continuous-energy U-235 fission cross section data
fission = u235[18]

Now, we use matplotlib and seaborn to plot the continuous-energy and multi-group cross sections on a single plot.


In [31]:
# Create a loglog plot of the U-235 continuous-energy fission cross section 
plt.loglog(fission.xs['294K'].x, fission.xs['294K'].y, color='b', linewidth=1)

# Extract energy group bounds and MGXS values to plot
nufission = xs_library[fuel_cell.id]['fission']
energy_groups = nufission.energy_groups
x = energy_groups.group_edges
y = nufission.get_xs(nuclides=['U235'], order_groups='decreasing', xs_type='micro')
y = np.squeeze(y)

# Fix low energy bound to the value defined by the ACE library
x[0] = fission.xs['294K'].x[0]

# Extend the mgxs values array for matplotlib's step plot
y = np.insert(y, 0, y[0])

# Create a step plot for the MGXS
plt.plot(x, y, drawstyle='steps', color='r', linewidth=3)

plt.title('U-235 Fission Cross Section')
plt.xlabel('Energy [eV]')
plt.ylabel('Micro Fission XS')
plt.legend(['Continuous', 'Multi-Group'])
plt.xlim((x.min(), x.max()))


Out[31]:
(9.9999999999999991e-06, 20000000.0)

Another useful type of illustration is scattering matrix sparsity structures. First, we extract Pandas DataFrames for the H-1 and O-16 scattering matrices.


In [32]:
# Construct a Pandas DataFrame for the microscopic nu-scattering matrix
nuscatter = xs_library[moderator_cell.id]['nu-scatter']
df = nuscatter.get_pandas_dataframe(xs_type='micro')

# Slice DataFrame in two for each nuclide's mean values
h1 = df[df['nuclide'] == 'H1']['mean']
o16 = df[df['nuclide'] == 'O16']['mean']

# Cast DataFrames as NumPy arrays
h1 = h1.as_matrix()
o16 = o16.as_matrix()

# Reshape arrays to 2D matrix for plotting
h1.shape = (fine_groups.num_groups, fine_groups.num_groups)
o16.shape = (fine_groups.num_groups, fine_groups.num_groups)

Matplotlib's imshow routine can be used to plot the matrices to illustrate their sparsity structures.


In [33]:
# Create plot of the H-1 scattering matrix
fig = plt.subplot(121)
fig.imshow(h1, interpolation='nearest', cmap='jet')
plt.title('H-1 Scattering Matrix')
plt.xlabel('Group Out')
plt.ylabel('Group In')
plt.grid()

# Create plot of the O-16 scattering matrix
fig2 = plt.subplot(122)
fig2.imshow(o16, interpolation='nearest', cmap='jet')
plt.title('O-16 Scattering Matrix')
plt.xlabel('Group Out')
plt.ylabel('Group In')
plt.grid()

# Show the plot on screen
plt.show()