adding back files to be reviewed

This commit is contained in:
Paul Romano 2019-10-28 11:55:45 -05:00
parent ae28233110
commit bc09d1ef55
1244 changed files with 301904 additions and 0 deletions

280
scripts/casl_chain.py Executable file
View file

@ -0,0 +1,280 @@
# This dictionary contains the 255-nuclides, simplified burnup chain used in
# CASL-ORIGEN, which can be found in Appendix A of Kang Seog Kim, "Specification
# for the VERA Depletion Benchmark Suite", CASL-U-2015-1014-000, Rev. 0,
# ORNL/TM-2016/53, 2016.
#
# Note 32 of the 255 nuclides appeare twice as they are both activation
# nuclides (category 1) and fission product nuclides (category 3).
# Te129 has been added due to it's link to I129 production.
CASL_CHAIN = {
# Nuclide: (Stable, CAT, IFPY, Special yield treatment)
# Stable: True if nuclide has no decay reactions
# CAT: Category of nuclides
# 1-Activation nuclides
# 2-Heavy metal nuclides
# 3-Fission product nuclides
# IFPY: Indicator of fission product yield
# 0-Non FPY
# 1-Direct FPY (-1 indicates (stable+metastable) direct FPY)
# 2-Cumulative FPY
# 3-Special treatment with weight fractions
# Special yield: (nuclide_i/weight_i/IFPY_i)
'B10': (True, 1, 0, None),
'B11': (True, 1, 0, None),
'O16': (True, 1, 0, None),
'Ag107': (True, 1, 0, None),
'Ag109': (True, 1, 0, None), # redundant as FP
'Ag110': (False, 1, 0, None), # redundant as FP
'Cd110': (True, 1, 0, None), # redundant as FP
'Cd111': (True, 1, 0, None), # redundant as FP
'Cd112': (True, 1, 0, None),
'Cd113': (True, 1, 0, None), # redundant as FP
'Cd114': (True, 1, 0, None),
'Cd115': (False, 1, 0, None),
'In113': (True, 1, 0, None),
'In115': (True, 1, 0, None), # redundant as FP
'Sm152': (True, 1, 0, None), # redundant as FP
'Sm153': (False, 1, 0, None), # redundant as FP
'Eu151': (True, 1, 0, None), # redundant as FP
'Eu152': (False, 1, 0, None),
'Eu152_m1': (False, 1, 0, None),
'Eu153': (True, 1, 0, None), # redundant as FP
'Eu154': (False, 1, 0, None), # redundant as FP
'Eu155': (False, 1, 0, None), # redundant as FP
'Eu156': (False, 1, 0, None), # redundant as FP
'Eu157': (False, 1, 0, None), # redundant as FP
'Gd152': (True, 1, 0, None),
'Gd154': (True, 1, 0, None), # redundant as FP
'Gd155': (True, 1, 0, None), # redundant as FP
'Gd156': (True, 1, 0, None), # redundant as FP
'Gd157': (True, 1, 0, None), # redundant as FP
'Gd158': (True, 1, 0, None), # redundant as FP
'Gd159': (False, 1, 0, None), # redundant as FP
'Gd160': (True, 1, 0, None), # redundant as FP
'Gd161': (False, 1, 0, None), # redundant as FP
'Tb159': (True, 1, 0, None), # redundant as FP
'Tb160': (False, 1, 0, None), # redundant as FP
'Tb161': (False, 1, 0, None), # redundant as FP
'Dy160': (True, 1, 0, None), # redundant as FP
'Dy161': (True, 1, 0, None), # redundant as FP
'Dy162': (True, 1, 0, None), # redundant as FP
'Dy163': (True, 1, 0, None), # redundant as FP
'Dy164': (True, 1, 0, None), # redundant as FP
'Dy165': (False, 1, 0, None), # redundant as FP
'Ho165': (True, 1, 0, None), # redundant as FP
'Er162': (True, 1, 0, None),
'Er164': (True, 1, 0, None),
'Er166': (True, 1, 0, None),
'Er167': (True, 1, 0, None),
'Er168': (True, 1, 0, None),
'Er169': (False, 1, 0, None),
'Er170': (True, 1, 0, None),
'Er171': (False, 1, 0, None),
'Tm169': (True, 1, 0, None),
'Tm170': (False, 1, 0, None),
'Tm171': (False, 1, 0, None),
'Hf174': (True, 1, 0, None),
'Hf176': (True, 1, 0, None),
'Hf177': (True, 1, 0, None),
'Hf178': (True, 1, 0, None),
'Hf179': (True, 1, 0, None),
'Hf180': (True, 1, 0, None),
'Hf181': (False, 1, 0, None),
'Ta181': (True, 1, 0, None),
'Ta182': (False, 1, 0, None),
'Th230': (False, 2, 0, None),
'Th231': (False, 2, 0, None),
'Th232': (False, 2, 0, None),
'Th233': (False, 2, 0, None),
'Th234': (False, 2, 0, None),
'Pa231': (False, 2, 0, None),
'Pa232': (False, 2, 0, None),
'Pa233': (False, 2, 0, None),
'Pa234': (False, 2, 0, None),
'U232': (False, 2, 0, None),
'U233': (False, 2, 0, None),
'U234': (False, 2, 0, None),
'U235': (False, 2, 0, None),
'U236': (False, 2, 0, None),
'U237': (False, 2, 0, None),
'U238': (False, 2, 0, None),
'U239': (False, 2, 0, None),
'Np236': (False, 2, 0, None),
'Np237': (False, 2, 0, None),
'Np238': (False, 2, 0, None),
'Np239': (False, 2, 0, None),
'Np240': (False, 2, 0, None),
'Np240_m1': (False, 2, 0, None),
'Pu236': (False, 2, 0, None),
'Pu237': (False, 2, 0, None),
'Pu238': (False, 2, 0, None),
'Pu239': (False, 2, 0, None),
'Pu240': (False, 2, 0, None),
'Pu241': (False, 2, 0, None),
'Pu242': (False, 2, 0, None),
'Pu243': (False, 2, 0, None),
'Am241': (False, 2, 0, None),
'Am242': (False, 2, 0, None),
'Am242_m1': (False, 2, 0, None),
'Am243': (False, 2, 0, None),
'Am244': (False, 2, 0, None),
'Am244_m1': (False, 2, 0, None),
'Cm242': (False, 2, 0, None),
'Cm243': (False, 2, 0, None),
'Cm244': (False, 2, 0, None),
'Cm245': (False, 2, 0, None),
'Cm246': (False, 2, 0, None),
'Br81': (True, 3, 2, None),
'Br82': (False, 3, 2, None),
'Kr82': (True, 3, 3, [('Br82_m1', 0.024, 1), ('Kr82', 1.000, 1)]),
'Kr83': (True, 3, 2, None),
'Kr84': (True, 3, 2, None),
'Kr85': (False, 3, 2, None),
'Kr86': (True, 3, 2, None),
'Sr89': (False, 3, 2, None),
'Sr90': (False, 3, 2, None),
'Y89': (True, 3, 1, None),
'Y90': (False, 3, 1, None),
'Y91': (False, 3, 2, None),
'Zr91': (True, 3, 1, None),
'Zr93': (False, 3, 2, None),
'Zr95': (False, 3, 2, None),
'Zr96': (True, 3, 2, None),
'Nb95': (False, 3, 3, [('Nb95',1.000, 1), ('Nb95_m1', 0.944, 1)]),
'Mo95': (True, 3, 3, [('Nb95_m1',0.056, 1), ('Mo95', 1.000, 1)]),
'Mo96': (True, 3, 3, [('Nb96',1.000, 1), ('Mo96', 1.000, 1)]),
'Mo97': (True, 3, 2, None),
'Mo98': (True, 3, 2, None),
'Mo99': (False, 3, 2, None),
'Mo100': (True, 3, 2, None),
'Tc99': (False, 3, 1, None),
'Tc99_m1': (False, 3, 1, None),
'Tc100': (False, 3, 1, None),
'Ru100': (True, 3, 1, None),
'Ru101': (True, 3, 2, None),
'Ru102': (True, 3, 2, None),
'Ru103': (False, 3, 2, None),
'Ru104': (True, 3, 2, None),
'Ru105': (False, 3, 2, None),
'Ru106': (False, 3, 2, None),
'Rh102': (False, 3, 1, None),
'Rh102_m1': (False, 3, 1, None),
'Rh103': (True, 3, 1, None),
'Rh103_m1': (False, 3, 1, None),
'Rh104': (False, 3, 1, None),
'Rh105': (False, 3, 1, None),
'Rh105_m1': (False, 3, 1, None),
'Rh106': (False, 3, 1, None),
'Rh106_m1': (False, 3, 1, None),
'Pd104': (True, 3, 1, None),
'Pd105': (True, 3, 1, None),
'Pd106': (True, 3, 1, None),
'Pd107': (False, 3, 2, None),
'Pd108': (True, 3, 2, None),
'Pd109': (False, 3, 2, None),
'Ag109': (True, 3, 1, None),
'Ag109_m1': (False, 3, 1, None),
'Ag110': (False, 3, 2, None),
'Ag110_m1': (False, 3, 2, None),
'Ag111': (False, 3, 2, None),
'Cd110': (True, 3, 1, None),
'Cd111': (True, 3, 3, [('Ag110', -1.000, 2), ('Cd110', 1.000, 2), ('Cd111', 1.000, 1)]),
'Cd113': (True, 3, 2, None),
'In115': (True, 3, 2, None),
'Sb121': (True, 3, 2, None),
'Sb123': (False, 3, 2, None),
'Sb125': (False, 3, 2, None),
'Sb127': (False, 3, 2, None),
'Te127': (False, 3, -1, None),
'Te127_m1': (False, 3, -1, None),
'Te129': (False, 3, 1, None),
'Te129_m1': (False, 3, 2, None),
'Te132': (False, 3, 2, None),
'I127': (True, 3, 1, None),
'I128': (False, 3, 3, [('I128', 0.931, 2)]),
'I129': (False, 3, 3, [('I129', 1.000, 2), ('I129', -1.000, 2)]),
'I130': (False, 3, 2, None),
'I131': (False, 3, 2, None),
'I132': (False, 3, 1, None),
'I135': (False, 3, 2, None),
'Xe128': (True, 3, 1, None),
'Xe130': (True, 3, 1, None),
'Xe131': (True, 3, 1, None),
'Xe132': (True, 3, 1, None),
'Xe133': (False, 3, 2, None),
'Xe134': (True, 3, 2, None),
'Xe135': (False, 3, 1, None),
'Xe135_m1': (False, 3, 1, None),
'Xe136': (True, 3, 2, None),
'Xe137': (False, 3, 2, None),
'Cs133': (True, 3, 1, None),
'Cs134': (False, 3, 1, None),
'Cs135': (False, 3, 1, None),
'Cs136': (False, 3, 1, None),
'Cs137': (False, 3, 1, None),
'Ba134': (True, 3, 1, None),
'Ba137': (True, 3, 1, None),
'Ba140': (False, 3, 2, None),
'La139': (True, 3, 2, None),
'La140': (False, 3, 1, None),
'Ce140': (True, 3, 1, None),
'Ce141': (False, 3, 2, None),
'Ce142': (True, 3, 2, None),
'Ce143': (False, 3, 2, None),
'Ce144': (False, 3, 2, None),
'Pr141': (True, 3, 1, None),
'Pr142': (False, 3, 1, None),
'Pr143': (False, 3, 1, None),
'Pr144': (False, 3, 1, None),
'Nd142': (True, 3, 1, None),
'Nd143': (True, 3, 1, None),
'Nd144': (False, 3, 1, None),
'Nd145': (True, 3, 2, None),
'Nd146': (True, 3, 2, None),
'Nd147': (False, 3, 2, None),
'Nd148': (True, 3, 2, None),
'Nd149': (False, 3, 2, None),
'Nd150': (True, 3, 2, None),
'Nd151': (False, 3, 2, None),
'Pm147': (False, 3, 1, None),
'Pm148': (False, 3, -1, None),
'Pm148_m1': (False, 3, -1, None),
'Pm149': (False, 3, 1, None),
'Pm150': (False, 3, 1, None),
'Pm151': (False, 3, 1, None),
'Sm147': (False, 3, 1, None),
'Sm148': (False, 3, 1, None),
'Sm149': (False, 3, 1, None),
'Sm150': (True, 3, 1, None),
'Sm151': (False, 3, 1, None),
'Sm152': (True, 3, 2, None),
'Sm153': (False, 3, 2, None),
'Sm154': (True, 3, 2, None),
'Sm155': (False, 3, 2, None),
'Eu151': (True, 3, 1, None),
'Eu153': (True, 3, 1, None),
'Eu154': (False, 3, 1, None),
'Eu155': (False, 3, 1, None),
'Eu156': (False, 3, 2, None),
'Eu157': (False, 3, 2, None),
'Gd154': (True, 3, 1, None),
'Gd155': (True, 3, 1, None),
'Gd156': (True, 3, 1, None),
'Gd157': (True, 3, 1, None),
'Gd158': (True, 3, 2, None),
'Gd159': (False, 3, 2, None),
'Gd160': (True, 3, 2, None),
'Gd161': (False, 3, 2, None),
'Tb159': (True, 3, 1, None),
'Tb160': (False, 3, 1, None),
'Tb161': (False, 3, 1, None),
'Dy160': (True, 3, 1, None),
'Dy161': (True, 3, 1, None),
'Dy162': (True, 3, 2, None),
'Dy163': (True, 3, 2, None),
'Dy164': (True, 3, 2, None),
'Dy165': (False, 3, 2, None),
'Ho165': (True, 3, 3, [('Dy165_m1', 0.022, 2), ('Ho165', 1.000, 1)])
}

