montepy.data_inputs.material module#

Classes:

Material([input, number])

A class to represent an MCNP material.

Data:

DEFAULT_INDENT

The default number of spaces to indent on a new line by.

MAX_PRINT_ELEMENTS

The maximum number of elements to print in a material string descripton.

class montepy.data_inputs.material.Material(input: Input | str = None, number: int = None)#

Bases: DataInputAbstract, Numbered_MCNP_Object

A class to represent an MCNP material.

Examples

First it might be useful to load an example problem:

import montepy
problem = montepy.read_input("foo.imcnp")
mat = problem.materials[1]
print(mat)
MATERIAL: 1, ['hydrogen', 'oxygen']

Materials are iterable#

Materials look like a list of tuples, and is iterable. Whether or not the material is defined in mass fraction or atom fraction is stored for the whole material in is_atom_fraction(). The fractions (atom or mass) of the componenets are always positive, because MontePy believes in physics.

assert mat.is_atom_fraction # ensures it is in atom_fraction

for nuclide, fraction in mat:
    print("nuclide", nuclide, fraction)

This would display:

nuclide  H-1     (80c) 2.0
nuclide  O-16    (80c) 1.0

As a list, Materials can be indexed:

oxygen, ox_frac = mat[1]
mat[1] = (oxygen, ox_frac + 1e-6)
del mat[1]

If you need just the nuclides or just the fractions of components in this material see: nuclides() and values().

You can check if a Nuclide is in a Material#

You can check if a Nuclide or Element is in a Material with in.

>>> montepy.Nuclide("H-1") in mat
True
>>> "H-1" in mat
True
>>> montepy.Element(1) in mat
True
>>> montepy.Element(92) in mat
False

Add New Component#

The easiest way to add new components to a material is with add_nuclide().

# add boric acid to water
boric_acid_frac = 1e-6
mat[0]
# Add by nuclide object
mat.add_nuclide(oxygen, ox_frac + 3 * boric_acid_frac)
# add by nuclide Name or ZAID
mat.add_nuclide("B-10.80c", 1e-6)
print(mat)
MATERIAL: 1, ['hydrogen', 'oxygen', 'boron']

Default Libraries#

Also materials have the concept of default_libraries(). These are the libraries set by NLIB, PLIB, etc., which are used when a library of the correct LibraryType is not provided with the nuclide. default_libraries() acts like a dictionary, and can accept a string or a LibraryType as keys.

print(mat.default_libraries["plib"])
mat.default_libraries[montepy.LibraryType.NEUTRON] = "00c"
print(mat.default_libraries["nlib"])
80p
00c

Changed in version 1.0.0:

  • Added number parameter to constructor.

  • This was the primary change for this release. For more details on what changed see Migration plan for MontePy 1.0.0.
    • Switched to list-like data-structure

    • Added ability to search by Nuclide

    • Added Support for default libraries (e.g., nlib=80c).

type input:

Union[Input, str]

param input:

The Input syntax object this will wrap and parse.

type input:

Union[Input, str]

type number:

int

param number:

The number to set for this object.

type number:

int

Methods:

add_nuclide(nuclide, fraction)

Add a new component to this material of the given nuclide, and fraction.

add_thermal_scattering(law)

Adds thermal scattering law to the material

append(nuclide_frac_pair)

Appends the tuple to this material.

change_libraries(new_library)

Change the library for all nuclides in the material.

clear()

Clears all nuclide components from this material.

clone([starting_number, step])

Create a new independent instance of this object with a new number.

contains_all(*nuclides[, threshold, strict])

Checks if this material contains of all of the given nuclides.

contains_any(*nuclides[, threshold, strict])

Checks if this material contains any of the given nuclide.

find([name, element, A, meta_state, ...])

Finds all components that meet the given criteria.

find_vals([name, element, A, meta_state, ...])

A wrapper for find() that only returns the fractions of the components.

format_for_mcnp_input(mcnp_version)

Creates a list of strings representing this MCNP_Object that can be written to file.

get_material_elements()

Get the elements that are contained in this material.

get_nuclide_library(nuclide, library_type)

