Plate Type Fuel Assemblies
Collect all assemblies with plate type fuel. This includes typical irradiation targets using this fuel design.
Target plate holder
Models an assembly used to hold a variable number of target plates. It only
constructs the grid plate structure, but also provides methods to load target plates into empty plate slots. The
assembly type is called LoadablePlateAssembly, in the core.fuel_assembly module:
from core import *
def build(*args, **kwargs):
asm = fuel_assembly.LoadablePlateAssembly(name='MY_REACTOR_assembly_base_name')
asm.number_of_plates = 5
asm.pitches = 15 * units.mm
# etc
The macro has the following parameters:
- target_holder.pitches !
The distance between consecutive plate centers. Either a single value, in which case the pitch is assumed to be constant, or a list of values, giving the distance between plates from the bottom or left side. In the latter case, list must have exactly
target_holder.number_of_plates- 1 entries.
-
target_holder.grid_plate_pitch
: length
! The inner distance between grid (side) plates, along the length of the target plates.
Note
Grid plates are the structure supporting the plates. They are also frequently referred to as side plates.
- target_holder.orientation = horizontal
The plate orientation. If
horizontal, plates will be placed parallel to the \(x\)-axis, while ifvertical, plates will be parallel to the \(y\)-axis.
-
target_holder.center
: point
= 0,0,0 The center of the plate structure. This parameter is used to position the plates and plate slots. For example, the center of the first plate is,
>>> center[j] - 0.5 * sum(pitches)
where
jis 1 iftarget_holder.orientationishorizontaland 0 iftarget_holder.orientationisvertical.The \(z\)-coordinate of this parameter also determines the axial center of the plates.
- target_holder.slot_insert_depth !
Depth of the plate slot inserts in the grid plate. Either a single value, if all slots have the same depth, or a list of length
target_holder.number_of_plates.
- target_holder.slot_insert_width !
Width of the plate slot inserts in the grid plate. Either a single value, if all slots have the same width, or a list of length
target_holder.number_of_plates.
- target_holder.box
Radial bounding region. When the grid is clipped with a simple rectangular region, this parameter can be specified as a list of four values, giving the \(x\) and \(y\) limits respectively. For example:
>>> asm.box = [-4.05 * units.cm, 4.05 * units.cm, -4.05 * units.cm, 4.05 * units.cm]
will clip all grid cells with an \(8.1 \times 8.1\) square centered at the origin. Alternatively, any region can be specified.
Attention
The
target_holder.boxis independent oftarget_holder.center. That is, the \(xy\) center of this region is not necessarily the center of the assembly.
- target_holder.axial_region
Axial bounding region, used to clip grid cells. When the grid is bounded by a simple axial strip, this parameter can be specified as a list of two values, giving the \(z\) bounds. For example,
>>> asm.axial_region = [-40 * units.cm, 35 * units.cm]
will clip all cells to the region \(-40 <= z <= 35\). Alternatively, any region can be specified.
Attention
The
target_holder.axial_regionis independent oftarget_holder.center. That is, the \(z\) center is not necessarily the center of this region.
-
target_holder.coolant_channels
: list (str)
Specify which coolant channels should be added by the macro. This is a list of string entries (or
None), equal to the number of coolant channels (target_holder.number_of_plates- 1). The string value will be used to name the facility which fills the channel, whileNoneis used to indicate a channel that should not be added. For example, if there are 4 plates,asm.coolant_channels = ['channel-0', None, 'channel-1']
will add the channel between plate 0 and 1, and plate 2 and 3, but skip the central channel (between the plates 1 and 2).
By default, all channels are added with names
"coolant-channel-i".Note
Skipping channels are required when the space between plates will contain additional structure (e.g. control rods). Otherwise, intersecting cells will be present.
-
target_holder.moderator_material
: material
! Material that fills the gap between plate slots and regions between grid slots and fueled plates. In the case of an empty plate holder, it is also used to fill the cells that can later be filled with target plates.
The following table summarizes the cells added by this assembly macro:
Cells Created |
Material |
|---|---|
Grid plates |
|
Dummy plate cells |
|
Coolant channels |
|
Remaining cells in |
Attention
The macro fills the entire region defined by target_holder.box and target_holder.axial_region.
Thus, any additional cells added to the assembly should not intersect this region.
The following loadable facilities are added:
Facilities Added |
Description |
Default State |
|---|---|---|
water-channel-i [1] |
Coolant channel between plates \(i\) and \(i+1\) Can be used to load detectors between fuel plates. |
|
plate-slot-i |
Slot for target plate \(i\). |
Targets can also be loaded using the [ ] method. For example, to load a target into slot 0:
asm[0] = assemblies.MY_REACTOR_target_plate(name='TG1')
Target plate
Single plate assembly, which can be loaded into a Target plate holder. The object TargetPlate is
defined in the core.fuel_assembly module:
from core import *
def build(*args, **kwargs):
asm = fuel_assembly.TargetPlate(name='MY_REACTOR_target_plate_type')
asm.meat_width = 0.45 * units.mm
# etc
asm.construct_bundle()
Apart from the basic parameters described in Generic assembly, the following is used the define the plate structure:
-
target_plate.meat_width
: length
! Width of the active fueled region.
Note
Since the orientation is fixed, with the plate extending along the \(x\)-axis, this is the \(y\) dimension of the meat region.
-
target_plate.meat_length
: length
! Length of the active fueled region.
Note
Since the orientation is fixed, with the plate extending along the \(x\)-axis, this is the \(x\) dimension of the meat region.
-
target_plate.plate_width
: length
! Width of the total plate. This is equal to
target_plate.meat_widthplus two times the cladding thickness.Note
Since the orientation is fixed, with the plate extending along the \(x\)-axis, this is the \(y\) dimension of the plate.
Plate fuel assembly
Models standard plate type (MTR) fuel assemblies. The PlateAssembly class extends the Target plate holder
macro by adding all the fuel plates. The macro is also defined in the core.fuel_assembly module:
from core import *
def build(*args, **kwargs):
asm = fuel_assembly.PlateAssembly(name='MY_REACTOR_assembly_base_name')
asm.number_of_plates = 5
asm.pitches = 15 * units.mm
# etc
asm.construct_bundle()
It has all the parameters listed in Target plate holder, as well as the following:
- plate_asm.meat_width !
Width of the active fueled region. Either a single value if all plates have the same active width, or a list of values giving the width per plate. In the latter case, the list must have length equal to
target_holder.number_of_plates.Note
The width is the dimension perpendicular to the
target_holder.orientation. Thus, if the orientation is horizontal, the width is the \(y\) dimension of the plate, and the \(x\) dimension if the orientation is vertical.
- plate_asm.meat_length !
Length of the active fueled region. Either a single value if all plates have the same active length, or a list of values giving the width per plate. In the latter case, the list must have length equal to
target_holder.number_of_plates.Note
The length is the dimension parallel to the
target_holder.orientation. Thus, if the orientation is horizontal, the length is the \(x\) dimension of the plate, and the \(y\) dimension if the orientation is vertical.
- plate_asm.meat_height !
Height (\(z\) dimension) of the active fueled region. Either a single value if all plates have the same active height, or a list of values giving the height per plate. In the latter case, the list must have length equal to
target_holder.number_of_plates.Note
The maximum
plate_asm.meat_heightdetermines the assembly’s active height.
- plate_asm.plate_width !
Total width of the fuel plate. This includes the meat width, and cladding on both sides. Either a single value if all plates have the same width, or a list of values giving the width per plate.
Attention
The plate width must be less than or equal to the
target_holder.slot_insert_width.
- plate_asm.plate_length !
Total length of the fuel plate. This includes the meat length, and cladding on both sides. Either a single value if all plates have the same length, or a list of values giving the length per plate.
Attention
The plate length must be less than or equal to
target_holder.grid_plate_pitch+ 2 \(\times\)target_holder.slot_insert_depth.
- plate_asm.plate_height !
Total height of the fuel plate. This includes the meat height, and cladding on both sides. Either a single value if all plates have the same height, or a list of values giving the height per plate.
-
plate_asm.axially_fill_channels
: bool
= True Flag indicating if the cells above the plates should be added. These cell will fill everything defined by
target_holder.axial_region.Attention
This should be set to False if there are structural components (e.g. adapters), that will intersect with this region.
These parameters are illustrated below in radial and axial schematics.
Radial schematic of PlateAssembly structure.
Axial schematic of PlateAssembly structure. In the above, the outside plate’s plate_asm.plate_height
is longer than interior plates. This is typical for boxed assemblies.
The following table summarizes the cells added by this assembly macro:
Cells Created |
Material |
|---|---|
Grid (side) plates |
|
Fuel plate cladding |
|
Active fuel meat |
Contains |
Coolant channels [1] |
|
Remaining cells in |
Attention
If plate_asm.axially_fill_channels is True, the macro fills the entire region defined by
target_holder.box and target_holder.axial_region. Thus, any additional cells added to the assembly
should not intersect this region.
Otherwise, if plate_asm.axially_fill_channels is False, this will only create the grid (side plate), plate, and
water channels [1] cells.
The following loadable facilities are added:
Facilities Added |
Description |
Default State |
|---|---|---|
water-channel-i [1] |
Coolant channel between plates \(i\) and \(i+1\) Can be used to load detectors between fuel plates. |
Attention
Remember to set the initial material for the depletion mesh in the build module:
asm.fuel_bundle().depletion_mesh.initial_material_distribution = materials.my_fuel()
See Depletion meshes for plate type assemblies for more details.
Follower type plate assembly
Models standard plate type (MTR) fuel follower assembly. The FollowerPlateAssembly macro is also defined in the
core.fuel_assembly module:
from core import *
def build(*args, **kwargs):
asm = fuel_assembly.FollowerPlateAssembly(name='MY_REACTOR_assembly_base_name')
# plate bundle parameters
asm.number_of_plates = 5
asm.pitches = 15 * units.mm
# etc
# control parameters
asm.base_position = control.fully_extracted()
asm.travel_direction = control.up()
asm.total_travel_distance = 74.79 * units.cm
This macro simply combines the Plate fuel assembly and Control assembly types. The macro behaves exactly the same way as Plate fuel assembly (adds the same cells, etc.).
Attention
This macro does not add any structure related to the absorber part of the assembly. These cells should be added manually.
Plate assembly with burnable absorbers
Models standard plate type (MTR) fuel follower assembly, with burnable absorbers embedded in the side plates. The
PlateAssemblyWithBurnableAbsorbers macro is also defined in the core.fuel_bundle module:
from core import *
def build(*args, **kwargs):
asm = fuel_assembly.PlateAssemblyWithBurnableAbsorbers(name='MY_REACTOR_assembly_base_name')
# plate bundle parameters
asm.number_of_plates = 5
asm.pitches = 15 * units.mm
# etc
# new slot parameters
asm.ba_groove_width = 2 * units.mm
asm.ba_groove_depth = 2 * units.mm
# etc
It adds the following parameters to the Plate fuel assembly macro:
- plate_asm_with_ba.ba_groove_width !
Width of the slot in the grid plate that will house the absorber. Either a single value, if the grooves all have the same width, or a list of values.
- plate_asm_with_ba.ba_groove_depth !
Depth of the slot in the grid plate that will house the absorber. Either a single value, if the grooves all have the same depth, or a list of values.
-
plate_asm_with_ba.slot_fill
: string or material
= "moderator_material" Material that should be used to fill the groove slots outside the absorber material. It can be any material instance, or a string referring to one of the materials already used in the macro, that is:
grid_material,
clad_material, or
moderator_material.
-
plate_asm_with_ba.ba_loading
: list
! List describing which plate positions have additional absorber slots, and what the structure of the burnable absorbers are. This takes the form of a list, with
target_holder.number_of_platesentries. Each entry is again a list (or tuple) of two entries, giving the absorber structure that should be loaded into the left and right plate respectively. For example, assuming there are 21 plates, the following will load wires into every second plate slot:ba = fuel_assembly.WireBurnableAbsorber() ba.length = 308 * units.mm ba.diameter = 0.493 * units.mm ba.axial_seating = (-0.5 * 615 + 123 + 0.5 * 308) * units.mm fa.ba_loading = \ [[_ , _ ], [ba, ba], [_ , _ ], [ba, ba], [_, _], [ba, ba], [_, _], [ba, ba], [_, _], [ba, ba], [_, _], [ba, ba], [_, _], [ba, ba], [_, _], [ba, ba], [_, _], [ba, ba], [_, _], [ba, ba], [_, _]]
In the above, the
WireBurnableAbsorberis a predefined absorber structure. It has the following parameters:The
fuel_assemblymodule also contains aCladdedBurnableWireAbsorberdefinition, which models a cladded wire. In addition to theWireBurnableAbsorberparameters, it is defined by:-
cladded_wire_ba.clad_thickness
: length
! Radial thickness of the clad surrounding the wire. The total diameter of the wire plus clad is therefore
wire_ba.diameterplus two timescladded_wire_ba.clad_thickness.
- cladded_wire_ba.clad_axial_thickness = 0.0
Axial length of wire. Either a single value, if the bottom and top cladding is the same, or two values, giving the bottom and top value respectively.
-
cladded_wire_ba.clad_thickness
The structure defined by this macro is illustrated below:
Radial schematic of PlateAssemblyWithBurnableAbsorbers structure. Only the new parameters are illustrated. All
other parameters are as shown in Fig plate_assembly_radial. Here, only every second plate has a slot for a
burnable absorber.
Curved plate assembly
Under construction!
Depletion meshes for plate type assemblies
All assembly types adds a fuel_bundle, which manages the distribution of burnable materials among the fuel plates.
Each plate is counted as a separate fueled region (or primitive), indexed from 0
to target_holder.number_of_plates - 1. Grouping the plates into bundles is
accomplished by assigning a group index to each plate. For example, if there are 19 plates,
asm.burn_bundle[bundle_tags.fuel].depletion_mesh.bundles = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]
will produce 19 bundles with each plate depleted separately. Setting,
asm.burn_bundle[bundle_tags.fuel].depletion_mesh.bundles = [0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 0, 0, 0]
will create 3 different bundles, with
the first bundle containing the first three, and last three plates,
the second bundle contains plates 4, 5, 6 and 14, 15 and 16,
the third bundle contains all the remaining central plates.
The radial segments parameter of the fuel bundle’s depletion mesh divides the plates along its length. Currently, no subdivision in the width of the plate is performed.
The axial mesh simply divides the plates along their plate_asm.meat_height.
The default depletion mesh bundles all plates together, with no radial and axial sub-division. This can be customized later, depending on the application, by Customizing the depletion mesh.
When burnable absorber wires are present (e.g PlateAssemblyWithBurnableAbsorber), the depletion mesh for these structures can also be customized. In this case, the wires are the basic primitives, and they are bundled by specifying a two dimensional grid, with an index for each wire. Each row in the grid will have exactly two entries, one for each side plate.
For example, suppose there are 5 plates with a wire embedded on each side. Then,
asm.burn_bundle[bundle_tags.ba].depletion_mesh.bundles = \
[[0, 1],
[2, 3],
[4, 5],
[6, 7],
[8, 9]]
will burn all wires seperately (total of 10 bundles), while
asm.burn_bundle[bundle_tags.ba].depletion_mesh.bundles = \
[[0, 1],
[0, 1],
[0, 1],
[0, 1],
[0, 1]]
will group all wires on each side together (only two bundles).
In this case, the radial segments parameter of the fuel bundle’s depletion mesh divides the wires into radial rings. For example, if there are two bundles,
asm.burn_bundle[bundle_tags.ba].depletion_mesh.segments = \
[[0.5, 0.5], [0.4, 0.3, 0.3]]
will divide the first bundle wires into two rings with the same area, and the second bundle wires into three rings, with the inner most (central) zone having 40 percent of the total area, and the next two rings 30 percent each.
Finally, as with the plate region, the axial mesh divides the wires along their length.
Examples
This section gives complete build script examples for some of the assembly types described in this chapter.
Target plate holder assembly build script
from core.fuel_assembly import LoadablePlateAssembly
from csg import primitives
from csg.primitives import *
from core.units import units
from . import materials
from material_library.moderators import LightWater
def build(*args, **kwargs):
mp = LoadablePlateAssembly(name='IPEN-empty-irradiation-device', **kwargs)
mp.description = 'Irradiation Device (Holder) without any plates'
# ==================================================================================================================
# set some QA parameters
mp.__source__ = 'BRA_IPEN_B_2b_Irradiation Device'
mp.__version__ = '0.1.0'
mp.__author__ = 'lesego'
# ==================================================================================================================
# set plate bundle parameters
mp.number_of_plates = 5
mp.pitches = 2 * 2.5 * units.mm # centre plate 1 to centre plate 2
mp.grid_plate_pitch = 46.5 * units.mm
mp.slot_insert_depth = 2.0 * units.mm
mp.slot_insert_width = 2.5 * units.mm
box_length = (33.85 - 2 * 3.175) * units.mm
mp.box = [-27.75 * units.mm, 27.75 * units.mm, -0.5 * box_length, +0.5 * box_length]
holder_bottom = (172.0 - 170) * units.mm
mp.axial_region = [-87.0 * units.mm, 0.5 * 170.0 * units.mm]
# mp.axial_region = [-86 * units.mm, 86 * units.mm]
mp.grid_material = materials.miniplate_clad()
mp.moderator_material = LightWater(mass_density=0.99820 * units.g / units.cc)
# Temporarily fill the bundle space (speeds up the fill universe algorithm)
mp.create_bundle_place_holder()
# Add the side plate of the irradiation plate holder
side_plate_left_outer = Py(-16.925 * units.mm)
side_plate_left_inner = Py(-13.750 * units.mm)
side_plate_right_outer = Py(16.925 * units.mm)
side_plate_right_inner = Py(13.750 * units.mm)
side_plate_upper_bound = Px(31.750 * units.mm)
side_plate_lower_bound = Px(-31.750 * units.mm)
side_plate_top = Pz(85.0 * units.mm)
side_plate_bottom = Pz(-87.0 * units.mm)
holder_handler = (480.0 - 172.0) * units.mm
handler_extension_top = Pz(holder_handler)
side_plate_right = (~side_plate_right_inner & side_plate_right_outer & ~side_plate_bottom & handler_extension_top &
side_plate_upper_bound & ~side_plate_lower_bound)
mp.add_cell(side_plate_right,
material=materials.miniplate_clad(),
description='side plate right')
side_plate_left = (side_plate_left_inner & ~side_plate_left_outer & ~side_plate_bottom & side_plate_top &
side_plate_upper_bound & ~side_plate_lower_bound)
cutout = primitives.Cylinder(radius=15 * units.mm,
alignment=ALIGNMENT.Y_AXIS,
center=(1.5875 * units.mm, 85.0 * units.mm))
mp.add_cell(side_plate_left & ~cutout,
material=materials.miniplate_clad(),
description='side plate left')
mp.complete_universe(material=LightWater(mass_density=0.99820 * units.g / units.cc))
mp.construct_bundle()
# mp.simplify_cells()
return mp
if __name__ == '__main__':
from applications.assembly_archiver import main
main(source=build)
Basic plate type assembly build script
"""
SAFARI-1 fuel with simplified geometry
======================================
Plate type fuel assembly with 19.75% enriched U3Si2-Al fuel.
Sources
-------
SAFARI-1 benchmark description, Section 4.2
Assumptions and Simplifications
-------------------------------
- Top and bottom adapters are approximated as cylinders.
- Geometry of slots in side plates are guessed.
Version Log
-----------
- 1.0.0 : Initial model definition
- 1.1.0 : Update to better use new features
"""
import core.fuel_assembly
from csg import *
from csg.primitives import *
import material_library.moderators
from . import materials
def build(*args, **kwargs):
fa = core.fuel_assembly.PlateAssembly(name='SAFARI-1-LEU-fuel')
fa.description = 'SAFARI-1 fuel with simplified geometry'
# ==================================================================================================================
# Set some QA parameters
fa.__source__ = 'SAFARI-1 benchmark specifications'
fa.__version__ = '1.0.0'
fa.__author__ = 'S.A. Groenewald'
# ==================================================================================================================
# Set plate bundle parameters
fa.number_of_plates = 19
fa.pitches = 2.95 * units.mm + 1.275 * units.mm # coolant gap plus plate width
fa.plate_width = 1.275 * units.mm
fa.plate_length = 66.8 * units.mm + 2 * 2.5 * units.mm # distance between side plates + 2*(insert depth)
fa.plate_height = [682.9 * units.mm] + [625.48 * units.mm]*17 + [682.9 * units.mm] # outer plates extend further
fa.meat_width = 0.510 * units.mm
fa.meat_length = 63.00 * units.mm
fa.meat_height = 593.7 * units.mm
fa.grid_plate_pitch = 66.8 * units.mm
fa.slot_insert_depth = 2.5 * units.mm # slot insert depth guessed
fa.slot_insert_width = 1.275 * units.mm
fa.box = [-0.5 * 75.9 * units.mm, 0.5 * 75.9 * units.mm, -0.5 * 80.15 * units.mm, 0.5 * 80.15 * units.mm]
fa.axial_region = [-0.5 * 682.9 * units.mm, 0.5 * 682.9 * units.mm]
fa.clad_material = materials.al_clad()
fa.grid_material = materials.al_clad()
fa.moderator_material = material_library.moderators.H2O(mass_density=0.992 * units.g / units.cc) # from specs TABLE 5
# ==================================================================================================================
# Building end adapters
# Note: Cylinders are used as a simplified representation of both top and bottom adapters
top_adap = region_macros.axial_strip(lower=0.5 * 682.9 * units.mm,
upper=0.5 * 923.9 * units.mm)
bot_adap = region_macros.axial_strip(lower=-0.5 * 923.9 * units.mm,
upper=-0.5 * 682.9 * units.mm)
rad_out = Cylinder(radius=(0.5 * 73.0) * units.mm) # half of diameter, from specs FIG 10
rad_in = Cylinder(radius=(0.5 * 63.5) * units.mm)
# Top adapter
fa.add_cell(rad_out & ~rad_in & top_adap,
material=materials.al_ag3ne(),
description='Top adapter',
part='TopAdapter')
# Bottom adapter
fa.add_cell(rad_out & ~rad_in & bot_adap,
material=materials.al_ag3ne(),
description='Bottom adapter',
part='BottomAdapter')
# ==================================================================================================================
# Fill model with water (recommended to avoid empty cells when exported to the external code)
fa.complete_universe(material=fa.moderator_material)
# ==================================================================================================================
# Construct the fuel bundle (i.e. add all the fuel- and side plates, and moderator in between)
# More efficient to construct bundle after filling universe with water
fa.construct_bundle()
# ==================================================================================================================
# Initiate the fuel material
fa.fuel_bundle().depletion_mesh.initial_material_distribution = \
materials.fuel_leu(plate_volume=0.51 * units.mm * 63.00 * units.mm * 593.7 * units.mm)
return fa
if __name__ == '__main__':
from applications.assembly_archiver import main
main(source=build, world_box=(7.71 * units.cm, 8.1 * units.cm))
Plate assembly with burnable absorbers build script
"""
Standard fuel assembly
======================
Standard fuel assembly with 484 grams U-235, and cadmium absorbers in the grid plates.
Assumptions and simplifications
-------------------------------
1. To preserve a fixed water gap, the pitch (distance to fuel meat centers) for the outer plates were adjusted.
Need to verify that this is the correct assumption.
2. No additional handling structures were modeled on top of the assembly.
"""
from core.fuel_assembly import PlateAssemblyWithBurnableAbsorbers, WireBurnableAbsorber
from csg import *
from core.units import units
from core.place_holders import _
from material_library.moderators import LightWater
from . import materials
def build(*args, **kwargs):
fa = PlateAssemblyWithBurnableAbsorbers(name='OPAL_standard_fuel_assembly', **kwargs)
fa.description = 'Standard fuel assembly with burnable absorbers'
# ==================================================================================================================
# set some QA parameters
fa.__source__ = 'OPAL_reactor_specification_V2.pdf, Table 3, Figures 3 & 4'
fa.__version__ = '0.3.0'
fa.__author__ = 'francois'
# ==================================================================================================================
# set plate bundle parameters
fa.number_of_plates = 21
# Note that, to preserve the water gap, the outer pitch from fuel plate to fuel plate should be larger
fa.pitches = [2.45 * units.mm + 0.5 * 1.5 * units.mm + 0.5 * 1.35 * units.mm] + \
[2.45 * units.mm + 1.35 * units.mm] * 18 +\
[2.45 * units.mm + 0.5 * 1.5 * units.mm + 0.5 * 1.35 * units.mm]
# exterior plate inner plates exterior plate
fa.plate_width = [1.5 * units.mm] + [1.35 * units.mm] * 19 + [1.5 * units.mm]
fa.plate_length = 75.0 * units.mm
fa.plate_height = [825 * units.mm] + [655 * units.mm] * 19 + [825 * units.mm]
fa.meat_width = 0.61 * units.mm
fa.meat_length = 65.0 * units.mm
fa.meat_height = 615.0 * units.mm
fa.grid_plate_pitch = 80.5 * units.mm - 2.0 * 5.0 * units.mm
fa.slot_insert_depth = 2.5 * units.mm
fa.slot_insert_width = [1.6 * units.mm] + [1.45 * units.mm] * 19 + [1.6 * units.mm]
fa.box = [-40.25 * units.mm, 40.25 * units.mm, -40.25 * units.mm, 40.25 * units.mm]
top = (1045 - 615 - 158 - 145) * units.mm
fa.axial_region = [-0.5 * fa.meat_height[0] - 158 * units.mm, 0.5 * fa.meat_height[0] + top]
fa.clad_material = materials.cladding()
fa.grid_material = materials.al6061()
fa.moderator_material = LightWater(mass_density=0.99160 * units.g / units.cc, temperature=(273.15 + 40.0) * units.K)
# ==================================================================================================================
# Set the BA parameters
fa.ba_groove_width = 0.5 * units.mm
fa.ba_groove_depth = 0.6 * units.mm
ba = WireBurnableAbsorber()
ba.length = 308 * units.mm
ba.diameter = 0.493 * units.mm
ba.axial_seating = (-0.5 * 615 + 123 + 0.5 * 308) * units.mm
# Only odd numbered plates has a wire (on each side)
fa.ba_loading = \
[[_ , _ ],
[ba, ba],
[_ , _ ],
[ba, ba],
[_, _],
[ba, ba],
[_, _],
[ba, ba],
[_, _],
[ba, ba],
[_, _],
[ba, ba],
[_, _],
[ba, ba],
[_, _],
[ba, ba],
[_, _],
[ba, ba],
[_, _],
[ba, ba],
[_, _]]
# Add the fuel bundle cells
fa.construct_bundle()
# ==================================================================================================================
# End box section
cell.begin_part('Adapter')
axial = region_macros.axial_strip(lower=(-0.5 * 615 - 158 - 145) * units.mm,
upper=(-0.5 * 615 - 158) * units.mm)
adapter = region_macros.clipped_box(diameter=69 * units.mm, cut=8 * units.mm)
fa.add_cell(adapter & ~primitives.Cylinder(radius=30 * units.mm) & axial,
material=materials.al6061(),
description='Assembly end box')
# ==================================================================================================================
# Initiate the fuel material
fa.fuel_bundle().depletion_mesh.initial_material_distribution = materials.standard_fuel()
# ==================================================================================================================
# Initiate the BA material
fa.ba_bundle().depletion_mesh.initial_material_distribution = materials.cadmium()
# ==================================================================================================================
# Mesh completion settings
fa.set_background(material=fa.moderator_material) # fill remaining space with water
fa.mesh_completion_required = True # ensure that missing water cells are added during archiving
return fa
if __name__ == '__main__':
from applications.assembly_archiver import main
main(source=build)
Plate assembly with intra assembly control
"""
Control Fuel Assembly
=====================
Model of the special control (17 plate) fuel assembly with 93% enriched uranium.
Sources
-------
The IRR-1 facility specification document. In particular Table 5 and Figure 3.
Assumptions and Simplifications
-------------------------------
The upper section of the control assembly, containing the drive slot mechanisms, were not modelled.
Outstanding Issues
------------------
1. The structure above the active fuel is not clear, and is currently simply modelled as water.
Version Log
-----------
- 1.0.0 : Initial model definition
"""
from core import *
from csg import *
from material_library.moderators import LightWater
from . import materials
from .fuel_assembly import build_nozzle
upper_extent = 0.5 * 625.5 * units.mm + (1255 * units.mm - 625.5 * units.mm)
def guide_structure(ext=9.975 * units.mm, include_grid=False):
cells = cell.Part()
pitches = 2.1 * units.mm + 0.51 * units.mm + 2.0 * 0.38 * units.mm
guide_box_center = 0.5 * 17 * pitches + 6.93 * units.mm
lower_plate = (guide_box_center - 0.5 * 6.35 * units.mm - 1.27 * units.mm,
guide_box_center - 0.5 * 6.35 * units.mm)
grid_plate_pitch = 76.1 * units.mm - 2.0 * 4.75 * units.mm
axial = region_macros.axial_strip(-0.5 * 625.5 * units.mm,
0.5 * 625.5 * units.mm + (1255 * units.mm - 625.5 * units.mm))
cells.add_cell(axial &
region_macros.rectangle(-0.5 * grid_plate_pitch, 0.5 * grid_plate_pitch,
lower_plate[0], lower_plate[1]),
material=materials.al6061(),
part='GuidePlates')
upper_plate = (guide_box_center + 0.5 * 6.35 * units.mm,
guide_box_center + 0.5 * 6.35 * units.mm + 1.27 * units.mm)
axial = region_macros.axial_strip(-0.5 * 604 * units.mm - 44 * units.mm,
0.5 * 625.5 * units.mm + (1255 * units.mm - 625.5 * units.mm))
cells.add_cell(axial &
region_macros.rectangle(-0.5 * grid_plate_pitch, 0.5 * grid_plate_pitch,
upper_plate[0], upper_plate[1]),
material=materials.al6061(),
part='GuidePlates')
# extended grid plates
if include_grid:
lower_bound = 0.0 * units.mm
else:
lower_bound = 0.5 * 17 * pitches + 0.5 * pitches
cells.add_cell(axial & region_macros.rectangle(-0.5 * grid_plate_pitch - 4.75 * units.mm, -0.5 * grid_plate_pitch,
lower_bound, 0.5 * 80 * units.mm),
material=materials.al6061(),
part='Box')
cells.add_cell(axial & region_macros.rectangle(0.5 * grid_plate_pitch, 0.5 * grid_plate_pitch + 4.75 * units.mm,
lower_bound, 0.5 * 80 * units.mm),
material=materials.al6061(),
part='Box')
# add the guide channel
axial = region_macros.axial_strip(-0.5 * 625.5 * units.mm - ext,
0.5 * 625.5 * units.mm + (1255 * units.mm - 625.5 * units.mm))
cells.add_cell(axial & region_macros.rectangle(-0.5 * grid_plate_pitch, 0.5 * grid_plate_pitch,
lower_plate[1], upper_plate[0]),
facility='control-guide')
# reflect to get bottom channel
reflected = cell.reflect(ALIGNMENT.Y_AXIS, *cells)
cells.add_cells(*reflected)
# add the adapter here
clip = region_macros.rectangle(-0.5 * grid_plate_pitch, 0.5 * grid_plate_pitch,
-upper_plate[0], upper_plate[0])
nozzle = build_nozzle(2.0 * upper_plate[0],
ext, clip)
cells.add_cells(*nozzle)
return cells
def build(*args, **kwargs):
asm = fuel_assembly.PlateAssembly(name='IRR-1-control-fuel-assembly')
asm.description = 'Control Fuel Assembly'
# ==================================================================================================================
# Set some QA parameters
asm.__source__ = 'IRR-1 REACTOR SPECIFICATION'
asm.__version__ = '1.0.0'
asm.__author__ = 'francois'
# ==================================================================================================================
# Set fuel bundle parameters
asm.number_of_plates = 17
asm.meat_height = 604 * units.mm
asm.meat_width = 0.51 * units.mm
asm.meat_length = 63 * units.mm
asm.plate_length = 71 * units.mm
asm.plate_width = 0.51 * units.mm + 2.0 * 0.38 * units.mm
# Rest of side plate extensions modelled outside the bundle region
bottom_external_plate = - 0.5 * 604 * units.mm - 44 * units.mm
lower_external_plate_extension = - 0.5 * 625.5 * units.mm - bottom_external_plate
upper_external_plate_extension = 709 * units.mm - 625.5 * units.mm - lower_external_plate_extension
extension_est = 0.3 * lower_external_plate_extension # Estimated distance between bottom of plates and nozzle insert
asm.plate_height = 625.5 * units.mm
asm.slot_insert_depth = 2.2 * units.mm
asm.slot_insert_width = 1.3 * units.mm
# Coolant gap plus two times plate width
asm.pitches = 2.1 * units.mm + asm.plate_width[0]
asm.grid_plate_pitch = 76.1 * units.mm - 2.0 * 4.75 * units.mm
# outer assembly dimensions
asm.box = [-0.5 * 76.1 * units.mm, 0.5 * 76.1 * units.mm,
-0.5 * 17 * asm.pitches[0] - 0.5 * asm.pitches[0],
0.5 * 17 * asm.pitches[0] + 0.5 * asm.pitches[0]]
asm.axial_region = [- 0.5 * 625.5 * units.mm - extension_est, +0.5 * 625.5 * units.mm + extension_est]
asm.clad_material = materials.al6061(material.tags.clad)
asm.grid_material = materials.al6061(material.tags.structural)
asm.moderator_material = LightWater(pressure=1.8 * units.bar, temperature=35 * units.degC)
# use custom object to add side plate enforcing
asm.create_bundle_place_holder()
# ==================================================================================================================
# Grid plate extensions and handling structure above assembly box
axial = region_macros.axial_strip(+0.5 * 625.5 * units.mm + extension_est, upper_extent)
asm.add_cell(axial & asm.box &
(primitives.Px(-0.5 * asm.grid_plate_pitch) |
~primitives.Px(+0.5 * asm.grid_plate_pitch)),
material=asm.grid_material,
part='Box',
description='Grid upper extension')
# ==================================================================================================================
# Bottom grid extensions
axial = region_macros.axial_strip(-0.5 * 604 * units.mm - 44 * units.mm,
-0.5 * asm.plate_height[0] - extension_est)
asm.add_cell(axial & asm.box &
(primitives.Px(-0.5 * asm.grid_plate_pitch) |
~primitives.Px(+0.5 * asm.grid_plate_pitch)),
material=asm.grid_material,
part='Box',
description='Grid lower extension')
# ==================================================================================================================
# Guide structure
asm.add_facility('control-guide', state=asm.moderator_material)
asm.add_cells(*guide_structure(extension_est))
asm.complete_universe(material=asm.moderator_material)
asm.construct_bundle()
asm.fuel_bundle().depletion_mesh.initial_material_distribution = materials.uranium_aluminum()
return asm
if __name__ == '__main__':
from applications.assembly_archiver import main
main(source=build)