In [1]:
# Import Necessary Packages

%matplotlib inline
import openmc
import numpy as np
from math import pi, sin, cos
In [2]:
# ADD MATERIAL DEFINITIONS
# Fuel Material (MOX Fuels)
uranium = openmc.Material() # Depleted Uranium for ALFRED
uranium.add_nuclide('U234', 0.003)
uranium.add_nuclide('U235', 0.404)
uranium.add_nuclide('U236', 0.010)
uranium.add_nuclide('U238', 99.583)

plutonium = openmc.Material()
plutonium.add_nuclide('Pu238', 2.332)
plutonium.add_nuclide('Pu239', 56.873)
plutonium.add_nuclide('Pu240', 26.997)
plutonium.add_nuclide('Pu241', 6.105)
plutonium.add_nuclide('Pu242', 7.693)

oxygen = openmc.Material()
oxygen.add_element('O', 1.0)

uo2 = openmc.Material.mix_materials([uranium, oxygen],[0.3367, 0.6633])
puo2 = openmc.Material.mix_materials([plutonium, oxygen], [0.3367, 0.6633])

mox1 = openmc.Material.mix_materials([puo2, uo2], [0.217, 0.783], 'wo') # 21.7% PuO2 Enrichment
mox2 = openmc.Material.mix_materials([puo2, uo2], [0.278, 0.722], 'wo') # 27.8% PuO2 Enrichment

mox1.set_density('g/cm3', 11.07 * 0.95)    # Setting a density of 0.95 of theoretical density
mox2.set_density('g/cm3', 11.1 * 0.95)     # Setting a density of 0.95 of theoretical density

mox1.temperature = 1200
mox2.temperature = 1200

# Cladding Material (Ti-15-15 Steel)
clad = openmc.Material()
clad.add_element('Cr', 15, 'wo')
clad.add_element('Ni', 15, 'wo')
clad.add_element('Mo', 1.5, 'wo')
clad.add_element('Mn', 1.5, 'wo')
clad.add_element('Si', 0.9, 'wo')
clad.add_element('Ti', 0.4, 'wo')
clad.add_element('C', 0.09, 'wo')
clad.add_element('B', 0.006, 'wo')
clad.add_element('Fe', 65.604,'wo')
clad.set_density('g/cm3', 7.95)
clad.temperature = 900

# Coolant (Lead)
lead = openmc.Material()
lead.add_element('Pb', 1.0,)
lead.temperature = 700
lead.set_density('g/cm3', 10.6)
lead.depletable = True
lead.volume = 6134682.08   

# Gap (Helium)
he = openmc.Material()
he.add_element('He', 1)
he.set_density('g/cm3', 0.00016)
he.temperature= 700

# Absorber (Boron Carbide)
b4c = openmc.Material()
b4c.add_element('B', 4.0, enrichment=90, enrichment_target='B10', enrichment_type='wo')
b4c.add_element('C', 1.0)
b4c.set_density('g/cm3', 2.2)
b4c.temperature = 700

# Reflector (Yttria-Stabilized Zirconia)
zirconia = openmc.Material()
zirconia.add_elements_from_formula('ZrO2', 'ao', 1.0)

yttria = openmc.Material()
yttria.add_elements_from_formula('Y2O3', 'ao', 1.0)

ysz = openmc.Material.mix_materials([zirconia, yttria], [0.95, 0.05], 'wo')
ysz.temperature = 700
ysz.set_density('g/cm3', 6.08)

mat = openmc.Materials([mox1, mox2, clad, he, lead, b4c, ysz])
mat.export_to_xml()
In [3]:
# ADD PRIMARY GEOMETRY DEFINITIONS
# Surfaces
fuel_ir = openmc.ZCylinder(r=0.1)
fuel_or = openmc.ZCylinder(r=0.45)
clad_ir = openmc.ZCylinder(r=0.465)
clad_or = openmc.ZCylinder(r=0.525)

top = openmc.ZPlane(z0=+30)
bottom = openmc.ZPlane(z0=-30)
cr_top = openmc.ZPlane(z0=-24)
cr_down = openmc.ZPlane(z0=-84.5)
up = openmc.ZPlane(z0=+42, boundary_type='vacuum')
down = openmc.ZPlane(z0=-85, boundary_type='vacuum')

