This IPython Notebook illustrates the use of the openmc.mgxs.Library class. The Library class is designed to automate the calculation of multi-group cross sections for use cases with one or more domains, cross section types, and/or nuclides. In particular, this Notebook illustrates the following features:

  • Calculation of multi-energy-group and multi-delayed-group cross sections for a fuel assembly
  • Automated creation, manipulation and storage of MGXS with openmc.mgxs.Library
  • Steady-state pin-by-pin delayed neutron fractions (beta) for each delayed group.
  • Generation of surface currents on the interfaces and surfaces of a Mesh.

Generate Input Files


In [1]:
import math
import pickle

from IPython.display import Image
import matplotlib.pyplot as plt
import numpy as np

import openmc
import openmc.mgxs

%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')
b10 = openmc.Nuclide('B10')
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 materials for the fuel, water, and cladding of the fuel pins.


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)
water.add_nuclide(b10, 8.0042e-6)

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

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


In [4]:
# Instantiate a Materials object
materials_file = openmc.Materials((fuel, water, zircaloy))
materials_file.default_xs = '71c'

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

Now let's move on to the geometry. This problem will be a square array of fuel pins and control rod guide tubes for which we can use OpenMC's lattice/universe feature. The basic universe will have three regions for the fuel, the clad, and the surrounding coolant. The first step is to create the bounding surfaces for fuel and clad, as well as the outer bounding surfaces of the problem.


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=-10.71, boundary_type='reflective')
max_x = openmc.XPlane(x0=+10.71, boundary_type='reflective')
min_y = openmc.YPlane(y0=-10.71, boundary_type='reflective')
max_y = openmc.YPlane(y0=+10.71, boundary_type='reflective')
min_z = openmc.ZPlane(z0=-10., boundary_type='reflective')
max_z = openmc.ZPlane(z0=+10., boundary_type='reflective')

With the surfaces defined, we can now construct a fuel pin cell from cells that are defined by intersections of half-spaces created by the surfaces.


In [6]:
# Create a Universe to encapsulate a fuel pin
fuel_pin_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
fuel_pin_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
fuel_pin_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
fuel_pin_universe.add_cell(moderator_cell)

Likewise, we can construct a control rod guide tube with the same surfaces.


In [7]:
# Create a Universe to encapsulate a control rod guide tube
guide_tube_universe = openmc.Universe(name='Guide Tube')

# Create guide tube Cell
guide_tube_cell = openmc.Cell(name='Guide Tube Water')
guide_tube_cell.fill = water
guide_tube_cell.region = -fuel_outer_radius
guide_tube_universe.add_cell(guide_tube_cell)

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

# Create a moderator Cell
moderator_cell = openmc.Cell(name='Guide Tube Moderator')
moderator_cell.fill = water
moderator_cell.region = +clad_outer_radius
guide_tube_universe.add_cell(moderator_cell)

Using the pin cell universe, we can construct a 17x17 rectangular lattice with a 1.26 cm pitch.


In [8]:
# Create fuel assembly Lattice
assembly = openmc.RectLattice(name='1.6% Fuel Assembly')
assembly.pitch = (1.26, 1.26)
assembly.lower_left = [-1.26 * 17. / 2.0] * 2

Next, we create a NumPy array of fuel pin and guide tube universes for the lattice.


In [9]:
# Create array indices for guide tube locations in lattice
template_x = np.array([5, 8, 11, 3, 13, 2, 5, 8, 11, 14, 2, 5, 8,
                       11, 14, 2, 5, 8, 11, 14, 3, 13, 5, 8, 11])
template_y = np.array([2, 2, 2, 3, 3, 5, 5, 5, 5, 5, 8, 8, 8, 8,
                       8, 11, 11, 11, 11, 11, 13, 13, 14, 14, 14])

# Initialize an empty 17x17 array of the lattice universes
universes = np.empty((17, 17), dtype=openmc.Universe)

