pymcnp 0.1.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- demo/main.py +24 -0
- mcnptools/geometryGUI.py +56 -0
- mcnptools/mcnprun.py +187 -0
- pymcnp/__init__.py +22 -0
- pymcnp/cli/__init__.py +7 -0
- pymcnp/cli/_io.py +41 -0
- pymcnp/cli/_state.py +131 -0
- pymcnp/cli/file.py +49 -0
- pymcnp/cli/ls.py +161 -0
- pymcnp/cli/run.py +228 -0
- pymcnp/files/inp/__init__.py +553 -0
- pymcnp/files/inp/_cadquery.py +321 -0
- pymcnp/files/inp/block.py +71 -0
- pymcnp/files/inp/card.py +31 -0
- pymcnp/files/inp/cell.py +1619 -0
- pymcnp/files/inp/cells.py +82 -0
- pymcnp/files/inp/comment.py +82 -0
- pymcnp/files/inp/data.py +91 -0
- pymcnp/files/inp/datum.py +9984 -0
- pymcnp/files/inp/inp.py +207 -0
- pymcnp/files/inp/surface.py +5437 -0
- pymcnp/files/inp/surfaces.py +124 -0
- pymcnp/files/outp/__init__.py +5 -0
- pymcnp/files/outp/output.py +428 -0
- pymcnp/files/ptrac/__init__.py +11 -0
- pymcnp/files/ptrac/event.py +945 -0
- pymcnp/files/ptrac/header.py +375 -0
- pymcnp/files/ptrac/history.py +265 -0
- pymcnp/files/ptrac/ptrac.py +99 -0
- pymcnp/files/utils/__init__.py +0 -0
- pymcnp/files/utils/_parser.py +401 -0
- pymcnp/files/utils/errors.py +454 -0
- pymcnp/files/utils/types.py +493 -0
- pymcnp/main.py +75 -0
- pymcnp/version.py +16 -0
- pymcnp-0.1.2.dist-info/LICENSE +45 -0
- pymcnp-0.1.2.dist-info/METADATA +122 -0
- pymcnp-0.1.2.dist-info/RECORD +41 -0
- pymcnp-0.1.2.dist-info/WHEEL +5 -0
- pymcnp-0.1.2.dist-info/entry_points.txt +3 -0
- pymcnp-0.1.2.dist-info/top_level.txt +3 -0
demo/main.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
|
|
3
|
+
import docopt
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
DEMO_DOCOPT = """
|
|
7
|
+
Usage:
|
|
8
|
+
demo <inp>
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def main():
|
|
13
|
+
args = docopt.docopt(DEMO_DOCOPT)
|
|
14
|
+
|
|
15
|
+
try:
|
|
16
|
+
open(args['<inp>'])
|
|
17
|
+
print(f"[DEMO] Args: {' '.join(sys.argv)}")
|
|
18
|
+
except FileNotFoundError:
|
|
19
|
+
print('[DEMO] Input file not found.')
|
|
20
|
+
exit(1)
|
|
21
|
+
|
|
22
|
+
file = open('.' + ''.join(args['<inp>'].split('.')[:-1]) + '.outp', 'x')
|
|
23
|
+
file.write('MCNP Output! :)')
|
|
24
|
+
file.close()
|
mcnptools/geometryGUI.py
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""
|
|
2
|
+
GUI program to look at geometry
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import matplotlib.pyplot as plt
|
|
6
|
+
from mcnptools import build_geometry as bg
|
|
7
|
+
|
|
8
|
+
plt.rc('font', size=14)
|
|
9
|
+
plt.style.use('seaborn-v0_8-darkgrid')
|
|
10
|
+
fig = plt.figure(constrained_layout=True, figsize=(16, 8))
|
|
11
|
+
gs = fig.add_gridspec(1, 2, width_ratios=[0.7, 0.3], height_ratios=[1])
|
|
12
|
+
ax_3d = fig.add_subplot(gs[0, 0], projection='3d')
|
|
13
|
+
ax_menu = fig.add_subplot(gs[0, 1])
|
|
14
|
+
ax_menu.set_xticks([])
|
|
15
|
+
ax_menu.set_yticks([])
|
|
16
|
+
|
|
17
|
+
# MCNP file
|
|
18
|
+
file_path = 'test_output_files/geom_gui.i'
|
|
19
|
+
|
|
20
|
+
soil = bg.Geometry(
|
|
21
|
+
color='blue',
|
|
22
|
+
name='Soil',
|
|
23
|
+
h_menu=0,
|
|
24
|
+
fig=fig,
|
|
25
|
+
ax_3d=ax_3d,
|
|
26
|
+
ax_menu=ax_menu,
|
|
27
|
+
soil=True,
|
|
28
|
+
)
|
|
29
|
+
soil.make_object(x0=0, y0=0, z0=-200, height=150, radius=200, axis='z')
|
|
30
|
+
|
|
31
|
+
png = bg.Geometry(
|
|
32
|
+
color='green', name='PNG (TR1)', h_menu=0.89, fig=fig, ax_3d=ax_3d, ax_menu=ax_menu
|
|
33
|
+
)
|
|
34
|
+
png.make_object(x0=0, y0=-30, z0=0, height=30, radius=10, axis='y')
|
|
35
|
+
|
|
36
|
+
rover = bg.Geometry(
|
|
37
|
+
color='black',
|
|
38
|
+
name='Rover (TR2)',
|
|
39
|
+
h_menu=0.65,
|
|
40
|
+
fig=fig,
|
|
41
|
+
ax_3d=ax_3d,
|
|
42
|
+
ax_menu=ax_menu,
|
|
43
|
+
)
|
|
44
|
+
rover.make_object(x0=30, y0=-50, z0=0, height=100, radius=12, axis='y')
|
|
45
|
+
|
|
46
|
+
detector = bg.Geometry(
|
|
47
|
+
color='red',
|
|
48
|
+
name='Detector (TR3)',
|
|
49
|
+
h_menu=0.42,
|
|
50
|
+
fig=fig,
|
|
51
|
+
ax_3d=ax_3d,
|
|
52
|
+
ax_menu=ax_menu,
|
|
53
|
+
)
|
|
54
|
+
detector.make_object(x0=60, y0=0, z0=0, height=-10, radius=5, axis='z')
|
|
55
|
+
|
|
56
|
+
gui = bg.Transform(file_path, [soil, png, rover, detector])
|
mcnptools/mcnprun.py
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Run MCNP through Python using the package subprocess.
|
|
3
|
+
Code modifed from https://gist.github.com/abnowack
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
import subprocess
|
|
8
|
+
import shutil
|
|
9
|
+
import os
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def set_mcnp_environment(DATAPATH, ISCDATA, MCNPPATH, force=False):
|
|
14
|
+
if force or 'DATAPATH' not in os.environ:
|
|
15
|
+
os.environ['DATAPATH'] = DATAPATH
|
|
16
|
+
|
|
17
|
+
if force or 'ISCDATA' not in os.environ:
|
|
18
|
+
os.environ['ISCDATA'] = ISCDATA
|
|
19
|
+
|
|
20
|
+
if force or 'MCNPPATH' not in os.environ:
|
|
21
|
+
os.environ['MCNPPATH'] = MCNPPATH
|
|
22
|
+
os.environ['PATH'] += os.pathsep + str(os.environ['MCNPPATH'])
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def create_directory(directory):
|
|
26
|
+
"""
|
|
27
|
+
If directory already exists, append 1 to the name and create a new one.
|
|
28
|
+
If directory does not exist, create it.
|
|
29
|
+
|
|
30
|
+
Parameters:
|
|
31
|
+
directory (Path object): Directory path to check/create.
|
|
32
|
+
"""
|
|
33
|
+
if directory.exists():
|
|
34
|
+
print(f"Directory '{directory}' already exists.")
|
|
35
|
+
new_name = directory.name + f'-{np.random.randint(0, 999)}'
|
|
36
|
+
new_dir = directory.parent / new_name
|
|
37
|
+
new_dir.mkdir()
|
|
38
|
+
print(f"Directory '{new_dir}' created successfully.")
|
|
39
|
+
else:
|
|
40
|
+
new_dir = directory
|
|
41
|
+
new_dir.mkdir()
|
|
42
|
+
print(f"Directory '{new_dir}' created successfully.")
|
|
43
|
+
return new_dir
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def clean_directory(clean_dir):
|
|
47
|
+
shutil.rmtree(clean_dir)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
DATAPATH = r'C:\MCNP62\MCNP_DATA'
|
|
51
|
+
ISCDATA = r'C:\MCNP62\MCNP_CODE\MCNP620\Utilities\ISC\data'
|
|
52
|
+
MCNPPATH = r'C:\MCNP62\MCNP_CODE\bin'
|
|
53
|
+
|
|
54
|
+
set_mcnp_environment(DATAPATH, ISCDATA, MCNPPATH)
|
|
55
|
+
|
|
56
|
+
input_file = 'C:/Users/mayll/Documents/MCNP-tools/examples/Data/proton-dist.i'
|
|
57
|
+
# test_dir = "C:/Users/mayll/Documents/MCNP-tools/test-delete"
|
|
58
|
+
|
|
59
|
+
# args = f"i={input_file} o=testout.o"
|
|
60
|
+
|
|
61
|
+
# run = subprocess.run("mcnp6.exe " + args, shell=True, cwd=test_dir, capture_output=True)
|
|
62
|
+
# print(run)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def run_mcnp(input_file, out_dir=None, out_name=None, cores=1, clean=False):
|
|
66
|
+
"""
|
|
67
|
+
Python interface for running MCNP
|
|
68
|
+
|
|
69
|
+
Parameters
|
|
70
|
+
----------
|
|
71
|
+
input_file : string
|
|
72
|
+
Input file full path.
|
|
73
|
+
out_dir : string, optional.
|
|
74
|
+
Directory where output files will be saved. The default is None
|
|
75
|
+
(will be saved to the same directory as the input file)
|
|
76
|
+
out_name : string, optional.
|
|
77
|
+
Output file name. The default is None
|
|
78
|
+
(will be saved with the same name as the input file)
|
|
79
|
+
cores : int, optional
|
|
80
|
+
Number of threads used (not available for all particle types). The default is 1.
|
|
81
|
+
clean : bool, optional
|
|
82
|
+
Delete secondary output files. The default is False.
|
|
83
|
+
|
|
84
|
+
Returns
|
|
85
|
+
-------
|
|
86
|
+
Dictionary with information about the run.
|
|
87
|
+
"""
|
|
88
|
+
input_file = Path(input_file)
|
|
89
|
+
if out_dir is None:
|
|
90
|
+
out_dir = input_file.parent / 'test-folder'
|
|
91
|
+
new_out_dir = create_directory(out_dir)
|
|
92
|
+
else:
|
|
93
|
+
new_out_dir = Path(out_dir)
|
|
94
|
+
if out_name is None:
|
|
95
|
+
new_name = input_file.name
|
|
96
|
+
else:
|
|
97
|
+
new_name = out_name
|
|
98
|
+
if cores <= 2:
|
|
99
|
+
args = f'i={input_file} o={new_name}.o'
|
|
100
|
+
else:
|
|
101
|
+
args = f'i={input_file} o={new_name}.o tasks {cores}'
|
|
102
|
+
|
|
103
|
+
args = f'i={input_file} o={new_name}.o'
|
|
104
|
+
run = subprocess.run('mcnp6.exe ' + args, shell=True, cwd=new_out_dir, capture_output=True)
|
|
105
|
+
return run
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
out_dir = 'C:/Users/mayll/Documents/MCNP-tools/examples/Data/test-folder'
|
|
109
|
+
run = run_mcnp(input_file=input_file)
|
|
110
|
+
|
|
111
|
+
# @contextmanager
|
|
112
|
+
# def run_mcnp(card, extra_args=None, params=None, cores=1, clean=True):
|
|
113
|
+
# """ Python interface for running MCNP programs.
|
|
114
|
+
# Parameters
|
|
115
|
+
# ----------
|
|
116
|
+
# card : str
|
|
117
|
+
# MCNP input card, can contain variable expressions using str.format(params)
|
|
118
|
+
# extra_args: dict
|
|
119
|
+
# Dictionary of additional arguments for MCNP, eg `mcnp $KEY=$VALUE`
|
|
120
|
+
# params : dict, optional
|
|
121
|
+
# Values to apply on MCNP input card
|
|
122
|
+
# cores : int
|
|
123
|
+
# Number of CPU cores for MCNP to run on
|
|
124
|
+
# clean : bool
|
|
125
|
+
# Clean the temporary output directory
|
|
126
|
+
# Returns
|
|
127
|
+
# -------
|
|
128
|
+
# run : subprocess.CompletedProcess
|
|
129
|
+
# Contains successful run information
|
|
130
|
+
# output_dir : file directory
|
|
131
|
+
# Temporary output directory containing MCNP results
|
|
132
|
+
# """
|
|
133
|
+
# if params:
|
|
134
|
+
# card = card.format(**params)
|
|
135
|
+
|
|
136
|
+
# args = []
|
|
137
|
+
# if extra_args:
|
|
138
|
+
# for (arg, val) in extra_args:
|
|
139
|
+
# args.append('{}={}'.format(arg, val))
|
|
140
|
+
|
|
141
|
+
# args.append('tasks {}'.format(cores))
|
|
142
|
+
|
|
143
|
+
# # create temp folder
|
|
144
|
+
# output_dir = tempfile.mkdtemp()
|
|
145
|
+
# with open(output_dir + '\\input.i', 'w') as f:
|
|
146
|
+
# f.write(card)
|
|
147
|
+
|
|
148
|
+
# args.append('i=input.i')
|
|
149
|
+
|
|
150
|
+
# # mcnp doesn't use errorcodes or stderr, so Popen doesnt add features
|
|
151
|
+
# # stick with simpler check_output and parse stdout
|
|
152
|
+
# run = subprocess.run(['mcnp6.exe'] + args, shell=True, cwd=output_dir, capture_output=True)
|
|
153
|
+
|
|
154
|
+
# # check for errors in stdout
|
|
155
|
+
# stdout_str = str(run.stdout)
|
|
156
|
+
# if 'bad trouble' in stdout_str or 'fatal error' in stdout_str:
|
|
157
|
+
# print('Error in MCNP outout')
|
|
158
|
+
# print(run.args)
|
|
159
|
+
# print(run.stdout)
|
|
160
|
+
# status = False
|
|
161
|
+
# else:
|
|
162
|
+
# status = True
|
|
163
|
+
|
|
164
|
+
# try:
|
|
165
|
+
# yield (run, output_dir)
|
|
166
|
+
# finally:
|
|
167
|
+
# if clean:
|
|
168
|
+
# print(output_dir)
|
|
169
|
+
# clean_directory(output_dir)
|
|
170
|
+
|
|
171
|
+
# if __name__ == '__main__':
|
|
172
|
+
# DATAPATH=r'C:\MCNP62\MCNP_DATA'
|
|
173
|
+
# ISCDATA=r'C:\MCNP62\MCNP_CODE\MCNP620\Utilities\ISC\data'
|
|
174
|
+
# MCNPPATH=r'C:\MCNP62\MCNP_CODE\bin'
|
|
175
|
+
|
|
176
|
+
# set_mcnp_environment(DATAPATH, ISCDATA, MCNPPATH)
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
# input_card = \
|
|
180
|
+
# r"""PUT YOUR MCNP INPUT CARD HERE
|
|
181
|
+
# IT CAN HAVE {} for formatting the card with values filled in by params arg in run_mcnp
|
|
182
|
+
# """
|
|
183
|
+
|
|
184
|
+
# # use run_mcnp in the following way as a context manager
|
|
185
|
+
# with run_mcnp(input_card, cores=4, clean=False) as (run, out_dir):
|
|
186
|
+
# print(run.stdout)
|
|
187
|
+
# print(out_dir)
|
pymcnp/__init__.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from . import cli
|
|
2
|
+
from .files import inp
|
|
3
|
+
from .files import outp
|
|
4
|
+
from .files import ptrac
|
|
5
|
+
from .files import utils
|
|
6
|
+
from .files.inp import Inp
|
|
7
|
+
from .files.outp import ReadOutput
|
|
8
|
+
from .files.ptrac import Ptrac
|
|
9
|
+
|
|
10
|
+
from .version import __version__
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"cli",
|
|
14
|
+
"inp",
|
|
15
|
+
"outp",
|
|
16
|
+
"ptrac",
|
|
17
|
+
"utils",
|
|
18
|
+
"Inp",
|
|
19
|
+
"ReadOutput",
|
|
20
|
+
"Ptrac",
|
|
21
|
+
"__version__",
|
|
22
|
+
]
|
pymcnp/cli/__init__.py
ADDED
pymcnp/cli/_io.py
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""
|
|
2
|
+
'_utils'
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import datetime
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
ERROR_INSUFFICENT_ARGS = '\x1b[1mpymcnp: \x1b[31mERROR:\x1b[0m Insufficent Arguments.'
|
|
9
|
+
ERROR_EXCESSIVE_ARGS = '\x1b[1mpymcnp: \x1b[31mERROR:\x1b[0m Excesive Arguments.'
|
|
10
|
+
ERROR_UNRECOGNIZED_ARGS = '\x1b[1mpymcnp: \x1b[31mERROR:\x1b[0m Unrecognized Arguments.'
|
|
11
|
+
ERROR_UNRECOGNIZED_OPTION = '\x1b[1mpymcnp: \x1b[31mERROR:\x1b[0m Unrecognized Option.'
|
|
12
|
+
ERROR_ALIAS_NOT_FOUND = '\x1b[1mpymcnp: \x1b[31mERROR:\x1b[0m INP Alias Not Found.'
|
|
13
|
+
ERROR_FILE_NOT_FOUND = '\x1b[1mpymcnp: \x1b[31mERROR:\x1b[0m File Not Found.'
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def ERROR_INP_VALUE(msg: str) -> str:
|
|
17
|
+
return '\x1b[1mpymcnp: \x1b[31mERROR:\x1b[0m INP Syntax Error: ' + msg
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def ERROR_INP_SYNTAX(msg: str) -> str:
|
|
21
|
+
return '\x1b[1mpymcnp: \x1b[31mERROR:\x1b[0m INP Value Error: ' + msg
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
INFO_RUNNING_CQEDITOR = '\x1b[1mpymcnp: \x1b[31m\x1b[34mINFO:\x1b[0m Launching CQ-Editor.'
|
|
25
|
+
INFO_RUNNING_MCNP = '\x1b[1mpymcnp: \x1b[31m\x1b[34mINFO:\x1b[0m Launching MCNP.'
|
|
26
|
+
INFO_BUILD_INP = '\x1b[1mpymcnp: \x1b[31m\x1b[34mINFO:\x1b[0m Built INP.'
|
|
27
|
+
INFO_BUILD_CELL = '\x1b[1mpymcnp: \x1b[31m\x1b[34mINFO:\x1b[0m Built Cell.'
|
|
28
|
+
INFO_BUILD_SURFACE = '\x1b[1mpymcnp: \x1b[31m\x1b[34mINFO:\x1b[0m Built Surface.'
|
|
29
|
+
INFO_BUILD_DATUM = '\x1b[1mpymcnp: \x1b[31m\x1b[34mINFO:\x1b[0m Built Datum.'
|
|
30
|
+
INFO_BUILD_TITLE = '\x1b[1mpymcnp: \x1b[31m\x1b[34mINFO:\x1b[0m Built Title.'
|
|
31
|
+
INFO_BUILD_MESSAGE = '\x1b[1mpymcnp: \x1b[31m\x1b[34mINFO:\x1b[0m Built Message.'
|
|
32
|
+
INFO_BUILD_OTHER = '\x1b[1mpymcnp: \x1b[31m\x1b[34mINFO:\x1b[0m Built Other.'
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def get_timestamp() -> str:
|
|
36
|
+
return datetime.datetime.today().strftime('%Y-%m-%d--%H-%M-%S')
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def error(msg):
|
|
40
|
+
print(msg)
|
|
41
|
+
exit(1)
|
pymcnp/cli/_state.py
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import inspect
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
import sys
|
|
4
|
+
from typing import Callable
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class FileTable:
|
|
8
|
+
"""Store information in a file, so that it can be used across multiple processes.
|
|
9
|
+
|
|
10
|
+
We use this mechanism to store information that is needed when, for example,
|
|
11
|
+
running MCNP simulations in parallel.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
def __init__(self):
|
|
15
|
+
self.table = {}
|
|
16
|
+
self.path = Path.cwd() / '.pymcnp' / '_files.py'
|
|
17
|
+
|
|
18
|
+
self.path.parent.mkdir(exist_ok=True, parents=True)
|
|
19
|
+
|
|
20
|
+
if not self.path.is_file():
|
|
21
|
+
self.path.write_text('table = {}')
|
|
22
|
+
|
|
23
|
+
def append(self, alias, path):
|
|
24
|
+
self._sync_up()
|
|
25
|
+
|
|
26
|
+
if alias in self._table:
|
|
27
|
+
raise ValueError
|
|
28
|
+
|
|
29
|
+
self._table[alias] = path
|
|
30
|
+
self._sync_down()
|
|
31
|
+
|
|
32
|
+
def remove(self, alias):
|
|
33
|
+
self._sync_up()
|
|
34
|
+
|
|
35
|
+
if alias not in self._table:
|
|
36
|
+
raise ValueError
|
|
37
|
+
|
|
38
|
+
path = self._table.pop(alias)
|
|
39
|
+
self._sync_down()
|
|
40
|
+
|
|
41
|
+
return path
|
|
42
|
+
|
|
43
|
+
def access(self, alias):
|
|
44
|
+
self._sync_up()
|
|
45
|
+
|
|
46
|
+
if alias not in self._table:
|
|
47
|
+
raise ValueError
|
|
48
|
+
|
|
49
|
+
return self._table[alias]
|
|
50
|
+
|
|
51
|
+
def _sync_up(self):
|
|
52
|
+
"""Read information from `_files.py`."""
|
|
53
|
+
|
|
54
|
+
path = sys.path
|
|
55
|
+
sys.path.append(str(self.path.parent.absolute()))
|
|
56
|
+
import _files
|
|
57
|
+
|
|
58
|
+
sys.path = path
|
|
59
|
+
|
|
60
|
+
self._table = _files.table
|
|
61
|
+
|
|
62
|
+
return self
|
|
63
|
+
|
|
64
|
+
def _sync_down(self):
|
|
65
|
+
"""Write information to `_files.py`."""
|
|
66
|
+
|
|
67
|
+
self.path.write_text(f'table = {self._table.__repr__()}')
|
|
68
|
+
|
|
69
|
+
def __iter__(self):
|
|
70
|
+
self = self._sync_up()
|
|
71
|
+
return iter(self._table.items())
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class RunConfig:
|
|
75
|
+
"""Store pre and posthooks as well as the run command for parallel runs."""
|
|
76
|
+
|
|
77
|
+
def __init__(self):
|
|
78
|
+
self.path = Path.cwd() / '.pymcnp' / '_run.py'
|
|
79
|
+
self.command = 'mcnp'
|
|
80
|
+
|
|
81
|
+
self.path.parent.mkdir(exist_ok=True, parents=True)
|
|
82
|
+
|
|
83
|
+
if not self.path.is_file():
|
|
84
|
+
self._sync_down()
|
|
85
|
+
|
|
86
|
+
def prehook(self):
|
|
87
|
+
pass
|
|
88
|
+
|
|
89
|
+
def posthook(self):
|
|
90
|
+
pass
|
|
91
|
+
|
|
92
|
+
def set_command(self, command: str):
|
|
93
|
+
self.command = command
|
|
94
|
+
self._sync_down()
|
|
95
|
+
|
|
96
|
+
def set_prehook(self, prehook: Callable):
|
|
97
|
+
self.prehook = prehook
|
|
98
|
+
self._sync_down()
|
|
99
|
+
|
|
100
|
+
def set_posthook(self, posthook: Callable):
|
|
101
|
+
self.posthook = posthook
|
|
102
|
+
self._sync_down()
|
|
103
|
+
|
|
104
|
+
def _sync_up(self):
|
|
105
|
+
"""Read command, prehook, and posthook from `_run.py`."""
|
|
106
|
+
|
|
107
|
+
path = sys.path
|
|
108
|
+
sys.path.append(str(self.path.parent.absolute()))
|
|
109
|
+
import _run
|
|
110
|
+
|
|
111
|
+
sys.path = path
|
|
112
|
+
|
|
113
|
+
self.command = _run.command
|
|
114
|
+
self.prehook = _run.prehook
|
|
115
|
+
self.posthook = _run.posthook
|
|
116
|
+
|
|
117
|
+
return self
|
|
118
|
+
|
|
119
|
+
def _sync_down(self):
|
|
120
|
+
"""Write command, prehook, and posthook to `_run.py`."""
|
|
121
|
+
|
|
122
|
+
prehook = 'def prehook():\n' + ''.join(inspect.getsourcelines(self.prehook)[0][1:])
|
|
123
|
+
posthook = 'def posthook():\n' + ''.join(inspect.getsourcelines(self.posthook)[0][1:])
|
|
124
|
+
|
|
125
|
+
self.path.write_text(
|
|
126
|
+
f"command = '{self.command}'\n" + '\n' + prehook + '\n' + posthook + '\n'
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
table = FileTable()._sync_up()
|
|
131
|
+
run = RunConfig()._sync_up()
|
pymcnp/cli/file.py
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""
|
|
2
|
+
``file`` provides utilities for aliasing PyMCNP file objects.
|
|
3
|
+
|
|
4
|
+
``file`` contains the procedures for executing the ``pymcnp file`` command.
|
|
5
|
+
This module underpins the CLI by simplifying commands.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import sys
|
|
9
|
+
|
|
10
|
+
import docopt
|
|
11
|
+
|
|
12
|
+
from . import _state
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
PYMCNP_INP_DOC = """
|
|
16
|
+
Usage:
|
|
17
|
+
pymcnp file <alias> ( --read=<file> | --delete )
|
|
18
|
+
|
|
19
|
+
Options:
|
|
20
|
+
-r --read=<file> Read INP file and create alias.
|
|
21
|
+
-d --delete Delete alias.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def main(argv: list[str] = sys.argv[1:]) -> None:
|
|
26
|
+
"""
|
|
27
|
+
``main`` executes the ``pymcnp file`` command.
|
|
28
|
+
|
|
29
|
+
``main`` processes the given command line arguments, and creates or deletes
|
|
30
|
+
PyMCNP aliased INP objects.
|
|
31
|
+
|
|
32
|
+
Parameters:
|
|
33
|
+
argv: Tokenized list of CLI arguments.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
args = docopt.docopt(PYMCNP_INP_DOC, argv=argv)
|
|
37
|
+
|
|
38
|
+
if args['--read']:
|
|
39
|
+
# Adding alias to save.
|
|
40
|
+
try:
|
|
41
|
+
_state.table.append(args['<alias>'], args['--read'])
|
|
42
|
+
except ValueError:
|
|
43
|
+
print('ALREADY!')
|
|
44
|
+
elif args['--delete']:
|
|
45
|
+
# Removing alias from save.
|
|
46
|
+
try:
|
|
47
|
+
_state.table.remove(args['<alias>'])
|
|
48
|
+
except ValueError:
|
|
49
|
+
print('NOT THERE!')
|
pymcnp/cli/ls.py
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"""
|
|
2
|
+
``ls`` provides utilities for listing MCNP information.
|
|
3
|
+
|
|
4
|
+
``ls`` contains the procedures for executing the ``pymcnp ls`` command and
|
|
5
|
+
utilities for listing MCNP information.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import sys
|
|
9
|
+
from typing import Final
|
|
10
|
+
|
|
11
|
+
import docopt
|
|
12
|
+
|
|
13
|
+
from ..files import inp
|
|
14
|
+
from . import _state
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Ls:
|
|
18
|
+
"""
|
|
19
|
+
``Ls``
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def __init__(self, inpt: inp.Inp):
|
|
23
|
+
"""
|
|
24
|
+
``__init__`` initializes ``Ls``.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
if inpt is None:
|
|
28
|
+
raise ValueError
|
|
29
|
+
|
|
30
|
+
self.inpt: Final[inp.Inp] = inpt
|
|
31
|
+
|
|
32
|
+
def list_cells(self) -> str:
|
|
33
|
+
"""
|
|
34
|
+
``list_cells`` tabulates INP object cell card information.
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
String of INP object cell information.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
out = (
|
|
41
|
+
'\x1b[4m{:^12.12}\x1b[24m ' * 3 + '\x1b[4m{:^25.25}\x1b[24m \x1b[4m{:^25.25}\x1b[24m\n'
|
|
42
|
+
)
|
|
43
|
+
out = out.format('NUMBER', 'MATERIAL', 'DENSITY', 'GEOMETRY', 'OPTIONS')
|
|
44
|
+
|
|
45
|
+
for cell in self.inpt.cells._cards.values():
|
|
46
|
+
out += (
|
|
47
|
+
f"{cell.number.to_mcnp():<12} "
|
|
48
|
+
f"{cell.material.to_mcnp():<12} "
|
|
49
|
+
f"{cell.density.to_mcnp() if cell.density.to_mcnp() else '':<12} "
|
|
50
|
+
f"{cell.geometry.to_mcnp():<25} {'':<25}\n"
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
return out
|
|
54
|
+
|
|
55
|
+
def list_surfaces(self) -> str:
|
|
56
|
+
"""
|
|
57
|
+
``list_surfaces`` tabulates INP object surface card information.
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
String of INP object surface information.
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
out = '\x1b[4m{:^12.12}\x1b[24m \x1b[4m{:^12.12}\x1b[24m \x1b[4m{:^12.12}\x1b[24m \x1b[4m{:^51.51}\x1b[24m\n'
|
|
64
|
+
out = out.format('NUMBER', 'MNEMONIC', 'TRANSFORM', 'PARAMETERS')
|
|
65
|
+
|
|
66
|
+
for surface in self.inpt.surfaces._cards.values():
|
|
67
|
+
out += (
|
|
68
|
+
f"{surface.number.to_mcnp():<12} "
|
|
69
|
+
f"{surface.mnemonic.to_mcnp():<12} "
|
|
70
|
+
f"{surface.transfrom.to_mcnp() if surface.transform else '':<12} "
|
|
71
|
+
f"{'':<51}\n"
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
return out
|
|
75
|
+
|
|
76
|
+
def list_data(self) -> str:
|
|
77
|
+
"""
|
|
78
|
+
``list_data`` tabulates INP object data card information.
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
String of INP object data information.
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
out = '\x1b[4m{:^12.12}\x1b[24m \x1b[4m{:^12.12}\x1b[24m \x1b[4m{:^12.12}\x1b[24m \x1b[4m{:^51.51}\x1b[24m\n'
|
|
85
|
+
out = out.format('NUMBER', 'SUFFIX', 'DESIGNATOR', 'PARAMETERS')
|
|
86
|
+
|
|
87
|
+
for datum in self.inpt.data._cards.values():
|
|
88
|
+
out += (
|
|
89
|
+
f"{datum.mnemonic:<12.12} "
|
|
90
|
+
f"{datum.suffix.to_mcnp() if hasattr(datum, 'suffix') else '':<12} "
|
|
91
|
+
f"{datum.designator.to_mcnp() if hasattr(datum, 'designator') else '':<12} "
|
|
92
|
+
f"{'':<51.51}\n"
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
return out
|
|
96
|
+
|
|
97
|
+
@staticmethod
|
|
98
|
+
def list_inpts(inpts: tuple[str, inp.Inp]) -> str:
|
|
99
|
+
"""
|
|
100
|
+
``list_inpts`` tabulates INP objects.
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
String of INP object inpt information.
|
|
104
|
+
"""
|
|
105
|
+
|
|
106
|
+
out = '\x1b[4m{:^25.25}\x1b[24m \x1b[4m{:^51.51}\x1b[24m \x1b[4m{:^51.51}\x1b[24m\n'.format(
|
|
107
|
+
'NAME', 'TITLE', 'OTHER'
|
|
108
|
+
)
|
|
109
|
+
for alias, inpt in list(inpts):
|
|
110
|
+
out += f'{alias:<25.25} {inpt.title:<51.51} {repr(inpt.other):<51.51}\n'
|
|
111
|
+
|
|
112
|
+
return out
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
PYMCNP_LS_DOC = """
|
|
116
|
+
Usage:
|
|
117
|
+
pymcnp ls [(<alias> (--cells|--surfaces|--data)...)]
|
|
118
|
+
|
|
119
|
+
Options:
|
|
120
|
+
-f --file List from INP file.
|
|
121
|
+
-c --cells List aliased INP cell cards.
|
|
122
|
+
-s --surfaces List aliased INP surface cards.
|
|
123
|
+
-d --data List aliased INP data cards.
|
|
124
|
+
"""
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def main(argv: list[str] = sys.argv[1:]) -> None:
|
|
128
|
+
"""
|
|
129
|
+
``main`` executes the ``pymcnp ls`` command.
|
|
130
|
+
|
|
131
|
+
``main`` processes the given command line arguments, and it lists, prints,
|
|
132
|
+
and tabulates PyMCNP object contents.
|
|
133
|
+
|
|
134
|
+
Parameters:
|
|
135
|
+
argv: Tokenized list of CLI arguments.
|
|
136
|
+
"""
|
|
137
|
+
|
|
138
|
+
args = docopt.docopt(PYMCNP_LS_DOC, argv=argv)
|
|
139
|
+
|
|
140
|
+
if args['<alias>']:
|
|
141
|
+
# Listing aliased PyMCNP object content.
|
|
142
|
+
|
|
143
|
+
try:
|
|
144
|
+
filename = _state.table.access(args['<alias>'])
|
|
145
|
+
except ValueError:
|
|
146
|
+
print('NOPE!')
|
|
147
|
+
exit(1)
|
|
148
|
+
|
|
149
|
+
ls = Ls(inp.Inp.from_mcnp_file(filename))
|
|
150
|
+
|
|
151
|
+
if args['--cells']:
|
|
152
|
+
print(ls.list_cells())
|
|
153
|
+
if args['--surfaces']:
|
|
154
|
+
print(ls.list_surfaces())
|
|
155
|
+
if args['--data']:
|
|
156
|
+
print(ls.list_data())
|
|
157
|
+
else:
|
|
158
|
+
# Listing all aliased PyMCNP objects.
|
|
159
|
+
print(
|
|
160
|
+
Ls.list_inpts([(alias, inp.Inp.from_mcnp_file(path)) for alias, path in _state.table])
|
|
161
|
+
)
|