Skip to content

Commit 4659ff9

Browse files
authored
Merge pull request #115 from paulromano/hash-model-xml
Support opening single model XML files
2 parents 0ac2580 + b6beb4a commit 4659ff9

6 files changed

Lines changed: 102 additions & 78 deletions

File tree

openmc_plotter/__init__.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
21
__version__ = '0.3.1'

openmc_plotter/__main__.py

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
#!/usr/bin/env python
2-
31
from argparse import ArgumentParser
42
from pathlib import Path
53
from threading import Thread
@@ -13,28 +11,28 @@
1311
from . import __version__
1412
from .main_window import MainWindow, _openmcReload
1513

14+
1615
def main():
1716
ap = ArgumentParser(description='OpenMC Plotter GUI')
1817
version_str = f'OpenMC Plotter Version: {__version__}'
1918
ap.add_argument('-v', '--version', action='version', version=version_str,
2019
help='Display version info.')
21-
ap.add_argument('-d', '--model-directory', default=os.curdir,
22-
help='Location of model dir (default is current dir)')
2320
ap.add_argument('-e','--ignore-settings', action='store_false',
2421
help='Ignore plot_settings.pkl file if present.')
2522
ap.add_argument('-s', '--threads', type=int, default=None,
2623
help='If present, number of threads used to generate plots.')
24+
ap.add_argument('model_path', nargs='?', default=os.curdir,
25+
help='Location of model XML file or a directory containing '
26+
'XML files (default is current dir)')
2727

2828
args = ap.parse_args()
2929

30-
os.chdir(args.model_directory)
31-
3230
run_app(args)
3331

3432

3533
def run_app(user_args):
36-
path_icon = str(Path(__file__).parent / 'assets/openmc_logo.png')
37-
path_splash = str(Path(__file__).parent / 'assets/splash.png')
34+
path_icon = str(Path(__file__).parent / 'assets' / 'openmc_logo.png')
35+
path_splash = str(Path(__file__).parent / 'assets' / 'splash.png')
3836

3937
app = QApplication(sys.argv)
4038
app.setOrganizationName("OpenMC")
@@ -53,7 +51,7 @@ def run_app(user_args):
5351
QtCore.Qt.AlignHCenter | QtCore.Qt.AlignBottom)
5452
app.processEvents()
5553
# load OpenMC model on another thread
56-
openmc_args = {'threads': user_args.threads}
54+
openmc_args = {'threads': user_args.threads, 'model_path': user_args.model_path}
5755
loader_thread = Thread(target=_openmcReload, kwargs=openmc_args)
5856
loader_thread.start()
5957
# while thread is working, process app events
@@ -67,7 +65,7 @@ def run_app(user_args):
6765

6866
font_metric = QtGui.QFontMetrics(app.font())
6967
screen_size = app.primaryScreen().size()
70-
mainWindow = MainWindow(font_metric, screen_size)
68+
mainWindow = MainWindow(font_metric, screen_size, user_args.model_path)
7169
# connect splashscreen to main window, close when main window opens
7270
mainWindow.loadGui(use_settings_pkl=user_args.ignore_settings)
7371
mainWindow.show()

openmc_plotter/docks.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -678,9 +678,9 @@ def update(self):
678678
self.tallySelector.addItem("None")
679679
for idx, tally in enumerate(self.model.statepoint.tallies.values()):
680680
if tally.name == "":
681-
self.tallySelector.addItem('Tally {}'.format(tally.id), userData=tally.id)
681+
self.tallySelector.addItem(f'Tally {tally.id}', userData=tally.id)
682682
else:
683-
self.tallySelector.addItem('Tally {} "{}"'.format(tally.id, tally.name), userData=tally.id)
683+
self.tallySelector.addItem(f'Tally {tally.id} "{tally.name}"', userData=tally.id)
684684
self.tally_map[idx] = tally
685685
self.updateSelectedTally()
686686
self.updateMinMax()

