diff --git a/doc/source/api/montepy.particle.rst b/doc/source/api/montepy.particle.rst
index 7b887d96..42d3cb64 100644
--- a/doc/source/api/montepy.particle.rst
+++ b/doc/source/api/montepy.particle.rst
@@ -4,6 +4,5 @@ montepy.particle module
.. automodule:: montepy.particle
:members:
- :inherited-members:
:undoc-members:
:show-inheritance:
diff --git a/doc/source/api/montepy.surfaces.surface_type.rst b/doc/source/api/montepy.surfaces.surface_type.rst
index ec5e4d77..cbec5e51 100644
--- a/doc/source/api/montepy.surfaces.surface_type.rst
+++ b/doc/source/api/montepy.surfaces.surface_type.rst
@@ -4,6 +4,5 @@ montepy.surfaces.surface\_type module
.. automodule:: montepy.surfaces.surface_type
:members:
- :inherited-members:
:undoc-members:
:show-inheritance:
diff --git a/doc/source/changelog.rst b/doc/source/changelog.rst
index 8d810620..67e2f4b2 100644
--- a/doc/source/changelog.rst
+++ b/doc/source/changelog.rst
@@ -11,7 +11,7 @@ MontePy Changelog
**Features Added**
* Redesigned how Materials hold Material_Components. See :ref:`migrate 0 1` (:pull:`507`).
-* Made it easier to create an Isotope, or now Nuclide: ``montepy.Nuclide("H-1.80c")`` (:issue:`505`).
+* Made it easier to create an Isotope (now Nuclide): ``montepy.Nuclide("H-1.80c")`` (:issue:`505`).
* When a typo in an object attribute is made an Error is raised rather than silently having no effect (:issue:`508`).
* Improved material printing to avoid very long lists of components (:issue:`144`).
* Allow querying for materials by components (:issue:`95`).
diff --git a/doc/source/conf.py b/doc/source/conf.py
index a410895d..cefc22e6 100644
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -68,6 +68,8 @@
# Display the version
display_version = True
+linkcheck_ignore = ["https://nucleardata.lanl.gov/.*"]
+
# -- External link configuration ---------------------------------------------
UM63 = (
"https://mcnp.lanl.gov/pdf_files/TechReport_2022_LANL_LA-UR-22-30006"
diff --git a/doc/source/dev_standards.rst b/doc/source/dev_standards.rst
index e2607f8a..3ca9da19 100644
--- a/doc/source/dev_standards.rst
+++ b/doc/source/dev_standards.rst
@@ -45,6 +45,13 @@ Design Philosophy
#. Defer to vanilla python, and only use the standard library. Currently the only dependencies are `numpy `_ and `sly `_.
There must be good justification for breaking from this convention and complicating things for the user.
+Style Guide
+-----------
+
+#. Thou shall be `PEP 8 `_, and use `black `_.
+#. Spaces not tabs with 4 spaces for an indent.
+#. External imports before internal imports with a blank line in between. All imports are alphabetized.
+
Doc Strings
-----------
diff --git a/doc/source/developing.rst b/doc/source/developing.rst
index 0265bf5f..ab333a49 100644
--- a/doc/source/developing.rst
+++ b/doc/source/developing.rst
@@ -690,3 +690,18 @@ Users are more like to use this dynamic code.
In general this philosophy is: if it's not the source of truth,
it should be a generator.
+Constants and Meta Data Structures
+----------------------------------
+
+MontePy uses constants and data structures to utilize meta-programming
+and remove redundant code.
+Typical constants can be found in :mod:`montepy.constants`.
+
+Here are the other data structures to be aware of:
+
+* :class:`~montepy.mcnp_problem.MCNP_Problem` ``_NUMBERED_OBJ_MAP``: maps a based numbered object to its collection
+ class. This is used for loading all problem numbered object collections in an instance.
+* :func:`montepy.data_inputs.data_parser.PREFIX_MATCHES` is a set of the data object classes. The prefix is taken from
+ the classes. A data object must be a member of this class for it to automatically parse new data objects.
+* :class:`~montepy.cell.Cell` ``_INPUTS_TO_PROPERTY`` maps a cell modifier class to the attribute to load it into for a
+ cell. The boolean is whether multiple input instances are allowed.
diff --git a/doc/source/migrations/migrate0_1.rst b/doc/source/migrations/migrate0_1.rst
index 81d4be5d..3a88c327 100644
--- a/doc/source/migrations/migrate0_1.rst
+++ b/doc/source/migrations/migrate0_1.rst
@@ -21,43 +21,47 @@ and can be advantageous.
See :issue:`504` for more details.
Due to this it was decided that the best way forward was to abandon the old design,
and to create a brand new data structure.
-This means that backwards compatibility *will* be broken,
-and so this fix is leading to a major version release.
+This means that backwards compatibility *was* broken,
+and so this fix led to a major version release.
Deprecations
------------
-The following properties and objects are currently deprecated,
-and will be removed in MontePy 1.0.0.
+The following properties and objects are currently deprecated
+and were removed in MontePy 1.0.0.
-* :func:`montepy.data_inputs.material.Material.material_components`.
+* :func:`~montepy.data_inputs.material.Material.material_components`.
This is the dictionary that caused this design problem.
-* :class:`montepy.data_inputs.material_components.MaterialComponents`
- This is the class that stores information in the above dictionary.
- It is largely excess object wrapping, that makes the material interface
+* :class:`~montepy.data_inputs.material_component.MaterialComponent`:
+ This was the class that stores information in the above dictionary.
+ It was largely excess object wrapping that made the material interface
overly complex.
-* :class:`montepy.data_inputs.Isotope` will be renamed to ``Nuclide``.
- This is to better align with MCNP documentation,
- and better reflect that the nuclear data for a nuclide can represent
+* :class:`~montepy.data_inputs.isotope.Isotope` was renamed to :class:`~montepy.data_inputs.nuclide.Nuclide`.
+ This is to better align with MCNP documentation
+ and to better reflect that the nuclear data for a nuclide can represent
isotopic, isomeric, or atomic data.
New Interface & Migration
-------------------------
+For more details, see the new :ref:`mat_tutorial` tutorial in the getting started guide,
+as well as the example in the :class:`~montepy.data_inputs.material.Material` documentation.
+
.. note::
This design is not finalized and is subject to change.
This is the currently planned design for ``1.0.0a1``.
If you have input you can `join the discussion `_.
- This is also where alpha-testing will be announced.
+ For feedback on the alpha test, please `join this discussion `_.
``material_components`` removal
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-Material composition data has moved from ``Material.material_components`` to the ``Material`` itself.
+Material composition data has moved from ``Material.material_components`` to the
+:class:`~montepy.data_inputs.material.Material` itself.
``Material`` is now a list-like iterable.
It is a list of tuples which are ``(nuclide, fraction)`` pairs.
@@ -76,37 +80,173 @@ Searching Components
^^^^^^^^^^^^^^^^^^^^
Finding a specific ``Nuclide`` in a ``Material`` is now much easier.
-First there will be a ``Material.find`` method that takes either a ``Nuclide`` string,
+First, there is a :func:`~montepy.data_inputs.material.Material.find` method that takes either a ``Nuclide`` string,
or various over search criteria (e.g., ``element``),
and creates a generator of all matching component tuples.
If you want to check if a ``Material`` contains a specific ``Nuclide``
you can simply test ``nuclide in material``.
-The ``Material.contains`` function will provide more options,
-such as setting a minimum threshold, and testing for multiple nuclides at once.
+The :func:`~montepy.data_inputs.material.Material.contains` function will provide more options,
+such as setting a minimum threshold and testing for multiple nuclides at once.
Adding Nuclides
^^^^^^^^^^^^^^^
-Adding a new nuclide will be easiest with the ``add_nuclide`` function.
-Editing Nuclide Compositon
-^^^^^^^^^^^^^^^^^^^^^^^^^^
+Adding a new nuclide is easiest with the :func:`~montepy.data_inputs.material.Material.add_nuclide` function.
+
+Editing Nuclide Composition
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
Editing a material composition will be very similar to editing a ``list``.
Existing components can be set to a nuclide component nuclide.
Also existing components can be deleted with ``del``.
+For just editing the fractions or nuclides the functions:
+:func:`~montepy.data_inputs.material.Material.nuclides`
+and :func:`~montepy.data_inputs.material.Material.values` provide the easiest interface.
``Isotope`` Deprecation and Removal
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-The decision was made to remove the name ``Isotope``.
+The decision was made to remove the name :class:`montepy.data_inputs.isotope.Isotope`.
This is because not all material components are an isotope,
they may be an isomer, or event an element.
-Rather the MCNP generalized terminology of ``Nuclide`` was adopted.
+Rather the MCNP generalized terminology of :class:`montepy.data_inputs.nuclide.Nuclide` was adopted.
The idea of a specific nuclide, e.g., ``H-1`` was separated from an
MCNP material component e.g., ``1001.80c``.
-The actual ``Nuclide`` information was moved to a new class: ``Nucleus``,
+The actual ``Nuclide`` information was moved to a new class: :class:`~montepy.data_inputs.nuclide.Nucleus`
that is immutable.
-The ``Nuclide`` wraps this and adds a ``Library`` object to specify the nuclear data that is used.
+The :class:`~montepy.data_inputs.nuclide.Nuclide` wraps this and adds a :class:`~montepy.data_inputs.nuclide.Library` object to specify the nuclear data that is used.
It makes sense to be able to change a library.
It does not make sense to change the intrinsic properties of a nuclide (i.e., ``Z``, ``A``, etc.).
+
+
+Code Comparison between 0.x and 1.x
+-----------------------------------
+
+Here are some example code blocks of various material operations in both versions.
+
+Iterating over Material Components
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In MontePy 0.x
+""""""""""""""
+
+.. testcode::
+ :skipif: True
+
+ import montepy
+ problem = montepy.read_input("foo.imcnp")
+ mat = problem.materials[1]
+ for component in mat.material_components.values():
+ print(component.fraction, component.isotope)
+
+This would print:
+
+.. testoutput::
+
+ 2.0 H-1 (80c)
+ 1.0 O-16 (80c)
+
+In MontePy 1.x
+""""""""""""""
+
+.. testcode::
+
+ import montepy
+ problem = montepy.read_input("foo.imcnp")
+ mat = problem.materials[1]
+ for nuclide, fraction in mat:
+ print(fraction, nuclide)
+
+Would print:
+
+.. testoutput::
+
+ 2.0 H-1 (80c)
+ 1.0 O-16 (80c)
+
+Adding Material Components
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Appending and editing the material components in a material in MontePy 0.x
+was rather clunky. That was a large part of the motivation for this release.
+
+In MontePy 0.x
+""""""""""""""
+.. testcode::
+ :skipif: True
+
+ from montepy.data_inputs.isotope import Isotope
+ from montepy.data_inputs.material_component import MaterialComponent
+ #construct new isotope
+ new_isotope = Isotope("5010.80c")
+ # construct new component
+ comp = MaterialComponent(new_isotope, 1e-6)
+ # add actual component to material
+ mat.material_components[new_isotope] = comp
+
+In MontePy 1.x
+""""""""""""""
+
+.. testcode::
+
+ mat.add_nuclide("B-10.80c", 1e-6)
+
+
+Finding, Editing, and Deleting a Component
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Accessing a specific component is another reason for this release.
+As you may have noticed, ``material_components`` is a dictionary with the keys being an ``Isotope``.
+Due to a bug in MontePy 0.x, the exact instance of an Isotope must be passed as the key to access that item.
+
+In MontePy 0.x
+""""""""""""""
+
+.. testcode::
+ :skipif: True
+
+ target_isotope = Isotope("5010.80c")
+ key = None
+ for isotope in mat.material_components:
+ if isotope.element == target_isotope.element and isotope.A == target_isotope.A:
+ key = isotope
+ break
+ # get material component object
+ comp = mat[key]
+ # edit it. This will update the material because everything is a pointer
+ comp.fraction = 2e-6
+ # delete the component
+ del mat[key]
+
+
+In MontePy 1.x
+""""""""""""""
+
+.. testcode::
+
+ target_isotope = montepy.Nuclide("B-10.80c")
+ for comp_idx, (nuc, fraction) in mat.find(target_isotope):
+ break
+ # update fraction
+ mat.values[comp_idx] = 2e-6
+ # delete component
+ del mat[comp_idx]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/doc/source/starting.rst b/doc/source/starting.rst
index f0873b28..13aa37bb 100644
--- a/doc/source/starting.rst
+++ b/doc/source/starting.rst
@@ -439,7 +439,7 @@ Surfaces
The most important unsung heroes of an MCNP problem are the surfaces.
They may be tedious to work with but you can't get anything done without them.
-MCNP supports *alot* of types of surfaces, and all of them are special in their own way.
+MCNP supports *a lot* of types of surfaces, and all of them are special in their own way.
You can see all the surface types here: :class:`~montepy.surfaces.surface_type.SurfaceType`.
By default all surfaces are an instance of :class:`~montepy.surfaces.surface.Surface`.
They will always have the properties: ``surface_type``, and ``surface_constants``.
@@ -705,7 +705,7 @@ This will completely redefine the cell's geometry. You can also modify the geome
fuel_cyl.number = 20
fuel_cyl.radius = 1.20
other_fuel_region = -fuel_cyl
- fuel_cell.geometry |= other_fuel_region
+ fuel_cell.geometry |= other_fuel_region #||
.. warning::
@@ -784,6 +784,344 @@ For example:
>>> new_cell.material.number
100
+
+.. _mat_tutorial:
+
+Materials
+---------
+
+Materials are how the nuclide concentrations in cells are specified.
+MontePy has always supported materials, but since version 1.0.0,
+the design of the interface has significantly improved.
+
+Specifying Nuclides
+^^^^^^^^^^^^^^^^^^^
+
+To specify a material, one needs to be able to specify the nuclides that are contained in it.
+This is done through :class:`~montepy.data_inputs.nuclide.Nuclide` objects.
+This actually a wrapper of a :class:`~montepy.data_inputs.nuclide.Nucleus` and a :class:`~montepy.data_inputs.nuclide.Library` object.
+Users should rarely need to interact with the latter two objects, but it is good to be aware of them.
+The general idea is that a ``Nuclide`` instance represents a specific set of ACE data that for a ``Nucleus``,
+which represents only a physical nuclide with a given ``Library``.
+
+The easiest way to specify a Nuclide is by its string name.
+MontePy supports all valid MCNP ZAIDs for MCNP 6.2, and MCNP 6.3.0.
+See :class:`~montepy.data_inputs.nuclide.Nuclide` for how metastable isomers are handled.
+However, ZAIDs (like many things in MCNP) are cumbersome.
+Therefore, MontePy also supports its own nuclide names as well, which are meant to be more intuitive.
+These are very similar to the names introduced with MCNP 6.3.1 (section 1.2.2): this follows:
+
+.. code-block::
+
+ Nn[-A][mS][.library]
+
+Where:
+
+* ``Nn`` is the atomic symbol of the nuclide, case insensitive. This is required.
+* ``A`` is the atomic mass. Zero-padding is not needed. Optional.
+* ``S`` is the metastable isomeric state. Only states 1 - 4 are allowed. Optional.
+* ``library`` is the library extension of the nuclide. This only supports MCNP 6.2, 6.3 formatting, i.e., 2 - 3 digits followed by a single letter. Optional.
+
+The following are all valid ways to specify a nuclide:
+
+.. doctest::
+
+ >>> import montepy
+ >>> montepy.Nuclide("1001.80c")
+ Nuclide('H-1.80c')
+ >>> montepy.Nuclide("H-1.80c")
+ Nuclide('H-1.80c')
+ >>> montepy.Nuclide("H-1.710nc")
+ Nuclide('H-1.710nc')
+ >>> montepy.Nuclide("H")
+ Nuclide('H-0')
+ >>> montepy.Nuclide("Co-60m1")
+ Nuclide('Co-60m1')
+ >>> montepy.Nuclide("Co")
+ Nuclide('Co-0')
+
+
+.. note::
+
+ The new SZAID and Name syntax for nuclides introduced with MCNP 6.3.1 is not currently supported by MontePy.
+ This support likely will be added soon, but probably not prior to MCNP 6.3.1 being available on RSICC.
+
+
+Working with Material Components
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Iterating over Material Components
+""""""""""""""""""""""""""""""""""
+
+Materials are list-like iterables of tuples.
+
+.. testcode::
+
+ mat = problem.materials[1]
+
+ for comp in mat:
+ print(comp)
+
+This shows:
+
+.. testoutput::
+
+ (Nuclide('U-235.80c'), 5.0)
+ (Nuclide('U-238.80c'), 95.0)
+
+If you need just the nuclide or just the fractions, these are accessible by:
+:func:`~montepy.data_inputs.material.Material.nuclides` and
+:func:`~montepy.data_inputs.material.Material.values`, respectively.
+
+.. testcode::
+
+ for nuclide in mat.nuclides:
+ print(repr(nuclide))
+ for fraction in mat.values:
+ print(fraction)
+
+shows:
+
+.. testoutput::
+
+ Nuclide('U-235.80c')
+ Nuclide('U-238.80c')
+ 5.0
+ 95.0
+
+Updating Components of Materials
+""""""""""""""""""""""""""""""""
+
+Materials are also list-like in that they are settable by index.
+The material must always be set to a tuple of a nuclide and a fraction.
+
+For instance:
+
+.. testcode::
+
+ nuclide = mat[0][0]
+ mat[0] = (nuclide, 4.0)
+
+Generally this is pretty clunky, so
+:func:`~montepy.data_inputs.material.Material.nuclides` and
+:func:`~montepy.data_inputs.material.Material.values` are also settable.
+To undo the previous changes:
+
+.. testcode::
+
+ mat.values[0] = 5.0
+ print(mat[0])
+
+This outputs:
+
+.. testoutput::
+
+ (Nuclide('U-235.80c'), 5.0)
+
+Adding Components to a Material
+"""""""""""""""""""""""""""""""
+
+To add components to a material use either
+:func:`~montepy.data_inputs.material.Material.add_nuclide`, or
+:func:`~montepy.data_inputs.material.Material.append`.
+:func:`~montepy.data_inputs.material.Material.add_nuclide` is generally the easier method to use.
+It accepts a nuclide or the name of a nuclide, and its fraction.
+
+.. note::
+
+ When adding a new component it is not possible to change whether the fraction is in atom fraction
+ or mass fraction.
+ This is settable through :func:`~montepy.data_inputs.material.Material.is_atom_fraction`.
+
+.. testcode::
+
+ mat.add_nuclide("B-10.80c", 1e-6)
+ for comp in mat:
+ print(comp)
+
+.. testoutput::
+
+ (Nuclide('U-235.80c'), 5.0)
+ (Nuclide('U-238.80c'), 95.0)
+ (Nuclide('B-10.80c'), 1e-06)
+
+
+Libraries
+^^^^^^^^^
+
+MCNP nuclear data comes pre-packaged in multiple different libraries that come from different nuclear data sources
+(e.g., ENDF/B-VIII.0),
+at different temperatures,
+and for different data needs, e.g., neutron data vs. photo-atomic data.
+For more details see `LA-UR-17-20709 `_, or
+`LANL's nuclear data libraries `_.
+
+All :class:`~montepy.data_inputs.nuclide.Nuclide` have a :class:`~montepy.data_inputs.nuclide.Nuclide.library`,
+though it may be just ``""``.
+These can be manually set for each nuclide.
+If you wish to change all of the components in a material to use the same library you can use
+:func:`~montepy.data_inputs.material.Material.change_libraries`.
+
+MCNP has a precedence system for determining which library use in a specific instance.
+This precedence order is:
+
+#. The library specified with the nuclide e.g., ``80c`` in ``1001.80c``.
+#. The library specified as default for the material e.g., ``nlib = 80c``.
+#. The library specified as default in the default material, ``M0``.
+#. The first matching entry in the ``XSDIR`` file.
+
+.. note::
+
+ MontePy currently does not support reading an ``XSDIR`` file. It will not provide information for
+ that final step.
+
+Which library will be used for a given nuclide, material, and problem can be checked with:
+:func:`~montepy.data_inputs.material.Material.get_nuclide_library`.
+
+.. seealso::
+
+ * :manual63:`5.6.1`
+ * :manual62:`108`
+
+
+Finding Materials and Nuclides
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Next, we will cover how to find if
+
+* a nuclide is in a material
+* multiple nuclides are in a material
+* a range of nuclides (e.g., transuranics) is in a material
+* specific materials are in a problem.
+
+Check if Nuclide in Material
+""""""""""""""""""""""""""""
+
+First, you can test if a :class:`~montepy.data_inputs.nuclide.Nuclide`
+(or :class:`~montepy.data_inputs.nuclide.Nucleus`, or :class:`~montepy.data_inputs.element.Element`, or ``str``),
+is in a material.
+This is generally interpreted broadly rather than explicitly.
+For instance, if the test nuclide has no library this will match
+for all libraries, not just the empty library.
+Similarly, an elemental nuclide, e.g., ``H-0``, will match all nuclides based
+on the element, not just the elemental nuclide.
+
+.. doctest::
+
+ >>> montepy.Nuclide('H-1.80c') in mat
+ False
+ >>> montepy.Element(92) in mat
+ True
+ >>> "U-235" in mat
+ True
+ >>> "U-235.70c" in mat
+ False
+ >>> montepy.Nuclide("B-0") in mat
+ True
+
+For more complicated checks there is the :func:`~montepy.data_inputs.material.Material.contains`.
+This takes a plurality of nuclides as well as a threshold.
+This returns ``True`` if and only if the material contains *all* nuclides
+with a fraction above the threshold.
+
+.. doctest::
+
+ >>> mat.contains("H-1.80c")
+ False
+ >>> mat.contains("U-235", "U-238", threshold=1.0)
+ True
+ >>> mat.contains("U-235.80c", "B-10")
+ True
+ >>> mat.contains("U-235.80c", "B-10", threshold=1e-3)
+ False
+
+Finding Nuclides
+""""""""""""""""
+
+Often you may need to only work a subset of the components in a material.
+:func:`~montepy.data_inputs.material.Material.find`.
+This returns a Generator of the index of the matching component, and then the component tuple.
+
+.. testcode::
+
+ # find all uraium nuclides
+ for idx, (nuclide, fraction) in mat.find("U"):
+ print(idx, nuclide, fraction)
+
+.. testoutput::
+
+ 0 U-235 (80c) 5.0
+ 1 U-238 (80c) 95.0
+
+There are also other fancy ways to pass slices, for instance to find all transuranics.
+See the examples in :func:`~montepy.data_inputs.material.Material.find` for more details.
+
+There is a related function as well :func:`~montepy.data_inputs.material.Material.find_vals`,
+which accepts the same arguments but only returns the matching fractions.
+This is great for instance to calculate the heavy metal fraction of a fuel:
+
+.. testcode::
+
+ # get all heavy metal fractions
+ hm_fraction = sum(mat.find_vals(element=slice(90,None))) # slice is requires an end value to accept a start
+ print(hm_fraction)
+
+Shows:
+
+.. testoutput::
+
+ 100.0
+
+Finding Materials
+"""""""""""""""""
+
+There are a lot of cases where you may want to find specific materials in a problem,
+for instance getting all steels in a problem.
+This is done with the function :func:`~montepy.materials.Materials.get_containing`
+of :class:`~montepy.materials.Materials`.
+It takes the same arguments as :func:`~montepy.data_inputs.material.Material.contains`
+previously discussed.
+
+Mixing Materials
+^^^^^^^^^^^^^^^^
+
+Commonly materials are a mixture of other materials.
+For instance a good idea for defining structural materials might be to create a new material for each element,
+that adds the naturally occurring nuclides of the element,
+and then mixing those elements together to make steel, zircaloy, etc.
+This mixing is done with :class:`~montepy.materials.Materials.mix`.
+Note this is a method of ``Materials`` and not ``Material``.
+
+.. note::
+
+ Materials can only be combined if they are all atom fraction or mass fraction.
+
+.. note::
+
+ The materials being mixed will be normalized prior to mixing (the original materials are unaffected).
+
+.. testcode::
+
+ mats = problem.materials
+ h2o = montepy.Material()
+ h2o.number = 1
+ h2o.add_nuclide("1001.80c", 2.0)
+ h2o.add_nuclide("8016.80c", 1.0)
+
+ boric_acid = montepy.Material()
+ boric_acid.number = 2
+ for nuclide, fraction in {
+ "1001.80c": 3.0,
+ "B-10.80c": 1.0 * 0.189,
+ "B-11.80c": 1.0 * 0.796,
+ "O-16.80c": 3.0
+ }.items():
+ boric_acid.add_nuclide(nuclide, fraction)
+
+ # boric acid concentration
+ boron_conc = 100e-6 # 100 ppm
+ borated_water = mats.mix([h2o, boric_acid], [1 - boron_conc, boron_conc])
+
Universes
---------
diff --git a/montepy/constants.py b/montepy/constants.py
index 069691bb..abe1091f 100644
--- a/montepy/constants.py
+++ b/montepy/constants.py
@@ -37,10 +37,10 @@
Citations:
-* 5.1.60 and 6.1.0: Section 2.6.2 of LA-UR-18-20808
-* 6.2.0: Section 1.1.1 of LA-UR-17-29981
-* 6.3.0: Section 3.2.2 of LA-UR-22-30006
-* 6.3.1: Section 3.2.2 of LA-UR-24-24602
+* 5.1.60 and 6.1.0: Section 2.6.2 of `LA-UR-18-20808 `_
+* 6.2.0: Section 1.1.1: :manual62:`13`
+* 6.3.0: :manual63:`3.2.2`
+* 6.3.1: Section 3.2.2 of `LA-UR-24-24602 `_
"""
DEFAULT_VERSION = (6, 3, 0)
diff --git a/montepy/input_parser/syntax_node.py b/montepy/input_parser/syntax_node.py
index af8d6c78..bdae6f87 100644
--- a/montepy/input_parser/syntax_node.py
+++ b/montepy/input_parser/syntax_node.py
@@ -730,7 +730,7 @@ def _grab_beginning_comment(self, extra_padding):
def __eq__(self, other):
if not isinstance(other, (type(self), str)):
- raise "PaddingNode can only be compared to PaddingNode or str"
+ return False
if isinstance(other, type(self)):
other = other.format()
return self.format() == other
@@ -1379,9 +1379,7 @@ def _check_if_needs_end_padding(self, value):
def __eq__(self, other):
if not isinstance(other, (type(self), str, int, float)):
- raise TypeError(
- f"ValueNode can't be equal to {type(other)} type. {other} given."
- )
+ return False
if isinstance(other, ValueNode):
other_val = other.value
if self.type != other.type:
@@ -1764,9 +1762,7 @@ def remove(self, obj):
def __eq__(self, other):
if not isinstance(other, (type(self), list)):
- raise TypeError(
- f"ListNode can only be compared to a ListNode or List. {other} given."
- )
+ return False
if len(self) != len(other):
return False
for lhs, rhs in zip(self, other):
diff --git a/montepy/particle.py b/montepy/particle.py
index 6e52f9dd..2c9b6ca7 100644
--- a/montepy/particle.py
+++ b/montepy/particle.py
@@ -7,7 +7,7 @@ class Particle(str, Enum):
"""
Supported MCNP supported particles.
- Taken from Table 2-2 of LA-UR-17-29981.
+ Taken from :manual62:`46`.
"""
NEUTRON = "N"
@@ -68,7 +68,7 @@ class LibraryType(str, Enum):
.. versionadded:: 1.0.0
- Taken from section of 5.6.1 of LA-UR-22-30006
+ Taken from :manual63:`5.6.1`.
"""
def __new__(cls, value, particle=None):
diff --git a/tests/test_syntax_parsing.py b/tests/test_syntax_parsing.py
index 67c5e5fa..8d03f7f0 100644
--- a/tests/test_syntax_parsing.py
+++ b/tests/test_syntax_parsing.py
@@ -361,8 +361,7 @@ def test_value_str(self):
def test_value_equality(self):
value_node1 = syntax_node.ValueNode("1", int)
self.assertTrue(value_node1 == value_node1)
- with self.assertRaises(TypeError):
- value_node1 == syntax_node.PaddingNode("")
+ assert not value_node1 == syntax_node.PaddingNode("")
value_node2 = syntax_node.ValueNode("2", int)
self.assertTrue(value_node1 != value_node2)
value_node3 = syntax_node.ValueNode("hi", str)
@@ -570,8 +569,7 @@ def test_padding_eq(self):
self.assertTrue(pad != " hi ")
pad1 = syntax_node.PaddingNode(" ")
self.assertTrue(pad == pad1)
- with self.assertRaises(TypeError):
- pad == 1
+ assert not pad == 1
def test_comment_init(self):
comment = syntax_node.CommentNode("$ hi")
@@ -722,8 +720,7 @@ def test_list_equality(self):
list_node1 = syntax_node.ListNode("list")
for i in range(20):
list_node1.append(syntax_node.ValueNode("1.0", float))
- with self.assertRaises(TypeError):
- list_node1 == "hi"
+ assert not list_node1 == "hi"
list2 = [syntax_node.ValueNode("1.0", float)] * 19
self.assertTrue(not list_node1 == list2)
list2 = [syntax_node.ValueNode("1.0", float)] * 20