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