openmc_plotter/main_window.py

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import copy
22
from functools import partial
3-
import os
3+
from pathlib import Path
44
import pickle
55
from threading import Thread
66

@@ -20,15 +20,14 @@
2020
except ImportError:
2121
_HAVE_VTK = False
2222

23-
from .plotmodel import PlotModel, DomainTableModel, hash_file
23+
from .plotmodel import PlotModel, DomainTableModel, hash_model
2424
from .plotgui import PlotImage, ColorDialog
2525
from .docks import DomainDock, TallyDock
2626
from .overlays import ShortcutsOverlay
2727
from .tools import ExportDataDialog
2828

29-
_COORD_LEVELS = 0
3029

31-
def _openmcReload(threads=None):
30+
def _openmcReload(threads=None, model_path='.'):
3231
# reset OpenMC memory, instances
3332
openmc.lib.reset()
3433
openmc.lib.finalize()
@@ -37,18 +36,22 @@ def _openmcReload(threads=None):
3736
args = ["-c"]
3837
if threads is not None:
3938
args += ["-s", str(threads)]
39+
args.append(model_path)
4040
openmc.lib.init(args)
4141
openmc.lib.settings.verbosity = 1
4242

43+
4344
class MainWindow(QMainWindow):
4445
def __init__(self,
4546
font=QtGui.QFontMetrics(QtGui.QFont()),
46-
screen_size=QtCore.QSize()):
47+
screen_size=QtCore.QSize(),
48+
model_path='.'):
4749
super().__init__()
4850

4951
self.screen = screen_size
5052
self.font_metric = font
5153
self.setWindowTitle('OpenMC Plot Explorer')
54+
self.model_path = Path(model_path)
5255

5356
def loadGui(self, use_settings_pkl=True):
5457

@@ -451,7 +454,7 @@ def loadModel(self, reload=False, use_settings_pkl=True):
451454
if reload:
452455
self.resetModels()
453456
else:
454-
self.model = PlotModel(use_settings_pkl)
457+
self.model = PlotModel(use_settings_pkl, self.model_path)
455458

456459
# update plot and model settings
457460
self.updateRelativeBases()
@@ -1151,11 +1154,10 @@ def closeEvent(self, event):
11511154

11521155
def saveSettings(self):
11531156
if self.model.statepoint:
1154-
self.model.statepoint.close()
1157+
self.model.statepoint.close()
11551158

1156-
# get hashes for geometry.xml and material.xml at close
1157-
mat_xml_hash = hash_file('materials.xml')
1158-
geom_xml_hash = hash_file('geometry.xml')
1159+
# get hashes for material.xml and geometry.xml at close
1160+
mat_xml_hash, geom_xml_hash = hash_model(self.model_path)
11591161

11601162
pickle_data = {
11611163
'version': self.model.version,
@@ -1164,7 +1166,11 @@ def saveSettings(self):
11641166
'mat_xml_hash': mat_xml_hash,
11651167
'geom_xml_hash': geom_xml_hash
11661168
}
1167-
with open('plot_settings.pkl', 'wb') as file:
1169+
if self.model_path.is_file():
1170+
settings_pkl = self.model_path.with_name('plot_settings.pkl')
1171+
else:
1172+
settings_pkl = self.model_path / 'plot_settings.pkl'
1173+
with settings_pkl.open('wb') as file:
11681174
pickle.dump(pickle_data, file)
11691175

11701176
def exportTallyData(self):

openmc_plotter/plotmodel.py

Lines changed: 73 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
from ast import literal_eval
22
from collections import defaultdict
33
import copy
4+
import hashlib
45
import itertools
5-
import threading
66
import os
7+
from pathlib import Path
78
import pickle
8-
import hashlib
9+
import threading
910

1011
from PySide2.QtWidgets import QItemDelegate, QColorDialog, QLineEdit, QMessageBox
1112
from PySide2.QtCore import QAbstractTableModel, QModelIndex, Qt, QSize, QEvent
@@ -18,7 +19,7 @@
1819
from .statepointmodel import StatePointModel
1920
from .plot_colors import random_rgb, reset_seed
2021

