mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-26 21:25:36 -04:00
adding back files to be reviewed
This commit is contained in:
parent
ae28233110
commit
bc09d1ef55
1244 changed files with 301904 additions and 0 deletions
280
scripts/casl_chain.py
Executable file
280
scripts/casl_chain.py
Executable 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
205
scripts/openmc-ace-to-hdf5
Executable 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
106
scripts/openmc-get-photon-data
Executable 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
99
scripts/openmc-make-compton
Executable 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)
|
||||
46
scripts/openmc-make-depletion-chain
Executable file
46
scripts/openmc-make-depletion-chain
Executable 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()
|
||||
240
scripts/openmc-make-depletion-chain-casl
Executable file
240
scripts/openmc-make-depletion-chain-casl
Executable 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()
|
||||
50
scripts/openmc-make-stopping-powers
Executable file
50
scripts/openmc-make-stopping-powers
Executable 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
164
scripts/openmc-make-test-data
Executable 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
325
scripts/openmc-plot-mesh-tally
Executable 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
78
scripts/openmc-track-to-vtk
Executable 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
301
scripts/openmc-update-inputs
Executable 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
225
scripts/openmc-update-mgxs
Executable 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
99
scripts/openmc-validate-xml
Executable 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
72
scripts/openmc-voxel-to-vtk
Executable 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()
|
||||
Loading…
Add table
Add a link
Reference in a new issue