205
scripts/openmc-ace-to-hdf5 Executable file
View file

@ -0,0 +1,205 @@
#!/usr/bin/env python3
import argparse
import os
import xml.etree.ElementTree as ET
import warnings
import openmc.data
description = """
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 --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).
"""
class CustomFormatter(argparse.ArgumentDefaultsHelpFormatter,
argparse.RawDescriptionHelpFormatter):
pass
parser = argparse.ArgumentParser(
description=description,
formatter_class=CustomFormatter
)
parser.add_argument('libraries', nargs='*',
help='ACE libraries to convert to HDF5')
parser.add_argument('-d', '--destination', default='.',
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('--xml', help='Old-style cross_sections.xml that '
'lists ACE libraries')
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()
if not os.path.isdir(args.destination):
os.mkdir(args.destination)
# If the --xml argument was given, get the list of ACE libraries directory from
# <ace_table> elements within the specified cross_sections.xml file
ace_libraries = []
if args.xml is not None:
tree = ET.parse(args.xml)
root = tree.getroot()
if root.find('directory') is not None:
directory = root.find('directory').text
else:
directory = os.path.dirname(args.xml)
for ace_table in root.findall('ace_table'):
path = os.path.join(directory, ace_table.attrib['path'])
if path not in ace_libraries:
ace_libraries.append(path)
elif args.xsdir is not None:
# Find 'directory' section
lines = open(args.xsdir, 'r').readlines()
for index, line in enumerate(lines):
if line.strip().lower() == 'directory':
break
else:
raise IOError("Could not find 'directory' section in MCNP xsdir file")
# Handle continuation lines indicated by '+' at end of line
lines = lines[index + 1:]
continue_lines = [i for i, line in enumerate(lines)
if line.strip().endswith('+')]
for i in reversed(continue_lines):
lines[i] += lines[i].strip()[:-1] + lines.pop(i + 1)
# Create list of ACE libraries
for line in lines:
words = line.split()
if len(words) < 3:
continue
path = os.path.join(os.path.dirname(args.xsdir), words[2])
if path not in ace_libraries:
ace_libraries.append(path)
elif args.xsdata is not None:
with open(args.xsdata, 'r') as xsdata:
for line in xsdata:
words = line.split()
if len(words) >= 9:
path = os.path.join(os.path.dirname(args.xsdata), words[8])
if path not in ace_libraries:
ace_libraries.append(path)
else:
ace_libraries = args.libraries
nuclides = {}
library = openmc.data.DataLibrary()
for filename in ace_libraries:
# Check that ACE library exists
if not os.path.exists(filename):
warnings.warn("ACE library '{}' does not exist.".format(filename))
continue
lib = openmc.data.ace.Library(filename)
for table in lib.tables:
name, xs = table.name.split('.')
if xs.endswith('c'):
# Continuous-energy neutron data
if name not in nuclides:
try:
neutron = openmc.data.IncidentNeutron.from_ace(
table, args.metastable)
except Exception as e:
print('Failed to convert {}: {}'.format(table.name, e))
continue
print('Converting {} (ACE) to {} (HDF5)'.format(table.name,
neutron.name))
# Determine filename
outfile = os.path.join(args.destination,
neutron.name.replace('.', '_') + '.h5')
neutron.export_to_hdf5(outfile, 'w', libver=args.libver)
# Register with library
library.register_file(outfile)
# Add nuclide to list
nuclides[name] = outfile
else:
# Then we only need to append the data
try:
neutron = \
openmc.data.IncidentNeutron.from_hdf5(nuclides[name])
print('Converting {} (ACE) to {} (HDF5)'
.format(table.name, neutron.name))
neutron.add_temperature_from_ace(table, args.metastable)
neutron.export_to_hdf5(nuclides[name] + '_1', 'w',
libver=args.libver)
os.rename(nuclides[name] + '_1', nuclides[name])
except Exception as e:
print('Failed to convert {}: {}'.format(table.name, e))
continue
elif xs.endswith('t'):
# Adjust name to be the new thermal scattering name
name = openmc.data.get_thermal_name(name)
# Thermal scattering data
if name not in nuclides:
try:
thermal = openmc.data.ThermalScattering.from_ace(table)
except Exception as e:
print('Failed to convert {}: {}'.format(table.name, e))
continue
print('Converting {} (ACE) to {} (HDF5)'.format(table.name,
thermal.name))
# Determine filename
outfile = os.path.join(args.destination,
thermal.name.replace('.', '_') + '.h5')
thermal.export_to_hdf5(outfile, 'w', libver=args.libver)
# Register with library
library.register_file(outfile)
# Add data to list
nuclides[name] = outfile
else:
# Then we only need to append the data
try:
thermal = openmc.data.ThermalScattering.from_hdf5(
nuclides[name])
print('Converting {} (ACE) to {} (HDF5)'
.format(table.name,thermal.name))
thermal.add_temperature_from_ace(table)
thermal.export_to_hdf5(nuclides[name] + '_1', 'w',
libver=args.libver)
os.rename(nuclides[name] + '_1', nuclides[name])
except Exception as e:
print('Failed to convert {}: {}'.format(table.name, e))
continue
# Write cross_sections.xml
libpath = os.path.join(args.destination, 'cross_sections.xml')
library.export_to_xml(libpath)

106
scripts/openmc-get-photon-data Executable file
View file

@ -0,0 +1,106 @@
#!/usr/bin/env python3
"""
Download ENDF/B-VII.1 ENDF data from NNDC for photo-atomic and atomic
relaxation data and convert it to an HDF5 library for use with OpenMC.
This data is used for photon transport in OpenMC.
"""
import os
import sys
import shutil
import zipfile
import argparse
from io import BytesIO
from urllib.request import urlopen
import openmc.data
class CustomFormatter(argparse.ArgumentDefaultsHelpFormatter,
argparse.RawDescriptionHelpFormatter):
pass
parser = argparse.ArgumentParser(
description=__doc__,
formatter_class=CustomFormatter
)
parser.add_argument('-c', '--cross-sections',
help='cross_sections.xml file to append libraries to')
args = parser.parse_args()
base_url = 'http://www.nndc.bnl.gov/endf/b7.1/zips/'
files = ['ENDF-B-VII.1-photoat.zip', 'ENDF-B-VII.1-atomic_relax.zip']
block_size = 16384
# ==============================================================================
# DOWNLOAD FILES FROM NNDC SITE
if not os.path.exists('photon_hdf5'):
os.mkdir('photon_hdf5')
for f in files:
# Establish connection to URL
url = base_url + f
req = urlopen(url)
# Get file size from header
file_size = req.length
downloaded = 0
# Check if file already downloaded
if os.path.exists(f):
if os.path.getsize(f) == file_size:
print('Skipping ' + f)
continue
else:
overwrite = input('Overwrite {}? ([y]/n) '.format(f))
if overwrite.lower().startswith('n'):
continue
# Copy file to disk
print('Downloading {}... '.format(f), end='')
with open(f, 'wb') as fh:
while True:
chunk = req.read(block_size)
if not chunk: break
fh.write(chunk)
downloaded += len(chunk)
status = '{0:10} [{1:3.2f}%]'.format(
downloaded, downloaded * 100. / file_size)
print(status + chr(8)*len(status), end='')
print('')
# ==============================================================================
# EXTRACT FILES
for f in files:
print('Extracting {0}...'.format(f))
zipfile.ZipFile(f).extractall()
# ==============================================================================
# GENERATE HDF5 DATA LIBRARY
# If previous cross_sections.xml was specified, load it in
if args.cross_sections is not None:
lib_path = args.cross_sections
library = openmc.data.DataLibrary.from_xml(lib_path)
else:
lib_path = os.path.join('photon_hdf5', 'cross_sections.xml')
library = openmc.data.DataLibrary()
for z in range(1, 101):
element = openmc.data.ATOMIC_SYMBOL[z]
print('Generating HDF5 file for Z={} ({})...'.format(z, element))
# Generate instance of IncidentPhoton
photo_file = os.path.join('photoat', 'photoat-{:03}_{}_000.endf'.format(z, element))
atom_file = os.path.join('atomic_relax', 'atom-{:03}_{}_000.endf'.format(z, element))
f = openmc.data.IncidentPhoton.from_endf(photo_file, atom_file)
# Write HDF5 file and register it
hdf5_file = os.path.join('photon_hdf5', element + '.h5')
f.export_to_hdf5(hdf5_file, 'w')
library.register_file(hdf5_file)
library.export_to_xml(lib_path)

99
scripts/openmc-make-compton Executable file
View file

@ -0,0 +1,99 @@
#!/usr/bin/env python
import os
import sys
import tarfile
from urllib.request import urlopen
import numpy as np
import h5py
base_url = 'http://geant4.cern.ch/support/source/'
filename = 'G4EMLOW.6.48.tar.gz'
block_size = 16384
# ==============================================================================
# DOWNLOAD FILES FROM GEANT4 SITE
# Establish connection to URL
req = urlopen(base_url + filename)
# Get file size from header
file_size = req.length
downloaded = 0
# Check if file already downloaded
download = True
if os.path.exists(filename):
if os.path.getsize(filename) == file_size:
print('Already downloaded ' + filename)
download = False
else:
overwrite = input('Overwrite {}? ([y]/n) '.format(filename))
if overwrite.lower().startswith('n'):
download = False
if download:
# Copy file to disk
print('Downloading {}... '.format(filename), end='')
with open(filename, 'wb') as fh:
while True:
chunk = req.read(block_size)
if not chunk: break
fh.write(chunk)
downloaded += len(chunk)
status = '{0:10} [{1:3.2f}%]'.format(
downloaded, downloaded * 100. / file_size)
print(status + chr(8)*len(status), end='')
print('')
# ==============================================================================
# EXTRACT FILES FROM TGZ
if not os.path.isdir('G4EMLOW6.48'):
with tarfile.open(filename, 'r') as tgz:
print('Extracting {0}...'.format(filename))
tgz.extractall()
# ==============================================================================
# GENERATE COMPTON PROFILE HDF5 FILE
print('Generating compton_profiles.h5...')
shell_file = os.path.join('G4EMLOW6.48', 'doppler', 'shell-doppler.dat')
with open(shell_file, 'r') as shell:
with h5py.File('compton_profiles.h5', 'w') as f:
# Read/write electron momentum values
pz = np.loadtxt(os.path.join('G4EMLOW6.48', 'doppler', 'p-biggs.dat'))
f.create_dataset('pz', data=pz)
for Z in range(1, 101):
# Create group for this element
group = f.create_group('{:03}'.format(Z))
# Read data into one long array
path = os.path.join('G4EMLOW6.48', 'doppler', 'profile-{}.dat'.format(Z))
J = np.fromstring(open(path, 'r').read(), sep=' ')
# Determine number of electron shells and reshape
n_shells = J.size // 31
J.shape = (n_shells, 31)
# Write Compton profile for this Z
group.create_dataset('J', data=J)
# Determine binding energies and number of electrons for each shell
num_electrons = []
binding_energy = []
while True:
words = shell.readline().split()
if words[0] == '-1':
break
num_electrons.append(float(words[0]))
binding_energy.append(float(words[1]))
# Write binding energies and number of electrons
group.create_dataset('num_electrons', data=num_electrons)
group.create_dataset('binding_energy', data=binding_energy)

View file

@ -0,0 +1,46 @@
#!/usr/bin/env python3
import os
from pathlib import Path
from zipfile import ZipFile
from openmc._utils import download
import openmc.deplete
URLS = [
'http://www.nndc.bnl.gov/endf/b7.1/zips/ENDF-B-VII.1-neutrons.zip',
'http://www.nndc.bnl.gov/endf/b7.1/zips/ENDF-B-VII.1-decay.zip',
'http://www.nndc.bnl.gov/endf/b7.1/zips/ENDF-B-VII.1-nfy.zip'
]
def main():
endf_dir = os.environ.get("OPENMC_ENDF_DATA")
if endf_dir is not None:
endf_dir = Path(endf_dir)
elif all(os.path.isdir(lib) for lib in ("neutrons", "decay", "nfy")):
endf_dir = Path(".")
else:
for url in URLS:
basename = download(url)
with ZipFile(basename, 'r') as zf:
print('Extracting {}...'.format(basename))
zf.extractall()
endf_dir = Path(".")
decay_files = tuple((endf_dir / "decay").glob("*endf"))
neutron_files = tuple((endf_dir / "neutrons").glob("*endf"))
nfy_files = tuple((endf_dir / "nfy").glob("*endf"))
# check files exist
for flist, ftype in [(decay_files, "decay"), (neutron_files, "neutron"),
(nfy_files, "neutron fission product yield")]:
if not flist:
raise IOError("No {} endf files found in {}".format(ftype, endf_dir))
chain = openmc.deplete.Chain.from_endf(decay_files, nfy_files, neutron_files)
chain.export_to_xml('chain_endfb71.xml')
if __name__ == '__main__':
main()

View file

@ -0,0 +1,240 @@
#!/usr/bin/env python3
import glob
import os
from zipfile import ZipFile
from collections import OrderedDict, defaultdict
from io import StringIO
from itertools import chain
try:
import lxml.etree as ET
_have_lxml = True
except ImportError:
import xml.etree.ElementTree as ET
_have_lxml = False
import openmc.data
import openmc.deplete
from openmc._xml import clean_indentation
from openmc.deplete.chain import _REACTIONS
from openmc.deplete.nuclide import Nuclide, DecayTuple, ReactionTuple
from openmc._utils import download
from casl_chain import CASL_CHAIN
URLS = [
'http://www.nndc.bnl.gov/endf/b7.1/zips/ENDF-B-VII.1-neutrons.zip',
'http://www.nndc.bnl.gov/endf/b7.1/zips/ENDF-B-VII.1-decay.zip',
'http://www.nndc.bnl.gov/endf/b7.1/zips/ENDF-B-VII.1-nfy.zip'
]
def main():
if os.path.isdir('./decay') and os.path.isdir('./nfy') and os.path.isdir('./neutrons'):
endf_dir = '.'
elif 'OPENMC_ENDF_DATA' in os.environ:
endf_dir = os.environ['OPENMC_ENDF_DATA']
else:
for url in URLS:
basename = download(url)
with ZipFile(basename, 'r') as zf:
print('Extracting {}...'.format(basename))
zf.extractall()
endf_dir = '.'
decay_files = glob.glob(os.path.join(endf_dir, 'decay', '*.endf'))
fpy_files = glob.glob(os.path.join(endf_dir, 'nfy', '*.endf'))
neutron_files = glob.glob(os.path.join(endf_dir, 'neutrons', '*.endf'))
# Create a Chain
chain = openmc.deplete.Chain()
print('Reading ENDF nuclear data from "{}"...'.format(os.path.abspath(endf_dir)))
# Create dictionary mapping target to filename
print('Processing neutron sub-library files...')
reactions = {}
for f in neutron_files:
evaluation = openmc.data.endf.Evaluation(f)
name = evaluation.gnd_name
if name in CASL_CHAIN:
reactions[name] = {}
for mf, mt, nc, mod in evaluation.reaction_list:
if mf == 3:
file_obj = StringIO(evaluation.section[3, mt])
openmc.data.endf.get_head_record(file_obj)
q_value = openmc.data.endf.get_cont_record(file_obj)[1]
reactions[name][mt] = q_value
# Determine what decay and FPY nuclides are available
print('Processing decay sub-library files...')
decay_data = {}
for f in decay_files:
data = openmc.data.Decay(f)
name = data.nuclide['name']
if name in CASL_CHAIN:
decay_data[name] = data
for name in CASL_CHAIN:
if name not in decay_data:
print('WARNING: {} has no decay data!'.format(name))
print('Processing fission product yield sub-library files...')
fpy_data = {}
for f in fpy_files:
data = openmc.data.FissionProductYields(f)
name = data.nuclide['name']
if name in CASL_CHAIN:
fpy_data[name] = data
print('Creating depletion_chain...')
missing_daughter = []
missing_rx_product = []
missing_fpy = []
for idx, parent in enumerate(sorted(decay_data, key=openmc.data.zam)):
data = decay_data[parent]
nuclide = Nuclide()
nuclide.name = parent
chain.nuclides.append(nuclide)
chain.nuclide_dict[parent] = idx
if not CASL_CHAIN[parent][0] and \
not data.nuclide['stable'] and data.half_life.nominal_value != 0.0:
nuclide.half_life = data.half_life.nominal_value
nuclide.decay_energy = sum(E.nominal_value for E in
data.average_energies.values())
sum_br = 0.0
for i, mode in enumerate(data.modes):
type_ = ','.join(mode.modes)
if mode.daughter in decay_data:
target = mode.daughter
else:
print('missing {} {} {}'.format(parent, ','.join(mode.modes), mode.daughter))
continue
# Write branching ratio, taking care to ensure sum is unity
br = mode.branching_ratio.nominal_value
sum_br += br
if i == len(data.modes) - 1 and sum_br != 1.0:
br = 1.0 - sum(m.branching_ratio.nominal_value
for m in data.modes[:-1])
# Append decay mode
nuclide.decay_modes.append(DecayTuple(type_, target, br))
if parent in reactions:
reactions_available = set(reactions[parent].keys())
for name, mts, changes in _REACTIONS:
if mts & reactions_available:
delta_A, delta_Z = changes
A = data.nuclide['mass_number'] + delta_A
Z = data.nuclide['atomic_number'] + delta_Z
daughter = '{}{}'.format(openmc.data.ATOMIC_SYMBOL[Z], A)
if name not in chain.reactions:
chain.reactions.append(name)
if daughter not in decay_data:
missing_rx_product.append((parent, name, daughter))
daughter = 'Nothing'
# Store Q value
for mt in sorted(mts):
if mt in reactions[parent]:
q_value = reactions[parent][mt]
break
else:
q_value = 0.0
nuclide.reactions.append(ReactionTuple(
name, daughter, q_value, 1.0))
if any(mt in reactions_available for mt in [18, 19, 20, 21, 38]):
if parent in fpy_data:
q_value = reactions[parent][18]
nuclide.reactions.append(
ReactionTuple('fission', 0, q_value, 1.0))
if 'fission' not in chain.reactions:
chain.reactions.append('fission')
else:
missing_fpy.append(parent)
if parent in fpy_data:
fpy = fpy_data[parent]
if fpy.energies is not None:
nuclide.yield_energies = fpy.energies
else:
nuclide.yield_energies = [0.0]
for E, table_yd, table_yc in zip(nuclide.yield_energies, fpy.independent, fpy.cumulative):
yields = defaultdict(float)
for product in table_yd:
if product in decay_data:
# identifier
ifpy = CASL_CHAIN[product][2]
# 1 for independent
if ifpy == 1:
if product not in table_yd:
print('No independent fission yields found for {} in {}'.format(product, parent))
else:
yields[product] += table_yd[product].nominal_value
# 2 for cumulative
elif ifpy == 2:
if product not in table_yc:
print('No cumulative fission yields found for {} in {}'.format(product, parent))
else:
yields[product] += table_yc[product].nominal_value
# -1 for stable + unstable
elif ifpy == -1:
if product not in table_yd:
print('No independent fission yields found for {} in {}'.format(product, parent))
else:
yields[product] += table_yc[product].nominal_value
product_meta = '{}_m1'.format(product)
if product_meta in table_yd:
yields[product] += table_yc[product_meta].nominal_value
# 3 for special treatment with weight fractions
elif ifpy == 3:
for tuple_i in CASL_CHAIN[product][3]:
name_i, weight_i, ifpy_i = tuple_i
if name_i not in table_yd:
print('No fission yields found for {} in {}'.format(name_i, parent))
else:
if ifpy_i == 1:
yields[product] += weight_i * table_yd[name_i].nominal_value
elif ifpy_i == 2:
yields[product] += weight_i * table_yc[name_i].nominal_value
nuclide.yield_data[E] = []
for k in sorted(yields, key=openmc.data.zam):
nuclide.yield_data[E].append((k, yields[k]))
# Display warnings
if missing_daughter:
print('The following decay modes have daughters with no decay data:')
for mode in missing_daughter:
print(' {}'.format(mode))
print('')
if missing_rx_product:
print('The following reaction products have no decay data:')
for vals in missing_rx_product:
print('{} {} -> {}'.format(*vals))
print('')
if missing_fpy:
print('The following fissionable nuclides have no fission product yields:')
for parent in missing_fpy:
print(' ' + parent)
print('')
chain.export_to_xml('chain_casl.xml')
if __name__ == '__main__':
main()

View file

@ -0,0 +1,50 @@
#!/usr/bin/env python
from urllib.parse import urlencode
from urllib.request import urlopen
from lxml import html
import numpy as np
import h5py
from openmc.data import ATOMIC_SYMBOL
base_url = 'https://physics.nist.gov/cgi-bin/Star/e_table-t.pl'
energies = np.logspace(-3, 3, 200)
data = {'matno': '', 'Energies': '\n'.join(str(x) for x in energies)}
columns = {1: 's_collision', 2: 's_radiative'}
# ==============================================================================
# SCRAPE DATA FROM ESTAR SITE AND GENERATE STOPPING POWER HDF5 FILE
print('Generating stopping_powers.h5...')
with h5py.File('stopping_powers.h5', 'w') as f:
# Write energies
f.create_dataset('energy', data=energies)
for Z in range(1, 99):
print('Processing {} data...'.format(ATOMIC_SYMBOL[Z]))
# Update form-encoded data to send in POST request for this element
data['matno'] = '{:03}'.format(Z)
payload = urlencode(data).encode("utf-8")
# Retrieve data from ESTAR site
r = urlopen(url=base_url, data=payload).read()
# Remove text and reformat data
r = html.fromstring(r).xpath('//pre//text()')
values = np.fromstring(' '.join(r[12:-5]), sep=' ').reshape((-1, 5)).T
# Create group for this element
group = f.create_group('{:03}'.format(Z))
# Write the mean excitation energy
attributes = np.fromstring(r[3], sep=' ')
group.attrs['I'] = attributes[2]
# Write collision and radiative stopping powers
for i in columns:
group.create_dataset(columns[i], data=values[i])

164
scripts/openmc-make-test-data Executable file
View file

@ -0,0 +1,164 @@
#!/usr/bin/env python3
"""
Download ENDF/B-VII.1 ENDF and ACE files from NNDC and WMP files from GitHub and
generate a full HDF5 library with incident neutron, incident photon, thermal
scattering data, and windowed multipole data. This data is used for OpenMC's
regression test suite.
"""
import glob
import os
from pathlib import Path
import tarfile
import tempfile
from urllib.parse import urljoin
import zipfile
import openmc.data
from openmc._utils import download
base_ace = 'http://www.nndc.bnl.gov/endf/b7.1/aceFiles/'
base_endf = 'http://www.nndc.bnl.gov/endf/b7.1/zips/'
base_wmp = 'https://github.com/mit-crpg/WMP_Library/releases/download/v1.1/'
files = [
(base_ace, 'ENDF-B-VII.1-neutron-293.6K.tar.gz', '9729a17eb62b75f285d8a7628ace1449'),
(base_ace, 'ENDF-B-VII.1-tsl.tar.gz', 'e17d827c92940a30f22f096d910ea186'),
(base_endf, 'ENDF-B-VII.1-neutrons.zip', 'e5d7f441fc4c92893322c24d1725e29c'),
(base_endf, 'ENDF-B-VII.1-photoat.zip', '5192f94e61f0b385cf536f448ffab4a4'),
(base_endf, 'ENDF-B-VII.1-atomic_relax.zip', 'fddb6035e7f2b6931e51a58fc754bd10'),
(base_wmp, 'WMP_Library_v1.1.tar.gz', '8523895928dd6ba63fba803e3a45d4f3')
]
def fix_zaid(table, old, new):
filename = os.path.join('tsl', table)
with open(filename, 'r') as fh:
text = fh.read()
text = text.replace(old, new, 1)
with open(filename, 'w') as fh:
fh.write(text)
pwd = Path.cwd()
output_dir = pwd / 'nndc_hdf5'
os.makedirs('nndc_hdf5/photon', exist_ok=True)
with tempfile.TemporaryDirectory() as tmpdir:
# Temporarily change dir
os.chdir(tmpdir)
# =========================================================================
# Download files from NNDC server
for base, fname, checksum in files:
download(urljoin(base, fname), checksum)
# =========================================================================
# EXTRACT FILES FROM TGZ
for _, f, _ in files:
print('Extracting {}...'.format(f))
path = Path(f)
if path.suffix == '.gz':
with tarfile.open(f, 'r') as tgz:
if 'tsl' in f:
tgz.extractall(path='tsl')
else:
tgz.extractall()
elif path.suffix == '.zip':
zipfile.ZipFile(f).extractall()
# =========================================================================
# FIX ZAID ASSIGNMENTS FOR VARIOUS S(A,B) TABLES
print('Fixing ZAIDs for S(a,b) tables')
fix_zaid('bebeo.acer', '8016', ' 0')
fix_zaid('obeo.acer', '4009', ' 0')
library = openmc.data.DataLibrary()
# =========================================================================
# INCIDENT NEUTRON DATA
neutron_files = sorted(glob.glob('ENDF-B-VII.1-neutron-293.6K/*.ace'))
for f in neutron_files:
print('Converting {}...'.format(os.path.basename(f)))
data = openmc.data.IncidentNeutron.from_ace(f)
# Check for fission energy release data
endf_filename = 'neutrons/n-{:03}_{}_{:03}{}.endf'.format(
data.atomic_number,
data.atomic_symbol,
data.mass_number,
'm{}'.format(data.metastable) if data.metastable else ''
)
ev = openmc.data.endf.Evaluation(endf_filename)
if (1, 458) in ev.section:
endf_data = openmc.data.IncidentNeutron.from_endf(ev)
data.fission_energy = endf_data.fission_energy
# Add 0K elastic scattering data for select nuclides
if data.name in ('U235', 'U238', 'Pu239'):
data.add_elastic_0K_from_endf(endf_filename)
# Determine filename
outfile = output_dir / (data.name + '.h5')
data.export_to_hdf5(outfile, 'w', 'earliest')
# Register with library
library.register_file(outfile)
# =========================================================================
# THERMAL SCATTERING DATA
thermal_files = sorted(glob.glob('tsl/*.acer'))
for f in thermal_files:
print('Converting {}...'.format(os.path.basename(f)))
data = openmc.data.ThermalScattering.from_ace(f)
# Determine filename
outfile = output_dir / (data.name + '.h5')
data.export_to_hdf5(outfile, 'w', 'earliest')
# Register with library
library.register_file(outfile)
# =========================================================================
# INCIDENT PHOTON DATA
for z in range(1, 101):
element = openmc.data.ATOMIC_SYMBOL[z]
print('Generating HDF5 file for Z={} ({})...'.format(z, element))
# Generate instance of IncidentPhoton
photo_file = Path('photoat') / 'photoat-{:03}_{}_000.endf'.format(z, element)
atom_file = Path('atomic_relax') / 'atom-{:03}_{}_000.endf'.format(z, element)
data = openmc.data.IncidentPhoton.from_endf(photo_file, atom_file)
# Write HDF5 file and register it
outfile = output_dir / 'photon' / (element + '.h5')
data.export_to_hdf5(outfile, 'w', 'earliest')
library.register_file(outfile)
# =========================================================================
# WINDOWED MULTIPOLE DATA
# Move data into output directory
os.rename('WMP_Library', str(output_dir / 'wmp'))
# Add multipole data to library
for f in sorted(glob.glob('{}/wmp/*.h5'.format(output_dir))):
print('Registering WMP file {}...'.format(f))
library.register_file(f)
library.export_to_xml(output_dir / 'cross_sections.xml')
# =========================================================================
# CREATE TARBALL AND MOVE BACK
print('Creating compressed archive...')
test_tar = pwd / 'nndc_hdf5_test.tar.xz'
with tarfile.open(str(test_tar), 'w:xz') as txz:
txz.add('nndc_hdf5')
# Change back to original directory
os.chdir(str(pwd))

325
scripts/openmc-plot-mesh-tally Executable file
View file

@ -0,0 +1,325 @@
#!/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
class MeshPlotter(tk.Frame):
def __init__(self, parent, filename):
tk.Frame.__init__(self, 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('<<ComboboxSelected>>', 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('<<ComboboxSelected>>', 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('<<ComboboxSelected>>', 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('<<ComboboxSelected>>', 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('<<ComboboxSelected>>', 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):
if not event:
widget = None
else:
widget = event.widget
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'] = ['{0} to {1}'.format(*f.bins[i:i+2])
for i in range(len(f.bins) - 1)]
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('<<ComboboxSelected>>', 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], f.bins[index + 1])
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)
# Find which tallies are mesh tallies
self.meshTallies = []
for itally, tally in self.datafile.tallies.items():
if any([isinstance(f, MeshFilter) 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()

78
scripts/openmc-track-to-vtk Executable file
View file

@ -0,0 +1,78 @@
#!/usr/bin/env python3
"""Convert HDF5 particle track to VTK poly data.
"""
import os
import argparse
import struct
import h5py
import vtk
def _parse_args():
# Create argument parser.
parser = argparse.ArgumentParser(
description='Convert particle track file to a .pvtp file.')
parser.add_argument('input', metavar='IN', type=str, nargs='+',
help='Input particle track data filename(s).')
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'
# Initialize data arrays and offset.
points = vtk.vtkPoints()
cells = vtk.vtkCellArray()
point_offset = 0
for fname in args.input:
# Write coordinate values to points array.
track = h5py.File(fname)
n_particles = track.attrs['n_particles']
n_coords = track.attrs['n_coords']
coords = []
for i in range(n_particles):
coords.append(track['coordinates_' + str(i + 1)].value)
for j in range(n_coords[i]):
points.InsertNextPoint(coords[i][j,:])
for i in range(n_particles):
# Create VTK line and assign points to line.
line = vtk.vtkPolyLine()
line.GetPointIds().SetNumberOfIds(n_coords[i])
for j in range(n_coords[i]):
line.GetPointIds().SetId(j, point_offset + j)
# Add line to cell array
cells.InsertNextCell(line)
point_offset += n_coords[i]
data = vtk.vtkPolyData()
data.SetPoints(points)
data.SetLines(cells)
writer = vtk.vtkXMLPPolyDataWriter()
if vtk.vtkVersion.GetVTKMajorVersion() > 5:
writer.SetInputData(data)
else:
writer.SetInput(data)
writer.SetFileName(args.out)
writer.Write()
if __name__ == '__main__':
main()

301
scripts/openmc-update-inputs Executable file
View file

@ -0,0 +1,301 @@
#!/usr/bin/env python3
"""Update OpenMC's input XML files to the latest format.
"""
import argparse
from difflib import get_close_matches
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/GND names (e.g., Am242_m1). Thermal scattering table names will be
changed from ACE aliases (e.g., HH2O) to HDF5/GND 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
# 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']
nucname = nucname.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)

225
scripts/openmc-update-mgxs Executable file
View file

@ -0,0 +1,225 @@
#!/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
description = """\
Update OpenMC's deprecated multi-group cross section XML files to the latest
HDF5-based format."""
def parse_args():
"""Read the input files from the commandline."""
# Create argument parser
parser = argparse.ArgumentParser(description=description,
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()
else:
if entry in element.attrib:
value = element.attrib[entry].strip()
else:
value = None
return value
if __name__ == '__main__':
args = parse_args()
# Parse the XML data.
tree = ET.parse(args['input'])
root = tree.getroot()
# Get old metadata
temp = tree.find('group_structure').text.strip()
temp = np.array(temp.split())
group_structure = temp.astype(np.float)
# Convert from MeV to eV
group_structure *= 1.e6
energy_groups = openmc.mgxs.EnergyGroups(group_structure)
temp = tree.find('inverse-velocity')
if temp is not None:
temp = temp.text.strip()
temp = np.array(temp.split())
inverse_velocity = temp.astype(np.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.Warning('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)
temp = get_data(xsdata_elem, 'total')
if temp is not None:
temp = np.array(temp.split(), dtype=float)
total = temp.astype(np.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)
temp = get_data(xsdata_elem, 'absorption')
temp = np.array(temp.split())
absorption = temp.astype(np.float)
absorption.shape = xsd[i].xs_shapes['[G]']
xsd[i].set_absorption(absorption, temperature)
temp = get_data(xsdata_elem, 'scatter')
temp = np.array(temp.split())
scatter = temp.astype(np.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)
temp = get_data(xsdata_elem, 'multiplicity')
if temp is not None:
temp = np.array(temp.split())
multiplicity = temp.astype(np.float)
multiplicity.shape = xsd[i].xs_shapes["[G][G']"]
xsd[i].set_multiplicity_matrix(multiplicity, temperature)
temp = get_data(xsdata_elem, 'fission')
if temp is not None:
temp = np.array(temp.split())
fission = temp.astype(np.float)
fission.shape = xsd[i].xs_shapes['[G]']
xsd[i].set_fission(fission, temperature)
temp = get_data(xsdata_elem, 'kappa_fission')
if temp is not None:
temp = np.array(temp.split())
kappa_fission = temp.astype(np.float)
kappa_fission.shape = xsd[i].xs_shapes['[G]']
xsd[i].set_kappa_fission(kappa_fission, temperature)
temp = get_data(xsdata_elem, 'chi')
if temp is not None:
temp = np.array(temp.split())
chi = temp.astype(np.float)
chi.shape = xsd[i].xs_shapes['[G]']
xsd[i].set_chi(chi, temperature)
else:
chi = None
temp = get_data(xsdata_elem, 'nu_fission')
if temp is not None:
temp = np.array(temp.split())
nu_fission = temp.astype(np.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'])

99
scripts/openmc-validate-xml Executable file
View file

@ -0,0 +1,99 @@
#!/usr/bin/env python3
import os
import sys
import glob
import lxml.etree as etree
from subprocess import call
from optparse import OptionParser
# Command line parsing
parser = OptionParser()
parser.add_option('-r', '--relaxng-path', dest='relaxng',
help="Path to RelaxNG files.")
parser.add_option('-i', '--input-path', dest='inputs', default=os.getcwd(),
help="Path to OpenMC input files." )
(options, args) = parser.parse_args()
# Colored output
if sys.stdout.isatty():
OK = '\033[92m'
FAIL = '\033[91m'
NOT_FOUND = '\033[93m'
ENDC = '\033[0m'
BOLD = '\033[1m'
else:
OK = ''
FAIL = ''
ENDC = ''
BOLD = ''
NOT_FOUND = ''
# Get absolute paths
if options.relaxng is not None:
relaxng_path = os.path.abspath(options.relaxng)
if options.inputs is not None:
inputs_path = os.path.abspath(options.inputs)
# Search for relaxng path if not set
if options.relaxng is None:
xml_validate_path = os.path.abspath(os.path.dirname(sys.argv[0]))
if "bin" in xml_validate_path:
relaxng_path = os.path.join(xml_validate_path, "..", "share", "relaxng")
elif os.path.join("src", "utils") in xml_validate_path:
relaxng_path = os.path.join(xml_validate_path, "..", "relaxng")
else:
raise Exception("Set RelaxNG path with -r command line option.")
if not os.path.exists(relaxng_path):
raise Exception("RelaxNG path: {0} does not exist, set with -r "
"command line option.".format(relaxng_path))
# Make sure there are .rng files in RelaxNG path
rng_files = glob.glob(os.path.join(relaxng_path, "*.rng"))
if len(rng_files) == 0:
raise Exception("No .rng files found in RelaxNG "
"path: {0}.".format(relaxng_path))
# Get list of xml input files
xml_files = glob.glob(os.path.join(inputs_path, "*.xml"))
if len(xml_files) == 0:
raise Exception("No .xml files found at input path: {0}"
".".format(inputs_path))
# Begin loop around input files
for xml_file in xml_files:
text = "Validating {0}".format(os.path.basename(xml_file))
print(text + '.'*(30 - len(text)), end="")
# Validate the XML file
try:
xml_tree = etree.parse(xml_file)
except etree.XMLSyntaxError as e:
print(BOLD + FAIL + '[XML ERROR]' + ENDC)
print(" {0}".format(e))
continue
# Get xml_filename prefix
xml_prefix = os.path.basename(xml_file)
xml_prefix = xml_prefix.split(".")[0]
# Search for rng file
rng_file = os.path.join(relaxng_path, xml_prefix + ".rng")
if rng_file in rng_files:
# read in RelaxNG
relaxng_doc = etree.parse(rng_file)
relaxng = etree.RelaxNG(relaxng_doc)
# validate xml file again RelaxNG
try:
relaxng.assertValid(xml_tree)
print(BOLD + OK + '[VALID]' + ENDC)
except (etree.DocumentInvalid, TypeError) as e:
print(BOLD + FAIL + '[NOT VALID]' + ENDC)
print(" {0}".format(e))
# RNG file does not exist
else:
print(BOLD + NOT_FOUND + '[NO RELAXNG FOUND]' + ENDC)

72
scripts/openmc-voxel-to-vtk Executable file
View file

@ -0,0 +1,72 @@
#!/usr/bin/env python3
import struct
import sys
from argparse import ArgumentParser
import numpy as np
import h5py
import vtk
_min_version = (2,0)
def main():
# Process command line arguments
parser = ArgumentParser()
parser.add_argument('voxel_file', help='Path to voxel file')
parser.add_argument('-o', '--output', action='store',
default='plot', help='Path to output VTK file.')
args = parser.parse_args()
# Read data from voxel file
fh = h5py.File(args.voxel_file, 'r')
# check version
version = tuple(fh.attrs['version'])
if version < _min_version:
old_version = ".".join(map(str,version))
min_version = ".".join(map(str,_min_version))
err_msg = "This voxel file's version is {}. This script " \
"only supports voxel files with version {} or " \
"higher. Please generate a new voxel file using " \
"a newer version of OpenMC.".format(old_version, min_version)
raise ValueError(err_msg)
dimension = fh.attrs['num_voxels']
width = fh.attrs['voxel_width']
lower_left = fh.attrs['lower_left']
nx, ny, nz = dimension
upper_right = lower_left + width*dimension
grid = vtk.vtkImageData()
grid.SetDimensions(nx+1, ny+1, nz+1)
grid.SetOrigin(*lower_left)
grid.SetSpacing(*width)
# transpose data from OpenMC ordering (zyx) to VTK ordering (xyz)
# and flatten to 1-D array
print("Reading and translating data...")
h5data = fh['data'][...]
data = vtk.vtkIntArray()
data.SetName("id")
# set the array using the h5data array
data.SetArray(h5data, h5data.size, True)
# add data to image grid
grid.GetCellData().AddArray(data)
writer = vtk.vtkXMLImageDataWriter()
if vtk.vtkVersion.GetVTKMajorVersion() > 5:
writer.SetInputData(grid)
else:
writer.SetInput(grid)
if not args.output.endswith(".vti"):
args.output += ".vti"
writer.SetFileName(args.output)
print("Writing VTK file {}...".format(args.output))
writer.Write()
if __name__ == '__main__':
main()