# Fill the array with the fuel pin and guide tube universes
universes[:,:] = fuel_pin_universe
universes[template_x, template_y] = guide_tube_universe

# Store the array of universes in the lattice
assembly.universes = universes

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 [10]:
# Create root Cell
root_cell = openmc.Cell(name='root cell')
root_cell.fill = assembly

# Add boundary planes
root_cell.region = +min_x & -max_x & +min_y & -max_y & +min_z & -max_z

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

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


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

In [12]:
# Export to "geometry.xml"
geometry.export_to_xml()

With the geometry and materials finished, we now just need to define simulation parameters. In this case, we will use 10 inactive batches and 40 active batches each with 2500 particles.


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

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

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

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

Let us also create a Plots file that we can use to verify that our fuel assembly geometry was created successfully.


In [14]:
# Instantiate a Plot
plot = openmc.Plot(plot_id=1)
plot.filename = 'materials-xy'
plot.origin = [0, 0, 0]
plot.pixels = [250, 250]
plot.width = [-10.71*2, -10.71*2]
plot.color = 'mat'

# Instantiate a Plots object, add Plot, and export to "plots.xml"
plot_file = openmc.Plots([plot])
plot_file.export_to_xml()

With the plots.xml file, we can now generate and view the plot. OpenMC outputs plots in .ppm format, which can be converted into a compressed format like .png with the convert utility.


In [15]:
# Run openmc in plotting mode
openmc.plot_geometry(output=False)


Out[15]:
0

In [16]:
# Convert OpenMC's funky ppm to png
!convert materials-xy.ppm materials-xy.png

# Display the materials plot inline
Image(filename='materials-xy.png')


Out[16]:

As we can see from the plot, we have a nice array of fuel and guide tube pin cells with fuel, cladding, and water!

Create an MGXS Library

Now we are ready to generate multi-group cross sections! First, let's define 20-energy-group, 1-energy-group, and 6-delayed-group structures.


In [17]:
# Instantiate a 20-group EnergyGroups object
energy_groups = openmc.mgxs.EnergyGroups()
energy_groups.group_edges = np.logspace(-3, 7.3, 21)

# Instantiate a 1-group EnergyGroups object
one_group = openmc.mgxs.EnergyGroups()
one_group.group_edges = np.array([energy_groups.group_edges[0], energy_groups.group_edges[-1]])

# Instantiate a 6-delayed-group list
delayed_groups = list(range(1,7))

Next, we will instantiate an openmc.mgxs.Library for the energy and delayed groups with our the fuel assembly geometry.


In [18]:
# Instantiate a tally mesh                                                                                                                                                                  
mesh = openmc.Mesh(mesh_id=1)
mesh.type = 'regular'
mesh.dimension = [17, 17, 1]
mesh.lower_left = [-10.71, -10.71, -10000.]
mesh.width = [1.26, 1.26, 20000.]

# Initialize an 20-energy-group and 6-delayed-group MGXS Library
mgxs_lib = openmc.mgxs.Library(geometry)
mgxs_lib.energy_groups  = energy_groups
mgxs_lib.delayed_groups = delayed_groups

# Specify multi-group cross section types to compute
mgxs_lib.mgxs_types = ['total', 'transport', 'nu-scatter matrix', 'kappa-fission', 'inverse-velocity', 'chi-prompt',
                      'prompt-nu-fission', 'chi-delayed', 'delayed-nu-fission', 'beta']

# Specify a "mesh" domain type for the cross section tally filters
mgxs_lib.domain_type = 'mesh'

# Specify the mesh domain over which to compute multi-group cross sections
mgxs_lib.domains = [mesh]

# Construct all tallies needed for the multi-group cross section library
mgxs_lib.build_library()

# Create a "tallies.xml" file for the MGXS Library
tallies_file = openmc.Tallies()
mgxs_lib.add_to_tallies_file(tallies_file, merge=True)

