Monte Carlo Fundamentals
Rosetta Stone
Same task, three codes. A side-by-side syntax reference for MCNP, OpenMC, and Serpent.
1. Define Materials
UO₂ fuel — 4.5 % enriched, 10.97 g/cm³. Each code uses ZAID-style nuclide identifiers and atom/weight fractions, but the card syntax differs.
MCNP
c --- UO2 fuel 4.5% enriched
c density set on cell card
m1 92235.80c 4.5 $ U-235
92238.80c 95.5 $ U-238
8016.80c 200.0 $ O-16Serpent
% UO2 fuel 4.5% enriched
mat fuel -10.97
92235.09c 4.5
92238.09c 95.5
8016.09c 200.0OpenMC
uo2 = openmc.Material(name='UO2')
uo2.add_nuclide('U235', 4.5)
uo2.add_nuclide('U238', 95.5)
uo2.add_nuclide('O16', 200.0)
uo2.set_density('g/cm3', 10.97)2. Define Surfaces
A fuel-pin cylinder (radius 0.4096 cm) and a bounding box for the unit cell.
MCNP
c --- Surfaces
1 cz 0.4096 $ fuel pin
2 rpp -0.63 0.63
-0.63 0.63
-1.0 1.0 $ bounding boxSerpent
% --- Surfaces
surf 1 cylz 0.0 0.0 0.4096
surf 2 cuboid -0.63 0.63
-0.63 0.63
-1.0 1.0OpenMC
pin = openmc.ZCylinder(r=0.4096)
box = openmc.model.RectangularPrism(
width=1.26, height=1.26,
boundary_type='reflective'
)3. Define Cells
Fuel inside the cylinder, water outside. MCNP uses surface sense signs; Serpent and OpenMC use similar but distinct syntax.
MCNP
c --- Cells
c id mat dens surfs
1 1 -10.97 -1 $ fuel
2 2 -1.0 1 -2 $ water
3 0 2 $ outsideSerpent
% --- Cells
cell 1 0 fuel -1 % fuel
cell 2 0 water 1 -2 % water
cell 3 0 outside 2 % outsideOpenMC
fuel_cell = openmc.Cell(
fill=uo2, region=-pin)
water_cell = openmc.Cell(
fill=water, region=+pin & -box)
root = openmc.Universe(
cells=[fuel_cell, water_cell])4. Source Definition (Criticality)
A fission source for k-eigenvalue calculations. All three codes need the number of particles per cycle, the number of inactive/active cycles, and an initial source point.
MCNP
c --- Criticality source
KCODE 10000 1.0 50 250
c nsrck rkk ikz klc
KSRC 0.0 0.0 0.0Serpent
% --- Criticality source
% neutrons cycles inactive
set pop 10000 250 50
src 1 sp 0.0 0.0 0.0OpenMC
settings = openmc.Settings()
settings.batches = 250
settings.inactive = 50
settings.particles = 10000
src = openmc.IndependentSource()
src.space = openmc.stats.Point(
(0.0, 0.0, 0.0))
settings.source = [src]5. Tallies
Neutron flux in the fuel cell. MCNP uses an F4 cell tally; Serpent uses a det detector card; OpenMC builds tallies from filters and scores.
MCNP
c --- Cell-average flux in fuel
F4:n 1 $ cell 1 flux
E4 0 0.625e-6 20.0
c thermal / fast bins (MeV)Serpent
% --- Cell-average flux in fuel
det flux dc 1 $ cell 1
de myerg 3 2 $ 2-bin energy grid
0.0
0.625E-6
20.0OpenMC
tally = openmc.Tally(name='flux')
tally.filters = [
openmc.CellFilter([fuel_cell])
]
tally.scores = ['flux']
tallies = openmc.Tallies([tally])6. Running
Command-line invocation for each code.
MCNP
mcnp6 i=input o=output r=runtpeSerpent
sss2 -omp 4 inputOpenMC
model = openmc.Model(
geometry, materials, settings, tallies)
model.run(threads=4)7. Boundary Conditions
Reflective boundaries — particles hitting the surface are mirror-reflected back. Useful for infinite-lattice or symmetry models.
MCNP
c --- Reflective BC: * prefix on SURFACE card
*2 rpp -0.63 0.63 -0.63 0.63 -1 1
c
c --- Cell cards reference surface normally
1 1 -10.97 -1 $ fuel
2 2 -1.0 1 -2 $ water
3 0 2 $ void outsideSerpent
% --- Reflective BC (all surfaces)
% 1 = vacuum (default)
% 2 = reflective
% 3 = periodic
set bc 2OpenMC
pin.boundary_type = 'reflective'
# or set at construction:
box = openmc.model.RectangularPrism(
width=1.26, height=1.26,
boundary_type='reflective')8. Temperature Assignment
Setting temperature for Doppler broadening. MCNP specifies kT in MeV on the cell card; Serpent and OpenMC use Kelvin directly.
MCNP
c --- Temperature on cell
c TMP = kT in MeV
c 900 K → 8.617e-11 × 900
c = 7.756e-8 MeV
1 1 -10.97 -1 TMP=7.756e-8Serpent
% --- Temperature on material (K)
mat fuel -10.97 tmp 900
92235.09c 4.5
92238.09c 95.5
8016.09c 200.0OpenMC
# Temperature is set on the cell (K)
fuel_cell.temperature = 900Conversion: MCNP's TMP card takes energy in MeV (kT = K × 8.617 × 10⁻¹¹ MeV/K). Serpent and OpenMC accept temperature directly in Kelvin. In OpenMC, temperature is set on the cell, not the material.
9. Thermal Scattering — S(α,β)
Adding thermal scattering treatment for hydrogen in light water. Required for accurate thermal-spectrum calculations.
MCNP
c --- Water with S(a,b)
m2 1001.80c 2.0
8016.80c 1.0
mt2 lwtr.20tSerpent
% --- Water with S(a,b)
therm lwtr lwj3.22t
mat water -1.0 moder lwtr 1001
1001.06c 2.0
8016.06c 1.0OpenMC
water = openmc.Material(name='water')
water.add_nuclide('H1', 2.0)
water.add_nuclide('O16', 1.0)
water.set_density('g/cm3', 1.0)
water.add_s_alpha_beta('c_H_in_H2O')10. Density & Fraction Sign Conventions
All three codes use sign conventions for density and material fractions, but the details vary.
| Convention | MCNP | Serpent | OpenMC |
|---|---|---|---|
| Density (g/cm³) | Negative on cell card | Negative on mat card | set_density('g/cm3', val) |
| Density (atoms/b-cm) | Positive on cell card | Positive on mat card | set_density('atom/b-cm', val) |
| Weight fractions | Negative fractions on m card | Negative fractions on mat card | add_nuclide(..., percent_type='wo') |
| Atom fractions | Positive fractions on m card | Positive fractions on mat card | add_nuclide(..., percent_type='ao') |
Key difference: MCNP and Serpent share the same sign convention (negative = mass density / weight fraction, positive = atom density / atom fraction). OpenMC avoids sign tricks entirely — units and fraction types are explicit string parameters.