Figures out which nuclear data library will be used for the given nuclide in this given material in this given problem.

link_to_problem(problem)

Links the input to the parent problem for this input.

mcnp_str([mcnp_version])

Returns a string of this input as it would appear in an MCNP input file.

normalize()

Normalizes the components fractions so that they sum to 1.0.

update_pointers(data_inputs)

Updates pointer to the thermal scattering data

validate()

Validates that the object is in a usable state.

wrap_string_for_mcnp(string, mcnp_version, ...)

Wraps the list of the words to be a well formed MCNP input.

Attributes:

cells

A generator of the cells that use this material.

classifier

The syntax tree object holding the data classifier.

comments

The comments associated with this input if any.

data

The syntax tree actually holding the data.

default_libraries

The default libraries that are used when a nuclide doesn't have a relevant library specified.

is_atom_fraction

If true this constituent is in atom fraction, not weight fraction.

leading_comments

Any comments that come before the beginning of the input proper.

material_components

The internal dictionary containing all the components of this material.

nuclides

Get just the fractions, or values from this material.

number

The current number of the object that will be written out to a new input.

old_number

The material number that was used in the read file

parameters

A dictionary of the additional parameters for the object.

particle_classifiers

The particle class part of the input identifier as a parsed list.

prefix

The text part of the input identifier parsed from the input.

prefix_modifier

The modifier to a name prefix that was parsed from the input.

thermal_scattering

The thermal scattering law for this material

trailing_comment

The trailing comments and padding of an input.

values

Get just the fractions, or values from this material.

static wrap_string_for_mcnp(string, mcnp_version, is_first_line, suppress_blank_end=True) list[str]#

Wraps the list of the words to be a well formed MCNP input.

multi-line inputs will be handled by using the indentation format, and not the “&” method.

Parameters:
  • string (str) – A long string with new lines in it, that needs to be chunked appropriately for MCNP inputs

  • mcnp_version (tuple) – the tuple for the MCNP that must be formatted for.

  • is_first_line (bool) – If true this will be the beginning of an MCNP input. The first line will not be indented.

  • suppress_blank_end (bool) – Whether or not to suppress any blank lines that would be added to the end. Good for anywhere but cell modifiers in the cell block.

Returns:

A list of strings that can be written to an input file, one item to a line.

Return type:

list

add_nuclide(nuclide: Nuclide | Nucleus | Element | str | Integral, fraction: float)#

Add a new component to this material of the given nuclide, and fraction.

Added in version 1.0.0.

Parameters:
  • nuclide (Nuclide, str, int) – The nuclide to add, which can be a string Identifier, or ZAID.

  • fraction (float) – the fraction of this component being added.

add_thermal_scattering(law)#

Adds thermal scattering law to the material

Parameters:

law (str) – the law that is mcnp formatted

append(nuclide_frac_pair: tuple[Nuclide, float])#

Appends the tuple to this material.

Added in version 1.0.0.

Parameters:

nuclide_frac_pair (tuple[Nuclide, float]) – a tuple of the nuclide and the fraction to add.

change_libraries(new_library: str | Library)#

Change the library for all nuclides in the material.

Added in version 1.0.0.

Parameters:

new_library (Union[str, Library]) – the new library to set all Nuclides to use.

clear()#

Clears all nuclide components from this material.

Added in version 1.0.0.

clone(starting_number=None, step=None)#

Create a new independent instance of this object with a new number.

This relies mostly on copy.deepcopy.

Notes

If starting_number, or step are not specified starting_number(), and step() are used as default values, if this object is tied to a problem. For instance a Material will use problem.materials default information. Otherwise 1 will be used as default values

Added in version 0.5.0.

Parameters:
  • starting_number (int) – The starting number to request for a new object number.

  • step (int) – the step size to use to find a new valid number.

Returns:

a cloned copy of this object.

Return type:

type(self)

contains_all(*nuclides: Nuclide | Nucleus | Element | str | Integral, threshold: float = 0.0, strict: bool = False) bool#

Checks if this material contains of all of the given nuclides.

A boolean “and” is used for this comparison. That is this material must contain all nuclides at or above the given threshold in order to return true.

Examples

