Packaged Fuel Array (Universe and Lattice)#
Problem Description#
A three-dimensional fixed-source problem featuring two identical fuel assemblies placed side-by-side inside a water-filled box. Each assembly uses a composite “shooting-star” fuel geometry built from the union of two orthogonal cylinders enclosed by a cladding sphere.
This example demonstrates MC/DC’s universe, translation, and rotation capabilities for constructive solid geometry (CSG) packaging.
Geometry and Materials#
The global domain is a rectangular box: \(x \in [-10,10]\), \(y \in [-5,5]\), \(z \in [-5,5]\) cm, with vacuum boundary conditions.
Each assembly is defined as a universe containing three cells:
Fuel — union of a z-aligned and an x-aligned cylinder (radius 1 cm, half-length 5 cm).
Cladding — spherical shell (radius 3 cm) surrounding the fuel.
Water — region outside the cladding sphere.
The left assembly is translated to \((-5,0,0)\) cm; the right assembly is translated to \((+5,0,0)\) cm and rotated \(10°\) about the \(y\)-axis.
Region |
\(\Sigma_c\) |
\(\Sigma_s\) |
\(\Sigma_f\) |
\(\nu\) |
Fuel |
0.45 |
— |
0.55 |
2.5 |
Cladding |
0.05 |
0.95 |
— |
— |
Water |
0.02 |
0.08 |
— |
— |
Physical Assumptions#
Mono-energetic (one-speed) neutron transport.
Isotropic scattering.
Steady-state fixed-source calculation.
No delayed neutrons.
Numerical Setup#
Spatial mesh (tally) |
\(201 \times 101\) in the \((x,z)\)-plane |
Tally score |
Fission rate |
Source particles |
\(10^{3}\) (demonstration) |
Batches |
2 |
Quantities of Interest#
Two-dimensional fission rate distribution in the \((x,z)\)-plane.
Relative standard deviation map for convergence assessment.
Reference Solution#
No analytical reference. The geometry can be verified using MC/DC’s
built-in simulation.visualize_model() method to render the CSG model.
Step-by-Step Walkthrough#
1. Materials (lines 1–27)
1import numpy as np
2import mcdc
3
4simulation = mcdc.Simulation("Packaged fuel array")
5
6# ======================================================================================
7# Materials
8# ======================================================================================
9
10fuel = mcdc.Material.multigroup(
11 capture=np.array([0.45]),
12 fission=np.array([0.55]),
13 nu_p=np.array([2.5]),
14)
15
16cover = mcdc.Material.multigroup(
17 capture=np.array([0.05]),
18 scatter=np.array([[0.95]]),
19)
20
21water = mcdc.Material.multigroup(
22 capture=np.array([0.02]),
23 scatter=np.array([[0.08]]),
24)
25
26# ======================================================================================
27# The assembly
Three mono-energetic materials: fissile fuel, a scattering cladding, and water moderator.
2. Assembly Geometry — Shooting-Star CSG (lines 29–54)
29
30# Surfaces
31cylinder_z = mcdc.Surface.CylinderZ(center=[0.0, 0.0], radius=1.0)
32cylinder_x = mcdc.Surface.CylinderX(center=[0.0, 0.0], radius=1.0)
33
34top_z = mcdc.Surface.PlaneZ(z=2.5)
35bot_z = mcdc.Surface.PlaneZ(z=-2.5)
36top_x = mcdc.Surface.PlaneX(x=2.5)
37bot_x = mcdc.Surface.PlaneX(x=-2.5)
38
39sphere = mcdc.Surface.Sphere(center=[0.0, 0.0, 0.0], radius=3.0)
40
41# Cells
42pellet_z = -cylinder_z & +bot_z & -top_z
43pellet_x = -cylinder_x & +bot_x & -top_x
44shooting_star = pellet_z | pellet_x
45fuel_shooting_star = mcdc.Cell(region=shooting_star, fill=fuel)
46cover_sphere = mcdc.Cell(region=-sphere & ~shooting_star, fill=cover)
47water_tank = mcdc.Cell(region=+sphere, fill=water)
48
49# ======================================================================================
50# Copy the assembly via universe cells
51# ======================================================================================
52
53# Set the universe
54assembly = mcdc.Universe(cells=[fuel_shooting_star, cover_sphere, water_tank])
The fuel region is the union of a z-cylinder and an x-cylinder (the “shooting star”). The cladding fills the sphere minus the fuel. Water fills outside the sphere. These three cells form a reusable universe.
3. Packaging with Universe, Translation, and Rotation (lines 56–80)
56# Set container cell surfaces
57min_x = mcdc.Surface.PlaneX(x=-10.0, boundary_condition="vacuum")
58mid_x = mcdc.Surface.PlaneX(x=0.0)
59max_x = mcdc.Surface.PlaneX(x=10.0, boundary_condition="vacuum")
60min_y = mcdc.Surface.PlaneY(y=-5.0, boundary_condition="vacuum")
61max_y = mcdc.Surface.PlaneY(y=5.0, boundary_condition="vacuum")
62min_z = mcdc.Surface.PlaneZ(z=-5.0, boundary_condition="vacuum")
63max_z = mcdc.Surface.PlaneZ(z=5.0, boundary_condition="vacuum")
64
65# Make copies via universe cells
66container_left = +min_y & -max_y & +min_z & -max_z & +min_x & -mid_x
67container_right = +min_y & -max_y & +min_z & -max_z & +mid_x & -max_x
68assembly_left = mcdc.Cell(region=container_left, fill=assembly, translation=[-5, 0, 0])
69assembly_right = mcdc.Cell(
70 region=container_right, fill=assembly, translation=[+5, 0, 0], rotation=[0, 10, 0]
71)
72
73# Set model
74simulation.set_model([assembly_left, assembly_right])
75
76# ======================================================================================
77# Set source
78# ======================================================================================
79
80source = mcdc.Source(x=[-0.1, 0.1], isotropic=True, energy=0)
The assembly universe is placed twice using mcdc.Cell(..., fill=assembly):
Left — translated to \((-5, 0, 0)\).
Right — translated to \((+5, 0, 0)\) and rotated 10° about \(y\).
simulation.set_model() tells MC/DC these are the top-level cells.
4. Source, Tallies, Settings, and Run (lines 82–105)
82
83# ======================================================================================
84# Set tallies, settings, and run MC/DC
85# ======================================================================================
86
87# Tallies
88mesh = mcdc.MeshStructured(
89 x=np.linspace(-10, 10, 201),
90 z=np.linspace(-5, 5, 101),
91)
92tally = mcdc.Tally(mesh=mesh, scores=["fission"])
93simulation.set_tallies([tally])
94
95# Settings
96simulation.settings.N_particle = 1000
97simulation.settings.N_batch = 2
98simulation.settings.active_bank_buffer = 1000
99
100# Run (or visualize)
101visualize = False
102if not visualize:
103 simulation.run()
104else:
105 colors = {
A point-like source near the centre, a structured mesh tally for the
\((x,z)\)-plane fission rate, and 1 000 particles in 2 batches.
The active_bank_buffer accommodates fission-born particles.
5. Optional Visualization (lines 107–end)
107 cover: "gray",
108 water: "blue",
109 }
110 simulation.visualize_model(
111 vis_plane="xz",
112 y=0.0,
113 x=[-11.0, 11.0],
114 z=[-6, 6],
115 pixels=(400, 400),
116 colors=colors,
117 time=[0.0],
118 save_as=None,
119 )
Set visualize = True to render the CSG geometry with
simulation.visualize_model() instead of running the transport.
What to try:
Change the rotation angle and observe the effect on the fission map.
Add a third assembly copy with a different translation.
Use
mcdc.Latticeinstead of manual universe placement.
Full Input#
Click here to view the input file: examples/fuel_array_packaged/input.py.
The complete input used for this example is embedded below:
1import numpy as np
2import mcdc
3
4simulation = mcdc.Simulation("Packaged fuel array")
5
6# ======================================================================================
7# Materials
8# ======================================================================================
9
10fuel = mcdc.Material.multigroup(
11 capture=np.array([0.45]),
12 fission=np.array([0.55]),
13 nu_p=np.array([2.5]),
14)
15
16cover = mcdc.Material.multigroup(
17 capture=np.array([0.05]),
18 scatter=np.array([[0.95]]),
19)
20
21water = mcdc.Material.multigroup(
22 capture=np.array([0.02]),
23 scatter=np.array([[0.08]]),
24)
25
26# ======================================================================================
27# The assembly
28# ======================================================================================
29
30# Surfaces
31cylinder_z = mcdc.Surface.CylinderZ(center=[0.0, 0.0], radius=1.0)
32cylinder_x = mcdc.Surface.CylinderX(center=[0.0, 0.0], radius=1.0)
33
34top_z = mcdc.Surface.PlaneZ(z=2.5)
35bot_z = mcdc.Surface.PlaneZ(z=-2.5)
36top_x = mcdc.Surface.PlaneX(x=2.5)
37bot_x = mcdc.Surface.PlaneX(x=-2.5)
38
39sphere = mcdc.Surface.Sphere(center=[0.0, 0.0, 0.0], radius=3.0)
40
41# Cells
42pellet_z = -cylinder_z & +bot_z & -top_z
43pellet_x = -cylinder_x & +bot_x & -top_x
44shooting_star = pellet_z | pellet_x
45fuel_shooting_star = mcdc.Cell(region=shooting_star, fill=fuel)
46cover_sphere = mcdc.Cell(region=-sphere & ~shooting_star, fill=cover)
47water_tank = mcdc.Cell(region=+sphere, fill=water)
48
49# ======================================================================================
50# Copy the assembly via universe cells
51# ======================================================================================
52
53# Set the universe
54assembly = mcdc.Universe(cells=[fuel_shooting_star, cover_sphere, water_tank])
55
56# Set container cell surfaces
57min_x = mcdc.Surface.PlaneX(x=-10.0, boundary_condition="vacuum")
58mid_x = mcdc.Surface.PlaneX(x=0.0)
59max_x = mcdc.Surface.PlaneX(x=10.0, boundary_condition="vacuum")
60min_y = mcdc.Surface.PlaneY(y=-5.0, boundary_condition="vacuum")
61max_y = mcdc.Surface.PlaneY(y=5.0, boundary_condition="vacuum")
62min_z = mcdc.Surface.PlaneZ(z=-5.0, boundary_condition="vacuum")
63max_z = mcdc.Surface.PlaneZ(z=5.0, boundary_condition="vacuum")
64
65# Make copies via universe cells
66container_left = +min_y & -max_y & +min_z & -max_z & +min_x & -mid_x
67container_right = +min_y & -max_y & +min_z & -max_z & +mid_x & -max_x
68assembly_left = mcdc.Cell(region=container_left, fill=assembly, translation=[-5, 0, 0])
69assembly_right = mcdc.Cell(
70 region=container_right, fill=assembly, translation=[+5, 0, 0], rotation=[0, 10, 0]
71)
72
73# Set model
74simulation.set_model([assembly_left, assembly_right])
75
76# ======================================================================================
77# Set source
78# ======================================================================================
79
80source = mcdc.Source(x=[-0.1, 0.1], isotropic=True, energy=0)
81simulation.set_sources([source])
82
83# ======================================================================================
84# Set tallies, settings, and run MC/DC
85# ======================================================================================
86
87# Tallies
88mesh = mcdc.MeshStructured(
89 x=np.linspace(-10, 10, 201),
90 z=np.linspace(-5, 5, 101),
91)
92tally = mcdc.Tally(mesh=mesh, scores=["fission"])
93simulation.set_tallies([tally])
94
95# Settings
96simulation.settings.N_particle = 1000
97simulation.settings.N_batch = 2
98simulation.settings.active_bank_buffer = 1000
99
100# Run (or visualize)
101visualize = False
102if not visualize:
103 simulation.run()
104else:
105 colors = {
106 fuel: "red",
107 cover: "gray",
108 water: "blue",
109 }
110 simulation.visualize_model(
111 vis_plane="xz",
112 y=0.0,
113 x=[-11.0, 11.0],
114 z=[-6, 6],
115 pixels=(400, 400),
116 colors=colors,
117 time=[0.0],
118 save_as=None,
119 )
How to Run#
From inside examples/fuel_array_packaged run:
python input.py
Expected Output#
An HDF5 mesh tally and optional visualization images produced by the
simulation.visualize_model() method when run with visualization enabled.