# Regions
center_region = -fuel_ir & -up & +down
fuel_region = +fuel_ir & -fuel_or & -top & +bottom
gap_region = +fuel_or & -clad_ir & -top & +bottom
clad_region = +clad_ir & -clad_or & -top & +bottom
coolant_region = +clad_or & -up & +down
In [4]:
# Define Inner Assembly Fuel Pins
center_cell1 = openmc.Cell(region=center_region)
fuel_cell1 = openmc.Cell(fill=mox1, region=fuel_region)
gap_cell1 = openmc.Cell(fill=he, region=gap_region)
clad_cell1 = openmc.Cell(fill=clad, region=clad_region)
coolant_cell1 = openmc.Cell(fill=lead, region=coolant_region)

fuel_u1 = openmc.Universe(cells=[center_cell1, fuel_cell1, gap_cell1, clad_cell1, coolant_cell1])
In [5]:
# Plot Inner Pincell
fuel_u1.plot(width=(1.5,1.5), pixels=(150,150), color_by='material')
Out[5]:
<Axes: xlabel='x [cm]', ylabel='y [cm]'>
No description has been provided for this image
In [6]:
# Define Inner Fuel Assembly
all_lead_out = openmc.Cell(fill=lead)
all_lead_out_u = openmc.Universe(cells=[all_lead_out])
in_lat = openmc.HexLattice(name='inner_fuel_assembly')
in_lat.center = (0., 0.)
in_lat.pitch = (1.386,)
in_lat.outer = all_lead_out_u

in_ring6 = [fuel_u1]*36
in_ring5 = [fuel_u1]*30
in_ring4 = [fuel_u1]*24
in_ring3 = [fuel_u1]*18
in_ring2 = [fuel_u1]*12
in_ring1 = [fuel_u1]*6
in_ring0 = [fuel_u1]

in_lat.universes = [in_ring6, in_ring5, in_ring4, in_ring3, in_ring2, in_ring1, in_ring0]
in_lat.orientation = 'y'

outer_in_surface = openmc.model.HexagonalPrism(edge_length=9.0, orientation='y')

main_in_assembly = openmc.Cell(fill=in_lat, region=-outer_in_surface & -top & +bottom)

in_plenum_top = openmc.Cell(fill=lead, region= -outer_in_surface & -up & +top)
in_plenum_bottom = openmc.Cell(fill=lead, region= -outer_in_surface & +down & -bottom)

out_in_assembly = openmc.Cell(fill=lead, region=+outer_in_surface & -up & +down)

main_in_u = openmc.Universe(cells=[main_in_assembly, out_in_assembly, in_plenum_bottom, in_plenum_top])
In [7]:
# Plot Inner Assembly
main_in_u.plot(width=(20,20), pixels=(250,250), color_by='material')
Out[7]:
<Axes: xlabel='x [cm]', ylabel='y [cm]'>
No description has been provided for this image
In [8]:
# Define Outer Assembly Fuel Pins
center_cell2 = openmc.Cell(region=center_region)
fuel_cell2 = openmc.Cell(fill=mox2, region=fuel_region)
gap_cell2 = openmc.Cell(fill=he, region=gap_region)
clad_cell2 = openmc.Cell(fill=clad, region=clad_region)
coolant_cell2 = openmc.Cell(fill=lead, region=coolant_region)

fuel_u2 = openmc.Universe(cells=[center_cell2, fuel_cell2, gap_cell2, clad_cell2, coolant_cell2])

# The plot is same as fuel_u1
In [9]:
# Define Outer Fuel Assembly
out_lat = openmc.HexLattice(name='assembly')
out_lat.center = (0., 0.)
out_lat.pitch = (1.386,)
out_lat.outer=all_lead_out_u
out_lat.orientation = 'y'

out_ring6 = [fuel_u2]*36
out_ring5 = [fuel_u2]*30
out_ring4 = [fuel_u2]*24
out_ring3 = [fuel_u2]*18
out_ring2 = [fuel_u2]*12
out_ring1 = [fuel_u2]*6
out_ring0 = [fuel_u2]

