The Assembly Build Module

An assembly build module defines a component’s physical model, that is, the geometric structure and the materials they are made of. It also defines what parts of the assembly will change during irradiation, and where loadable intra-assembly positions are located.

Upon execution of the module, a binary assembly archive (with extension .asm) is created. This (and not the module itself), becomes the main data carrier for any information associated with the assembly. During archiving, the system will automatically calculate a polyhedral mesh representation of your geometry. This is used in the visualization pipeline, as well as in geometry algorithms (mesh generation, volume calculation etc.).

Attention

When the archive is generated for the first time, it will only contain the structure definition of the assembly and the associated polyhedral mesh. As you continue through the model preparation steps, the system will add additional data (e.g. the assembly’s nodal representation, exposure data bases used for inventory transfers) to the archive. Thus, if the .asm file is deleted, more than just a re archiving of this script might be required to recover all the data.

Note

The build module is usually created as part of the assembly archiver application input. This application facilitates the archiving, and interaction with the model through the command line interface.

Basic structure of an assembly build module

Like any other python module (or script), the header section contains imports from various packages and modules. These typically include the following:

  • The Constructive Solid Geometry package used to construct geometry cells. The entire package can be imported using:

    >>> from csg import *
    
  • Base system functionality is accessed by importing the core package:

    >>> from core import *
    

    This included the generic assembly definition and tags in the assembly module, as well as various pre-defined macros in the fuel_assembly module. See Choosing an Assembly Class for more information.

  • The common material module for your assembly library. Usually called materials.py, and imported with:

    >>> from . import materials
    

The bulk of the module implements a build method, which defines, constructs, and returns an assembly instance. It should have the following calling signature:

build(**kwargs):

Defines the assembly type and assembly structure.

Parameters:

kwargs – Optional list of keyword value pairs. This can be used to customize the construction of your assembly.

Returns:

An assembly instance.

The build method usually contains the following steps:

  1. Initiate the chosen assembly type.

  2. Set basic parameters required by the assembly type.

  3. Interactively modify the assembly structure by adding cells, defining loadable facilities and burnable regions.

  4. Return the constructed assembly instance.

Finally, the module’s main method invokes the assembly_archiver application which creates and stores the assembly in binary file, so that it can be accessed without calling the build method:

if __name__ == '__main__':
    from applications.assembly_archiver import main

    main(source=build, world_box=(7.71 * units.cm, 8.1 * units.cm))

Interacting with the assembly instance

The build function starts with the creation of an assembly instance. Then, the main body of the build method contains input that adds structure (cells) to the assembly, flags loadable positions, and defines additional burnable structures.

Create an assembly instance

The first step is create an appropriate assembly instance. Available assembly macros (or types), are summarized in the following table.

Assembly Type

Brief Description

Generic

Basic assembly type with no predefined structure.

Control

Assembly used to control reactivity (e.g control and shutdown banks or rods)

Target plate holder

Rig that can be loaded with target plates.

Target plate

Single plate assembly, which can be loaded into a Target plate holder.

Plate Assembly

Plate type (MTR) fuel assembly.

Plate Follower

Control rod with a plate type (MTR) fuel follower.

Plate with BA

Plate type (MTR) fuel assembly with embedded burnable absorbers.

Reflector or Pool

Component describing the reflector or pool area (outside the core).

Core

Component describing the core structure and layout.

Pin Bundles

Collects the pins in a particular layout, and adds some additional structure.

Pins

Pins placed in a Pin Bundles.

Coated Particles

Arbitrary number of spherical shells, with the inner most sphere the kernel (or core) region.

Pebbles

Spherical fuel pebble consisting of a reflector region and dispersed fuel zone.

Pebble bed core

Component describing the layout and movement of pebbles in the core

For example, the following will create a generic assembly instance:

def build(*args, **kwargs):

    asm = assembly.Assembly(name='MY_REACTOR_assembly_base_name')

See Choosing an Assembly Class for a more detailed description and usage instructions.

Adding cells

Cells, which defines the assembly structure, are added using the add_cell method, which has the same signature used when constructing a cell:

asm.add_cell(structure, material=None, facility=None, bundle=None, description=None, part=None, outside=False)

Creates and/or add a cell to the assembly structure.

