Collections and Numbered Objects#

Collection: NumberedObjectCollection#

This should be subclassed for any collection of objects that are numbered. For example: cells, surfaces, materials, universes, tallies, etc. By default you need to do almost nothing. The class that will be added to this collection must have the property obj.number.

How to __init__#

Your init signature should be def __init__(self, objects=None) All you need to then do is call super, with the class this will wrap. For example the init function for Cells

def __init__(self, cells=None):
    super().__init__(montepy.Cell, cells)

Collection: NumberedDataObjectCollection#

This is a subclass of NumberedObjectCollection, which is designed for DataInputAbstract instances. It is a wrapper that will ensure that all of its items are also in data_inputs.

Numbered Object: Numbered_MCNP_Object#

MCNP allows many types of number objects like cells, surfaces, and tallies. The only thing special about this is that it requires there be the properties: number and old_number. The old_number is what was read from the input file, and should not mutate. The number is the object’s current number and should mutate. The parent class provides a system to link to a problem via self._problem. Note this field can be None. When setting a number you must check for numbering collisions with the method: check_number(). This function returns nothing, but will raise an error when a number collision occurs. For example the Surface number setter looks like:

@number.setter
def number(self, number):
    assert isinstance(number, int)
    assert number > 0
    if self._problem:
        self._problem.surfaces.check_number(number)
    self._surface_number = number

Surface: Surface#

This is the parent class for all Surface classes. You will also need to update parse_surface(). You should expose clear parameters such as radius or location. format_for_mcnp_input() is handled by default.

How the Classes are Built#

All of the children of Surface use the montepy.surfaces.surface._SurfaceClassFactory metaclass. This takes a spec that is of type _SurfaceTypeSpec, which then contains a list of _SurfaceParamSpec instances. The metaclass then adds the given _SurfaceParamSpec as properties to the class, and handles ensuring that the data is properly loaded during parsing. For more details see the current implementations of existing classes as examples.

Data Inputs: DataInputAbstract#

This class is the parent for all inputs that show up in the data block. When adding a child you will also need to update the parse_data() function. This can be done by adding the class to PREFIX_MATCHES. In general first comply with standards for this class’s parent: MCNP_Object. If you need to link objects after parsing (e.g. resolving number references to objects), override _parse_tree().

During init the inputs’ “name word” (e.g., M3, kcode, f7:n) is validated and parsed. Conceptually these names can contain up to four sections. This information is stored in an instance of ClassifierNode.

  1. A prefix_modifier this modifies the whole card with a special character such as *tr5

  2. A Prefix, which is a series of letters that identifies the type such as m

  3. A number, which numbers it. These must be an unsigned integer.

  4. A particle classifier such as :n,p.

You control the parsing behavior through three methods: _class_prefix(), _has_number(), and _has_classifier(). See the documentation for how to set these.

Using the parse_data() Function#

The function parse_data() handles converting a data_input to the correct class automatically. It uses the set PREFIX_MATCH to do this. This lists all classes that the function will look into for a matching class prefix. Inputs that should not be parsed can have their prefix added to VERBOTEN in that file.

The parse_data function will use the fast_parse option for parsing the data_input. This method will only match the first word/classifier using the ClassifierParser. Based upon this the function will decide which class to run for a full parse. By default all subclasses will use the DataParser class. If you need to use a custom parser you do so by setting self._parser.

How to Add an Object to MCNP_Problem#

The MCNP_Problem automatically consumes problem level data inputs, and adds them to itself. Cards this would be appropriate for would be things like mode and kcode. To do this it uses the dictionary inputs_to_property in the __load_data_inputs_to_object method. To add a problem level data Object you need to

  1. Add it inputs_to_property. The key will be the object class, and the value will be a string for the attribute it should be loaded to.

  2. Add a property that exposes this attribute in a desirable way.

Making a Numbered Object: Numbered_MCNP_Object#

MCNP allows many types of number objects like cells, surfaces, and tallies. First you need to provide the property number, and old_number. The parent class provides a system to link to a problem via self._problem. Note this field can be None. When setting a number you must check for numbering collisions with the method: check_number(). This function returns nothing, but will raise an error when a number collision occurs.