out_lat.universes = [out_ring6, out_ring5, out_ring4, out_ring3, out_ring2, out_ring1, out_ring0]

outer_out_surface = openmc.model.HexagonalPrism(edge_length=9, orientation='y')

main_out_assembly = openmc.Cell(fill=out_lat, region=-outer_out_surface & -top & +bottom)

out_plenum_top = openmc.Cell(fill=lead, region=-outer_out_surface & -up & +top)
out_plenum_bottom = openmc.Cell(fill=lead, region=-outer_out_surface & +down & -bottom)

out_out_assembly = openmc.Cell(fill=lead, region=+outer_out_surface & -up & +down)

main_out_u = openmc.Universe(cells=[main_out_assembly, out_out_assembly, out_plenum_bottom, out_plenum_top])

# The plot is same as inner assembly
In [10]:
# Define Shutdown Rod
outer_sr_surface = openmc.model.HexagonalPrism(edge_length=9, orientation='y')
sr_cell = openmc.Cell(fill=lead, region=-outer_sr_surface & -up & +down)
out_sr_cell = openmc.Cell(fill=lead, region=+outer_sr_surface & -up & +down)
sr_u = openmc.Universe(cells=[sr_cell, out_sr_cell])
In [11]:
# Define Control Rod

calendria_ir = 6.44780
calendria_or = 6.58750
r_rod = 1.48
r_clad = 1.53

ring_radii = np.array([0.0, 3.2, 6.2])

# These are the surfaces that will divide each of the rings
radial_surf = [openmc.ZCylinder(r=r) for r in
               (ring_radii[:-1] + ring_radii[1:])/2]

lead_cells = []
for i in range(ring_radii.size):
    # Create annular region
    if i == 0:
        lead_region = -radial_surf[i]  & -up & +down
    elif i == ring_radii.size - 1:
        lead_region = +radial_surf[i-1]  & -up & +down
    else:
        lead_region = +radial_surf[i-1] & -radial_surf[i]  & -up & +down
        
    lead_cells.append(openmc.Cell(fill=lead, region=lead_region  & -up & +down))

cr_u = openmc.Universe(cells=lead_cells)

# Pin Universe
surf_rod = openmc.ZCylinder(r=r_rod)

rod_cell = openmc.Cell(fill=b4c, region=-surf_rod & -cr_top & +cr_down)
clad_cell = openmc.Cell(fill=clad, region=+surf_rod  & -cr_top & +cr_down)

pin_universe = openmc.Universe(cells=(rod_cell, clad_cell))

num_pins = [1, 6, 12]
angles = [0, 30, 15]

cr_top_cell=openmc.Cell(fill=lead, region=-up & +cr_top)
cr_down_cell=openmc.Cell(fill=lead, region=+down & -cr_down)
cr_cyl_ir = openmc.ZCylinder(r=8)
cr_cyl_or = openmc.ZCylinder(r=8.5)

for i, (r, n, a) in enumerate(zip(ring_radii, num_pins, angles)):
    for j in range(n):
        # Determine the location of center of pin
        theta = (a + j/n*360.) * pi/180.
        x = r*cos(theta)
        y = r*sin(theta)
        
        pin_boundary = openmc.ZCylinder(x0=x, y0=y, r=r_clad)
        lead_cells[i].region &= +pin_boundary  
        
        # Create each fuel pin -- note that we explicitly assign an ID so 
        # that we can identify the pin later when looking at tallies
        pin = openmc.Cell(fill=pin_universe, region=-pin_boundary & -cr_top & +cr_down)
        pin.translation = (x, y, 0)
        pin.id = (i + 1)*100 + j
        cr_u.add_cell(pin)
        cr_u.add_cell(cr_top_cell)
        cr_u.add_cell(cr_down_cell) 
