diff --git a/src/pymcnp/files/inp/cell.py b/src/pymcnp/files/inp/cell.py index 20eb7c5..e1e5021 100644 --- a/src/pymcnp/files/inp/cell.py +++ b/src/pymcnp/files/inp/cell.py @@ -331,7 +331,8 @@ def from_mcnp(source: str): source = _parser.Preprocessor.process_inp(source) tokens = _parser.Parser( - re.split(r":|=| ", source), errors.MCNPSyntaxError(errors.MCNPSyntaxCodes.TOOFEW_CELL_OPTION) + re.split(r":|=|[()] | [()]| ", source.strip(")")), + errors.MCNPSyntaxError(errors.MCNPSyntaxCodes.TOOFEW_CELL_OPTION), ) # Processing Keyword @@ -344,7 +345,7 @@ def from_mcnp(source: str): match keyword: case Cell.CellOption.CellKeyword.IMPORTANCE: tokens.popl() - value = types.McnpInteger.from_mcnp(tokens.popr()) + value = types.McnpReal.from_mcnp(tokens.popr()) designator = types.Designator.from_mcnp(tokens.popr()) case Cell.CellOption.CellKeyword.VOLUME: @@ -432,7 +433,7 @@ def from_mcnp(source: str): elif len(entries) == 1: value = entries[0] else: - raise errors.MCNPSemanticErrors(errors.MCNPSemanticCodes.TOOLONG_CELL_OPTION) + raise errors.MCNPSyntaxError(errors.MCNPSyntaxCodes.TOOLONG_CELL_OPTION) case Cell.CellOption.CellKeyword.FILL | Cell.CellOption.CellKeyword.FILL_ANGLE: tokens.popl() @@ -441,7 +442,7 @@ def from_mcnp(source: str): if ":" in source: if len(entries) <= 6: - raise errors.MCNPSemanticErrors(errors.MCNPSemanticCodes.TOOFEW_CELL_OPTION) + raise errors.MCNPSyntaxError(errors.MCNPSyntaxCodes.TOOFEW_CELL_OPTION) value = ( (entries[0], entries[1]), @@ -457,7 +458,7 @@ def from_mcnp(source: str): elif len(entries) == 14: value = tuple(entries) else: - raise errors.MCNPSemanticErrors(errors.MCNPSemanticCodes.TOOFEW_CELL_OPTION) + raise errors.MCNPSyntaxError(errors.MCNPSyntaxCodes.TOOFEW_CELL_OPTION) case _: assert False, "Impossible" @@ -513,7 +514,7 @@ def to_arguments(self) -> dict: "keyword": self.keyword.to_mcnp(), "m": self.suffix.to_mcnp() if hasattr(self.__class__, "suffix") else None, "n": self.designator if hasattr(self.__class__, "designator") else None, - "value": self.value.to_mcnp(), + "value": self.value.to_mcnp() if hasattr(self.value, "to_mcnp") else self.value, } class Importance(CellOption): @@ -528,7 +529,7 @@ class Importance(CellOption): designator: Cell card option particle designator. """ - def __init__(self, importance: types.McnpInteger, designator: types.Designator): + def __init__(self, importance: types.McnpReal, designator: types.Designator): """ ``__init__`` initializes ``Importance``. @@ -1105,45 +1106,24 @@ def __init__(self, value: tuple, is_angle: bool = False): self.keyword: final[CellOption.CellKeyword] = Cell.CellOption.CellKeyword.FILL if isinstance(value[0], tuple): - if ( - value[0] is None - or len(value[0]) != 2 - or value[0][0] is None - or value[0][1] is None - or not (0 <= value[0][0]) - or not (0 <= value[0][1]) - or not (value[0][0] <= value[0][1]) - ): + if len(value) < 4: + raise errors.MCNPSemanticError(errors.MCNPSemanticCodes.INVALID_CELL_OPTION_VALUE) + + i, j, k, numbers = value + + if i is None or len(i) != 2 and i[1] > i[0]: raise errors.MCNPSemanticError(errors.MCNPSemanticCodes.INVALID_CELL_OPTION_VALUE) - if ( - value[1] is None - or len(value[1]) != 2 - or value[1][0] is None - or value[1][1] is None - or not (0 <= value[1][0]) - or not (0 <= value[1][1]) - or not (value[1][0] <= value[1][1]) - ): + if j is None or len(j) != 2 and j[1] > j[0]: raise errors.MCNPSemanticError(errors.MCNPSemanticCodes.INVALID_CELL_OPTION_VALUE) - if ( - value[2] is None - or len(value[2]) != 2 - or value[2][0] is None - or value[2][1] is None - or not (0 <= value[2][0]) - or not (0 <= value[2][1]) - or not (value[2][0] <= value[2][1]) - ): + if k is None or len(k) != 2 and k[1] > k[0]: raise errors.MCNPSemanticError(errors.MCNPSemanticCodes.INVALID_CELL_OPTION_VALUE) - if value[3] is None or len(value[3]) != ( - (value[0][1] - value[0][0] + 1) * (value[1][1] - value[1][0] + 1) * (value[2][1] - value[2][0] + 1) - ): + if numbers is None or len(numbers) != (i[1] - i[0] + 1) * (j[1] - j[0] + 1) * (k[1] - k[0] + 1): raise errors.MCNPSemanticError(errors.MCNPSemanticCodes.INVALID_CELL_OPTION_VALUE) - for number in value[3]: + for number in numbers: if number is None or not (0 <= number <= 99_999_999): raise errors.MCNPSemanticError(errors.MCNPSemanticCodes.INVALID_CELL_OPTION_VALUE) diff --git a/src/pymcnp/files/inp/datum.py b/src/pymcnp/files/inp/datum.py index d7de0cb..ecd1a19 100644 --- a/src/pymcnp/files/inp/datum.py +++ b/src/pymcnp/files/inp/datum.py @@ -375,7 +375,11 @@ def from_mcnp(source: str, line: types.McnpInteger = None): match mnemonic: case Datum.DatumMnemonic.VOLUME: tokens.popl() - has_no = True if tokens.peekl() == "no" else False + if tokens.peekl() == "no": + tokens.popl() + has_no = True + else: + has_no = False volumes = tuple(types.McnpReal.from_mcnp(tokens.popl()) for _ in range(0, len(tokens))) datum = Volume(volumes, has_no=has_no) @@ -391,7 +395,7 @@ def from_mcnp(source: str, line: types.McnpInteger = None): entries = tuple(types.McnpReal.from_mcnp(tokens.popl()) for _ in range(0, len(tokens))) displacement = tuple(entries[:3]) rotation = (tuple(entries[3:6]), tuple(entries[6:9]), tuple(entries[9:12])) - system = int(entires[12]) + system = int(entries[-1]) datum = Transformation(displacement, rotation, system) @@ -635,8 +639,11 @@ def from_mcnp(source: str, line: types.McnpInteger = None): tokens.popl() designator = types.Designator.from_mcnp(tokens.popl()) - match designator: - case types.Designator.NEUTRON: + if len(designator.particles) != 1: + raise errors.MCNPSyntaxError(errors.MCNPSyntaxCodes.TOOMANY_DATUM_PHYS) + + match designator.particles[0]: + case types.Designator.Particle.NEUTRON: emax = types.McnpReal.from_mcnp(tokens.popl()) emcnf = types.McnpReal.from_mcnp(tokens.popl()) iunr = types.McnpInteger.from_mcnp(tokens.popl()) @@ -658,7 +665,7 @@ def from_mcnp(source: str, line: types.McnpInteger = None): parameters = (emax, emcnf, iunr, colif, cutn, ngam, i_int_model, i_els_model) - case types.Designator.PHOTON: + case types.Designator.Particle.PHOTON: emcpf = types.McnpReal.from_mcnp(tokens.popl()) ides = types.McnpInteger.from_mcnp(tokens.popl()) nocoh = types.McnpInteger.from_mcnp(tokens.popl()) @@ -670,7 +677,7 @@ def from_mcnp(source: str, line: types.McnpInteger = None): parameters = (emcpf, ides, nocoh, ispn, nodop, fism) - case types.Designator.ELECTRON: + case types.Designator.Particle.ELECTRON: emax = types.McnpReal.from_mcnp(tokens.popl()) ides = types.McnpInteger.from_mcnp(tokens.popl()) ibad = types.McnpInteger.from_mcnp(tokens.popl()) @@ -705,7 +712,7 @@ def from_mcnp(source: str, line: types.McnpInteger = None): ckvnum, ) - case types.Designator.PROTON: + case types.Designator.Particle.PROTON: emax = types.McnpReal.from_mcnp(tokens.popl()) ean = types.McnpReal.from_mcnp(tokens.popl()) tabl = types.McnpReal.from_mcnp(tokens.popl()) @@ -906,7 +913,7 @@ def from_mcnp(source: str, line: types.McnpInteger = None): datum = SourceDefinition(pairs) case _: - datum = _Placeholder(tokens.popl(), [tokens.popl() for _ in range(0, len(tokens))]) + datum = _Placeholder(mnemonic, [tokens.popl() for _ in range(0, len(tokens))]) if tokens: raise errors.MCNPSyntaxError(errors.MCNPSyntaxCodes.TOOLONG_DATUM) @@ -6258,13 +6265,13 @@ def __init__(self, designator: types.Designator, parameters: tuple[any]): raise errors.MCNPSemanticError(errors.MCNPSemanticCodes.INVALID_DATUM_PARAMETERS) match designator: - case types.Designator.NEUTRON: + case types.Designator.Particle.NEUTRON: obj = ParticlePhysicsOptionsNeutron(*parameters) - case types.Designator.PHOTON: + case types.Designator.Particle.PHOTON: obj = ParticlePhysicsOptionsPhoton(*parameters) - case types.Designator.ELECTRON: + case types.Designator.Particle.ELECTRON: obj = ParticlePhysicsOptionsElectron(*parameters) - case types.Designator.PROTON: + case types.Designator.Particle.PROTON: obj = ParticlePhysicsOptionsPhoton(*parameters) case _: obj = ParticlePhysicsOptionsOther(designator, *parameters) @@ -6350,7 +6357,7 @@ def __init__( self.id: final[str] = f"phys:n" self.mnemonic = Datum.DatumMnemonic.PARTICLE_PHYSICS_OPTIONS self.parameters = (emax, emcnf, iunr, colif, cutn, ngam, i_int_model, i_els_model) - self.designator = types.Designator.NEUTRON + self.designator = types.Designator.Particle.NEUTRON self.emax = emax self.emcnf = emcnf @@ -6425,7 +6432,7 @@ def __init__( self.id: final[str] = f"phys:p" self.mnemonic = Datum.DatumMnemonic.PARTICLE_PHYSICS_OPTIONS self.parameters = (emcpf, ides, nocoh, ispn, nodop, fism) - self.designator = types.Designator.PHOTON + self.designator = types.Designator.Particle.PHOTON self.emcpf = emcpf self.ides = ides @@ -6557,7 +6564,7 @@ def __init__( electron_method_boundary, ckvnum, ) - self.designator = types.Designator.ELECTRON + self.designator = types.Designator.Particle.ELECTRON self.emax = emax self.ides = ides @@ -6668,7 +6675,7 @@ def __init__( self.id: final[str] = f"phys:h" self.mnemonic = Datum.DatumMnemonic.PARTICLE_PHYSICS_OPTIONS self.parameters = (emax, ean, tabl, istrg, recl, i_mcs_model, i_int_model, i_els_model, efac, ckvnum, drp) - self.designator = types.Designator.PROTON + self.designator = types.Designator.Particle.PROTON self.emax = emax self.ean = ean diff --git a/src/pymcnp/files/utils/_parser.py b/src/pymcnp/files/utils/_parser.py index a0e160f..3ac5e6b 100644 --- a/src/pymcnp/files/utils/_parser.py +++ b/src/pymcnp/files/utils/_parser.py @@ -158,8 +158,20 @@ class Preprocessor: @staticmethod def _process_jump(string: str) -> str: - for match in re.finditer(r"\s(\d+)j\s", string): - string = string[: match.start(0)] + " j " * int(match[1]) + string[match.end(0) :] + for match in re.finditer(r"(\s)(\d+)j(\s)", string): + string = string[: match.start(0)] + match[1] + f" j" * int(match[2]) + match[3] + string[match.end(0) :] + + return string + + @staticmethod + def _process_repeat(string: str) -> str: + for match in re.finditer(r"\s(\S+)\s(\d*)r(\s)", string): + string = ( + string[: match.start(0)] + + f" {match[1]}" * (int(match[2] if match[2] else 1) + 1) + + match[3] + + string[match.end(0) :] + ) return string @@ -308,6 +320,7 @@ def process_inp(string: str, hasComments=True, hasColumnarData=True) -> str: string = Preprocessor._process_case(string) string = Preprocessor._process_tabs(string) string = Preprocessor._process_jump(string) + string = Preprocessor._process_repeat(string) string = Preprocessor._process_continuation(string) if hasColumnarData: diff --git a/src/pymcnp/files/utils/types.py b/src/pymcnp/files/utils/types.py index bdf5dfd..9289b3c 100644 --- a/src/pymcnp/files/utils/types.py +++ b/src/pymcnp/files/utils/types.py @@ -351,6 +351,15 @@ def __ge__(a, b: McnpInteger | int): def __ne__(a, b: McnpInteger | int): return a.value != b.value if isinstance(b, McnpInteger) else a.value != b + def __add__(a, b: McnpInteger | float): + return McnpInteger(a.value + b.value) if isinstance(b, McnpInteger) else McnpInteger(a.value + b) + + def __sub__(a, b: McnpInteger | float): + return McnpInteger(a.value - b.value) if isinstance(b, McnpInteger) else McnpInteger(a.value - b) + + def __mul__(a, b: McnpInteger | float): + return McnpInteger(a.value * b.value) if isinstance(b, McnpInteger) else McnpInteger(a.value * b) + class McnpReal: """ @@ -440,3 +449,12 @@ def __ge__(a, b: McnpReal | float): def __ne__(a, b: McnpReal | float): return a.value != b.value if isinstance(b, McnpReal) else a.value != b + + def __add__(a, b: McnpReal | float): + return McnpReal(a.value + b.value) if isinstance(b, McnpReal) else McnpReal(a.value + b) + + def __sub__(a, b: McnpReal | float): + return McnpReal(a.value - b.value) if isinstance(b, McnpReal) else McnpReal(a.value - b) + + def __mul__(a, b: Mcnpreal | float): + return McnpReal(a.value * b.value) if isinstance(b, McnpReal) else McnpReal(a.value * b) diff --git a/tests/test_new.py b/tests/test_new.py index 42c93b5..8920f56 100644 --- a/tests/test_new.py +++ b/tests/test_new.py @@ -189,7 +189,7 @@ class Test_CellOption: VALID_EXAMPLES = [ ( pymcnp.inp.Cell.CellOption.CellKeyword("imp"), - pymcnp.utils.types.McnpInteger(0), + pymcnp.utils.types.McnpReal(0.5), None, pymcnp.utils.types.Designator(("n", "p")), ),