Working with Distributions

In rapyds a distribution is a field of value(s) over the (physical) phase space. They are used to store output from responses, and is also used to specify external sources. This section gives a general overview of the distribution interface, as well as the various distributions available in rapyds.

Instantiating Distributions

In general, a distribution simply models a functional \(f:R^m \to R\). Which components of the underlying phase space the distribution covers is specified using the distribution.variables parameter.

Distribution.variables

: string or list

The phase space variable(s) this distribution covers. It is specified by giving one or more (a list) of the following tokens:

Phase space variables.

Symbol

Phase Space Component

x

The \(x\) coordinate in cartesian geometry.

y

The \(y\) coordinate in cartesian geometry.

z

The \(z\) coordinate in cartesian geometry.

r

The radial coordinate is cylindrical geometry.

theta

The polar angle coordinate in cylindrical geometry.

e

The energy component.

t

The time component.

The number of variables also determines the phase space dimension of the distribution.

Distribution.aggregate

: sum, mean, min, or max

= sum

Determines how ranges, and variables not explicitly specified when inserting or retrieving data should be handled. For example, if sum is specified, the total over all dimensions perpendicular to specified variables will be used. The options can be described mathematically as follows:

Let \(f\) denote the distribution of interest, and suppose its phase space is decomposed as \(\mathbf{A}\times\mathbf{B}\). Then, a query specifying only variable values in \(\mathbf{A}\) will yield the following:

  • If Distribution.aggregate is sum:

    \[q(\mathbf{a}=\mathbf{a}_0) = \int_{\mathbf{B}}d\mathbf{b}\, f(\mathbf{a}=\mathbf{a}_0, \mathbf{b})\]
  • If Distribution.aggregate is average:

    \[q(\mathbf{a}=\mathbf{a}_0) =\frac{1}{|\mathbf{B}|} \int_{\mathbf{B}}d\mathbf{b}\, f(\mathbf{a}=\mathbf{a}_0, \mathbf{b})\]
  • If Distribution.aggregate is min:

    \[q(\mathbf{a}=\mathbf{a}_0) = \min_{\mathbf{b}\in\mathbf{B}}f(\mathbf{a}=\mathbf{a}_0, \mathbf{b})\]
  • If Distribution.aggregate is max:

    \[q(\mathbf{a}=\mathbf{a}_0) = \max_{\mathbf{b}\in\mathbf{B}}f(\mathbf{a}=\mathbf{a}_0, \mathbf{b})\]

Accessing Distribution Values

Distribution.get_value(**query)

Retrieve a value from the distribution.

Parameters:

query

The phase space coordinates at which a value from the distribution should be retrieved. Takes the form of keyword value pairs, with keys listed in phase space tokens, followed by the corresponding phase space value.

Instead of a value, a range can also be specified, by passing the keywords <v>_min andor <v>_max (here, <v> must be replaced by one of the phase space tokens).

For example, if dist is a distribution covering the \(x\) coordinate and energy domains, then, assuming dist.aggregate='sum':

Query examples.

Syntax

Description

dist.get_value(x=5 * units.cm, e=10 * units.eV)

Retrieve the value at \(x\) equal to 5 cm and energy 10 eV

dist.get_value(x=5 * units.cm, e_max=100 * units.eV)

Retrieve the value at \(x\) equal to 5 cm, integrated over all energies less than 100 eV

dist.get_value(x=5 * units.cm, e_min=10 * units.eV, e_max=100 * units.eV)

Retrieve the value at \(x\) equal to 5 cm, integrated over all energies less than 100 eV, and greater than 10 eV

dist.get_value(x=5 * units.cm)

Retrieve the value at \(x\) equal to 5 cm, integrated over the energy domain

dist.get_value()

The integral of the distribution over its entire domain

Note

How range and unspecified values are treated, is determined by the Distribution.aggregate parameter.

Distribution.set_value(value, **at)

Insert a value into the distribution at a particular point.

Parameters:
  • value – Value to insert (or score).

  • at – The phase space coordinates at which a value should be inserted. Takes the form of keyword value pairs, with keys listed in phase space tokens, followed by the corresponding phase space value.

When the phase space point values are integers, this call will set the nodes or moments defining the distribution. How the insertion at not discrete points are handled, depends on the distribution type, and/or the interpolation rules used.

Attention

Unlike Distribution.get_value(), all phase space variables must be specified, and ranges are not allowed.

Distribution.slice(coord, **query)

Produces a slice through the distribution along a specified coordinate in phase space.

Parameters:
Returns:

Two lists, the first a set op points in the variable coord, and the second the distribution values along these points, as determined by query and Distribution.aggregate.

Attention

The variable specified with coord can not also appear in query.

Note

The return value is suitable for use as the data value when using the plotting directive.

Distribution Containers

This section lists the distribution types available in the distributions module.

class distributions.Flat(**kwargs)

Represents a trivial distribution (e.g. without any shape), over the phase space region.