Parameters:
  • structure – Any valid CSG region, or an existing Cell instance.

  • material (material) – Material that fills the region.

  • facility (str) – Mark this cell as containing the specified facility. This means that the contents of this cell is controlled by the assembly. See Specifying loadable facilities.

  • bundle (bundle_tag) – Indicate that the cell contains a burn bundle. This means that the contents of the cell is controlled by the specified burnable material manager. See Specifying burn bundles.

  • description (str) – Short description of what the cell is modeling.

  • part (str) – Assembly part this cell belongs to. Parts are used to group cells into real physical parts, and is required when using the CAD link to documenting models.

  • outside (bool) – Flag indicating if the cell falls outside the region of interest. That is, cell with outside True is considered to lie outside the boundary of the problem domain.

Returns:

A Cell instance.

Multiple existing cells can be added using the add_cells method:

asm.add_cells(*cells)

Adds multiple cells to the assembly structure.

Parameters:

cells – Sequence of cell instances.

The above method is useful when adding results from composites or adapters. For example:

>>> from csg import *
>>> rs = composites.RoundedSquare()
>>> rs.square_radius = 2.0 * units.cm
>>> rs.corner_radius = 0.5 * units.cm
>>> rs.height = 5.0 * units.cm
>>> cells = rs.build()
>>> asm.add_cells(*cells)

Attention

Recall the the * operator is used to turn a list (or tuple) into a sequence of arguments.

Specifying loadable facilities

Facilities are used to denote positions in the assembly that can be filled with different materials or other assemblies. Typical examples are:

  • Irradiation target positions.

  • The contents of beam tubes in the pool or reflector area.

  • Positions in the assembly were detectors will be inserted.

Any facility must first be added to the assembly instance:

asm.add_facility(name, center=(0, 0, 0), state=None)
Parameters:
  • name (str) – Tag used to identify the facility. It will be used later to modify the content of all the cells filled with this facility.

  • center (point) – Facility seating. Assembly’s loaded into this facility will be moved so that their center aligns with this position.

  • state – The default object that fills this facility. During construction, a material must be specified.

A cell is associated with this facility my setting its facility parameter equal to the facility name. The contents of these cells are then controlled by changing this facility’s state. See for instance Loading facilities.

Specifying burn bundles

This mechanism is used to define overlay material meshes, which can be modified without changing the assembly geometry. Many of the built-in assembly types automatically adds depletion bundles, which is sufficient in most cases. However, if materials other than fuel or burnable absorbers needs to be activated, a custom overlay mesh should be added. Currently, the following options are available:

Rectangular mesh

Activate materials on a simple rectangular mesh:

mesh = fuel_bundles.HexahedralBundle()

The mesh object accepts the following parameters which defines its structure:

dimensions

: list or tuple

!

Three values with length dimensions, giving the overall \(x\), \(y\) and \(z\) coordinate sizes respectively.

pitches

: list

!

A list of three entries, with each entry a list of mesh sizes. Once again, the first entry defines the \(x\)-coordinate mesh sizes, the second the :mesh:`y`-coordinate sizes, and finally the \(z\)-coordinate size.

center

: point

= `(0, 0, 0)`

The center point of the mesh.

For example, the following will create an overlay mesh centered at the origin, with two equal sized meshes in each coordinate direction:

mesh = fuel_bundles.HexahedralBundle()
mesh.dimensions = (1.5 * units.cm, 1.5 * units.cm, 8 * units.cm)
mesh.pitches = [[0.5, 0.5], [0.5, 0.5], [0.5, 0.5]]

Once created, the bundles must be assigned to the assembly using a bundle_tag. For example, supposing this mesh will be used to activate a reflector element:

asm.burn_bundle[bundle_tags.reflector] = mesh

Finally, the cells whose content is defined by this material mesh should have their bundle variable set to this bundle_tag, e.g.

asm.add_cell(structure, bundle=bundle_tags.reflector)

Note

The system will calculate the intersection of the mesh cells with the real geometry cells, and set volumes accordingly. Thus, it is not necessary that mesh cells align with the geometry. The mesh should however cover the intended activation area.

When customizing the depletion mesh in later applications, note that each mesh cell is considered a fueled primitive, numbered lexicographically from bottom to top. Thus, for the above example,

asm.burn_bundle[bundle_tags.reflector].depletion_mesh.bundles = [0, 0, 0, 0, 1, 1, 1, 1]

will activate all positions in the bottom and top layer together.

Attention

The overlay bundle can not be segmented further using axial or radial segments, so make sure that enough segments are defined at assembly construction.

Auto generating background or missing cells

