Skip to content

Commit

Permalink
Merge branch 'develop' into 206-sly-syntax-error-for-numbers-in-read-…
Browse files Browse the repository at this point in the history
…cards
  • Loading branch information
MicahGale authored Apr 15, 2024
2 parents b41f598 + 2e52934 commit 97e8172
Show file tree
Hide file tree
Showing 6 changed files with 101 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
38 changes: 37 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 Expand Up @@ -116,6 +137,21 @@ def cells(self):
if cell.material == self:
yield cell

def format_for_mcnp_input(self, mcnp_version):
"""
Creates a string representation of this MCNP_Object that can be
written to file.
:param mcnp_version: The tuple for the MCNP version that must be exported to.
:type mcnp_version: tuple
:return: a list of strings for the lines that this input will occupy.
:rtype: list
"""
lines = super().format_for_mcnp_input(mcnp_version)
if self.thermal_scattering is not None:
lines += self.thermal_scattering.format_for_mcnp_input(mcnp_version)
return lines

def add_thermal_scattering(self, law):
"""
Adds thermal scattering law to the material
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
4 changes: 4 additions & 0 deletions tests/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,10 @@ def test_write_to_file(self):
for i, data in enumerate(self.simple_problem.data_inputs):
if isinstance(data, material.Material):
self.assertEqual(data.number, test_problem.data_inputs[i].number)
if data.thermal_scattering is not None:
assert (
test_problem.data_inputs[i].thermal_scattering is not None
)
elif isinstance(data, volume.Volume):
self.assertEqual(str(data), str(test_problem.data_inputs[i]))
else:
Expand Down
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 97e8172

Please sign in to comment.