21-
ID, NAME, COLOR, COLORLABEL, MASK, HIGHLIGHT = tuple(range(0, 6))
22+
ID, NAME, COLOR, COLORLABEL, MASK, HIGHLIGHT = range(6)
2223

2324
_VOID_REGION = -1
2425
_NOT_FOUND = -2
@@ -28,7 +29,6 @@
2829
_PROPERTY_INDICES = {'temperature': 0, 'density': 1}
2930

3031
_REACTION_UNITS = 'Reactions per Source Particle'
31-
_FLUX_UNITS = 'Particle-cm per Source Particle'
3232
_PRODUCTION_UNITS = 'Particles Produced per Source Particle'
3333
_ENERGY_UNITS = 'eV per Source Particle'
3434

@@ -60,10 +60,11 @@
6060
'Std. Dev.': 'std_dev',
6161
'Rel. Error': 'rel_err'}
6262

63-
def hash_file(filename):
63+
64+
def hash_file(path):
6465
# return the md5 hash of a file
6566
h = hashlib.md5()
66-
with open(filename,'rb') as file:
67+
with path.open('rb') as file:
6768
chunk = 0
6869
while chunk != b'':
6970
# read 32768 bytes at a time
@@ -72,50 +73,66 @@ def hash_file(filename):
7273
return h.hexdigest()
7374

7475

