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:

  1. Fuel — union of a z-aligned and an x-aligned cylinder (radius 1 cm, half-length 5 cm).

  2. Cladding — spherical shell (radius 3 cm) surrounding the fuel.

  3. 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.

Cross-section data (mono-energetic, cm-1)

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 mcdc.visualize() function to render the CSG model.

Step-by-Step Walkthrough

1. Materials (lines 1–27)

 1import numpy as np
 2import mcdc
 3
 4# ======================================================================================
 5# Materials
 6# ======================================================================================
 7
 8fuel = mcdc.MaterialMG(
 9    capture=np.array([0.45]),
10    fission=np.array([0.55]),
11    nu_p=np.array([2.5]),
12)
13
14cover = mcdc.MaterialMG(
15    capture=np.array([0.05]),
16    scatter=np.array([[0.95]]),
17)
18
19water = mcdc.MaterialMG(
20    capture=np.array([0.02]),
21    scatter=np.array([[0.08]]),
22)
23
24# ======================================================================================
25# The assembly
26# ======================================================================================
27

Three mono-energetic materials: fissile fuel, a scattering cladding, and water moderator.

2. Assembly Geometry — Shooting-Star CSG (lines 29–54)

29cylinder_z = mcdc.Surface.CylinderZ(center=[0.0, 0.0], radius=1.0)
30cylinder_x = mcdc.Surface.CylinderX(center=[0.0, 0.0], radius=1.0)
31
32top_z = mcdc.Surface.PlaneZ(z=2.5)
33bot_z = mcdc.Surface.PlaneZ(z=-2.5)
34top_x = mcdc.Surface.PlaneX(x=2.5)
35bot_x = mcdc.Surface.PlaneX(x=-2.5)
36
37sphere = mcdc.Surface.Sphere(center=[0.0, 0.0, 0.0], radius=3.0)
38
39# Cells
40pellet_z = -cylinder_z & +bot_z & -top_z
41pellet_x = -cylinder_x & +bot_x & -top_x
42shooting_star = pellet_z | pellet_x
43fuel_shooting_star = mcdc.Cell(region=shooting_star, fill=fuel)
44cover_sphere = mcdc.Cell(region=-sphere & ~shooting_star, fill=cover)
45water_tank = mcdc.Cell(region=+sphere, fill=water)
46
47# ======================================================================================
48# Copy the assembly via universe cells
49# ======================================================================================
50
51# Set the universe
52assembly = mcdc.Universe(cells=[fuel_shooting_star, cover_sphere, water_tank])
53
54# Set container cell surfaces

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)

56mid_x = mcdc.Surface.PlaneX(x=0.0)
57max_x = mcdc.Surface.PlaneX(x=10.0, boundary_condition="vacuum")
58min_y = mcdc.Surface.PlaneY(y=-5.0, boundary_condition="vacuum")
59max_y = mcdc.Surface.PlaneY(y=5.0, boundary_condition="vacuum")
60min_z = mcdc.Surface.PlaneZ(z=-5.0, boundary_condition="vacuum")
61max_z = mcdc.Surface.PlaneZ(z=5.0, boundary_condition="vacuum")
62
63# Make copies via universe cells
64container_left = +min_y & -max_y & +min_z & -max_z & +min_x & -mid_x
65container_right = +min_y & -max_y & +min_z & -max_z & +mid_x & -max_x
66assembly_left = mcdc.Cell(region=container_left, fill=assembly, translation=[-5, 0, 0])
67assembly_right = mcdc.Cell(
68    region=container_right, fill=assembly, translation=[+5, 0, 0], rotation=[0, 10, 0]
69)
70
71# Root universe
72mcdc.simulation.set_root_universe(cells=[assembly_left, assembly_right])
73
74# ======================================================================================
75# Set source
76# ======================================================================================
77
78mcdc.Source(x=[-0.1, 0.1], isotropic=True, energy_group=0)
79
80# ======================================================================================

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\).

set_root_universe() tells MC/DC these are the top-level cells.

4. Source, Tallies, Settings, and Run (lines 82–105)

 82# ======================================================================================
 83
 84# Tallies
 85mesh = mcdc.MeshStructured(
 86    x=np.linspace(-10, 10, 201),
 87    z=np.linspace(-5, 5, 101),
 88)
 89mcdc.Tally(mesh=mesh, scores=["fission"])
 90
 91# Settings
 92mcdc.settings.N_particle = 1000
 93mcdc.settings.N_batch = 2
 94mcdc.settings.active_bank_buffer = 1000
 95
 96# Run (or visualize)
 97visualize = False
 98if not visualize:
 99    mcdc.run()
100else:
101    colors = {
102        fuel: "red",
103        cover: "gray",
104        water: "blue",
105    }

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        "xz", y=0.0, x=[-11.0, 11.0], z=[-6, 6], pixels=(400, 400), colors=colors
108    )