# Instantiate a current tally
mesh_filter = openmc.MeshFilter(mesh)
current_tally = openmc.Tally(name='current tally')
current_tally.scores = ['current']
current_tally.filters = [mesh_filter]

# Add current tally to the tallies file
tallies_file.append(current_tally)

# Export to "tallies.xml"
tallies_file.export_to_xml()

Now, we can run OpenMC to generate the cross sections.


In [19]:
# Run OpenMC
openmc.run()


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

                   | 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 14:09:42
    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 B10 from /home/romano/openmc/scripts/nndc_hdf5/B10.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.03852                       
        2/1    0.99743                       
        3/1    1.02987                       
        4/1    1.04472                       
        5/1    1.02183                       
        6/1    1.05263                       
        7/1    0.99048                       
        8/1    1.02753                       
        9/1    1.03159                       
       10/1    1.04005                       
       11/1    1.05278                       
       12/1    1.02555    1.03917 +/- 0.01362
       13/1    0.99400    1.02411 +/- 0.01699
       14/1    1.03508    1.02685 +/- 0.01232
       15/1    1.00055    1.02159 +/- 0.01090
       16/1    1.01334    1.02022 +/- 0.00900
       17/1    0.99822    1.01707 +/- 0.00823
       18/1    1.01767    1.01715 +/- 0.00713
       19/1    1.05052    1.02086 +/- 0.00730
       20/1    1.03133    1.02190 +/- 0.00661
       21/1    1.04112    1.02365 +/- 0.00623
       22/1    1.04175    1.02516 +/- 0.00588
       23/1    1.01909    1.02469 +/- 0.00543
       24/1    1.07119    1.02801 +/- 0.00603
       25/1    0.97414    1.02442 +/- 0.00666
       26/1    1.04709    1.02584 +/- 0.00639
       27/1    1.05872    1.02777 +/- 0.00631
       28/1    1.03930    1.02841 +/- 0.00598
       29/1    1.01488    1.02770 +/- 0.00570
       30/1    1.04513    1.02857 +/- 0.00548
       31/1    0.99538    1.02699 +/- 0.00545
       32/1    1.00106    1.02581 +/- 0.00532
       33/1    0.99389    1.02442 +/- 0.00527
       34/1    0.99938    1.02338 +/- 0.00516
       35/1    1.02161    1.02331 +/- 0.00495
       36/1    1.04084    1.02398 +/- 0.00480
       37/1    0.98801    1.02265 +/- 0.00481
       38/1    1.01348    1.02232 +/- 0.00464
       39/1    1.06693    1.02386 +/- 0.00474
       40/1    1.07729    1.02564 +/- 0.00491
       41/1    1.03191    1.02585 +/- 0.00475
       42/1    1.05209    1.02667 +/- 0.00468
       43/1    1.02997    1.02677 +/- 0.00453
       44/1    1.07288    1.02812 +/- 0.00460
       45/1    1.01268    1.02768 +/- 0.00449
       46/1    1.03759    1.02796 +/- 0.00437
       47/1    1.02620    1.02791 +/- 0.00425
       48/1    1.02509    1.02783 +/- 0.00414
       49/1    1.01075    1.02740 +/- 0.00406
       50/1    0.99403    1.02656 +/- 0.00404
 Creating state point statepoint.50.h5...

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


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

 Total time for initialization     =  5.5777E-01 seconds
   Reading cross sections          =  4.0851E-01 seconds
 Total time in simulation          =  3.0735E+01 seconds
   Time in transport only          =  3.0468E+01 seconds
   Time in inactive batches        =  2.5750E+00 seconds
   Time in active batches          =  2.8160E+01 seconds
   Time synchronizing fission bank =  7.0866E-03 seconds
     Sampling source sites         =  5.6963E-03 seconds
     SEND/RECV source sites        =  1.2941E-03 seconds
   Time accumulating tallies       =  1.2199E-01 seconds
 Total time for finalization       =  3.0383E-03 seconds
 Total time elapsed                =  3.1316E+01 seconds
 Calculation Rate (inactive)       =  9708.82 neutrons/second
 Calculation Rate (active)         =  3551.09 neutrons/second

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

 k-effective (Collision)     =  1.02436 +/-  0.00318
 k-effective (Track-length)  =  1.02656 +/-  0.00404
 k-effective (Absorption)    =  1.02601 +/-  0.00333
 Combined k-effective        =  1.02539 +/-  0.00276
 Leakage Fraction            =  0.00000 +/-  0.00000

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