class distributions.Discrete(**kwargs)

Represents a piece-wise constant one dimensional distribution. Its domain is represented by a sequence of adjacent (but disjoint) intervals or bins.

Parameters:

kwargs – Can be used to (optionally) initiate any of the distribution’s parameters (e.g. Distribution.variables, Distribution.aggregate or Discrete.bins).

Apart from the standard distribution parameters, distribution.Discrete has the following extra parameters:

Discrete.bins

: list or tuple

The bin structure. Can be specified as a monotonically increasing list of bin bounds, or, for equal sized bins, in the form (v_min, v_max, n_bins), where v_min, v_max is the minimum and maximum value respectively, and n_bins the number of bins.

Attention

When specifying the bin bounds explicitly, the upper and lower bounds must also be given. Thus, for \(n\) bins, there should be \(n+1\) bounds.

For example, the following will create a discrete energy distribution with two bins:

d = distributions.Discrete(variables='e')
d.bins = [1.0E-11 * units.MeV, 6.25E-7 * units.MeV, 20.0 * units.MeV]

When calling Distribution.get_value() or Distribution.set_value() on a Discrete distribution, bin index values can also be passed. For example, in the above distribution

d.get_value(e=19 * units.MeV) == d.get_value(e=1)
True

Note

For equal sized bins, it is recommend that the (v_min, v_max, n_bins) is used, as certain plugins may only support this option.

class distributions.Interpolated(**kwargs)

Represents a continuous one dimensional distribution, anchored at a discrete set of nodes in phase space, and using a specified interpolation rule.

Apart from the standard distribution parameters, distribution.Interpolated has the following extra parameters:

Interpolated.nodes

: list or tuple

The points in phase space at which the distribution is anchored. Similar to Discrete.bins, with the same syntax.

Interpolated.interpolation

: linear, quadratic or cubic

How values in between Interpolated.nodes are deduced. Either piecewise linear, quadratic or cubic splines.

class distributions.Tensor(*dist, **kwargs)

Create a distribution over a multi-dimensional phase space by combining separate distributions, using an outer (or tensor) product approach.

Parameters:
  • dist – A sequence of Distributions that will be added to the outer product.

  • kwargs – Specify the distributions to combine using their phase space tokens as keys. This pattern can only be used if each distribution is one dimensional (see the examples below).

When using discrete (bin) distributions (such as distributions.Discrete), then the tensor effectively subdivides each bin with another bin structure from a different portion of phase space.

The domain of the tensor can be described mathematically as follows:

If \(f_i:A_i\to R\), \(i=1,\ldots,n\) are distributions on phase space \(A_i\), then the tensor \(T\) is a distribution on the direct sum \(A_1\oplus\ldots\oplus A_n\). In particular, the individual phase spaces \(A_i\) must be perpendicular, that is, the Distribution.variables of each of the distributions specified using dist (or kwargs) must be disjoint.

For example, the following will create three energy bins, and further subdivide each energy bin into 10 spatial bins:

d = Tensor(Discrete(variables='e', bins=[1.0E-11 * units.MeV, 6.25E-7 * units.MeV, 20.0 * units.MeV]),
           Discrete(variables='x', bins=(-1.0 * units.cm, 1.0 * units.cm, 10)))

The above can also be produced using the following equivalent keyword based construction:

d = Tensor(e=Discrete(bins=[1.0E-11 * units.MeV, 6.25E-7 * units.MeV, 20.0 * units.MeV]),
           x=Discrete(bins=(-1.0 * units.cm, 1.0 * units.cm, 10)))

Attention

The Distribution.variables in this case is deduced automatically, and should not be set explicitly.

distributions.cartesian_mesh(x=None, y=None, z=None, transformation=None)

Create a rectangular mesh distribution. This is a convenience function that creates a special distributions.Tensor instance using distributions.Discrete instances.

Parameters:
  • x (list or tuple) – The bin structure along the \(x\) coordinate.

  • y (list or tuple) – The bin structure along the \(y\) coordinate.

  • z (list or tuple) – The bin structure along the \(z\) coordinate.

  • transformation (affine_transformation) – Optional transformation that should be applied to the mesh.

All the ranges (x, y or z), can be specified as an explicit list of bounds, or a simpler notation for equal sized bins (see Discrete.bins). If bounds are not specified along a particular coordinate direction, the mesh will be unbounded in this coordinate.

For example, the following,

m = distributions.cartesian_mesh(x=(-1.0 * units.cm, 1.0 * units.cm, 10),
                                 y=[0.0 * units.cm, 1.0 * units.cm, 2.0 * units.cm],
                                 z=(-10 * units.cm, 0 * units.cm, 10))

is equivalent to

m = distribution.Tensor(x=distributions.Discrete(bins=(-1.0 * units.cm, 1.0 * units.cm, 10)),
                        y=distributions.Discrete(bins=[0.0 * units.cm, 1.0 * units.cm, 2.0 * units.cm]),
                        z=distributions.Discrete(bins=(-10 * units.cm, 0 * units.cm, 10)))
