|
5 | 5 | from copy import deepcopy |
6 | 6 | from math import pi |
7 | 7 | import re |
| 8 | +from pathlib import Path |
8 | 9 |
|
9 | 10 | import numpy as np |
10 | 11 |
|
|
24 | 25 | """, re.VERBOSE |
25 | 26 | ) |
26 | 27 |
|
| 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 | + |
27 | 38 | _CELL1_RE = re.compile(r'\s*(\d+)\s+(\d+)([ \t0-9:#().dDeE\+-]+)\s*(.*)') |
28 | 39 | _CELL2_RE = re.compile(r'\s*(\d+)\s+like\s+(\d+)\s+but\s*(.*)') |
29 | 40 | _CELL_FILL_RE = re.compile(r'\s*(\d+)\s*(?:\((.*)\))?') |
@@ -252,22 +263,52 @@ def parse_data(section): |
252 | 263 | return data |
253 | 264 |
|
254 | 265 |
|
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. |
257 | 270 |
|
258 | 271 | Parameters |
259 | 272 | ---------- |
260 | 273 | filename : str |
261 | 274 | Path to MCNP file |
262 | 275 |
|
| 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 | +
|
263 | 305 | Returns |
264 | 306 | ------- |
265 | 307 | list of str |
266 | 308 | List containing one string for each block |
267 | 309 |
|
268 | 310 | """ |
269 | 311 | # Find beginning of cell section |
270 | | - text = open(filename, 'r').read() |
271 | 312 | m = re.search(r'^[ \t]*(\d+)[ \t]+', text, flags=re.MULTILINE) |
272 | 313 | text = text[m.start():] |
273 | 314 | return re.split('\n[ \t]*\n', text) |
@@ -331,8 +372,11 @@ def parse(filename): |
331 | 372 | Dictionary containing data-block information, including materials |
332 | 373 |
|
333 | 374 | """ |
| 375 | + # Read the text of the file and any referenced files into memory |
| 376 | + text = expand_read_cards(filename) |
| 377 | + |
334 | 378 | # Split file into main three sections (cells, surfaces, data) |
335 | | - sections = split_mcnp(filename) |
| 379 | + sections = split_mcnp(text) |
336 | 380 |
|
337 | 381 | # Sanitize lines (remove comments, continuation lines, etc.) |
338 | 382 | cell_section = sanitize(sections[0]) |
|
0 commit comments