import montepy
problem = montepy.read_input("tests/inputs/test.imcnp")

# try to find LEU materials
for mat in problem.materials:
    if mat.contains_all("U-235", threshold=0.02):
        # your code here
        pass

# try to find a uranium
for mat in problem.materials:
    if mat.contains_all("U"):
        pass

Notes

The difference between contains_all() and contains_any() is only for how they handle being given multiple nuclides. This does not impact how given Elements will match daughter Nuclides. This is handled instead by strict.

Notes

For details on how to use the strict argument see the examples in: find().

Added in version 1.0.0.

Parameters:
  • *nuclides (Union[Nuclide, Nucleus, Element, str, int]) – a plurality of nuclides to check for.

  • threshold (float) – the minimum concentration of a nuclide to be considered. The material components are not first normalized.

  • strict (bool) – If True this does not let an elemental nuclide match all child isotopes, isomers, nor will an isotope match all isomers, nor will a blank library match all libraries.

Returns:

whether or not this material contains all components given above the threshold.

Return type:

bool

Raises:
  • TypeError – if any argument is of the wrong type.

  • ValueError – if the fraction is not positive or zero, or if nuclide cannot be interpreted as a Nuclide.

contains_any(*nuclides: Nuclide | Nucleus | Element | str | Integral, threshold: float = 0.0, strict: bool = False) bool#

Checks if this material contains any of the given nuclide.

A boolean “or” is used for this comparison. That is, this material must contain any nuclides at or above the given threshold in order to return true.

Examples

import montepy
problem = montepy.read_input("tests/inputs/test.imcnp")

# try to find any fissile materials
for mat in problem.materials:
    if mat.contains_any("U-235", "U-233", "Pu-239", threshold=1e-6):
        pass

Notes

For details on how to use the strict argument see the examples in: find().

Added in version 1.0.0.

Parameters:
  • *nuclides (Union[Nuclide, Nucleus, Element, str, int]) – a plurality of nuclides to check for.

  • threshold (float) – the minimum concentration of a nuclide to be considered. The material components are not first normalized.

  • strict (bool) – If True this does not let an elemental nuclide match all child isotopes, isomers, nor will an isotope match all isomers, nor will a blank library match all libraries.

Returns:

whether or not this material contains all components given above the threshold.

Return type:

bool

Raises:
  • TypeError – if any argument is of the wrong type.

  • ValueError – if the fraction is not positive or zero, or if nuclide cannot be interpreted as a Nuclide.

find(name: str = None, element: Element | str | Integral | slice = None, A: int | slice = None, meta_state: int | slice = None, library: str | slice = None, strict: bool = False) Generator[tuple[int, tuple[Nuclide, float]]]#

Finds all components that meet the given criteria.

The criteria are additive, and a component must match all criteria. That is the boolean and operator is used. Slices can be specified at most levels allowing to search by a range of values. For numerical quantities slices are rather intuitive, and follow the same rules that list indices do. For elements slices are by Z number only. For the library the slicing is done using string comparisons.

Examples

import montepy
mat = montepy.Material()
mat.number = 1

# make non-sense material
for nuclide in ["U-235.80c", "U-238.70c", "Pu-239.00c", "O-16.00c", "C-0", "C-12.00c", "Fe-56"]:
    mat.add_nuclide(nuclide, 0.1)

print("Get all uranium nuclides.")
print(list(mat.find(element = "U")))

print("Get all transuranics")
print(list(mat.find(element = slice(92, 100))))

print("Get all ENDF/B-VIII.0")
print(list(mat.find(library = slice("00c", "09c"))))

This would print:

Get all uranium nuclides.
[(0, (Nuclide('U-235.80c'), 0.1)), (1, (Nuclide('U-238.70c'), 0.1))]
Get all transuranics
[(0, (Nuclide('U-235.80c'), 0.1)), (1, (Nuclide('U-238.70c'), 0.1)), (2, (Nuclide('Pu-239.00c'), 0.1))]
Get all ENDF/B-VIII.0
[(2, (Nuclide('Pu-239.00c'), 0.1)), (3, (Nuclide('O-16.00c'), 0.1)), (5, (Nuclide('C-12.00c'), 0.1))]