distributions.cylindrical_mesh(r, theta=None, axial=None, alignment='z', center=(0, 0, 0), transformation=None)

Create a cylindrical mesh distribution.

Parameters:
  • r (list or tuple) – The radial bin structure.

  • theta (list or tuple) – The polar angle bin structure. If not specified, no angular bins will be created.

  • axial (list or tuple) – The bin structure along the coordinate axis perpendicular to the radial plane. This coordinate is determined by the alignment parameter.

  • alignment (string) –

    Determines how the cylindrical mesh is aligned in the cartesian coordinate system. It can be specified by either giving the coordinate along which the axial mesh extend, or the radial plane:

    Cylindrical mesh alignment options.

    Option

    Description

    ’z’ or ‘xy’

    The axial mesh extends along the \(z\)-axis, and the radial plane is \(xy\).

    ’x’ or ‘yz’

    The axial mesh extends along the \(x\)-axis, and the radial plane is \(yz\).

    ’y’ or ‘xz’

    The axial mesh extends along the \(y\)-axis, and the radial plane is \(xz\).

  • center (point) – Where the cylindrical mesh is centered in the radial plane.

  • transformation (affine_transformation) – Optional transformation that should be applied to the mesh.

All the ranges (r, theta or axial), can be specified as an explicit list of bounds, or a simpler notation for equal sized bins (see Discrete.bins).

Note

Although center contains all three coordinate, only the values for the coordinates on the radial plane is used. For example, if alignment is z, then only the first two (\(x\) and \(y\) coordinates of center is used).

In the cylindrical mesh, a call to Distribution.get_value() can use either the polar r and theta keywords to specify radial mesh positions, or the standard cartesian coordinates x, y, and z.

class distributions.Distributed(dist=None, sub_tag='bin')

Models a distribution with components spread over discrete categories. Typical examples are distributions in different in-core channels, or ex-core positions.

Note

This distribution is created automatically when using certain targets (e.g. attached.InCoreChannels). It is rarely necessary to instantiate, or modify this distribution type.

Parameters:
  • dist – The distribution that will be used in sub categories. If not specified, the distribution might differ from one category to the next.

  • sub_tag – The tag (or key) that will be used to specify the sub category in queries, e.g. Distribution.get_value().

For example, if the categories are core loading positions, a typical query from this distribution has the following form:

v = dist.get_value(bin='CN', x=9.0 * units.cm, e=0.6 * units.eV)

Attaching Distributions

Distributions are usually attached to responses, in which case they are expected to be calculated, or sources, where they describe how particles are produced. In both cases, the distribution can be considered overlay (that is, all model elements are affected), or attached to particular model element(s), effectively restricting the response or source to these element(s). The attached module contains some objects which can be used to dynamically find targets based on certain rules. These are summarized below.

class attached.InCore(predicate=None)

Restricted to geometric elements (cells) in the model.reactor_core.

Parameters:

predicate (predicate or None) – Function object used to extract cells. Must take a cell instance as argument, and return True or False. If not specified, it is assumed that all cells in model.reactor_core are targeted.

For example, to target all cells with a particular part name:

tg = InCore(predicate=lambda c: c.part=='TargetPart')

Note

If model.pool is set and predicate is None, it will target model.pool.core_cell.

class attached.InCoreChannel(channel, predicate=None)

Restricted to geometric elements (cells) within a specified position in the model.core_map.

Parameters:
  • channel – Position in the model.core_map to target.

  • predicate (predicate or None) – Function object used to extract cells. Must take a cell instance as argument, and return True or False. If not specified, the entire component loaded in channel is assumed.

class attached.InCoreChannels(predicate=None)

Targets all channels (or positions) within the model.core_map.

Parameters:

predicate – Function object used to extract cells. Must take a cell instance as argument, and return True or False. If not specified, the entire component loaded in each channel is assumed.

When this target is used, a distributions.Distributed is created automatically, with the bin values equal to the position labels.

Note

If predicate is set, only the positions in model.core_map for which predicate return a non empty list of cells, will be present in the created distributions.Distributed.

Creating Responses

This section describes how to attach a distribution to a response function, which is then used to trigger the calculation of these distributions in certain application modes (e.g. critical_case). A response is created by instantiating a response.ResponseDistribution object:

from core.response import ResponseDistribution

resp = ResponseDistribution()
ResponseDistribution.particle = neutron

The incident particle type this response is bound to.

ResponseDistribution.to

Object used to deduce the model target(s) this response is attached to. Any of the objects listed in Attaching Distributions.

Note

If not specified, the ResponseDistribution.distribution will be estimated over the entire model (as an overlay).

ResponseDistribution.distribution

: Distribution

The function shape of this response. Can be any of the response containers listed in Distribution Containers.

Note

If not specified, a distributions.Flat distribution is assumed.

Creating Sources

A distribution can also be attached to a source, which generates particles for the