In [12]:
# Define Dummy/Reflector
outer_dummy_surface = openmc.model.HexagonalPrism(edge_length=9, orientation='y')
dummy_cell = openmc.Cell(fill=ysz, region=-outer_dummy_surface & -up & +down)
out_dummy_cell = openmc.Cell(fill=lead, region=+outer_dummy_surface & -up & +down)
dummy_u = openmc.Universe(cells=[dummy_cell, out_dummy_cell])
In [13]:
# Empty
outer_empty_surface = openmc.model.HexagonalPrism(edge_length=9, orientation='y')
empty_cell = openmc.Cell(fill=lead, region= None)
out_empty_cell = openmc.Cell(region= None)
empty_u = openmc.Universe(cells=[empty_cell,out_empty_cell])
In [14]:
# Define Core Geometry
core_lat = openmc.HexLattice(name='core')
core_lat.center = (0., 0.)
core_lat.pitch = (16.6,)
core_lat.outer = all_lead_out_u
core_lat.orientation = 'x'

core_ring10 =  ([empty_u]*3 + [dummy_u]*5 + [empty_u]*2)*6
core_ring9 = ([empty_u] + [dummy_u]*8)*6
core_ring8 = ([dummy_u]*3 + [main_out_u]*3 + [dummy_u]*2 )*6 
core_ring7 = [main_out_u]*42
core_ring6 = [main_out_u, main_out_u, cr_u, main_out_u, cr_u, main_out_u]*6
core_ring5 = [main_out_u]*30
core_ring4 = [main_in_u]*24
core_ring3 = [main_in_u]*18
core_ring2 = [sr_u, main_in_u, main_in_u]*4
core_ring1 = [main_in_u]*6
core_ring0 = [main_in_u]*1
core_lat.universes = [core_ring10, core_ring9, core_ring8, core_ring7, core_ring6, core_ring5, core_ring4, core_ring3, core_ring2, core_ring1, core_ring0]

outer_core_surface = openmc.ZCylinder(r=160, boundary_type='vacuum')

core = openmc.Cell(fill=core_lat, region=-outer_core_surface & -up & +down)

main_u = openmc.Universe(cells=[core])

geom = openmc.Geometry(main_u)
geom.export_to_xml()
In [15]:
# Plot Core Geometry

core_material_colors = {
    mox1:'red',
    mox2:'yellow',
    b4c:'black',
    lead:'silver',
    clad:'yellow',
    ysz:'purple',
    he:'red'
}

main_u.plot(width=(330,330), pixels=(500,500), color_by='material', colors=core_material_colors)

# Increase values in pixels to get better images
Out[15]:
<Axes: xlabel='x [cm]', ylabel='y [cm]'>
No description has been provided for this image
In [16]:
# Settings
# Use variables for better usability in getting tallies from values
number_of_batches = 20
number_of_particles = 10000