The statepoint is now ready to be analyzed by the Library. We simply have to load the tallies from the statepoint into the Library and our MGXS objects will compute the cross sections for us under-the-hood.


In [21]:
# Initialize MGXS Library with OpenMC statepoint data
mgxs_lib.load_from_statepoint(sp)

# Extrack the current tally separately
current_tally = sp.get_tally(name='current tally')

Using Tally Arithmetic to Compute the Delayed Neutron Precursor Concentrations

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 compute the delayed neutron precursor concentrations using the Beta and DelayedNuFissionXS objects. The delayed neutron precursor concentrations are modeled using the following equations:

$$\frac{\partial}{\partial t} C_{k,d} (t) = \int_{0}^{\infty}\mathrm{d}E'\int_{\mathbf{r} \in V_{k}}\mathrm{d}\mathbf{r} \beta_{k,d} (t) \nu_d \sigma_{f,x}(\mathbf{r},E',t)\Phi(\mathbf{r},E',t) - \lambda_{d} C_{k,d} (t) $$$$C_{k,d} (t=0) = \frac{1}{\lambda_{d}} \int_{0}^{\infty}\mathrm{d}E'\int_{\mathbf{r} \in V_{k}}\mathrm{d}\mathbf{r} \beta_{k,d} (t=0) \nu_d \sigma_{f,x}(\mathbf{r},E',t=0)\Phi(\mathbf{r},E',t=0) $$

In [22]:
# Set the time constants for the delayed precursors (in seconds^-1)
precursor_halflife = np.array([55.6, 24.5, 16.3, 2.37, 0.424, 0.195])
precursor_lambda = -np.log(0.5) / precursor_halflife

beta = mgxs_lib.get_mgxs(mesh, 'beta')

# Create a tally object with only the delayed group filter for the time constants
beta_filters = [f for f in beta.xs_tally.filters if type(f) is not openmc.DelayedGroupFilter]
lambda_tally = beta.xs_tally.summation(nuclides=beta.xs_tally.nuclides)
for f in beta_filters:
    lambda_tally = lambda_tally.summation(filter_type=type(f), remove_filter=True) * 0. + 1.

# Set the mean of the lambda tally and reshape to account for nuclides and scores
lambda_tally._mean = precursor_lambda
lambda_tally._mean.shape = lambda_tally.std_dev.shape

# Set a total nuclide and lambda score
lambda_tally.nuclides = [openmc.Nuclide(name='total')]
lambda_tally.scores = ['lambda']

delayed_nu_fission = mgxs_lib.get_mgxs(mesh, 'delayed-nu-fission')

# Use tally arithmetic to compute the precursor concentrations
precursor_conc = beta.xs_tally.summation(filter_type=openmc.EnergyFilter, remove_filter=True) * \
    delayed_nu_fission.xs_tally.summation(filter_type=openmc.EnergyFilter, remove_filter=True) / lambda_tally
    
# The difference is a derived tally which can generate Pandas DataFrames for inspection
precursor_conc.get_pandas_dataframe().head(10)


Out[22]:
mesh 1 delayedgroup nuclide score mean std. dev.
x y z
0 1 1 1 1 total (((delayed-nu-fission / nu-fission) * (delayed... 0.002406 0.000557
1 1 1 1 2 total (((delayed-nu-fission / nu-fission) * (delayed... 0.000937 0.000073
2 1 1 1 3 total (((delayed-nu-fission / nu-fission) * (delayed... 0.007412 0.000841
3 1 1 1 4 total (((delayed-nu-fission / nu-fission) * (delayed... 0.072924 0.005015
4 1 1 1 5 total (((delayed-nu-fission / nu-fission) * (delayed... 0.034008 0.002213
5 1 1 1 6 total (((delayed-nu-fission / nu-fission) * (delayed... 0.002561 0.000366
6 1 2 1 1 total (((delayed-nu-fission / nu-fission) * (delayed... 0.011966 0.004607
7 1 2 1 2 total (((delayed-nu-fission / nu-fission) * (delayed... 0.000917 0.000075
8 1 2 1 3 total (((delayed-nu-fission / nu-fission) * (delayed... 0.007980 0.000879
9 1 2 1 4 total (((delayed-nu-fission / nu-fission) * (delayed... 0.084940 0.005351

Another useful feature of the Python API is the ability to extract the surface currents for the interfaces and surfaces of a mesh. We can inspect the currents for the mesh by getting the pandas dataframe.


In [23]:
current_tally.get_pandas_dataframe().head(10)


Out[23]:
mesh 1 surface nuclide score mean std. dev.
x y z
0 1 1 1 x-min out total current 0.00000 0.000000
1 1 1 1 x-max out total current 0.00000 0.000000
2 1 1 1 y-min out total current 0.02985 0.000678
3 1 1 1 y-max out total current 0.03023 0.000637
4 1 1 1 z-min out total current 0.00000 0.000000
5 1 1 1 z-max out total current 0.00000 0.000000
6 1 1 1 x-min in total current 0.03085 0.000628
7 1 1 1 x-max in total current 0.03058 0.000609
8 1 1 1 y-min in total current 0.00000 0.000000
9 1 1 1 y-max in total current 0.00000 0.000000

Cross Section Visualizations

In addition to inspecting the data in the tallies by getting the pandas dataframe, we can also plot the tally data on the domain mesh. Below is the delayed neutron fraction tallied in each mesh cell for each delayed group.


In [24]:
# Extract the energy-condensed delayed neutron fraction tally
beta_by_group = beta.get_condensed_xs(one_group).xs_tally.summation(filter_type='energy', remove_filter=True)
beta_by_group.mean.shape = (17, 17, 6)
beta_by_group.mean[beta_by_group.mean == 0] = np.nan

# Plot the betas
plt.figure(figsize=(18,9))
fig = plt.subplot(231)
plt.imshow(beta_by_group.mean[:,:,0], interpolation='none', cmap='jet')
plt.colorbar()
plt.title('Beta - delayed group 1')

fig = plt.subplot(232)
plt.imshow(beta_by_group.mean[:,:,1], interpolation='none', cmap='jet')
plt.colorbar()
plt.title('Beta - delayed group 2')

fig = plt.subplot(233)
plt.imshow(beta_by_group.mean[:,:,2], interpolation='none', cmap='jet')
plt.colorbar()
plt.title('Beta - delayed group 3')

fig = plt.subplot(234)
plt.imshow(beta_by_group.mean[:,:,3], interpolation='none', cmap='jet')
plt.colorbar()
plt.title('Beta - delayed group 4')

fig = plt.subplot(235)
plt.imshow(beta_by_group.mean[:,:,4], interpolation='none', cmap='jet')
plt.colorbar()
plt.title('Beta - delayed group 5')

fig = plt.subplot(236)
plt.imshow(beta_by_group.mean[:,:,5], interpolation='none', cmap='jet')
plt.colorbar()
plt.title('Beta - delayed group 6')


Out[24]:
<matplotlib.text.Text at 0x7fdb1d74f208>

In [ ]: