diff --git a/openmc/_utils.py b/openmc/_utils.py index 83455c17aa..d16f556231 100644 --- a/openmc/_utils.py +++ b/openmc/_utils.py @@ -1,3 +1,4 @@ +import hashlib import os.path from pathlib import Path from urllib.parse import urlparse @@ -6,13 +7,15 @@ from urllib.request import urlopen _BLOCK_SIZE = 16384 -def download(url): +def download(url, checksum=None): """Download file from a URL Parameters ---------- url : str URL from which to download + checksum : str or None + MD5 checksum to check against Returns ------- @@ -46,4 +49,13 @@ def download(url): downloaded, downloaded * 100. / file_size) print(status + '\b'*len(status), end='') print('') + + if checksum is not None: + downloadsum = hashlib.md5(open(basename, 'rb').read()).hexdigest() + if downloadsum != checksum: + raise IOError("MD5 checksum for {} does not match. If this is your first " + "time receiving this message, please re-run the script. " + "Otherwise, please contact OpenMC developers by emailing " + "openmc-users@googlegroups.com.".format(basename)) + return basename diff --git a/scripts/openmc-make-test-data b/scripts/openmc-make-test-data new file mode 100755 index 0000000000..f2ae118c1b --- /dev/null +++ b/scripts/openmc-make-test-data @@ -0,0 +1,149 @@ +#!/usr/bin/env python3 + +""" +Download ENDF/B-VII.1 ENDF and ACE files from NNDC and generate a full HDF5 +library with incident neutron, incident photon, and thermal scattering 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/' +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') +] + + +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) + + +os.makedirs('nndc_hdf5/photon', exist_ok=True) + +with tempfile.TemporaryDirectory() as tmpdir: + # Save current working directory and temporarily change dir + pwd = os.getcwd() + 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 = os.path.join('nndc_hdf5', 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 = os.path.join('nndc_hdf5', 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 = 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)) + data = openmc.data.IncidentPhoton.from_endf(photo_file, atom_file) + + # Write HDF5 file and register it + outfile = os.path.join('nndc_hdf5', 'photon', element + '.h5') + data.export_to_hdf5(outfile, 'w', 'earliest') + library.register_file(outfile) + + library.export_to_xml(os.path.join('nndc_hdf5', 'cross_sections.xml')) + + # ========================================================================= + # CREATE TARBALL AND MOVE BACK + + test_tar = os.path.join(pwd, 'nndc_hdf5_test.tar.xz') + with tarfile.open(test_tar, 'w:xz') as txz: + txz.add('nndc_hdf5') + + # Change back to original directory + os.chdir(pwd)