removed old command line scripts (#3300)

Co-authored-by: Paul Romano <paul.k.romano@gmail.com>
This commit is contained in:
Jonathan Shimwell 2025-02-15 05:58:30 +01:00 committed by GitHub
parent be4396c12b
commit 11587786e0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 23 additions and 1284 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

View file

@ -71,9 +71,9 @@ sub-elements:
the PNG file format. The "voxel" plot type produces a binary datafile
containing voxel grid positioning and the cell or material (specified by the
``color`` tag) at the center of each voxel. Voxel plot files can be
processed into VTK files using the :ref:`scripts_voxel` script provided with
OpenMC and subsequently viewed with a 3D viewer such as VISIT or Paraview.
See the :ref:`io_voxel` for information about the datafile structure.
processed into VTK files using the :func:`openmc.voxel_to_vtk` function and
subsequently viewed with a 3D viewer such as VISIT or Paraview. See the
:ref:`io_voxel` for information about the datafile structure.
.. note:: High-resolution voxel files produced by OpenMC can be quite large,
but the equivalent VTK files will be significantly smaller.
@ -152,17 +152,17 @@ attributes or sub-elements. These are not used in "voxel" plots:
*Default*: 255 255 255 (white)
:show_overlaps:
Indicates whether overlapping regions of different cells are shown.
Indicates whether overlapping regions of different cells are shown.
*Default*: None
:overlap_color:
Specifies the RGB color of overlapping regions of different cells. Does not
do anything if ``show_overlaps`` is "false" or not specified. Should be 3
Specifies the RGB color of overlapping regions of different cells. Does not
do anything if ``show_overlaps`` is "false" or not specified. Should be 3
integers separated by spaces.
*Default*: 255 0 0 (red)
:meshlines:
The ``meshlines`` sub-element allows for plotting the boundaries of a
regular mesh on top of a plot. Only one ``meshlines`` element is allowed per

View file

@ -111,11 +111,11 @@ The voxel plot data is written to an :ref:`HDF5 file <io_voxel>`. The voxel file
can subsequently be converted into a standard mesh format that can be viewed in
`ParaView <https://www.paraview.org/>`_, `VisIt
<https://wci.llnl.gov/simulation/computer-codes/visit>`_, etc. This typically
will compress the size of the file significantly. The provided
:ref:`scripts_voxel` script can convert the HDF5 voxel file to VTK formats. Once
processed into a standard 3D file format, colors and masks can be defined using
the stored ID numbers to better explore the geometry. The process for doing this
will depend on the 3D viewer, but should be straightforward.
will compress the size of the file significantly. The
:func:`openmc.voxel_to_vtk` function can convert the HDF5 voxel file to VTK
formats. Once processed into a standard 3D file format, colors and masks can be
defined using the stored ID numbers to better explore the geometry. The process
for doing this will depend on the 3D viewer, but should be straightforward.
.. note:: 3D voxel plotting can be very computer intensive for the viewing
program (Visit, ParaView, etc.) if the number of voxels is large (>10

View file

@ -41,12 +41,9 @@ Plotting in 2D
--------------
The `example notebook`_ also demonstrates how to plot a structured mesh tally in
two dimensions using the Python API. One can also use the :ref:`scripts_plot`
script which provides an interactive GUI to explore and plot structured mesh
tallies for any scores and filter bins.
.. image:: ../_images/plotmeshtally.png
:width: 400px
two dimensions using the Python API. One can also use the `openmc-plotter
<https://github.com/openmc-dev/plotter/>`_ application that provides an
interactive GUI to explore and plot a much wider variety of tallies.
.. _usersguide_track:
@ -81,7 +78,7 @@ of three, e.g., if we wanted particles 3 and 4 from batch 1 and generation 2::
After running OpenMC, the working directory will contain a file of the form
"track_(batch #)_(generation #)_(particle #).h5" for each particle tracked.
These track files can be converted into VTK poly data files with the
:ref:`scripts_track` script.
:class:`openmc.Tracks` class.
----------------------
Source Site Processing

View file

@ -53,142 +53,3 @@ flags:
.. note:: If you're using the Python API, :func:`openmc.run` is equivalent to
running ``openmc`` from the command line.
.. _scripts_ace:
----------------------
``openmc-ace-to-hdf5``
----------------------
This script can be used to create HDF5 nuclear data libraries used by OpenMC if
you have existing ACE files. There are four different ways you can specify ACE
libraries that are to be converted:
1. List each ACE library as a positional argument. This is very useful in
conjunction with the usual shell utilities (``ls``, ``find``, etc.).
2. Use the ``--xml`` option to specify a pre-v0.9 cross_sections.xml file.
3. Use the ``--xsdir`` option to specify a MCNP xsdir file.
4. Use the ``--xsdata`` option to specify a Serpent xsdata file.
The script does not use any extra information from cross_sections.xml/ xsdir/
xsdata files to determine whether the nuclide is metastable. Instead, the
``--metastable`` argument can be used to specify whether the ZAID naming convention
follows the NNDC data convention (1000*Z + A + 300 + 100*m), or the MCNP data
convention (essentially the same as NNDC, except that the first metastable state
of Am242 is 95242 and the ground state is 95642).
The optional ``--fission_energy_release`` argument will accept an HDF5 file
containing a library of fission energy release (ENDF MF=1 MT=458) data. A
library built from ENDF/B-VII.1 data is released with OpenMC and can be found at
openmc/data/fission_Q_data_endb71.h5. This data is necessary for
'fission-q-prompt' and 'fission-q-recoverable' tallies, but is not needed
otherwise.
-h, --help show help message and exit
-d DESTINATION, --destination DESTINATION
Directory to create new library in
-m META, --metastable META
How to interpret ZAIDs for metastable nuclides. META
can be either 'nndc' or 'mcnp'. (default: nndc)
--xml XML Old-style cross_sections.xml that lists ACE libraries
--xsdir XSDIR MCNP xsdir file that lists ACE libraries
--xsdata XSDATA Serpent xsdata file that lists ACE libraries
--fission_energy_release FISSION_ENERGY_RELEASE
HDF5 file containing fission energy release data
.. _scripts_plot:
--------------------------
``openmc-plot-mesh-tally``
--------------------------
``openmc-plot-mesh-tally`` provides a graphical user interface for plotting mesh
tallies. The path to the statepoint file can be provided as an optional arugment
(if omitted, a file dialog will be presented).
.. _scripts_track_combine:
------------------------
``openmc-track-combine``
------------------------
This script combines multiple HDF5 :ref:`particle track files
<usersguide_track>` into a single HDF5 particle track file. The filenames of the
particle track files should be given as posititional arguments. The output
filename can also be changed with the ``-o`` flag:
-o OUT, --out OUT Output HDF5 particle track file
.. _scripts_track:
-----------------------
``openmc-track-to-vtk``
-----------------------
This script converts HDF5 :ref:`particle track files <usersguide_track>` to VTK
poly data that can be viewed with ParaView or VisIt. The filenames of the
particle track files should be given as posititional arguments. The output
filename can also be changed with the ``-o`` flag:
-o OUT, --out OUT Output VTK poly filename
------------------------
``openmc-update-inputs``
------------------------
If you have existing XML files that worked in a previous version of OpenMC that
no longer work with the current version, you can try to update these files using
``openmc-update-inputs``. If any of the given files do not match the most
up-to-date formatting, then they will be automatically rewritten. The old
out-of-date files will not be deleted; they will be moved to a new file with
'.original' appended to their name.
Formatting changes that will be made:
geometry.xml
Lattices containing 'outside' attributes/tags will be replaced with lattices
containing 'outer' attributes, and the appropriate cells/universes will be
added. Any 'surfaces' attributes/elements on a cell will be renamed 'region'.
materials.xml
Nuclide names will be changed from ACE aliases (e.g., Am-242m) to HDF5/GNDS
names (e.g., Am242_m1). Thermal scattering table names will be changed from
ACE aliases (e.g., HH2O) to HDF5/GNDS names (e.g., c_H_in_H2O).
----------------------
``openmc-update-mgxs``
----------------------
This script updates OpenMC's deprecated multi-group cross section XML files to
the latest HDF5-based format.
-i IN, --input IN Input XML file
-o OUT, --output OUT Output file in HDF5 format
.. _scripts_voxel:
---------------------------
``openmc-voxel-to-vtk``
---------------------------
When OpenMC generates :ref:`voxel plots <usersguide_voxel>`, they are in an
:ref:`HDF5 format <io_voxel>` that is not terribly useful by itself. The
``openmc-voxel-to-vtk`` script converts a voxel HDF5 file to a `VTK
<https://vtk.org/>`_ file. To run this script, you will need to have the VTK
Python bindings installed. To convert a voxel file, simply provide the path to
the file:
.. code-block:: sh
openmc-voxel-to-vtk voxel_1.h5
The ``openmc-voxel-to-vtk`` script also takes the following optional
command-line arguments:
-o, --output Path to output VTK file

View file

@ -751,11 +751,10 @@ instance, whereas the :meth:`openmc.Track.filter` method returns a new
with more than one process, a separate track file will be written for
each MPI process with the filename ``tracks_p#.h5`` where # is the
rank of the corresponding process. Multiple track files can be
combined with the :ref:`scripts_track_combine` script:
combined with the :meth:`openmc.Tracks.combine` method::
.. code-block:: sh
openmc-track-combine tracks_p*.h5 --out tracks.h5
track_files = [f"tracks_p{rank}.h5" for rank in range(32)]
openmc.Tracks.combine(track_files, "tracks.h5")
-----------------------
Restarting a Simulation

View file

@ -59,19 +59,10 @@ Repository = "https://github.com/openmc-dev/openmc"
Issues = "https://github.com/openmc-dev/openmc/issues"
[tool.setuptools.packages.find]
include = ['openmc*', 'scripts*']
include = ['openmc*']
exclude = ['tests*']
[tool.setuptools.package-data]
"openmc.data.effective_dose" = ["**/*.txt"]
"openmc.data" = ["*.txt", "*.DAT", "*.json", "*.h5"]
"openmc.lib" = ["libopenmc.dylib", "libopenmc.so"]
[project.scripts]
openmc-ace-to-hdf5 = "scripts.openmc_ace_to_hdf5:main"
openmc-plot-mesh-tally = "scripts.openmc_plot_mesh_tally:main"
openmc-track-combine = "scripts.openmc_track_combine:main"
openmc-track-to-vtk = "scripts.openmc_track_to_vtk:main"
openmc-update-inputs = "scripts.openmc_update_inputs:main"
openmc-update-mgxs = "scripts.openmc_update_mgxs:main"
openmc-voxel-to-vtk = "scripts.openmc_voxel_to_vtk:main"

View file

@ -1,156 +0,0 @@
#!/usr/bin/env python3
"""This script can be used to create HDF5 nuclear data libraries used by
OpenMC. There are four different ways you can specify ACE libraries that are to
be converted:
1. List each ACE library as a positional argument. This is very useful in
conjunction with the usual shell utilities (ls, find, etc.).
2. Use the --xsdir option to specify a MCNP xsdir file.
3. Use the --xsdata option to specify a Serpent xsdata file.
The script does not use any extra information from xsdir/xsdata files to
determine whether the nuclide is metastable. Instead, the --metastable argument
can be used to specify whether the ZAID naming convention follows the NNDC data
convention (1000*Z + A + 300 + 100*m), or the MCNP data convention (essentially
the same as NNDC, except that the first metastable state of Am242 is 95242 and
the ground state is 95642).
"""
import argparse
from functools import partial
import os
from pathlib import Path
import warnings
import openmc.data
from openmc.data.ace import TableType
def ace_to_hdf5(destination, xsdir, xsdata, libraries, metastable, libver):
if not destination.is_dir():
destination.mkdir(parents=True, exist_ok=True)
ace_libraries = []
if xsdir is not None:
ace_libraries.extend(openmc.data.ace.get_libraries_from_xsdir(xsdir))
elif xsdata is not None:
ace_libraries.extend(openmc.data.ace.get_libraries_from_xsdata(xsdata))
else:
ace_libraries = [Path(lib) for lib in libraries]
converted = {}
library = openmc.data.DataLibrary()
for path in ace_libraries:
# Check that ACE library exists
if not os.path.exists(path):
warnings.warn(f"ACE library '{path}' does not exist.")
continue
lib = openmc.data.ace.Library(path)
for table in lib.tables:
# Check type of the ACE table and determine appropriate class /
# conversion function
if table.data_type == TableType.NEUTRON_CONTINUOUS:
name = table.zaid
cls = openmc.data.IncidentNeutron
converter = partial(cls.from_ace, metastable_scheme=metastable)
elif table.data_type == TableType.THERMAL_SCATTERING:
# Adjust name to be the new thermal scattering name
name = openmc.data.get_thermal_name(table.zaid)
cls = openmc.data.ThermalScattering
converter = cls.from_ace
else:
print(f"Can't convert ACE table {table.name}")
continue
if name not in converted:
try:
data = converter(table)
except Exception as e:
print(f"Failed to convert {table.name}: {e}")
continue
print(f"Converting {table.name} (ACE) to {data.name} (HDF5)")
# Determine output filename
outfile = destination / (data.name.replace(".", "_") + ".h5")
data.export_to_hdf5(outfile, "w", libver=libver)
# Register with library
library.register_file(outfile)
# Add nuclide to list
converted[name] = outfile
else:
# Read existing HDF5 file
data = cls.from_hdf5(converted[name])
# Add data for new temperature
try:
print(f"Converting {table.name} (ACE) to {data.name} (HDF5)")
if table.data_type == TableType.NEUTRON_CONTINUOUS:
data.add_temperature_from_ace(table, metastable)
else:
data.add_temperature_from_ace(table)
except Exception as e:
print(f"Failed to convert {table.name}: {e}")
continue
# Re-export
data.export_to_hdf5(converted[name], "w", libver=libver)
# Write cross_sections.xml
library.export_to_xml(destination / "cross_sections.xml")
if __name__ == "__main__":
class CustomFormatter(
argparse.ArgumentDefaultsHelpFormatter, argparse.RawDescriptionHelpFormatter
):
pass
parser = argparse.ArgumentParser(
description=__doc__, formatter_class=CustomFormatter
)
parser.add_argument("libraries", nargs="*", help="ACE libraries to convert to HDF5")
parser.add_argument(
"-d",
"--destination",
type=Path,
default=Path.cwd(),
help="Directory to create new library in",
)
parser.add_argument(
"-m",
"--metastable",
choices=["mcnp", "nndc"],
default="nndc",
help="How to interpret ZAIDs for metastable nuclides",
)
parser.add_argument("--xsdir", help="MCNP xsdir file that lists " "ACE libraries")
parser.add_argument(
"--xsdata", help="Serpent xsdata file that lists " "ACE libraries"
)
parser.add_argument(
"--libver",
choices=["earliest", "latest"],
default="earliest",
help="Output HDF5 versioning. Use "
"'earliest' for backwards compatibility or 'latest' "
"for performance",
)
args = parser.parse_args()
ace_to_hdf5(
destination=args.destination,
xsdir=args.xsdir,
xsdata=args.xsdata,
libraries=args.libraries,
metastable=args.metastable,
libver=args.libver,
)

View file

@ -1,344 +0,0 @@
#!/usr/bin/env python3
"""Python script to plot tally data generated by OpenMC."""
import os
import sys
import argparse
import tkinter as tk
import tkinter.filedialog as filedialog
import tkinter.font as font
import tkinter.messagebox as messagebox
import tkinter.ttk as ttk
import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.backends.backend_tkagg import NavigationToolbar2Tk
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
import numpy as np
from openmc import StatePoint, MeshFilter, UnstructuredMesh
_COMBOBOX_SELECTED = '<<ComboboxSelected>>'
def mesh_filter_check(filter):
"""
Check that the filter is a usable mesh filter
"""
return isinstance(filter, MeshFilter) and not isinstance(filter.mesh, UnstructuredMesh)
class MeshPlotter(tk.Frame):
def __init__(self, parent, filename):
super().__init__(parent)
self.labels = {
'Cell': 'Cell:',
'Cellborn': 'Cell born:',
'Surface': 'Surface:',
'Material': 'Material:',
'Universe': 'Universe:',
'Energy': 'Energy in:',
'Energyout': 'Energy out:'
}
self.filterBoxes = {}
# Read data from source or leakage fraction file
self.get_file_data(filename)
# Set up top-level window
top = self.winfo_toplevel()
top.title('Mesh Tally Plotter: ' + filename)
top.rowconfigure(0, weight=1)
top.columnconfigure(0, weight=1)
self.grid(sticky=tk.W+tk.N)
# Create widgets and draw to screen
self.create_widgets()
self.update()
def create_widgets(self):
figureFrame = tk.Frame(self)
figureFrame.grid(row=0, column=0)
# Create the Figure and Canvas
self.dpi = 100
self.fig = Figure((5.0, 5.0), dpi=self.dpi)
self.canvas = FigureCanvasTkAgg(self.fig, master=figureFrame)
self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)
# Create the navigation toolbar, tied to the canvas
self.mpl_toolbar = NavigationToolbar2Tk(self.canvas, figureFrame)
self.mpl_toolbar.update()
self.canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=1)
# Create frame for comboboxes
self.selectFrame = tk.Frame(self)
self.selectFrame.grid(row=1, column=0, sticky=tk.W+tk.E)
# Tally selection
labelTally = tk.Label(self.selectFrame, text='Tally:')
labelTally.grid(row=0, column=0, sticky=tk.W)
self.tallyBox = ttk.Combobox(self.selectFrame, state='readonly')
self.tallyBox['values'] = [self.datafile.tallies[i].id
for i in self.meshTallies]
self.tallyBox.current(0)
self.tallyBox.grid(row=0, column=1, sticky=tk.W+tk.E)
self.tallyBox.bind(_COMBOBOX_SELECTED, self.update)
# Planar basis selection
labelBasis = tk.Label(self.selectFrame, text='Basis:')
labelBasis.grid(row=1, column=0, sticky=tk.W)
self.basisBox = ttk.Combobox(self.selectFrame, state='readonly')
self.basisBox['values'] = ('xy', 'yz', 'xz')
self.basisBox.current(0)
self.basisBox.grid(row=1, column=1, sticky=tk.W+tk.E)
self.basisBox.bind(_COMBOBOX_SELECTED, self.update)
# Axial level
labelAxial = tk.Label(self.selectFrame, text='Axial level:')
labelAxial.grid(row=2, column=0, sticky=tk.W)
self.axialBox = ttk.Combobox(self.selectFrame, state='readonly')
self.axialBox.grid(row=2, column=1, sticky=tk.W+tk.E)
self.axialBox.bind(_COMBOBOX_SELECTED, self.redraw)
# Option for mean/uncertainty
labelMean = tk.Label(self.selectFrame, text='Mean/Uncertainty:')
labelMean.grid(row=3, column=0, sticky=tk.W)
self.meanBox = ttk.Combobox(self.selectFrame, state='readonly')
self.meanBox['values'] = ('Mean', 'Absolute uncertainty',
'Relative uncertainty')
self.meanBox.current(0)
self.meanBox.grid(row=3, column=1, sticky=tk.W+tk.E)
self.meanBox.bind(_COMBOBOX_SELECTED, self.update)
# Scores
labelScore = tk.Label(self.selectFrame, text='Score:')
labelScore.grid(row=4, column=0, sticky=tk.W)
self.scoreBox = ttk.Combobox(self.selectFrame, state='readonly')
self.scoreBox.grid(row=4, column=1, sticky=tk.W+tk.E)
self.scoreBox.bind(_COMBOBOX_SELECTED, self.redraw)
# Filter label
boldfont = font.Font(weight='bold')
labelFilters = tk.Label(self.selectFrame, text='Filters:',
font=boldfont)
labelFilters.grid(row=5, column=0, sticky=tk.W)
def update(self, event=None):
widget = event.widget if event else None
tally_id = self.meshTallies[self.tallyBox.current()]
selectedTally = self.datafile.tallies[tally_id]
# Get mesh for selected tally
self.mesh = selectedTally.find_filter(MeshFilter).mesh
# Get mesh dimensions
if len(self.mesh.dimension) == 2:
self.nx, self.ny = self.mesh.dimension
self.nz = 1
else:
self.nx, self.ny, self.nz = self.mesh.dimension
# Repopulate comboboxes baesd on current basis selection
text = self.basisBox.get()
if text == 'xy':
self.axialBox['values'] = [str(i+1) for i in range(self.nz)]
elif text == 'yz':
self.axialBox['values'] = [str(i+1) for i in range(self.nx)]
else:
self.axialBox['values'] = [str(i+1) for i in range(self.ny)]
self.axialBox.current(0)
# If update() was called by a change in the basis combobox, we don't
# need to repopulate the filters
if widget == self.basisBox:
self.redraw()
return
# Update scores
self.scoreBox['values'] = selectedTally.scores
self.scoreBox.current(0)
# Remove any filter labels/comboboxes that exist
for row in range(6, self.selectFrame.grid_size()[1]):
for w in self.selectFrame.grid_slaves(row=row):
w.grid_forget()
w.destroy()
# create a label/combobox for each filter in selected tally
count = 0
for f in selectedTally.filters:
filterType = f.short_name
if filterType == 'Mesh':
continue
count += 1
# Create label and combobox for this filter
label = tk.Label(self.selectFrame, text=self.labels[filterType])
label.grid(row=count+6, column=0, sticky=tk.W)
combobox = ttk.Combobox(self.selectFrame, state='readonly')
self.filterBoxes[filterType] = combobox
# Set combobox items
if filterType in ['Energy', 'Energyout']:
combobox['values'] = ['{} to {}'.format(*ebin)
for ebin in f.bins]
else:
combobox['values'] = [str(i) for i in f.bins]
combobox.current(0)
combobox.grid(row=count+6, column=1, sticky=tk.W+tk.E)
combobox.bind(_COMBOBOX_SELECTED, self.redraw)
# If There are no filters, leave a 'None available' message
if count == 0:
count += 1
label = tk.Label(self.selectFrame, text="None Available")
label.grid(row=count+6, column=0, sticky=tk.W)
self.redraw()
def redraw(self, event=None):
basis = self.basisBox.current() + 1
axial_level = self.axialBox.current() + 1
mbvalue = self.meanBox.get()
# Get selected tally
tally_id = self.meshTallies[self.tallyBox.current()]
selectedTally = self.datafile.tallies[tally_id]
# Create spec_list
spec_list = []
for f in selectedTally.filters:
if f.short_name == 'Mesh':
mesh_filter = f
continue
elif f.short_name in ['Energy', 'Energyout']:
index = self.filterBoxes[f.short_name].current()
ebin = f.bins[index]
spec_list.append((type(f), (ebin,)))
else:
index = self.filterBoxes[f.short_name].current()
spec_list.append((type(f), (index,)))
dims = (self.nx, self.ny, self.nz)
text = self.basisBox.get()
if text == 'xy':
h_ind = 0
v_ind = 1
elif text == 'yz':
h_ind = 1
v_ind = 2
else:
h_ind = 0
v_ind = 2
axial_ind = 3 - (h_ind + v_ind)
dims = (dims[h_ind], dims[v_ind])
mesh_dim = len(self.mesh.dimension)
if mesh_dim == 3:
mesh_indices = [0,0,0]
else:
mesh_indices = [0,0]
matrix = np.zeros(dims)
for i in range(dims[0]):
for j in range(dims[1]):
if mesh_dim == 3:
mesh_indices[h_ind] = i + 1
mesh_indices[v_ind] = j + 1
mesh_indices[axial_ind] = axial_level
else:
mesh_indices[0] = i + 1
mesh_indices[1] = j + 1
filters, filter_bins = zip(*spec_list + [
(type(mesh_filter), (tuple(mesh_indices),))])
mean = selectedTally.get_values(
[self.scoreBox.get()], filters, filter_bins)
stdev = selectedTally.get_values(
[self.scoreBox.get()], filters, filter_bins,
value='std_dev')
if mbvalue == 'Mean':
matrix[i, j] = mean
elif mbvalue == 'Absolute uncertainty':
matrix[i, j] = stdev
else:
if mean > 0.:
matrix[i, j] = stdev/mean
else:
matrix[i, j] = 0.
# Clear the figure
self.fig.clear()
# Make figure, set up color bar
self.axes = self.fig.add_subplot(111)
cax = self.axes.imshow(matrix.transpose(), vmin=0.0, vmax=matrix.max(),
interpolation='none', origin='lower')
self.fig.colorbar(cax)
self.axes.set_xticks([])
self.axes.set_yticks([])
self.axes.set_aspect('equal')
# Draw canvas
self.canvas.draw()
def get_file_data(self, filename):
# Create StatePoint object and read in data
self.datafile = StatePoint(filename)
meshes = self.datafile.meshes
if any(isinstance(m, UnstructuredMesh) for m in meshes.values()):
warn_msg = "Unstructured meshes are present in the" \
" statepoint file but are not currently" \
" supported by this script"
messagebox.showwarning("Unstructured Meshes", message=warn_msg)
# Find which tallies are mesh tallies
self.meshTallies = []
for itally, tally in self.datafile.tallies.items():
if any([mesh_filter_check(f) for f in tally.filters]):
self.meshTallies.append(itally)
if not self.meshTallies:
messagebox.showerror("Invalid StatePoint File",
"File does not contain mesh tallies!")
sys.exit(1)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('statepoint', nargs='?', help='Statepoint file')
args = parser.parse_args()
# Hide root window
root = tk.Tk()
root.withdraw()
# If no filename given as command-line argument, open file dialog
if args.statepoint is None:
filename = filedialog.askopenfilename(title='Select statepoint file',
initialdir='.')
else:
filename = args.statepoint
if filename:
# Check to make sure file exists
if not os.path.isfile(filename):
messagebox.showerror("File not found",
"Could not find regular file: " + filename)
sys.exit(1)
app = MeshPlotter(root, filename)
root.deiconify()
root.mainloop()

View file

@ -1,24 +0,0 @@
#!/usr/bin/env python3
"""Combine multiple HDF5 particle track files."""
import argparse
import openmc
def main():
# Parse command-line arguments
parser = argparse.ArgumentParser(
description='Combine particle track files into a single .h5 file.')
parser.add_argument('input', metavar='IN', nargs='+',
help='Input HDF5 particle track filename(s).')
parser.add_argument('-o', '--out', metavar='OUT', default='tracks.h5',
help='Output HDF5 particle track file.')
args = parser.parse_args()
openmc.Tracks.combine(args.input, args.out)
if __name__ == '__main__':
main()

View file

@ -1,41 +0,0 @@
#!/usr/bin/env python3
"""Convert HDF5 particle track to VTK poly data.
"""
import argparse
import openmc
import vtk
def _parse_args():
# Create argument parser.
parser = argparse.ArgumentParser(
description='Convert particle track file(s) to a .pvtp file.')
parser.add_argument('input', metavar='IN', type=str,
help='Input particle track data filename.')
parser.add_argument('-o', '--out', metavar='OUT', type=str, dest='out',
help='Output VTK poly data filename.')
# Parse and return commandline arguments.
return parser.parse_args()
def main():
# Parse commandline arguments.
args = _parse_args()
# Make sure that the output filename ends with '.pvtp'.
if not args.out:
args.out = 'tracks.pvtp'
elif not args.out.endswith('.pvtp'):
args.out += '.pvtp'
# Write coordinate values to points array.
track_file = openmc.Tracks(args.input)
track_file.write_to_vtk(args.out)
if __name__ == '__main__':
main()

View file

@ -1,307 +0,0 @@
#!/usr/bin/env python3
"""Update OpenMC's input XML files to the latest format."""
import argparse
from itertools import chain
from random import randint
from shutil import move
import xml.etree.ElementTree as ET
import openmc.data
description = "Update OpenMC's input XML files to the latest format."
epilog = """\
If any of the given files do not match the most up-to-date formatting, then they
will be automatically rewritten. The old out-of-date files will not be deleted;
they will be moved to a new file with '.original' appended to their name.
Formatting changes that will be made:
geometry.xml: Lattices containing 'outside' attributes/tags will be replaced
with lattices containing 'outer' attributes, and the appropriate
cells/universes will be added. Any 'surfaces' attributes/elements on a cell
will be renamed 'region'.
materials.xml: Nuclide names will be changed from ACE aliases (e.g., Am-242m) to
HDF5/GNDS names (e.g., Am242_m1). Thermal scattering table names will be
changed from ACE aliases (e.g., HH2O) to HDF5/GNDS names (e.g., c_H_in_H2O).
"""
def parse_args():
"""Read the input files from the commandline."""
# Create argument parser.
parser = argparse.ArgumentParser(
description=description,
epilog=epilog,
formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument('input', metavar='IN', type=str, nargs='+',
help='Input XML file(s).')
# Parse and return commandline arguments.
return parser.parse_args()
def get_universe_ids(geometry_root):
"""Return a set of universe id numbers."""
root = geometry_root
out = set()
# Get the ids of universes defined by cells.
for cell in root.iter('cell'):
# Get universe attributes/elements
if 'universe' in cell.attrib:
uid = cell.attrib['universe']
out.add(int(uid))
elif cell.find('universe') is not None:
elem = cell.find('universe')
uid = elem.text
out.add(int(uid))
else:
# Default to universe 0
out.add(0)
# Get the ids of universes defined by lattices.
for lat in root.iter('lattice'):
# Get id attributes.
if 'id' in lat.attrib:
uid = lat.attrib['id']
out.add(int(uid))
# Get id elements.
elif lat.find('id') is not None:
elem = lat.find('id')
uid = elem.text
out.add(int(uid))
return out
def get_cell_ids(geometry_root):
"""Return a set of cell id numbers."""
root = geometry_root
out = set()
# Get the ids of universes defined by cells.
for cell in root.iter('cell'):
# Get id attributes.
if 'id' in cell.attrib:
cid = cell.attrib['id']
out.add(int(cid))
# Get id elements.
elif cell.find('id') is not None:
elem = cell.find('id')
cid = elem.text
out.add(int(cid))
return out
def find_new_id(current_ids, preferred=None):
"""Return a new id that is not already present in current_ids."""
distance_from_preferred = 21
max_random_attempts = 10000
# First, try to find an id near the preferred number.
if preferred is not None:
assert isinstance(preferred, int)
for i in range(1, distance_from_preferred):
if (preferred - i not in current_ids) and (preferred - i > 0):
return preferred - i
if (preferred + i not in current_ids) and (preferred + i > 0):
return preferred + i
# If that was unsuccessful, attempt to randomly guess a new id number.
for i in range(max_random_attempts):
num = randint(1, 2147483647)
if num not in current_inds:
return num
# Raise an error if an id was not found.
raise RuntimeError('Could not find a unique id number for a new universe.')
def get_lat_id(lattice_element):
"""Return the id integer of the lattice_element."""
assert isinstance(lattice_element, ET.Element)
if 'id' in lattice_element.attrib:
return int(lattice_element.attrib['id'].strip())
elif any([child.tag == 'id' for child in lattice_element]):
elem = lattice_element.find('id')
return int(elem.text.strip())
else:
raise RuntimeError('Could not find the id for a lattice.')
def pop_lat_outside(lattice_element):
"""Return lattice's outside material and remove from attributes/elements."""
assert isinstance(lattice_element, ET.Element)
# Check attributes.
if 'outside' in lattice_element.attrib:
material = lattice_element.attrib['outside'].strip()
del lattice_element.attrib['outside']
# Check subelements.
elif any([child.tag == 'outside' for child in lattice_element]):
elem = lattice_element.find('outside')
material = elem.text.strip()
lattice_element.remove(elem)
# No 'outside' specified. This means the outside is a void.
else:
material = 'void'
return material
def update_geometry(geometry_root):
"""Update the given XML geometry tree. Return True if changes were made."""
root = geometry_root
was_updated = False
# Get a set of already-used universe and cell ids.
uids = get_universe_ids(root)
cids = get_cell_ids(root)
taken_ids = uids.union(cids)
# Replace 'outside' with 'outer' in lattices.
for lat in chain(root.iter('lattice'), root.iter('hex_lattice')):
# Get the lattice's id.
lat_id = get_lat_id(lat)
# Ignore lattices that have 'outer' specified.
if any([child.tag == 'outer' for child in lat]): continue
if 'outer' in lat.attrib: continue
# Pop the 'outside' material.
material = pop_lat_outside(lat)
# Get an id number for a new outer universe. Ideally, the id should
# be close to the lattice's id.
new_uid = find_new_id(taken_ids, preferred=lat_id)
assert new_uid not in taken_ids
# Add the new universe filled with the old 'outside' material to the
# geometry.
new_cell = ET.Element('cell')
new_cell.attrib['id'] = str(new_uid)
new_cell.attrib['universe'] = str(new_uid)
new_cell.attrib['material'] = material
root.append(new_cell)
taken_ids.add(new_uid)
# Add the new universe to the lattice's 'outer' attribute.
lat.attrib['outer'] = str(new_uid)
was_updated = True
for surface in root.findall('surface'):
for attribute in ['type', 'coeffs', 'boundary']:
if surface.find(attribute) is not None:
value = surface.find(attribute).text
surface.attrib[attribute] = value
child_element = surface.find(attribute)
surface.remove(child_element)
was_updated = True
# Remove 'type' from lattice definitions.
for lat in root.iter('lattice'):
elem = lat.find('type')
if elem is not None:
lat.remove(elem)
was_updated = True
if 'type' in lat.attrib:
del lat.attrib['type']
was_updated = True
# Change 'width' to 'pitch' in lattice definitions.
for lat in root.iter('lattice'):
elem = lat.find('width')
if elem is not None:
elem.tag = 'pitch'
was_updated = True
if 'width' in lat.attrib:
lat.attrib['pitch'] = lat.attrib['width']
del lat.attrib['width']
was_updated = True
# Change 'surfaces' to 'region' in cell definitions
for cell in root.iter('cell'):
elem = cell.find('surfaces')
if elem is not None:
elem.tag = 'region'
was_updated = True
if 'surfaces' in cell.attrib:
cell.attrib['region'] = cell.attrib['surfaces']
del cell.attrib['surfaces']
was_updated = True
return was_updated
def update_materials(root):
"""Update the given XML materials tree. Return True if changes were made."""
was_updated = False
for material in root.findall('material'):
for nuclide in material.findall('nuclide'):
if 'name' in nuclide.attrib:
nucname = nuclide.attrib['name'].replace('-', '')
# If a nuclide name is in the ZAID notation (e.g., a number),
# convert it to the proper nuclide name.
if nucname.strip().isnumeric():
nucname = openmc.data.ace.get_metadata(int(nucname))[0]
nucname = nucname.replace('Nat', '0')
if nucname.endswith('m'):
nucname = nucname[:-1] + '_m1'
nuclide.set('name', nucname)
was_updated = True
elif nuclide.find('name') is not None:
name_elem = nuclide.find('name')
nucname = name_elem.text
nucname = nucname.replace('-', '')
nucname = nucname.replace('Nat', '0')
if nucname.endswith('m'):
nucname = nucname[:-1] + '_m1'
name_elem.text = nucname
was_updated = True
for sab in material.findall('sab'):
if 'name' in sab.attrib:
sabname = sab.attrib['name']
sab.set('name', openmc.data.get_thermal_name(sabname))
was_updated = True
elif sab.find('name') is not None:
name_elem = sab.find('name')
sabname = name_elem.text
name_elem.text = openmc.data.get_thermal_name(sabname)
was_updated = True
return was_updated
if __name__ == '__main__':
args = parse_args()
for fname in args.input:
# Parse the XML data.
tree = ET.parse(fname)
root = tree.getroot()
was_updated = False
if root.tag == 'geometry':
was_updated = update_geometry(root)
elif root.tag == 'materials':
was_updated = update_materials(root)
if was_updated:
# Move the original geometry file to preserve it.
move(fname, fname + '.original')
# Write a new geometry file.
tree.write(fname, xml_declaration=True)

View file

@ -1,212 +0,0 @@
#!/usr/bin/env python3
"""Update OpenMC's deprecated multi-group cross section XML files to the latest
HDF5-based format.
"""
import os
import warnings
import xml.etree.ElementTree as ET
import argparse
import numpy as np
import openmc.mgxs_library
def parse_args():
"""Read the input files from the commandline."""
# Create argument parser
parser = argparse.ArgumentParser(description=__doc__,
formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument('-i', '--input', type=argparse.FileType('r'),
help='input XML file')
parser.add_argument('-o', '--output', nargs='?', default='',
help='output file, in HDF5 format')
args = vars(parser.parse_args())
if args['output'] == '':
filename = args['input'].name
extension = os.path.splitext(filename)
if extension == '.xml':
filename = filename[:filename.rfind('.')] + '.h5'
args['output'] = filename
# Parse and return commandline arguments.
return args
def get_data(element, entry):
value = element.find(entry)
if value is not None:
value = value.text.strip()
elif entry in element.attrib:
value = element.attrib[entry].strip()
else:
value = None
return value
def main():
args = parse_args()
# Parse the XML data.
tree = ET.parse(args['input'])
root = tree.getroot()
# Get old metadata
group_structure = tree.find('group_structure').text.strip()
group_structure = np.array(group_structure.split(), dtype=float)
# Convert from MeV to eV
group_structure *= 1.e6
energy_groups = openmc.mgxs.EnergyGroups(group_structure)
inverse_velocity = tree.find('inverse-velocity')
if inverse_velocity is not None:
inverse_velocity = inverse_velocity.text.split()
inverse_velocity = np.array(inverse_velocity, dtype=float)
else:
inverse_velocity = None
xsd = []
names = []
# Now move on to the cross section data itself
for xsdata_elem in root.iter('xsdata'):
name = get_data(xsdata_elem, 'name')
temperature = get_data(xsdata_elem, 'kT')
if temperature is not None:
temperature = float(temperature) / openmc.data.K_BOLTZMANN * 1.E6
else:
temperature = 294.
temperatures = [temperature]
awr = get_data(xsdata_elem, 'awr')
if awr is not None:
awr = float(awr)
representation = get_data(xsdata_elem, 'representation')
if representation is None:
representation = 'isotropic'
if representation == 'angle':
n_azi = int(get_data(xsdata_elem, 'num_azimuthal'))
n_pol = int(get_data(xsdata_elem, 'num_polar'))
scatter_format = get_data(xsdata_elem, 'scatt_type')
if scatter_format is None:
scatter_format = 'legendre'
order = int(get_data(xsdata_elem, 'order'))
tab_leg = get_data(xsdata_elem, 'tabular_legendre')
if tab_leg is not None:
warnings.warn('The tabular_legendre option has moved to the '
'settings.xml file and must be added manually')
# Either add the data to a previously existing xsdata (if it is
# for the same 'name' but a different temperature), or create a
# new one.
try:
# It is in our list, so store that entry
i = names.index(name)
except ValueError:
# It is not in our list, so add it
i = -1
xsd.append(openmc.XSdata(name, energy_groups,
temperatures=temperatures,
representation=representation))
if awr is not None:
xsd[-1].atomic_weight_ratio = awr
if representation == 'angle':
xsd[-1].num_azimuthal = n_azi
xsd[-1].num_polar = n_pol
xsd[-1].scatter_format = scatter_format
xsd[-1].order = order
names.append(name)
if scatter_format == 'legendre':
order_dim = order + 1
else:
order_dim = order
if i != -1:
xsd[i].add_temperature(temperature)
total = get_data(xsdata_elem, 'total')
if total is not None:
total = np.array(total.split(), dtype=float)
total.shape = xsd[i].xs_shapes['[G]']
xsd[i].set_total(total, temperature)
if inverse_velocity is not None:
xsd[i].set_inverse_velocity(inverse_velocity, temperature)
absorption = get_data(xsdata_elem, 'absorption')
absorption = np.array(absorption.split(), dtype=float)
absorption.shape = xsd[i].xs_shapes['[G]']
xsd[i].set_absorption(absorption, temperature)
scatter = get_data(xsdata_elem, 'scatter')
scatter = np.array(scatter.split(), dtype=float)
# This is now a flattened-array of something that started with a
# shape of [Order][G][G']; we need to unflatten and then switch the
# ordering
in_shape = (order_dim, energy_groups.num_groups,
energy_groups.num_groups)
if representation == 'angle':
in_shape = (n_pol, n_azi) + in_shape
scatter.shape = in_shape
scatter = np.swapaxes(scatter, 2, 3)
scatter = np.swapaxes(scatter, 3, 4)
else:
scatter.shape = in_shape
scatter = np.swapaxes(scatter, 0, 1)
scatter = np.swapaxes(scatter, 1, 2)
xsd[i].set_scatter_matrix(scatter, temperature)
multiplicity = get_data(xsdata_elem, 'multiplicity')
if multiplicity is not None:
multiplicity = np.array(multiplicity.split(), dtype=float)
multiplicity.shape = xsd[i].xs_shapes["[G][G']"]
xsd[i].set_multiplicity_matrix(multiplicity, temperature)
fission = get_data(xsdata_elem, 'fission')
if fission is not None:
fission = np.array(fission.split(), dtype=float)
fission.shape = xsd[i].xs_shapes['[G]']
xsd[i].set_fission(fission, temperature)
kappa_fission = get_data(xsdata_elem, 'kappa_fission')
if kappa_fission is not None:
kappa_fission = np.array(kappa_fission.split(), dtype=float)
kappa_fission.shape = xsd[i].xs_shapes['[G]']
xsd[i].set_kappa_fission(kappa_fission, temperature)
chi = get_data(xsdata_elem, 'chi')
if chi is not None:
chi = np.array(chi.split(), dtype=float)
chi.shape = xsd[i].xs_shapes['[G]']
xsd[i].set_chi(chi, temperature)
else:
chi = None
nu_fission = get_data(xsdata_elem, 'nu_fission')
if nu_fission is not None:
nu_fission = np.array(nu_fission.split(), dtype=float)
if chi is not None:
nu_fission.shape = xsd[i].xs_shapes['[G]']
else:
nu_fission.shape = xsd[i].xs_shapes["[G][G']"]
xsd[i].set_nu_fission(nu_fission, temperature)
# Build library as we go, but first we have enough to initialize it
lib = openmc.MGXSLibrary(energy_groups)
lib.add_xsdatas(xsd)
lib.export_to_hdf5(args['output'])
if __name__ == '__main__':
main()

View file

@ -1,22 +0,0 @@
#!/usr/bin/env python3
from argparse import ArgumentParser
import openmc
if __name__ == "__main__":
# Process command line arguments
parser = ArgumentParser('Converts a voxel HDF5 file to a VTK file')
parser.add_argument("voxel_file", help="Path to voxel h5 file")
parser.add_argument(
"-o",
"--output",
action="store",
default="plot",
help="Path to output VTK file.",
)
args = parser.parse_args()
print("Reading and translating data...")
openmc.voxel_to_vtk(args.voxel_file, args.output)
print(f"Written VTK file {args.output}...")

View file

@ -1,7 +1,6 @@
import glob
import os
from pathlib import Path
from subprocess import call
import numpy as np
import openmc
@ -26,8 +25,8 @@ class TrackTestHarness(TestHarness):
# For MPI mode, combine track files
if config['mpi']:
call(['../../../scripts/openmc-track-combine', '-o', 'tracks.h5'] +
glob.glob('tracks_p*.h5'))
track_files = list(glob.glob('tracks_p*.h5'))
openmc.Tracks.combine(track_files, 'tracks.h5')
# Get string of track file information
outstr = ''

View file

@ -1,5 +1,4 @@
from difflib import unified_diff
from subprocess import check_call
import filecmp
import glob
import h5py
@ -487,8 +486,7 @@ class PlotTestHarness(TestHarness):
# Check that voxel h5 can be converted to vtk
for voxel_h5_filename in self._voxel_convert_checks:
check_call(['../../../scripts/openmc-voxel-to-vtk'] +
glob.glob(voxel_h5_filename))
openmc.voxel_to_vtk(voxel_h5_filename)
def _test_output_created(self):
"""Make sure *.png has been created."""