75-
class PlotModel():
76-
""" Geometry and plot settings for OpenMC Plot Explorer model
76+
def hash_model(model_path):
77+
"""Get hash values for materials.xml and geometry.xml (or model.xml)"""
78+
if model_path.is_file():
79+
mat_xml_hash = hash_file(model_path)
80+
geom_xml_hash = ""
81+
elif (model_path / 'model.xml').exists():
82+
mat_xml_hash = hash_file(model_path / 'model.xml')
83+
geom_xml_hash = ""
84+
else:
85+
mat_xml_hash = hash_file(model_path / 'materials.xml')
86+
geom_xml_hash = hash_file(model_path / 'geometry.xml')
87+
return mat_xml_hash, geom_xml_hash
7788

78-
Parameters
79-
----------
80-
use_settings_pkl : bool
81-
If True, use plot_settings.pkl file to reload settings
8289

83-
Attributes
84-
----------
85-
geom : openmc.Geometry instance
86-
OpenMC Geometry of the model
87-
modelCells : collections.OrderedDict
88-
Dictionary mapping cell IDs to openmc.Cell instances
89-
modelMaterials : collections.OrderedDict
90-
Dictionary mapping material IDs to openmc.Material instances
91-
ids : NumPy int array (v_res, h_res, 1)
92-
Mapping of plot coordinates to cell/material ID by pixel
93-
ids_map : NumPy int32 array (v_res, h_res, 3)
94-
Mapping of cell and material ids
95-
properties : Numpy float array (v_res, h_res, 3)
96-
Mapping of cell temperatures and material densities
97-
image : NumPy int array (v_res, h_res, 3)
98-
The current RGB image data
99-
statepoint : StatePointModel
100-
Simulation data model used to display tally results
101-
applied_filters : tuple of ints
102-
IDs of the applied filters for the displayed tally
103-
previousViews : list of PlotView instances
104-
List of previously created plot view settings used to undo
105-
changes made in plot explorer
106-
subsequentViews : list of PlotView instances
107-
List of undone plot view settings used to redo changes made
108-
in plot explorer
109-
defaultView : PlotView instance
110-
Default settings for given geometry
111-
currentView : PlotView instance
112-
Currently displayed plot settings in plot explorer
113-
activeView : PlotView instance
114-
Active state of settings in plot explorer, which may or may not
115-
have unapplied changes
90+
class PlotModel:
91+
"""Geometry and plot settings for OpenMC Plot Explorer model
92+
93+
Parameters
94+
----------
95+
use_settings_pkl : bool
96+
If True, use plot_settings.pkl file to reload settings
97+
model_path : pathlib.Path
98+
Path to model XML file or directory
99+
100+
Attributes
101+
----------
102+
geom : openmc.Geometry
103+
OpenMC Geometry of the model
104+
modelCells : collections.OrderedDict
105+
Dictionary mapping cell IDs to openmc.Cell instances
106+
modelMaterials : collections.OrderedDict
107+
Dictionary mapping material IDs to openmc.Material instances
108+
ids : NumPy int array (v_res, h_res, 1)
109+
Mapping of plot coordinates to cell/material ID by pixel
110+
ids_map : NumPy int32 array (v_res, h_res, 3)
111+
Mapping of cell and material ids
112+
properties : Numpy float array (v_res, h_res, 3)
113+
Mapping of cell temperatures and material densities
114+
image : NumPy int array (v_res, h_res, 3)
115+
The current RGB image data
116+
statepoint : StatePointModel
117+
Simulation data model used to display tally results
118+
applied_filters : tuple of ints
119+
IDs of the applied filters for the displayed tally
120+
previousViews : list of PlotView instances
121+
List of previously created plot view settings used to undo
122+
changes made in plot explorer
123+
subsequentViews : list of PlotView instances
124+
List of undone plot view settings used to redo changes made
125+
in plot explorer
126+
defaultView : PlotView
127+
Default settings for given geometry
128+
currentView : PlotView
129+
Currently displayed plot settings in plot explorer
130+
activeView : PlotView
131+
Active state of settings in plot explorer, which may or may not
132+
have unapplied changes
116133
"""
117134

118-
def __init__(self, use_settings_pkl):
135+
def __init__(self, use_settings_pkl, model_path):
119136
""" Initialize PlotModel class attributes """
120137

121138
# Retrieve OpenMC Cells/Materials
@@ -147,8 +164,13 @@ def __init__(self, use_settings_pkl):
147164

148165
self.defaultView = self.getDefaultView()
149166

150-
if use_settings_pkl and os.path.isfile('plot_settings.pkl'):
151-
with open('plot_settings.pkl', 'rb') as file:
167+
if model_path.is_file():
168+
settings_pkl = model_path.with_name('plot_settings.pkl')
169+
else:
170+
settings_pkl = model_path / 'plot_settings.pkl'
171+
172+
if use_settings_pkl and settings_pkl.is_file():
173+
with settings_pkl.open('rb') as file:
152174
try:
153175
data = pickle.load(file)
154176
except AttributeError:
@@ -176,8 +198,7 @@ def __init__(self, use_settings_pkl):
176198

177199
# get materials.xml and geometry.xml hashes to
178200
# restore additional settings if possible
179-
mat_xml_hash = hash_file('materials.xml')
180-
geom_xml_hash = hash_file('geometry.xml')
201+
mat_xml_hash, geom_xml_hash = hash_model(model_path)
181202
if mat_xml_hash == data['mat_xml_hash'] and \
182203
geom_xml_hash == data['geom_xml_hash']:
183204
restore_domains = True
@@ -1071,8 +1092,8 @@ def adopt_plotbase(self, view):
10711092
self.basis = view.basis
10721093

10731094

1074-
class DomainView():
1075-
""" Represents view settings for OpenMC cell or material.
1095+
class DomainView:
1096+
"""Represents view settings for OpenMC cell or material.
10761097
10771098
Parameters
10781099
----------

openmc_plotter/tools.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import copy
2-
from time import sleep
32

43
import numpy as np
54
import openmc
6-
from PySide2 import QtCore, QtGui, QtWidgets
5+
from PySide2 import QtCore, QtWidgets
76

87
from .custom_widgets import HorizontalLine
98
from .scientific_spin_box import ScientificDoubleSpinBox
109

10+
1111
class ExportDataDialog(QtWidgets.QDialog):
1212
"""
1313
A dialog to facilitate generation of VTK files for

0 commit comments

Comments
 (0)