Skip to content

Commit fc1ceb3

Browse files
tjlabosspaulromano
andauthored
Support READ cards (#30)
Co-authored-by: Paul Romano <[email protected]>
1 parent c7b9bc5 commit fc1ceb3

File tree

6 files changed

+97
-4
lines changed

6 files changed

+97
-4
lines changed

src/openmc_mcnp_adapter/parse.py

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from copy import deepcopy
66
from math import pi
77
import re
8+
from pathlib import Path
89

910
import numpy as np
1011

@@ -24,6 +25,16 @@
2425
""", re.VERBOSE
2526
)
2627

28+
_READ_RE = re.compile(r"""
29+
^ # Beginning of line
30+
\s*read # Keyword
31+
\s.*?file # Everything up to filename
32+
\s*=\s* # = sign (required) with optional spaces
33+
(\S+) # The file name is anything without whitespace
34+
.* # Anything else until end-of-line
35+
""", re.IGNORECASE | re.VERBOSE | re.MULTILINE
36+
)
37+
2738
_CELL1_RE = re.compile(r'\s*(\d+)\s+(\d+)([ \t0-9:#().dDeE\+-]+)\s*(.*)')
2839
_CELL2_RE = re.compile(r'\s*(\d+)\s+like\s+(\d+)\s+but\s*(.*)')
2940
_CELL_FILL_RE = re.compile(r'\s*(\d+)\s*(?:\((.*)\))?')
@@ -252,22 +263,52 @@ def parse_data(section):
252263
return data
253264

254265

255-
def split_mcnp(filename):
256-
"""Split MCNP file into three strings, one for each block
266+
def expand_read_cards(filename) -> str:
267+
"""Recursively read the MCNP input file and files referenced by READ cards
268+
269+
READ card keywords other than FILE are ignored.
257270
258271
Parameters
259272
----------
260273
filename : str
261274
Path to MCNP file
262275
276+
Returns
277+
-------
278+
str
279+
Text of the MCNP input file
280+
281+
"""
282+
path = Path(filename).resolve()
283+
text = path.read_text()
284+
for match in _READ_RE.finditer(text):
285+
card = match[0].strip()
286+
# If the requested path is absolute, use it directly
287+
requested = Path(match[1])
288+
target = requested if requested.is_absolute() else path.parent / requested
289+
if not target.is_file():
290+
errstr = f"In card {repr(card)}, failed to find: {target}"
291+
raise FileNotFoundError(errstr)
292+
subtext = expand_read_cards(target)
293+
text = text.replace(card, subtext)
294+
return text
295+
296+
297+
def split_mcnp(text):
298+
"""Split MCNP file into three strings, one for each block
299+
300+
Parameters
301+
----------
302+
text : str
303+
Text of the MCNP input file
304+
263305
Returns
264306
-------
265307
list of str
266308
List containing one string for each block
267309
268310
"""
269311
# Find beginning of cell section
270-
text = open(filename, 'r').read()
271312
m = re.search(r'^[ \t]*(\d+)[ \t]+', text, flags=re.MULTILINE)
272313
text = text[m.start():]
273314
return re.split('\n[ \t]*\n', text)
@@ -331,8 +372,11 @@ def parse(filename):
331372
Dictionary containing data-block information, including materials
332373
333374
"""
375+
# Read the text of the file and any referenced files into memory
376+
text = expand_read_cards(filename)
377+
334378
# Split file into main three sections (cells, surfaces, data)
335-
sections = split_mcnp(filename)
379+
sections = split_mcnp(text)
336380

337381
# Sanitize lines (remove comments, continuation lines, etc.)
338382
cell_section = sanitize(sections[0])

tests/inputs/testRead.imcnp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Testing read card
2+
C this is a comment
3+
read echo file=testReadTarget.imcnp encode
4+
5+
1 so 0.5
6+
7+
mode n
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
2 0 +1 $ lowest level
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Testing read card
2+
C this is a comment
3+
1 0 -1
4+
2 0 +1 $ lowest level
5+
c
6+
7+
1 so 0.5
8+
9+
mode n

tests/inputs/testReadTarget.imcnp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
1 0 -1
2+
read file=testReadRecursive.imcnp
3+
c

tests/test_read_file.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
from pathlib import Path
2+
import textwrap
3+
import pytest
4+
5+
from openmc_mcnp_adapter import mcnp_str_to_model, mcnp_to_model
6+
from openmc_mcnp_adapter.parse import expand_read_cards
7+
8+
9+
INPUT_DIR = Path(__file__).with_name("inputs")
10+
11+
12+
def test_read_not_found():
13+
deck = textwrap.dedent("""
14+
title
15+
c The next line points to an invalid file
16+
read file=/badfile.path
17+
""")
18+
with pytest.raises(FileNotFoundError):
19+
mcnp_str_to_model(deck)
20+
21+
22+
def test_read_recursive():
23+
reference = expand_read_cards(INPUT_DIR / "testReadReference.imcnp")
24+
trial = expand_read_cards(INPUT_DIR / "testRead.imcnp")
25+
assert trial == reference
26+
27+
28+
def test_recursive_mcnp_to_model():
29+
mcnp_to_model(INPUT_DIR / "testRead.imcnp")

0 commit comments

Comments
 (0)