settings = openmc.Settings()
settings.temperature = {'method':'interpolation'}
settings.batches = number_of_batches
settings.inactive = 5
settings.particles = number_of_particles
settings.export_to_xml()
In [17]:
openmc.run()
                                %%%%%%%%%%%%%%%
                           %%%%%%%%%%%%%%%%%%%%%%%%
                        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
                      %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
                    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
                   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
                                    %%%%%%%%%%%%%%%%%%%%%%%%
                                     %%%%%%%%%%%%%%%%%%%%%%%%
                 ###############      %%%%%%%%%%%%%%%%%%%%%%%%
                ##################     %%%%%%%%%%%%%%%%%%%%%%%
                ###################     %%%%%%%%%%%%%%%%%%%%%%%
                ####################     %%%%%%%%%%%%%%%%%%%%%%
                #####################     %%%%%%%%%%%%%%%%%%%%%
                ######################     %%%%%%%%%%%%%%%%%%%%
                #######################     %%%%%%%%%%%%%%%%%%
                 #######################     %%%%%%%%%%%%%%%%%
                 ######################     %%%%%%%%%%%%%%%%%
                  ####################     %%%%%%%%%%%%%%%%%
                    #################     %%%%%%%%%%%%%%%%%
                     ###############     %%%%%%%%%%%%%%%%
                       ############     %%%%%%%%%%%%%%%
                          ########     %%%%%%%%%%%%%%
                                      %%%%%%%%%%%

                 | The OpenMC Monte Carlo Code
       Copyright | 2011-2025 MIT, UChicago Argonne LLC, and contributors
         License | https://docs.openmc.org/en/latest/license.html
         Version | 0.15.2
     Commit Hash | e23760b0264c66fb7bb373aa0596801e5209d920
       Date/Time | 2025-06-29 23:08:11
   MPI Processes | 1
  OpenMP Threads | 8

 Reading settings XML file...
 Reading cross sections XML file...
 Reading materials XML file...
 Reading geometry XML file...
 Reading Pu238 from /home/triple-s/Documents/endfb80/neutron/Pu238.h5
 Reading Pu239 from /home/triple-s/Documents/endfb80/neutron/Pu239.h5
 Reading Pu240 from /home/triple-s/Documents/endfb80/neutron/Pu240.h5
 Reading Pu241 from /home/triple-s/Documents/endfb80/neutron/Pu241.h5
 Reading Pu242 from /home/triple-s/Documents/endfb80/neutron/Pu242.h5
 Reading O16 from /home/triple-s/Documents/endfb80/neutron/O16.h5
 Reading O17 from /home/triple-s/Documents/endfb80/neutron/O17.h5
 Reading O18 from /home/triple-s/Documents/endfb80/neutron/O18.h5
 Reading U234 from /home/triple-s/Documents/endfb80/neutron/U234.h5
 Reading U235 from /home/triple-s/Documents/endfb80/neutron/U235.h5
 Reading U236 from /home/triple-s/Documents/endfb80/neutron/U236.h5
 Reading U238 from /home/triple-s/Documents/endfb80/neutron/U238.h5
 Reading Cr50 from /home/triple-s/Documents/endfb80/neutron/Cr50.h5
 Reading Cr52 from /home/triple-s/Documents/endfb80/neutron/Cr52.h5
 Reading Cr53 from /home/triple-s/Documents/endfb80/neutron/Cr53.h5
 Reading Cr54 from /home/triple-s/Documents/endfb80/neutron/Cr54.h5
 Reading Ni58 from /home/triple-s/Documents/endfb80/neutron/Ni58.h5
 Reading Ni60 from /home/triple-s/Documents/endfb80/neutron/Ni60.h5
 Reading Ni61 from /home/triple-s/Documents/endfb80/neutron/Ni61.h5
 Reading Ni62 from /home/triple-s/Documents/endfb80/neutron/Ni62.h5
 Reading Ni64 from /home/triple-s/Documents/endfb80/neutron/Ni64.h5
 Reading Mo92 from /home/triple-s/Documents/endfb80/neutron/Mo92.h5
 Reading Mo94 from /home/triple-s/Documents/endfb80/neutron/Mo94.h5
 Reading Mo95 from /home/triple-s/Documents/endfb80/neutron/Mo95.h5
 Reading Mo96 from /home/triple-s/Documents/endfb80/neutron/Mo96.h5
 Reading Mo97 from /home/triple-s/Documents/endfb80/neutron/Mo97.h5
 Reading Mo98 from /home/triple-s/Documents/endfb80/neutron/Mo98.h5
 Reading Mo100 from /home/triple-s/Documents/endfb80/neutron/Mo100.h5
 Reading Mn55 from /home/triple-s/Documents/endfb80/neutron/Mn55.h5
 Reading Si28 from /home/triple-s/Documents/endfb80/neutron/Si28.h5
 Reading Si29 from /home/triple-s/Documents/endfb80/neutron/Si29.h5
 Reading Si30 from /home/triple-s/Documents/endfb80/neutron/Si30.h5
 Reading Ti46 from /home/triple-s/Documents/endfb80/neutron/Ti46.h5
 Reading Ti47 from /home/triple-s/Documents/endfb80/neutron/Ti47.h5
 Reading Ti48 from /home/triple-s/Documents/endfb80/neutron/Ti48.h5
 Reading Ti49 from /home/triple-s/Documents/endfb80/neutron/Ti49.h5
 Reading Ti50 from /home/triple-s/Documents/endfb80/neutron/Ti50.h5
 Reading C12 from /home/triple-s/Documents/endfb80/neutron/C12.h5
 Reading C13 from /home/triple-s/Documents/endfb80/neutron/C13.h5
 Reading B10 from /home/triple-s/Documents/endfb80/neutron/B10.h5
 Reading B11 from /home/triple-s/Documents/endfb80/neutron/B11.h5
 Reading Fe54 from /home/triple-s/Documents/endfb80/neutron/Fe54.h5
 Reading Fe56 from /home/triple-s/Documents/endfb80/neutron/Fe56.h5
 Reading Fe57 from /home/triple-s/Documents/endfb80/neutron/Fe57.h5
 Reading Fe58 from /home/triple-s/Documents/endfb80/neutron/Fe58.h5
 Reading Pb204 from /home/triple-s/Documents/endfb80/neutron/Pb204.h5
 Reading Pb206 from /home/triple-s/Documents/endfb80/neutron/Pb206.h5
 Reading Pb207 from /home/triple-s/Documents/endfb80/neutron/Pb207.h5
 Reading Pb208 from /home/triple-s/Documents/endfb80/neutron/Pb208.h5
 Reading He3 from /home/triple-s/Documents/endfb80/neutron/He3.h5
 Reading He4 from /home/triple-s/Documents/endfb80/neutron/He4.h5
 Reading Zr90 from /home/triple-s/Documents/endfb80/neutron/Zr90.h5
 Reading Zr91 from /home/triple-s/Documents/endfb80/neutron/Zr91.h5
 Reading Zr92 from /home/triple-s/Documents/endfb80/neutron/Zr92.h5
 Reading Zr94 from /home/triple-s/Documents/endfb80/neutron/Zr94.h5
 Reading Zr96 from /home/triple-s/Documents/endfb80/neutron/Zr96.h5
 WARNING: Negative value(s) found on probability table for nuclide Zr96 at 600K
 WARNING: Negative value(s) found on probability table for nuclide Zr96 at 900K
 Reading Y89 from /home/triple-s/Documents/endfb80/neutron/Y89.h5
 Minimum neutron data temperature: 600 K
 Maximum neutron data temperature: 2500 K
 Preparing distributed cell instances...
 Reading plot XML file...
 Writing summary.h5 file...
 Maximum neutron transport energy: 20000000 eV for Pu239
 Initializing source particles...

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

  Bat./Gen.      k            Average k
  =========   ========   ====================
        1/1    1.22124
        2/1    1.13446
        3/1    1.12988
        4/1    1.10178
        5/1    1.12222
        6/1    1.11108
        7/1    1.09043    1.10075 +/- 0.01033
        8/1    1.09537    1.09896 +/- 0.00623
        9/1    1.09709    1.09849 +/- 0.00443
       10/1    1.10083    1.09896 +/- 0.00346
       11/1    1.09638    1.09853 +/- 0.00286
       12/1    1.08244    1.09623 +/- 0.00334
       13/1    1.07458    1.09352 +/- 0.00396
       14/1    1.07291    1.09123 +/- 0.00418
       15/1    1.07256    1.08937 +/- 0.00418
       16/1    1.08410    1.08889 +/- 0.00381
       17/1    1.07678    1.08788 +/- 0.00362
       18/1    1.08841    1.08792 +/- 0.00333
       19/1    1.09078    1.08812 +/- 0.00309
       20/1    1.08594    1.08798 +/- 0.00288
 Creating state point statepoint.20.h5...

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

 Total time for initialization     = 1.0002e+01 seconds
   Reading cross sections          = 9.9163e+00 seconds
 Total time in simulation          = 3.1215e+01 seconds
   Time in transport only          = 3.1184e+01 seconds
   Time in inactive batches        = 8.1772e+00 seconds
   Time in active batches          = 2.3038e+01 seconds
   Time synchronizing fission bank = 1.6728e-02 seconds
     Sampling source sites         = 1.5487e-02 seconds
     SEND/RECV source sites        = 1.1978e-03 seconds
   Time accumulating tallies       = 7.1110e-06 seconds
   Time writing statepoints        = 6.2140e-03 seconds
 Total time for finalization       = 1.1880e-06 seconds
 Total time elapsed                = 4.1251e+01 seconds
 Calculation Rate (inactive)       = 6114.56 particles/second
 Calculation Rate (active)         = 6511 particles/second

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

 k-effective (Collision)     = 1.08950 +/- 0.00319
 k-effective (Track-length)  = 1.08798 +/- 0.00288
 k-effective (Absorption)    = 1.08978 +/- 0.00279
 Combined k-effective        = 1.08818 +/- 0.00296
 Leakage Fraction            = 0.19733 +/- 0.00145

In [ ]: