Adding burnup and state dependent cuts

These are sections were homogenization will be performed at different state and geometry conditions and burnup levels (if applicable). They are more akin to a traditional lattice calculation, and results will be used to form a state dependent homogenized library.

The application driver first performs pure burnup calculations for all defined depletion lines. It then goes back and performs the (more expensive) homogenization calculations at all geometry branches, and state conditions. This is illustrated by the following diagram:

../_images/lattice-calculation.png

For burnup dependent libraries, the application has the ability to calculate a homogenized microscopic cross sections at each state point. This enables the simulator to calculate reaction rates using the correct core spectrum, which is then used to re-calculate the transmutation chains.

Note

Burnup dependence is optional. These cuts can be also be used to calculate state dependent cross sections for non fuel assemblies.

Define burnable assemblies

If the cut is going to have depletion as one of its state parameters, the system needs to know which components in the heterogeneous model should be depleted. For this, the model’s load_map is used. Only named assemblies in the load_map will be depleted. For example, in a typical infinite environment problem, the heterogeneous model will resemble the following:

fa = assemblies.MY_REACTOR_fuel_assembly(name='FA')

parameters.generator.model.load_map = \
[[  _, '1'],
 ['A',  fa]]

parameters.generator.model.core_map = \
 [[  _, '1'],
  ['A',  _p]]

parameters.generator.model.core_pitches = 7.71 * units.cm, 8.1 * units.cm

Note

For lattice calculations, you should consider refining the deletable material mesh.

In larger colorset problems, the load_map can be used to specify which assemblies should be depleted along with the target assembly(s). For example,

f1 = assemblies.MY_REACTOR_fuel_assembly(name='FA1')
f2 = assemblies.MY_REACTOR_fuel_assembly(name='FA2')
ff = assemblies.MY_REACTOR_second_fuel_assembly(name='FF')

 parameters.generator.model.load_map = \
 [[  _, '1',  '2',  '3'],
  ['A',  f1,   ff,   _]]

 parameters.generator.model.core_map = \
  [[  _, '1',  '2',  '3'],
   ['A',  _p,   _p,   f2]]

Will burn the assemblies in the first two columns, but keep the last one fresh.

Burnable components that are not loaded directly in the core, but as facilities inside other components (e.g. rigs) are also allowed.

Add two dimensional cuts

As in static cuts, homogenization is performed on sections through the three dimensional model. State dependant cuts are added using the following method:

parameters.add_lattice_cut(label, position=0.0 * units.cm, width=1.0 * units.cm, rng=None, description=None)

Defines a section on which homogenization will be performed for different state parameters, geometric configurations, and burnup. There must be some fissionable material present in the cut.

Parameters:
  • label (str) – Name used to identify the section. It will be used to identify the cut on the command line. It is recommended to use a unique tag no longer than 12 characters.

  • position (length) – Center axial position of the section.

  • width (length) – Axial size of the section.

  • rng (tuple (length)) – Minimum and maximum axial position of the section.

  • description (str) – String giving more information about the cut (e.g. where it is located, why it was chosen, etc)

Returns:

Two values, the first a parameter set which configures the calculation, and the second a standard cut reference, as returned by parameters.add_cut.

Example:

parm, cut = parameters.add_lattice_cut('LAT-ACT', 0.0 * units.cm, fa.active_height(),
                                       description='State dependent homogenization of active region')

The returned parm set is used to add burn lines, state conditions and branches.

Alternatively, if there is no fuel in the section of interest, use the following:

parameters.add_reflector_lattice_cut(label, position=0.0 * units.cm, width=1.0 * units.cm, rng=None, description=None)

Defines a section on which homogenization will be performed for different state parameters and or geometric configurations.

Parameters:
  • label (str) – Name used to identify the section. It will be used to identify the cut on the command line. It is recommended to use a unique tag no longer than 12 characters.

  • position (length) – Center axial position of the section.

  • width (length) – Axial size of the section.

  • rng (tuple (length)) – Minimum and maximum axial position of the section.

  • description (str) – String giving more information about the cut (e.g. where it is located, why it was chosen, etc)

Returns:

Two values, the first a parameter set which configures the calculation, and the second a standard cut reference, as returned by parameters.add_cut.

Attention

Tabulation against burnup is not available for these cuts.

Set additional homogenization parameters

The returned set parm has methods for adding depletion lines, as well as the following parameters, which applies to all state conditions:

auxiliary_library

: string

= endfb-vii.1-172

Additional fine group library used to extract data (such as microscopic scattering exit distributions and kinetics parameters) not given by the chosen lattice solver. This must be the name of a valid multi-group library, in the native rapyds binary format. The system currently ships with the following options:

  • rapyds/data/endfb-vii.1-172: A 172 XMAS group structure microscopic library using ENDF-VII.1 evaluated data. This is the default value.

  • rapyds/data/jeff-3.1.2-172: A 172 XMAS group structure microscopic library using JEFF-3.1.2 evaluated data.

Note

With the exception of the lump isotopes, this library is not used to perform any cross section entry channel folding.

include_kinetics_data

: bool

= False

Flag indicating if kinetics data (e.g. precursor yields, decay constants, and delayed fission spectrum) for actinides should be included in the homogenization data.

Note

When targeting newer versions of MGRAC with spatial kinetics, this flag is switched on automatically.

colorset

: Container

= NA

Collects all parameters related to the geometry of the lattice calculation:

target_assemblies

: labeledgrid

= NA

Flags at which positions in the load_map homogenization should be performed. This should be a map containing the same assembly names appearing in the load map. For example, if the load map was defined as

fa = assemblies.MY_REACTOR_fuel_assembly(name='FA')

parameters.generator.model.load_map = \
[[  _, '1'],
 ['A',  fa]]

Then,

parm.colorset.target_assemblies = \
[[  _,  '1' ],
 ['A',  'FA']]

Note

The target_assemblies defaults to an empty load grid, so, instead of specifying a full map, you can also set the specific position(s), e.g,

parm.colorset.target_assemblies['A1'] = 'FA'

This parameter is replaced with a different method for the special case when the target assembly is segmented.

sub_node_mesh

: labeledgrid

= NA

Defines pin cell mesh structures for positions in the colorset. These sub meshes are used for flux and power reconstruction.

Each entry in the map is a list of length two, with the first entry a list of \(x\) pitches, and the second a list of \(y\) pitches. This then defines the two dimensional grid over which pin cell powers and fluxes will be calculated.

Note

Like the target_assemblies parameters, this defaults to an empty load grid, so, instead of specifying a full map, you can also set the specific position(s), e.g,

parm.colorset.sub_node_mesh['A1'] = mesh

The mesh can be specified manually, e.g.

mesh = [[0.7395] + [1.0383] * 6 +[0.7395],
        [1.061] + [0.427] * 16 + [1.061]]

Attention

The mesh will automatically be stretched to cover the entire nodal pitch, so relative values can be specified.

Alternatively, all of the fuel assembly macros provide a method which can be used to auto generate a mesh. For example, assuming the nodal pitch is 7.71 by 8.1 centimeter,

mesh =  fa.fuel_bundle().pin_cell_mesh(dx=7.71 * units.cm, dy=8.1 * units.cm, radial_segments=6)

will create a mesh that ensures that each fueled primitive (plate or pin) is its own unique mesh, and subdivide the mesh radially along the primitive into 6 equal segments. Note that the radial_segment parameter only applies to plate type fuel, and is ignored for pins.

microscopic_isotopes

: list

= NA

Defines isotopes for which microscopic cross sections will be calculated. A list of isotope must be specified for each burn bundle whose transmutation will be recalculated by the core solver (that is, is not fixed in the homogenized mixture).

The composition for fissionable material includes a number of actinides and fission products:

parm.colorset.microscopic_isotopes[bundle_tags.fuel] = \
['U-234', 'U-235', 'U-236', 'U-237', 'U-238', 'Np-237', 'Np-239', 'Pu-238', 'Pu-239', 'Pu-240', 'Pu-241', 'Pu-242',
 'Am-241', 'Am-243', 'Cm-242', 'Cm-243', 'Cm-244', 'Cm-245', 'I-135', 'Xe-135', 'Ce-141', 'Ce-142', 'Ce-144',
 'Pr-143', 'Nd-143', 'Nd-144',  'Nd-145', 'Nd-146', 'Nd-147', 'Nd-148', 'Pm-147', 'Pm-148', 'Pm-148m', 'Pm-149',
 'Sm-147', 'Sm-148', 'Sm-149', 'Cs-137']

Note

The isotopes list can have any number of isotopes, with the following restrictions:

  1. Each isotope in the list that is not in the initial material composition must be a daughter of another isotope in the list.

  2. For fuel mixtures I-135 and Xe-135 must always be present.

All isotopes not in the list will be lumped into a single (residual) cross section, which is fixed by the lattice calculation at all the state points, and can not be modified by the core solver.

For burnable absorbers, usually only the primary absorption isotope(s) are chosen. For example, if a cadmium based absorber is present:

parm.colorset.microscopic_isotopes[bundle_tags.ba] = ['Cd-113']

Note

To support future development, the interface can accept isotope list for any burn bundle. However, currently the nodal solver can only burn two bundles, fuel and burnable absorbers, independently.

homogenization_weights

: labeledgrid

= NA

Defines what node average quantity is used to collapse and later reconstruct the microscopic reaction rates for each position in the colorset. Currently the options are

node_flux()

Use the node average flux to weight and reconstruct microscopic cross sections. This is the default.

side_flux(*sides)

Use the side average flux to weight and reconstruct microscopic cross sections.

Parameters:

sides (str) – A list of side indicators, e.g. 'north', 'south', etc. The average side flux over all these sides will be used.

This option is more accurate for absorber located near the side of an assembly.

At each position, the weight is further connected to a burn bundle, e.g.

parm.colorset.homogenization_weights['1A'][bundle_tags.ba] = side_flux('east', 'west')

Note

Currently the side_flux option can only be used for burnable absorbers.

lump

: list (isotope)

List of additional isotopes that can be used as a pseudo fission product when creating exposure libraries. This is intended to represent absorption by products not explicitly listed in microscopic_isotopes.

Currently, lumping is only supported for the fuel bundle.

Note

Cross sections for isotopes in this list are calculated by folding the microscopic cross sections from the auxiliary_library with the homogenized flux.

Add a burn line

To initiate the homogenization at various state conditions, a burn line is added by invoking the following:

parm.add_burn_line(tag='main')
Parameters:

tag (str) – Name used to identify the depletion line.

Returns:

A data object which collects the parameters defining the depletion calculation.

For example, the following will add a burn line using the default tag:

burn = parm.add_burn_line()

The burn object accepts all the standard application parameters as well as:

burn.irradiation_history

Defines the amount and duration of depletion steps, as well as the state of the underlying model during each depletion step. This is a standard irradiation history object. For most lattice calculations, this is simply a list of day steps, at a constant power. For example:

steps = [
      0.1,
      0.25,
      0.5,
      0.75,
      1,
      2,
      3,
      4,
      6,
      7,
      8,
      9,
      10]


for t in steps:
    burn.irradiation_history.add_step(duration=t * units.days, power=20.0 / 16.0 * units.MW)

burn.irradiation_history.step_type = irradiations.cumulative()

However, the full complexity provided by the irradiation history object is supported.

at_steps

: list

List of burn step indices at which branch and off base calculations will be performed. If not specified, these calculations are performed at all depletion steps.

For example, the following will only perform branch homogenization calculations at burn steps 0 (fresh), 2 and 4:

burn.at_steps = [0, 2, 4]

The nominal state (fuel and moderator temperatures) at which depletion is performed can be modified using:

burn.set_state(*state_parameters)
Parameters:

state_parameters – Sequence of state parameter tags.

For example:

burn.set_state(state_parameter.fuel_temperature(60 * units.degC),
               state_parameter.moderator_temperature(40.0 * units.degC),
               state_parameter.moderator_density(0.99160 * units.g / units.cc))

Define off base conditions

An off base condition is defined as a perturbation in any state parameter from its nominal value, that is, the value used in the burn line. They are added to the burn line using:

burn.add_offbase(*states)
Parameters:

states – List of state parameter values.

The perturb method can be used to retrieve a state condition that perturbs a single parameter. For example,

nominal = burn.get_nominal_state()       # retrieve the nominal state

burn.add_offbase(nominal.perturb(state_parameters.fuel_temperature, +40.0))

will add an off base which raises only the fuel temperature by 40 degrees, while keeping all other parameters fixed.

Note

Off base conditions are applied to all geometry branches <Add geometry branch>.

Attention

Although the interface is fairly generic (allowing one to add any combination of state point values), take note of the restrictions in the current generation of library processing tools described in Limitations when using the current library generation line.

Add geometry branches

Unlike off base conditions, branches involve a physical change in the geometry of the target assembly(s). Typical examples are

  • Insertion of a control rod

  • Insertion or removal of absorber

A branch is added to a burn line using:

burn.add_branch(name='main')
Parameters:

name (str) – The tag used to identify the branch.

Returns:

A reference to the branch, which is used to modify the model geometry, and customise execution parameters.

The main branch must always be present. Thus, you script should contain a statement similar too:

main_branch = burn.add_branch('main')
main_branch.particles = 64000
main_branch.source_iteration = 25
main_branch.max_iteration = 625

Note

The execution parameters set here will apply to all the off base calculations at each selected depletion step.

Adding a rod branch usually takes the following form:

rod_branch = burn.add_branch('rodded')
rod_branch.model.set_banks(control.fully_inserted())
rod_branch.particles = 64000
rod_branch.source_iteration = 25
rod_branch.max_iteration = 725

Note

This assumes that a control rod was already added and configured in the model. See the section on configuring control structured.

Limitations when using the current library generation line

Although the lattice calculation interface is very generic, there are a number of limitations that must be adhered to when using the currently available library formats in OSCAR-5:

  • Only a single burnup line is supported.

  • The fitting tool POLX only supports a single state parameter perturbation in each off base. That is, no mixed state perturbations are allowed.

  • Only the following state parameters can be perturbed:

    • fuel temperature

    • moderator temperature

    • moderator density

    • boron concentration

  • A maximum of three geometry branches are allowed, and they must have the following tags:

    • 'main'

    • 'rodded' or 'control'

    • 'burnable_absorber'

Treatment of segmented assemblies

The system has a few additional interface elements that facilitates lattice calculations for assemblies that are segmented, that is, the homogenization mesh splits the assembly into a number of pieces.

Note

Segmented assembly lattice calculations are required when the overlay nodal mesh for the entire model intersects these assemblies.

The segments themselves are defined in the usual fashion by setting the homogenization_grid and homogenization_grid_pitches parameters. For example, the following will split the homogenization calculations in a 3 x 3 mesh.

parameters.homogenization_grid =\
 [[   _, 'A1', 'A2', 'A3'],
  ['11',     1,   1,    1],
  ['12',     1,   1,    1],
  ['13',     1,   1,    1]]

 parameters.homogenization_grid_pitches = [[23.65 * units.mm, 34.2 * units.mm, 23.65 * units.mm],
                                           [23.65 * units.mm, 34.2 * units.mm, 23.65 * units.mm]]

Attention

These segments must align with the actual nodal calculational mesh in all channels which can contain this assembly type.

When depleting a segmented assembly, first ensure that the depletion mesh is configured in such a way that each burn segment falls in a single sub segment.

Attention

Currently, segments lines are not allowed to intersect primitives (plates or pins)!

Instead of specifying a mixture name for each segment using the target_assemblies parameter, the following call can be used:

parm.colorset.set_segments(name, segments, rows=None, columns=None)
Parameters:
  • name (str) – Target assembly name.

  • segments (list) – A list or tuple of two entries, with the first entry a list of \(x\) pitches, and the second a list of \(y\) pitches.

  • rows (list) – List of consecutive row labels in the homogenization_grid containing the segmented target assembly.

  • columns (list) – List of consecutive column labels in the homogenization_grid containing the segmented target assembly.

When the lattice calculation targets only a single segmented assembly, the homogenization_grid_pitches can be used, and the rows and columns parameters may be omitted. For example,

parm.set_segments('TARGET', segments=parameters.homogenization_grid_pitches)

Otherwise, for multiple segmented assemblies, this call must be repeated for each target position.

Finally, how the different burnable components map to each segment must be specified:

parm.colorset.set_burn_bundle_segments(name, distribution, bundle=bundle_tag.fuel)
Parameters:
  • name (str) – Target assembly name.

  • distribution (list) – Describe how burnable primitives are mapped to the assembly segments. Given as a grid, with the same dimensions as the segment grid. Each entry in the grid describes which segments of fueled primitives are contained in the assembly segment. See below for more detail.

  • bundle (bundle_tag) – The target depletion bundle.

Each entry in the distribution grid must be a tuple with:

  • the first entry a list of primitive indices,

  • and the second a list of depletion mesh segment indices that intersects the assembly segment. Can be omitted if the all the depletion mesh segments fall into a mesh segment.

For example, the following illustrates the grouping of primitive segments in an plate type assembly broken into 3 by 3 segments:

# 3 by 3 grid mapping primitives to homogenization segments
# First cell contains plates 0 to 6 and the first radial segment, next cell contains plates 0 to 6 but the
# second radial segment etc
fuel_bundle_grid = \
 [[(range(15, 21), [0]), (range(15, 21),  [1]), (range(15, 21), [2])],
  [(range(6, 15),  [0]), (range(6, 15),   [1]), (range(6, 15),  [2])],
  [(range(0, 6),   [0]), (range(0, 6),    [1]), (range(0, 6),   [2])]]

 param.colorset.set_burn_bundle_segments('TARGET', fuel_bundle_grid, assembly.burn_bundle.fuel)

Attention

Although the system has an algorithm that can compute this distribution from the segment mesh, it is time consuming (especially for assemblies with a large number of primitives), and the results are currently not cached, meaning that it will be repeated each time the script is run. The implementation will be improved in a future release, but in the meantime, it is recommended that the map be specified manually.

The mapping should be specified for each depletion bundle with tabulated microscopic_isotopes.

Note

Although it requires more input, and produces more output, the method for homogenization segmented assemblies should not require any additional calculational time, as only a signal depletion and homogenization calculation is performed, irrespective of the number of segments.

Performing lattice calculations on the command line

This section focuses on cross section generation for lattice cuts, since it involves a lot more options than standard homogenization calculations. The general command line interaction is described in Running a cOMPoSe application module from the terminal.

Note

This only describes the generator mode functionality for these types of calculations. All other modes (library etc), has the same purpose and functionality as described in the general command line documentation

Burnup calculations

This takes the following form:

$ oscar5 MY_REACTOR.compose.my_module CUT_NAME generator [line] burn [options1] [mode] [options2]

Where:

For example, the typical usage sequence is (assuming the 'main' burn line is targeted):

$ oscar5 MY_REACTOR.compose.my_module CUT_NAME generator burn --config-file my_config.cfg execute --threads 24
$ oscar5 MY_REACTOR.compose.my_module CUT_NAME generator burn --config-file my_config.cfg post

The

$ oscar5 MY_REACTOR.compose.my_module CUT_NAME generator burn post --show

command will open an interactive GUI, showing the burnup dependent \(k_{inf}\), and number densities for all the microscopic_isotopes.

Homogenization calculations

This takes the following form:

$ oscar5 MY_REACTOR.compose.my_module CUT_NAME generator [line] homogenization [branch] [options1] [mode] [options2]

Where:

  • line is the name of the burn line, which defaults to 'main' if omitted.

  • branch is the name of the geometry branch. If omitted, options1 and mode will be applied to all branches.

  • options1 are any standard application options.

  • mode is any of the standard application modes, or any burn step and/or off base case (see below).

  • options2 any of the available options for the chosen mode.

For example, the typical usage sequence is (assuming the 'main' burn line is targeted):

$ oscar5 MY_REACTOR.compose.my_module CUT_NAME generator homogenization main --config-file my_config.cfg execute --threads 24
$ oscar5 MY_REACTOR.compose.my_module CUT_NAME generator homogenization main --config-file my_config.cfg post

which will launch all off base calculations at the selected depletion steps for the 'main' branch. The calculations at each burn step and off base conditions are available as sub modes burn-step-<i> and off-base-<i>. For example,

$ oscar5 MY_REACTOR.compose.my_module CUT_NAME generator homogenization main burn-step-0 --config-file my_config.cfg execute --force --threads 24

will recalculate all off base states for the base step (no burnup), and

$ oscar5 MY_REACTOR.compose.my_module CUT_NAME generator homogenization main burn-step-0 off-base-0 --config-file my_config.cfg execute --force --threads 24

will only recalculate the first off base condition at this step.