Strict (Explicit) Matching#

Generally this functions treats ambiguity implicitly, and will match as many nuclides as possible. This is generally useful, but not always. By default when only an element is given all daughter nuclides match, as seen above. However, MCNP does provide some “natural” or “elemental” nuclear data, and it would be helpful to find these sometimes. For instance, you may want to find all instances of elemental nuclides, and replace them with explicit isotopes (for instance migrating from ENDF/B-VII.1 to ENDF/B-VIII). In these cases the strict argument is needed. When strict is True an ambiguous A will only match elemental data:

print("Strict: False", list(mat.find(element="C")))
print("Strict: True", list(mat.find(element="C", strict=True)))

will print:

Strict: False [(4, (Nuclide('C-0'), 0.1)), (5, (Nuclide('C-12.00c'), 0.1))]
Strict: True [(4, (Nuclide('C-0'), 0.1))]

Similarly to find nuclides with no library defined you can use strict:

print("Strict: False", list(mat.find(library=None)))
print("Strict: True", list(mat.find(library=None, strict=True)))

This would print:

Strict: False [(0, (Nuclide('U-235.80c'), 0.1)), (1, (Nuclide('U-238.70c'), 0.1)), (2, (Nuclide('Pu-239.00c'), 0.1)), (3, (Nuclide('O-16.00c'), 0.1)), (4, (Nuclide('C-0'), 0.1)), (5, (Nuclide('C-12.00c'), 0.1)), (6, (Nuclide('Fe-56'), 0.1))]
Strict: True [(4, (Nuclide('C-0'), 0.1)), (6, (Nuclide('Fe-56'), 0.1))]

Added in version 1.0.0.

type name:

param name:

The name to pass to Nuclide to search by a specific Nuclide. If an element name is passed this will only match elemental nuclides.

type name:

str

type element:

param element:

the element to filter by, slices must be slices of integers. This will match all nuclides that are based on this element. e.g., “U” will match U-235 and U-238.

type element:

Element, str, int, slice

type A:

param A:

the filter for the nuclide A number.

type A:

int, slice

type meta_state:

param meta_state:

the metastable isomer filter.

type meta_state:

int, slice

type library:

param library:

the libraries to limit the search to.

type library:

str, slice

type strict:

param strict:

When true this will strictly match elements as only elements (when no A is given), and only match blank libraries when no library is given.

type strict:

bool

returns:

a generator of all matching nuclides, as their index and then a tuple of their nuclide, and fraction pairs that match.

rtype:

Generator[tuple[int, tuple[Nuclide, float]]]

Parameters:
  • name (str)

  • element (Union[Element, str, Integral, slice])

  • A (Union[int, slice])

  • meta_state (Union[int, slice])

  • library (Union[str, slice])

  • strict (bool)

Return type:

Generator[tuple[int, tuple[Nuclide, float]]]

find_vals(name: str = None, element: Element | str | int | slice = None, A: int | slice = None, meta_state: int | slice = None, library: str | slice = None, strict: bool = False) Generator[float]#

A wrapper for find() that only returns the fractions of the components.

For more examples see that function.

Examples

import montepy
mat = montepy.Material()
mat.number = 1

# make non-sense material
for nuclide in ["U-235.80c", "U-238.70c", "Pu-239.00c", "O-16.00c"]:
    mat.add_nuclide(nuclide, 0.1)

# get fraction that is uranium
print(sum(mat.find_vals(element= "U")))

which would intuitively print:

0.2

Added in version 1.0.0.

Parameters:
  • name (str) – The name to pass to Nuclide to search by a specific Nuclide. If an element name is passed this will only match elemental nuclides.

  • element (Element, str, int, slice) – the element to filter by, slices must be slices of integers. This will match all nuclides that are based on this element. e.g., “U” will match U-235 and U-238.

  • A (int, slice) – the filter for the nuclide A number.

  • meta_state (int, slice) – the metastable isomer filter.

  • library (str, slice) – the libraries to limit the search to.

  • strict (bool) – whether to strictly match elements as only elements (when no A is given), and only match blank libraries when no library is given.

