From 65c5ba6f3c37b0ed704ce484d7c2c33a2808be01 Mon Sep 17 00:00:00 2001 From: "Micah D. Gale" Date: Mon, 9 Dec 2024 14:16:37 -0600 Subject: [PATCH 01/15] Documented how to make new nuclides. --- doc/source/starting.rst | 55 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/doc/source/starting.rst b/doc/source/starting.rst index 441281ae..0f419ddc 100644 --- a/doc/source/starting.rst +++ b/doc/source/starting.rst @@ -641,7 +641,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:: @@ -720,6 +720,59 @@ For example: >>> new_cell.material.number 100 +Materials +--------- + +Materials are how he nuclide concentrations in cells are specified. +MontePy has always supported materials, but since version 1.0.0 the design of the interface has changed significantly, +and greatly 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 objects, but it is good to be aware of them. +The generally idea is that ``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 rather 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") + >>> montepy.Nuclide("H-1.80c") + >>> montepy.Nuclide("H-1.710nc") + >>> montepy.Nuclide("H") + >>> montepy.Nuclide("Co-60m1") + >>> montepy.Nuclide("Co") + + +.. 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. + Universes --------- From 4369359d67a5fa1e3b8e23a74b2a588e439bbfb3 Mon Sep 17 00:00:00 2001 From: "Micah D. Gale" Date: Mon, 9 Dec 2024 17:22:35 -0600 Subject: [PATCH 02/15] Updated docs to include material iteration. --- doc/source/starting.rst | 61 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/doc/source/starting.rst b/doc/source/starting.rst index 0f419ddc..5f308a34 100644 --- a/doc/source/starting.rst +++ b/doc/source/starting.rst @@ -761,11 +761,17 @@ The following are all valid ways to specify a nuclide: >>> 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:: @@ -773,6 +779,61 @@ The following are all valid ways to specify a nuclide: 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. + +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`. + +.. testcode:: + + for nuclide in mat.nuclides: + print(nuclide) + for fraction in mat.values: + print(value) + +shows: + +.. testoutput:: + + Nuclide('U-235.80c') + Nuclide('U-238.80c') + 5.0 + 95.0 + +Updating Components of Materials +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Adding Components to a Material +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Finding Materials +^^^^^^^^^^^^^^^^^ + +Finding Nuclides +^^^^^^^^^^^^^^^^ + +Mixing Materials +^^^^^^^^^^^^^^^^ + Universes --------- From 823988808acd32e85c3e2ce30de80c9aed5e2048 Mon Sep 17 00:00:00 2001 From: "Micah D. Gale" Date: Tue, 10 Dec 2024 09:32:59 -0600 Subject: [PATCH 03/15] Removed all the excess string methods from docs. --- doc/source/api/montepy.particle.rst | 1 - doc/source/api/montepy.surfaces.surface_type.rst | 1 - montepy/particle.py | 4 ++-- 3 files changed, 2 insertions(+), 4 deletions(-) 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/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): From 97cae92bd6610e9fd6e45a8b250c0b10469a9430 Mon Sep 17 00:00:00 2001 From: "Micah D. Gale" Date: Tue, 10 Dec 2024 09:34:31 -0600 Subject: [PATCH 04/15] Added lots of tutorials on new material features. --- doc/source/starting.rst | 238 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 230 insertions(+), 8 deletions(-) diff --git a/doc/source/starting.rst b/doc/source/starting.rst index 5f308a34..18132c42 100644 --- a/doc/source/starting.rst +++ b/doc/source/starting.rst @@ -720,6 +720,9 @@ For example: >>> new_cell.material.number 100 + +.. _mat_tutorial: + Materials --------- @@ -780,8 +783,11 @@ The following are all valid ways to specify a nuclide: 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. @@ -806,9 +812,9 @@ If you need just the nuclide, or just the fractions these are accessible by: .. testcode:: for nuclide in mat.nuclides: - print(nuclide) + print(repr(nuclide)) for fraction in mat.values: - print(value) + print(fraction) shows: @@ -820,20 +826,236 @@ shows: 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, and 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 -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +""""""""""""""""""""""""""""""" -Finding Materials -^^^^^^^^^^^^^^^^^ +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 and so 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, +if a material contains multiple nuclides, +specific nuclides in a material (e.g., transuranics), +or specific materials 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, zircalloy, etc. +This mixing is done with :class:`~imontepy.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 --------- From 555c6c1c497a52602987ea59cead9d03182192ed Mon Sep 17 00:00:00 2001 From: "Micah D. Gale" Date: Tue, 10 Dec 2024 09:34:59 -0600 Subject: [PATCH 05/15] Updated migration plan to link to docs and be in past tense. --- doc/source/migrations/migrate0_1.rst | 43 +++++++++++++++++----------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/doc/source/migrations/migrate0_1.rst b/doc/source/migrations/migrate0_1.rst index 81d4be5d..8c005308 100644 --- a/doc/source/migrations/migrate0_1.rst +++ b/doc/source/migrations/migrate0_1.rst @@ -21,24 +21,24 @@ 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 lead to a major version release. Deprecations ------------ The following properties and objects are currently deprecated, -and will be removed in MontePy 1.0.0. +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` +* ``MaterialComponents``: This is the class that stores information in the above dictionary. It is largely excess object wrapping, that makes the material interface overly complex. -* :class:`montepy.data_inputs.Isotope` will be renamed to ``Nuclide``. +* :class:`~montepy.data_inputs.isotope.Isotope` was renamed to :class:`~montepy.data_inputs.nuclide.Nuclide`. This is to better align with MCNP documentation, and better reflect that the nuclear data for a nuclide can represent isotopic, isomeric, or atomic data. @@ -47,17 +47,21 @@ and will be removed in MontePy 1.0.0. 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,42 @@ 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, +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.). From 58da12c4853fdbf60c08e8aabf4aeb1a60b880a1 Mon Sep 17 00:00:00 2001 From: "Micah D. Gale" Date: Tue, 10 Dec 2024 10:49:09 -0600 Subject: [PATCH 06/15] Documented random constants and stuff. --- doc/source/dev_standards.rst | 7 +++++++ doc/source/developing.rst | 15 +++++++++++++++ montepy/constants.py | 8 ++++---- 3 files changed, 26 insertions(+), 4 deletions(-) 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 bdfe2e73..8e23b764 100644 --- a/doc/source/developing.rst +++ b/doc/source/developing.rst @@ -684,3 +684,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/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) From 6ffcb7e1db1d103dd00bdf9b7a25c9b40c8bb7a8 Mon Sep 17 00:00:00 2001 From: Micah Gale Date: Fri, 13 Dec 2024 23:20:41 -0600 Subject: [PATCH 07/15] fixed small typos in docs. --- doc/source/migrations/migrate0_1.rst | 8 ++++---- doc/source/starting.rst | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/source/migrations/migrate0_1.rst b/doc/source/migrations/migrate0_1.rst index 8c005308..b0edb3f5 100644 --- a/doc/source/migrations/migrate0_1.rst +++ b/doc/source/migrations/migrate0_1.rst @@ -22,12 +22,12 @@ 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 *was* broken, -and so this fix lead to a major version release. +and so this fix led to a major version release. Deprecations ------------ -The following properties and objects are currently deprecated, +The following properties and objects are currently deprecated and were removed in MontePy 1.0.0. * :func:`~montepy.data_inputs.material.Material.material_components`. @@ -35,7 +35,7 @@ and were removed in MontePy 1.0.0. * ``MaterialComponents``: This is the class that stores information in the above dictionary. - It is largely excess object wrapping, that makes the material interface + It is largely excess object wrapping that makes the material interface overly complex. * :class:`~montepy.data_inputs.isotope.Isotope` was renamed to :class:`~montepy.data_inputs.nuclide.Nuclide`. @@ -55,7 +55,7 @@ as well as the example in the :class:`~montepy.data_inputs.material.Material` do 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 `_. - For feedback on the alpha test please `join this discussion `_. + For feedback on the alpha test, please `join this discussion `_. ``material_components`` removal ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/doc/source/starting.rst b/doc/source/starting.rst index 18132c42..cef02637 100644 --- a/doc/source/starting.rst +++ b/doc/source/starting.rst @@ -726,7 +726,7 @@ For example: Materials --------- -Materials are how he nuclide concentrations in cells are specified. +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 changed significantly, and greatly improved. @@ -1022,8 +1022,8 @@ 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, zircalloy, etc. -This mixing is done with :class:`~imontepy.materials.Materials.mix`. +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:: From 386c65bb62add9aa3f012066fbf2165e920831f7 Mon Sep 17 00:00:00 2001 From: Micah Gale Date: Fri, 13 Dec 2024 23:50:51 -0600 Subject: [PATCH 08/15] Started writing migration code comparison. --- doc/source/migrations/migrate0_1.rst | 48 ++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/doc/source/migrations/migrate0_1.rst b/doc/source/migrations/migrate0_1.rst index b0edb3f5..b9deb88c 100644 --- a/doc/source/migrations/migrate0_1.rst +++ b/doc/source/migrations/migrate0_1.rst @@ -119,3 +119,51 @@ that is immutable. 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) + + From 866b246846815ddc87088a24556727086b3a67fa Mon Sep 17 00:00:00 2001 From: Micah Gale Date: Sat, 14 Dec 2024 11:37:53 -0600 Subject: [PATCH 09/15] Completed examples of different code. --- doc/source/migrations/migrate0_1.rst | 85 +++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/doc/source/migrations/migrate0_1.rst b/doc/source/migrations/migrate0_1.rst index b9deb88c..7a466e3b 100644 --- a/doc/source/migrations/migrate0_1.rst +++ b/doc/source/migrations/migrate0_1.rst @@ -33,7 +33,7 @@ and were removed in MontePy 1.0.0. * :func:`~montepy.data_inputs.material.Material.material_components`. This is the dictionary that caused this design problem. -* ``MaterialComponents``: +* :class:`~montepy.data_inputs.material_component.MaterialComponent`: This is the class that stores information in the above dictionary. It is largely excess object wrapping that makes the material interface overly complex. @@ -166,4 +166,87 @@ Would print: 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 +is rather clunky, and a large reason 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 = Isotope("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] + + + + + + + + + + + + + + + + From f4371a0297f5c4e6f23d0e3db9855ec787d3d678 Mon Sep 17 00:00:00 2001 From: Micah Gale Date: Sun, 15 Dec 2024 14:24:06 -0600 Subject: [PATCH 10/15] Fixed typo in demo --- doc/source/migrations/migrate0_1.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/migrations/migrate0_1.rst b/doc/source/migrations/migrate0_1.rst index 7a466e3b..9e60c9a9 100644 --- a/doc/source/migrations/migrate0_1.rst +++ b/doc/source/migrations/migrate0_1.rst @@ -226,7 +226,7 @@ In MontePy 1.x .. testcode:: - target_isotope = Isotope("B-10.80c") + target_isotope = montepy.Nuclide("B-10.80c") for comp_idx, (nuc, fraction) in mat.find(target_isotope): break # update fraction From 77859bbcccbc89257c71117943971f3912ea4161 Mon Sep 17 00:00:00 2001 From: Micah Gale Date: Sun, 15 Dec 2024 14:24:35 -0600 Subject: [PATCH 11/15] Stopped raised typerror and instead just return false. --- montepy/input_parser/syntax_node.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/montepy/input_parser/syntax_node.py b/montepy/input_parser/syntax_node.py index 7d8843dd..ad238193 100644 --- a/montepy/input_parser/syntax_node.py +++ b/montepy/input_parser/syntax_node.py @@ -696,7 +696,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 @@ -1345,9 +1345,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: @@ -1736,9 +1734,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): From b728dbadbe5123e9c1121be398ebe9f03f4778c4 Mon Sep 17 00:00:00 2001 From: Micah Gale Date: Sun, 15 Dec 2024 14:26:28 -0600 Subject: [PATCH 12/15] update tests to not expect typeError. --- tests/test_syntax_parsing.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/tests/test_syntax_parsing.py b/tests/test_syntax_parsing.py index cbd80e82..adfd98a9 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) @@ -568,8 +567,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") @@ -719,8 +717,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 From 176e70aa126c8ea70ee477706f0d4eccae60f8a2 Mon Sep 17 00:00:00 2001 From: "Micah D. Gale" Date: Mon, 16 Dec 2024 14:01:00 -0600 Subject: [PATCH 13/15] Ignored nucleardata link as GH has been black listed. --- doc/source/conf.py | 2 ++ 1 file changed, 2 insertions(+) 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" From 5668e447ba59aa8555ac79eb33975932f4556975 Mon Sep 17 00:00:00 2001 From: "Travis J. Labossiere-Hickman" Date: Wed, 22 Jan 2025 13:20:39 -0700 Subject: [PATCH 14/15] Fix commas and wording --- doc/source/developing.rst | 2 +- doc/source/migrations/migrate0_1.rst | 24 ++++++++--------- doc/source/starting.rst | 40 +++++++++++++++------------- 3 files changed, 34 insertions(+), 32 deletions(-) diff --git a/doc/source/developing.rst b/doc/source/developing.rst index 8450846d..ab333a49 100644 --- a/doc/source/developing.rst +++ b/doc/source/developing.rst @@ -693,7 +693,7 @@ it should be a generator. Constants and Meta Data Structures ---------------------------------- -MontePy uses constants and data structures to utilize meta-programming, +MontePy uses constants and data structures to utilize meta-programming and remove redundant code. Typical constants can be found in :mod:`montepy.constants`. diff --git a/doc/source/migrations/migrate0_1.rst b/doc/source/migrations/migrate0_1.rst index 9e60c9a9..3a88c327 100644 --- a/doc/source/migrations/migrate0_1.rst +++ b/doc/source/migrations/migrate0_1.rst @@ -34,20 +34,20 @@ and were removed in MontePy 1.0.0. This is the dictionary that caused this design problem. * :class:`~montepy.data_inputs.material_component.MaterialComponent`: - This is the class that stores information in the above dictionary. - It is largely excess object wrapping that makes the material interface + 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.Isotope` was renamed to :class:`~montepy.data_inputs.nuclide.Nuclide`. - This is to better align with MCNP documentation, - and better reflect that the nuclear data for a nuclide can represent + 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, +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:: @@ -80,14 +80,14 @@ Searching Components ^^^^^^^^^^^^^^^^^^^^ Finding a specific ``Nuclide`` in a ``Material`` is now much easier. -First there is a :func:`~montepy.data_inputs.material.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 :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. +such as setting a minimum threshold and testing for multiple nuclides at once. Adding Nuclides ^^^^^^^^^^^^^^^ @@ -101,7 +101,7 @@ 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`, +:func:`~montepy.data_inputs.material.Material.nuclides` and :func:`~montepy.data_inputs.material.Material.values` provide the easiest interface. @@ -114,7 +114,7 @@ they may be an isomer, or event an element. 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: :class:`~montepy.data_inputs.nuclide.Nucleus`, +The actual ``Nuclide`` information was moved to a new class: :class:`~montepy.data_inputs.nuclide.Nucleus` that is immutable. 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. @@ -170,7 +170,7 @@ Adding Material Components ^^^^^^^^^^^^^^^^^^^^^^^^^^ Appending and editing the material components in a material in MontePy 0.x -is rather clunky, and a large reason for this release. +was rather clunky. That was a large part of the motivation for this release. In MontePy 0.x """""""""""""" @@ -198,8 +198,8 @@ 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. +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 """""""""""""" diff --git a/doc/source/starting.rst b/doc/source/starting.rst index 54c40cd7..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``. @@ -791,23 +791,23 @@ 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 changed significantly, -and greatly improved. +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. +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 objects, but it is good to be aware of them. -The generally idea is that ``Nuclide`` instance represents a specific set of ACE data that for a ``Nucleus``, which represents only a physical nuclide, -with a given ``Library``. +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 rather cumbersome. +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: @@ -844,7 +844,7 @@ The following are all valid ways to specify a nuclide: .. 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. + This support likely will be added soon, but probably not prior to MCNP 6.3.1 being available on RSICC. Working with Material Components @@ -869,9 +869,9 @@ This shows: (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`. +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:: @@ -902,7 +902,7 @@ For instance: nuclide = mat[0][0] mat[0] = (nuclide, 4.0) -Generally this is pretty clunky, and so +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: @@ -972,7 +972,7 @@ This precedence order is: .. note:: - MontePy currently does not support reading an ``XSDIR`` file and so will not provide information for + 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: @@ -987,16 +987,18 @@ Which library will be used for a given nuclide, material, and problem can be che Finding Materials and Nuclides ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Next, we will cover how to find if a nuclide is in a material, -if a material contains multiple nuclides, -specific nuclides in a material (e.g., transuranics), -or specific materials in a problem. +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``), +(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 From 98ff039db1c2e36bc604aa79814377df5d42ea3f Mon Sep 17 00:00:00 2001 From: "Travis J. Labossiere-Hickman" Date: Wed, 22 Jan 2025 13:20:48 -0700 Subject: [PATCH 15/15] Update changelog --- doc/source/changelog.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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`).