From 8a165bded5f1c76a7ee737d5a2dc4a8c2ecb5f1a Mon Sep 17 00:00:00 2001 From: Connor Moore Date: Mon, 2 Mar 2026 04:07:09 -0500 Subject: Added 37-element CANDU model and gitignore --- .gitignore | 3 ++ candu-37.py | 171 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 174 insertions(+) create mode 100644 .gitignore create mode 100644 candu-37.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d72ed98 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.xml +*.h5 +*.pkl diff --git a/candu-37.py b/candu-37.py new file mode 100644 index 0000000..281c339 --- /dev/null +++ b/candu-37.py @@ -0,0 +1,171 @@ +import openmc +import numpy as np + +#> Standard 37-element CANDU fuel bundle in OpenMC for AnnCon2026. This will +#> serve as a basis for a comparison with the Apollonian gasket verison. +#> Connor Moore, March 2026. + + +### Material Definitions ### + +#> Materials marked PNNL-15870 are from the 2021 revision of "Compendium of Material +#> Composition Data for Radiation Transport Modeling" published by the U.S. Department +#> of Homeland Security and Pacific Northwest National Laboratory. +#> + +#> The natural UO2 fuel +mat_fuel = openmc.Material(name="Natural Uranium Fuel (UO2)") +mat_fuel.add_element("U", 1.0, enrichment=0.71) +mat_fuel.add_element("O", 2.0) +mat_fuel.set_density("g/cc", 10.6) +#> Density of 10.6 g/cc is from The Essential CANDU, Ch. 17 (Fuel), 2.2, pp. 11 + +#> Pressure tube and calandria tube use Zircaloy-2 +mat_zircaloy_2 = openmc.Material(name="Zircaloy-2 (PNNL-15870)") +mat_zircaloy_2.add_nuclide("O16", 0.001194,"wo") +mat_zircaloy_2.add_nuclide("O17", 0.000000,"wo") +mat_zircaloy_2.add_nuclide("O18", 0.000003,"wo") +mat_zircaloy_2.add_element("Cr", 0.000997,"wo") +mat_zircaloy_2.add_element("Fe", 0.000997,"wo") +mat_zircaloy_2.add_element("Ni", 0.000499,"wo") +mat_zircaloy_2.add_nuclide("Zr90", 0.498109,"wo") +mat_zircaloy_2.add_nuclide("Zr91", 0.109835,"wo") +mat_zircaloy_2.add_nuclide("Zr92", 0.169730,"wo") +mat_zircaloy_2.add_nuclide("Zr94", 0.175752,"wo") +mat_zircaloy_2.add_nuclide("Zr96", 0.028918,"wo") +mat_zircaloy_2.add_element("Sn", 0.013962,"wo") + +#> The fuel cladding uses Zircaloy-4 +mat_zircaloy_4 = openmc.Material(name="Zircaloy-4 (PNNL-15870") +mat_zircaloy_4.add_nuclide("O16", 0.001193,"wo") +mat_zircaloy_4.add_nuclide("O17", 0.000000,"wo") +mat_zircaloy_4.add_nuclide("O18", 0.000003,"wo") +mat_zircaloy_4.add_element("Cr", 0.000997,"wo") +mat_zircaloy_4.add_element("Fe", 0.001993,"wo") +mat_zircaloy_4.add_nuclide("Zr90", 0.497860,"wo") +mat_zircaloy_4.add_nuclide("Zr91", 0.109780,"wo") +mat_zircaloy_4.add_nuclide("Zr92", 0.169646,"wo") +mat_zircaloy_4.add_nuclide("Zr94", 0.175665,"wo") +mat_zircaloy_4.add_nuclide("Zr96", 0.028904,"wo") +mat_zircaloy_4.add_element("Sn", 0.013955,"wo") + +#> Heavy water is used for moderation and cooling +mat_d2o = openmc.Material(name="Heavy Water (PNNL-15870)") +mat_d2o.add_nuclide("H2", 0.201133,"wo") +mat_d2o.add_nuclide("O16", 0.796703,"wo") +mat_d2o.add_nuclide("O17", 0.000323,"wo") +mat_d2o.add_nuclide("O18", 0.001842,"wo") +mat_d2o.add_s_alpha_beta("c_D_in_D2O") + +materials = openmc.Materials([mat_fuel, mat_zircaloy_2, mat_zircaloy_4, mat_d2o]) +materials.export_to_xml() + + +### Geometry Definition ### + +#> The general geometry of the 37-element bundle is from IGE335 by +#> Dr. Alain Hebert and contributors, part of the DRAGON project. +#> + +fuel_region_list = [] +clad_region_list = [] + +r_fuel = 0.60 +r_clad = 0.64 + +#> Define a function to create a fuel "pin" using a radius. + +def make_pin(rf: float, rc: float, x0: float, y0: float) -> None: + fuel_surf = openmc.ZCylinder(r=rf, x0=x0, y0=y0) + #> Hard-coded cladding thickness of 0.4 mm + clad_surf = openmc.ZCylinder(r=rc, x0=x0, y0=y0) + + fuel_region = -fuel_surf + clad_region = +fuel_surf & -clad_surf + + fuel_region_list.append(fuel_region) + clad_region_list.append(clad_region) + return + +#> Also define a function for making rings of pins + +def make_ring(n: int, r: float, alpha: float) -> None: + + for i in range(0,n): + theta = (i*(360/n) + alpha)*np.pi/180 + x = r*np.cos(theta) + y = r*np.sin(theta) + + make_pin(rf=r_fuel, rc=r_clad, x0=x, y0=y) + + +#> Start with the innermost pin +make_pin(rf=r_fuel, rc=r_clad, x0=0.0, y0=0.0) + +#> Add a ring of 6 elements around it. The radius is 1.4885 with an angle of 0.0 +make_ring(n=6, r=1.4885, alpha=0.0) + +#> The next ring has 12 pins at a radius of 2.8755, with an angle of 15 degrees +make_ring(n=12, r=2.8755, alpha=15.0) + +#> And the last one has 18 pins, a radius of 4.3305, and an angle of 0.0 +make_ring(n=18, r=4.3305, alpha=0.0) + +#> Combine the regions to make a fuel cell and a cladding cell +fuel_cell = openmc.Cell(name="UO2 Fuel Regions", region=openmc.Union(fuel_region_list), fill=mat_fuel) +clad_cell = openmc.Cell(name="Zircaloy-4 Cladding Regions", region=openmc.Union(clad_region_list), fill=mat_zircaloy_4) + +#> Add the pressure tube +pt_inner = openmc.ZCylinder(r=5.16890, x0=0.0, y0=0.0) +pt_outer = openmc.ZCylinder(r=5.60320, x0=0.0, y0=0.0) + +pt_region = +pt_inner & -pt_outer +pt_cell = openmc.Cell(name="Pressure Tube", region=pt_region, fill=mat_zircaloy_2) + +#> Pack the fuel with D2O +pt_d2o_region = ~(fuel_cell.region | clad_cell.region) & -pt_inner +pt_d2o_cell = openmc.Cell(name="D2O Coolant", region=pt_d2o_region, fill=mat_d2o) + +#> Add the calandria tube +ct_inner = openmc.ZCylinder(r=6.44780, x0=0.0, y0=0.0) +ct_outer = openmc.ZCylinder(r=6.58750, x0=0.0, y0=0.0) + +ct_region = +ct_inner & -ct_outer +ct_cell = openmc.Cell(name="Calandria Tube", region=ct_region, fill=mat_zircaloy_2) + +#> The space between the calandria tube and pressure tube is considered void +pt_ct_region = +pt_outer & -ct_inner +pt_ct_cell = openmc.Cell(name="Annulus Gap", region=pt_ct_region, fill=None) + +#> The lattice pitch for the assembly is 28.575, so apply a reflecting boundary +outer_boundary = openmc.model.RectangularPrism(width=28.575, height=28.575, origin=(0.0, 0.0), boundary_type="reflective") + +ct_d2o_region = +ct_outer & -outer_boundary +ct_d2o_cell = openmc.Cell(name="D2O Moderator", region=ct_d2o_region, fill=mat_d2o) + +universe = openmc.Universe(cells=[fuel_cell, clad_cell, pt_cell, pt_d2o_cell, ct_cell, pt_ct_cell, ct_d2o_cell]) + +geometry = openmc.Geometry(universe) +geometry.export_to_xml() + + +### Settings definition ### +settings = openmc.Settings() +settings.particles = 10000 +settings.batches = 200 +settings.inactive = 80 + +#> Set up the source to sample inside the pressure tube region uniformly +settings.source = openmc.IndependentSource() +settings.source.space = openmc.stats.CylindricalIndependent( + r = openmc.stats.PowerLaw(a=0, b=5.16890, n=1), + phi = openmc.stats.Uniform(0, 2*np.pi), + z = openmc.stats.Discrete([0.0], [1.0]) + ) +settings.source.energy = openmc.stats.Watt() + + +settings.export_to_xml() + +#> Run the model! +openmc.run() -- cgit v1.2.3