Returns:

a generator of fractions whose nuclide matches the criteria.

Return type:

Generator[float]

format_for_mcnp_input(mcnp_version)#

Creates a list of strings representing this MCNP_Object that can be written to file.

Parameters:

mcnp_version (tuple[int]) – The tuple for the MCNP version that must be exported to.

Returns:

a list of strings for the lines that this input will occupy.

Return type:

list

get_material_elements()#

Get the elements that are contained in this material.

This is sorted by the most common element to the least common.

Returns:

a sorted list of elements by total fraction

Return type:

list[Element]

get_nuclide_library(nuclide: Nuclide, library_type: LibraryType) Library | None#

Figures out which nuclear data library will be used for the given nuclide in this given material in this given problem.

This follows the MCNP lookup process and returns the first Library to meet these rules.

  1. The library extension for the nuclide. For example if the nuclide is 1001.80c for LibraryType("nlib"), Library("80c") will be returned.

  2. Next if a relevant nuclide library isn’t provided the default_libraries() will be used.

  3. Finally if the two other options failed M0 will be checked. These are stored in montepy.materials.Materials.default_libraries().

Notes

The final backup is that MCNP will use the first matching library in XSDIR. Currently MontePy doesn’t support reading an XSDIR file and so it will return none in this case.

Added in version 1.0.0.

Parameters:
  • nuclide (Union[Nuclide, str]) – the nuclide to check.

  • library_type (LibraryType) – the LibraryType to check against.

Returns:

the library that will be used in this scenario by MCNP.

Return type:

Union[Library, None]

Raises:

TypeError – If arguments of the wrong type are given.

Links the input to the parent problem for this input.

This is done so that inputs can find links to other objects.

Parameters:

problem (MCNP_Problem) – The problem to link this input to.

mcnp_str(mcnp_version: tuple[int] = None)#

Returns a string of this input as it would appear in an MCNP input file.

..versionadded:: 1.0.0

Parameters:

mcnp_version (tuple[int]) – The tuple for the MCNP version that must be exported to.

Returns:

The string that would have been printed in a file

Return type:

str

normalize()#

Normalizes the components fractions so that they sum to 1.0.

Added in version 1.0.0.

update_pointers(data_inputs: list[DataInput])#

Updates pointer to the thermal scattering data

Parameters:

data_inputs (list[DataInput]) – a list of the data inputs in the problem

validate()#

Validates that the object is in a usable state.

property cells: Generator[montepy.cell.Cell]#

A generator of the cells that use this material.

Returns:

an iterator of the Cell objects which use this.

Return type:

Generator[Cell]

property classifier#

The syntax tree object holding the data classifier.

For example this would container information like M4, or F104:n.

Returns:

the classifier for this data_input.

Return type:

ClassifierNode

property comments: list[PaddingNode]#

The comments associated with this input if any.

This includes all C comments before this card that aren’t part of another card, and any comments that are inside this card.

Returns:

a list of the comments associated with this comment.

Return type:

list

property data#

The syntax tree actually holding the data.

Returns:

The syntax tree with the information.

Return type:

ListNode

property default_libraries#

The default libraries that are used when a nuclide doesn’t have a relevant library specified.

Default Libraries#

Also materials have the concept of default_libraries(). These are the libraries set by NLIB, PLIB, etc., which are used when a library of the correct LibraryType is not provided with the nuclide. default_libraries() acts like a dictionary, and can accept a string or a LibraryType as keys.

print(mat.default_libraries["plib"])
mat.default_libraries[montepy.LibraryType.NEUTRON] = "00c"
print(mat.default_libraries["nlib"])
None
00c

Added in version 1.0.0.

property is_atom_fraction: bool#

If true this constituent is in atom fraction, not weight fraction.

Changed in version 1.0.0: This property is now settable.

Return type:

bool

property leading_comments: list[PaddingNode]#

Any comments that come before the beginning of the input proper.

Returns:

the leading comments.

Return type:

list

property material_components#

The internal dictionary containing all the components of this material.