Set visualize = True to render the CSG geometry with mcdc.visualize() 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.Lattice instead 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
  4# ======================================================================================
  5# Materials
  6# ======================================================================================
  7
  8fuel = mcdc.MaterialMG(
  9    capture=np.array([0.45]),
 10    fission=np.array([0.55]),
 11    nu_p=np.array([2.5]),
 12)
 13
 14cover = mcdc.MaterialMG(
 15    capture=np.array([0.05]),
 16    scatter=np.array([[0.95]]),
 17)
 18
 19water = mcdc.MaterialMG(
 20    capture=np.array([0.02]),
 21    scatter=np.array([[0.08]]),
 22)
 23
 24# ======================================================================================
 25# The assembly
 26# ======================================================================================
 27
 28# Surfaces
 29cylinder_z = mcdc.Surface.CylinderZ(center=[0.0, 0.0], radius=1.0)
 30cylinder_x = mcdc.Surface.CylinderX(center=[0.0, 0.0], radius=1.0)
 31
 32top_z = mcdc.Surface.PlaneZ(z=2.5)
 33bot_z = mcdc.Surface.PlaneZ(z=-2.5)
 34top_x = mcdc.Surface.PlaneX(x=2.5)
 35bot_x = mcdc.Surface.PlaneX(x=-2.5)
 36
 37sphere = mcdc.Surface.Sphere(center=[0.0, 0.0, 0.0], radius=3.0)
 38
 39# Cells
 40pellet_z = -cylinder_z & +bot_z & -top_z
 41pellet_x = -cylinder_x & +bot_x & -top_x
 42shooting_star = pellet_z | pellet_x
 43fuel_shooting_star = mcdc.Cell(region=shooting_star, fill=fuel)
 44cover_sphere = mcdc.Cell(region=-sphere & ~shooting_star, fill=cover)
 45water_tank = mcdc.Cell(region=+sphere, fill=water)
 46
 47# ======================================================================================
 48# Copy the assembly via universe cells
 49# ======================================================================================
 50
 51# Set the universe
 52assembly = mcdc.Universe(cells=[fuel_shooting_star, cover_sphere, water_tank])
 53
 54# Set container cell surfaces
 55min_x = mcdc.Surface.PlaneX(x=-10.0, boundary_condition="vacuum")
 56mid_x = mcdc.Surface.PlaneX(x=0.0)
 57max_x = mcdc.Surface.PlaneX(x=10.0, boundary_condition="vacuum")
 58min_y = mcdc.Surface.PlaneY(y=-5.0, boundary_condition="vacuum")
 59max_y = mcdc.Surface.PlaneY(y=5.0, boundary_condition="vacuum")
 60min_z = mcdc.Surface.PlaneZ(z=-5.0, boundary_condition="vacuum")
 61max_z = mcdc.Surface.PlaneZ(z=5.0, boundary_condition="vacuum")
 62
 63# Make copies via universe cells
 64container_left = +min_y & -max_y & +min_z & -max_z & +min_x & -mid_x
 65container_right = +min_y & -max_y & +min_z & -max_z & +mid_x & -max_x
 66assembly_left = mcdc.Cell(region=container_left, fill=assembly, translation=[-5, 0, 0])
 67assembly_right = mcdc.Cell(
 68    region=container_right, fill=assembly, translation=[+5, 0, 0], rotation=[0, 10, 0]
 69)
 70
 71# Root universe
 72mcdc.simulation.set_root_universe(cells=[assembly_left, assembly_right])
 73
 74# ======================================================================================
 75# Set source
 76# ======================================================================================
 77
 78mcdc.Source(x=[-0.1, 0.1], isotropic=True, energy_group=0)
 79
 80# ======================================================================================
 81# Set tallies, settings, and run MC/DC
 82# ======================================================================================
 83
 84# Tallies
 85mesh = mcdc.MeshStructured(
 86    x=np.linspace(-10, 10, 201),
 87    z=np.linspace(-5, 5, 101),
 88)
 89mcdc.Tally(mesh=mesh, scores=["fission"])
 90
 91# Settings
 92mcdc.settings.N_particle = 1000
 93mcdc.settings.N_batch = 2
 94mcdc.settings.active_bank_buffer = 1000
 95
 96# Run (or visualize)
 97visualize = False
 98if not visualize:
 99    mcdc.run()
100else:
101    colors = {
102        fuel: "red",
103        cover: "gray",
104        water: "blue",
105    }
106    mcdc.visualize(
107        "xz", y=0.0, x=[-11.0, 11.0], z=[-6, 6], pixels=(400, 400), colors=colors
108    )

How to Run

From the repository root run:

python examples/fuel_array_packaged/input.py

Expected Output

An HDF5 mesh tally and optional visualization images produced by the mcdc.visualize() helper when run with visualization enabled.