When building an assembly, typically only the actual physical structure is specified, and not the cells filling the outside space. These correspond to the background cells that will be filled with whatever the assembly is immersed in. However, when using the model in a calculation, the entire region must be meshed (that is, broken into cells). Instead of adding these cells manually (a fairly tedious process), the csg module has meshing algorithms which can deduce them automatically.

Note

The meshing algorithms do not introduce any new primitive regions or surfaces. It fills space using only the base constructs already in the assembly.

Attention

Mesh completion should only be called after all structural cells have been added. Before using these algorithms, also make sure that your geometry has no errors! In particular, the --check-intersections should not report any cell intersections.

There are two ways to trigger this functionality:

Inside the build module

Mesh completion can be triggered from within your build function by invoking the following (assuming asm is your assembly instance):

asm.complete_universe(algorithm='split', force=False, **kwargs)
Parameters:
  • algorithm (str) – Which meshing algorithm to use. Currently, the options are 'decompose' or 'split'. See the notes below for the difference between these two algorithms.

  • force (bool) – Force mesh completion at the place of the call. If False, the completion algorithm will only be called during the archive step.

  • **kwargs

    Parameters that will be passed to the cells created by the meshing algorithm. Any keyword accepted by the add_cell method is valid (e.g. material, facility, etc).

For example, to fill al newly created cells with a material, use

asm.complete_universe(material=lwt)

The 'decompose' algorithm first constructs the missing cavities by subtracting your existing structure from the entire space. It then fills these regions by recursively splitting them using the available primitives. Depending on the complexity of your model, the construction of cavities can be a very computationally and memory hungry operation.

The 'split' algorithm immediately starts to recursively split space using the available primitives, without calculating the missing regions. It then adds cells whenever it encounters an empty space. Unlike the previous algorithm, it visits all the regions, and not only the missing ones. Thus, the algorithm tends to run longer, and due to its recursive nature, can run out of stack space on certain operating systems.

Both methods have their drawbacks, but in most models their performance is comparable.

Note

The 'decompose' algorithm is older, and has seen the most use. However, it frequently requires user intervention in the model to work properly. In the future, this method will be discontinued in favor of the more robust and simpler 'split' algorithm.

Added in version 1.1.0: The force parameter must now be passed in order to ensure that mesh completion is performed at the calling point with only the current cells inserted. If not specified, asm.set_background(**kwargs) is called and the mesh_completion_required flag is set to True, which will ensure that mesh completion is automatically performed when archiving.

Most assembly macros (e.g. Plate fuel assembly) has the capability to replace its pre-defined structure cells with simplified placeholder cells before calling the mesh completion algorithm. This avoids adding unnecessary split regions, and significantly speeds up both algorithms.

When available, it used in the following order:

asm.create_bundle_place_holder()
asm.complete_universe(force=True, **kwargs)
asm.construct_bundle()

On the command line

Instead of placing the call to complete_universe in your build module, mesh completion can also be performed during the archiving step. For this to work properly, the assembly background must be configured in the build module:

asm.set_background(**kwargs)

Define what the contents of automatically created background cells should be.

param **kwargs:

Parameters that will be passed to the cells created by the meshing algorithm. Any keyword accepted by the add_cell method is valid (e.g. material, facility, etc).

For example, to fill all background cells with a material, use

asm.set_background(material=lwt)

Added in version 1.1.0: The mesh_completion_required flag can be set to True, e.g.

asm.mesh_completion_required = True

which will ensure that mesh completion is performed automatically, without requiring additional flags.

The 'decompose' algorithm is the called by passing the --complete-universe flag to the archive mode:

$ oscar5 MY_REACTOR.model.my_module archive --complete-universe

Deprecated since version 1.2.0: This option was removed. Use the --search-tree flag instead.

The ‘’split’` algorithm is activated using the --search-tree flag in the archive mode:

$ oscar5 MY_REACTOR.model.my_module archive --search-tree --verbose

Here, the optional --verbose flag specify how much feedback the algorithm should print to the screen. Note that this call does more than just fill missing cells: It also creates a cell index so that the plotter mode can be used without resorting to sub codes.

Changed in version 1.2.0: Although the --verbose flag is still accepted, it no longer has any affect. Switch to DEBUG log level instead:

$ oscar5 MY_REACTOR.model.my_module --log-level DEBUG archive --search-tree

Attention

Like all geometry algorithms, the meshing routines uses the infinite precision geometry kernel, making them robust (no round off errors), but slow.