Deprecated since version 0.4.1: MaterialComponent has been deprecated as part of a redesign for the material interface due to a critical bug in how MontePy handles duplicate nuclides. See Migration plan for MontePy 1.0.0.

Raises:

DeprecationWarning – This has been fully deprecated and cannot be used.

property nuclides#

Get just the fractions, or values from this material.

This acts like a list. It is iterable, and indexable.

Examples

import montepy
mat = montepy.Material()
mat.number = 5
enrichment = 0.04

# define UO2 with enrichment of 4.0%
mat.add_nuclide("8016.00c", 2/3)
mat.add_nuclide("U-235.00c", 1/3 * enrichment)
mat.add_nuclide("U-238.00c", 2/3 * (1 - enrichment))

for nuc in mat.nuclides:
    print(repr(nuc))
# iterables can be used with other functions
max_zaid = max(mat.nuclides)

this would print:

Nuclide('O-16.00c')
Nuclide('U-235.00c')
Nuclide('U-238.00c')
# get value by index
print(repr(mat.nuclides[0]))

# set the value, and double enrichment
mat.nuclides[1] = montepy.Nuclide("U-235.80c")
Nuclide('O-16.00c')

Added in version 1.0.0.

Return type:

Generator[Nuclide]

property number#

The current number of the object that will be written out to a new input.

Return type:

int

property old_number: int#

The material number that was used in the read file

Return type:

int

property parameters: dict[str, str]#

A dictionary of the additional parameters for the object.

e.g.: 1 0 -1 u=1 imp:n=0.5 has the parameters {"U": "1", "IMP:N": "0.5"}

Returns:

a dictionary of the key-value pairs of the parameters.

Return type:

unknown

Rytpe:

dict

property particle_classifiers#

The particle class part of the input identifier as a parsed list.

This is parsed from the input that was read.

For example: the classifier for F7:n is :n, and imp:n,p is :n,p This will be parsed as a list: [<Particle.NEUTRON: 'N'>, <Particle.PHOTON: 'P'>].

Returns:

the particles listed in the input if any. Otherwise None

Return type:

list

property prefix#

The text part of the input identifier parsed from the input.

For example: for a material like: m20 the prefix is m. this will always be lower case. Can also be called the mnemonic.

Returns:

The prefix read from the input

Return type:

str

property prefix_modifier#

The modifier to a name prefix that was parsed from the input.

For example: for a transform: *tr5 the modifier is *

Returns:

the prefix modifier that was parsed if any. None if otherwise.

Return type:

str

property thermal_scattering: ThermalScatteringLaw#

The thermal scattering law for this material

Return type:

ThermalScatteringLaw

property trailing_comment: list[PaddingNode]#

The trailing comments and padding of an input.

Generally this will be blank as these will be moved to be a leading comment for the next input.

Returns:

the trailing c style comments and intermixed padding (e.g., new lines)

Return type:

list

property values#

Get just the fractions, or values from this material.

This acts like a list. It is iterable, and indexable.

Examples

import montepy
mat = montepy.Material()
mat.number = 5
enrichment = 0.04

# define UO2 with enrichment of 4.0%
mat.add_nuclide("8016.00c", 2/3)
mat.add_nuclide("U-235.00c", 1/3 * enrichment)
mat.add_nuclide("U-238.00c", 2/3 * (1 - enrichment))

for val in mat.values:
    print(val)
# iterables can be used with other functions
max_frac = max(mat.values)
print("max", max_frac)

This would print:

0.6666666666666666
0.013333333333333332
0.6399999999999999
max 0.6666666666666666
# get value by index
print(mat.values[0])

# set the value, and double enrichment
mat.values[1] *= 2.0
print(mat.values[1])

This would print:

0.6666666666666666
0.026666666666666665

Added in version 1.0.0.

Return type:

Generator[float]

Parameters:
  • input (InitInput)

  • number (int)

montepy.data_inputs.material.DEFAULT_INDENT: int = 6#

The default number of spaces to indent on a new line by.

This is used for adding new material components. By default all components made from scratch are added to their own line with this many leading spaces.

montepy.data_inputs.material.MAX_PRINT_ELEMENTS: int = 5#

The maximum number of elements to print in a material string descripton.