Skip to content

Commit

Permalink
Fix(parser): Fixed parsing materials with implicit library.
Browse files Browse the repository at this point in the history
Fix bug that can't parse materials with implicit library specification.
  • Loading branch information
MicahGale authored Apr 15, 2024
2 parents 872662f + 5c57061 commit 2e52934
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 13 deletions.
22 changes: 12 additions & 10 deletions montepy/data_inputs/isotope.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,22 @@ class Isotope:

def __init__(self, ZAID="", node=None):
if node is not None and isinstance(node, ValueNode):
if node.type == float:
node = ValueNode(node.token, str, node.padding)
self._tree = node
ZAID = node.value
if "." in ZAID:
parts = ZAID.split(".")
try:
assert len(parts) == 2
int(parts[0])
except (AssertionError, ValueError) as e:
raise ValueError(f"ZAID: {ZAID} could not be parsed as a valid isotope")
self._ZAID = parts[0]
self.__parse_zaid()
parts = ZAID.split(".")
try:
assert len(parts) <= 2
int(parts[0])
except (AssertionError, ValueError) as e:
raise ValueError(f"ZAID: {ZAID} could not be parsed as a valid isotope")
self._ZAID = parts[0]
self.__parse_zaid()
if len(parts) == 2:
self._library = parts[1]
else:
raise ValueError(f"ZAID: {ZAID} could not be parsed as a valid isotope")
self._library = ""

def __parse_zaid(self):
"""
Expand Down
23 changes: 22 additions & 1 deletion montepy/data_inputs/material.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
from montepy.data_inputs import data_input, thermal_scattering
from montepy.data_inputs.isotope import Isotope
from montepy.data_inputs.material_component import MaterialComponent
from montepy.input_parser import syntax_node
from montepy.input_parser.material_parser import MaterialParser
from montepy import mcnp_object
from montepy.numbered_mcnp_object import Numbered_MCNP_Object
from montepy.errors import *
Expand All @@ -26,6 +28,8 @@ class Material(data_input.DataInputAbstract, Numbered_MCNP_Object):
:type input: Input
"""

_parser = MaterialParser()

def __init__(self, input=None):
self._material_components = {}
self._thermal_scattering = None
Expand All @@ -37,7 +41,24 @@ def __init__(self, input=None):
self._number = num
set_atom_frac = False
isotope_fractions = self._tree["data"]
for isotope_node, fraction in isotope_fractions:
if isinstance(isotope_fractions, syntax_node.ListNode):
# in python 3.12 this can be replaced with itertools.batched
def batch_gen():
it = iter(isotope_fractions)
while batch := tuple(itertools.islice(it, 2)):
yield batch

iterator = batch_gen()
elif isinstance(isotope_fractions, syntax_node.IsotopesNode):
iterator = iter(isotope_fractions)
else: # pragma: no cover
# this is a fall through error, that should never be raised,
# but is here just in case
raise MalformedInputError(
input,
f"Material definitions for material: {self.number} is not valid.",
)
for isotope_node, fraction in iterator:
isotope = Isotope(node=isotope_node)
fraction.is_negatable_float = True
if not set_atom_frac:
Expand Down
1 change: 1 addition & 0 deletions montepy/input_parser/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from . import cell_parser
from . import data_parser
from . import input_reader
from . import material_parser
from . import mcnp_input
from . import parser_base
from . import read_parser
Expand Down
31 changes: 31 additions & 0 deletions montepy/input_parser/material_parser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Copyright 2024, Battelle Energy Alliance, LLC All Rights Reserved.
from montepy.input_parser.data_parser import DataParser
from montepy.input_parser import syntax_node


class MaterialParser(DataParser):
debugfile = None

@_(
"introduction isotopes",
"introduction isotopes parameters",
)
def material(self, p):
ret = {}
for key, node in p.introduction.nodes.items():
ret[key] = node
ret["data"] = p.isotopes
if hasattr(p, "parameters"):
ret["parameters"] = p.parameters
return syntax_node.SyntaxNode("data", ret)

@_("isotope_fractions", "number_sequence", "isotope_hybrid_fractions")
def isotopes(self, p):
return p[0]

@_("number_sequence isotope_fraction", "isotope_hybrid_fractions isotope_fraction")
def isotope_hybrid_fractions(self, p):
ret = p[0]
for node in p.isotope_fraction[1:]:
ret.append(node)
return ret
18 changes: 16 additions & 2 deletions tests/test_material.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,22 @@ def test_material_init(self):
for component in material.material_components:
self.assertEqual(material.material_components[component].fraction, 0.5)

# test implicit library with syntax tree errors
in_str = """m1 1001 0.33
8016 0.666667"""
input_card = Input(in_str.split("\n"), BlockType.DATA)
material = Material(input_card)
# test implicit library
in_str = "M20 1001 0.5 2001 0.5 8016.710nc 0.5"
input_card = Input([in_str], BlockType.DATA)
material = Material(input_card)
self.assertEqual(material.number, 20)
self.assertEqual(material.old_number, 20)
self.assertTrue(material.is_atom_fraction)
for component in material.material_components:
self.assertEqual(material.material_components[component].fraction, 0.5)

# test weight fraction
in_str = "M20 1001.80c -0.5 8016.80c -0.5"
input_card = Input([in_str], BlockType.DATA)
material = Material(input_card)
Expand Down Expand Up @@ -164,8 +180,6 @@ def test_isotope_init(self):
Isotope("1001.80c.5")
with self.assertRaises(ValueError):
Isotope("hi.80c")
with self.assertRaises(ValueError):
Isotope("1001")

def test_isotope_metastable_init(self):
isotope = Isotope("13426.02c")
Expand Down

0 comments on commit 2e52934

Please sign in to comment.