Source code for openmc.data.library

import os
import lxml.etree as ET
import pathlib

import h5py

import openmc
from openmc._xml import clean_indentation, reorder_attributes


[docs]class DataLibrary(list): """Collection of cross section data libraries. This class behaves like a list where each item is a dictionary summarizing cross section data from a single file. The dictionary has keys 'path', 'type', and 'materials'. .. versionchanged:: 0.14.0 This class now behaves like a list rather than requiring you to access the list of libraries through a special attribute. """ def __init__(self): super().__init__() @property def libraries(self): # For backwards compatibility return self
[docs] def get_by_material(self, name, data_type='neutron'): """Return the library dictionary containing a given material. Parameters ---------- name : str Name of material, e.g. 'Am241' data_type : str Name of data type, e.g. 'neutron', 'photon', 'wmp', or 'thermal' .. versionadded:: 0.12 Returns ------- library : dict or None Dictionary summarizing cross section data from a single file; the dictionary has keys 'path', 'type', and 'materials'. """ for library in self: if name in library['materials'] and data_type in library['type']: return library return None
[docs] def remove_by_material(self, name: str, data_type='neutron'): """Remove the library dictionary containing a specific material Parameters ---------- name : str Name of material, e.g. 'Am241' data_type : str Name of data type, e.g. 'neutron', 'photon', 'wmp', or 'thermal' """ library = self.get_by_material(name, data_type) if library is not None: self.remove(library)
[docs] def register_file(self, filename): """Register a file with the data library. Parameters ---------- filename : str or Path Path to the file to be registered. If an ``xml`` file, treat as the depletion chain file without materials. """ if not isinstance(filename, pathlib.Path): path = pathlib.Path(filename) else: path = filename if path.suffix == '.xml': filetype = 'depletion_chain' materials = [] elif path.suffix == '.h5': with h5py.File(path, 'r') as h5file: filetype = h5file.attrs['filetype'].decode()[5:] materials = list(h5file) else: raise ValueError( "File type {} not supported by {}" .format(path.name, self.__class__.__name__)) library = {'path': str(path), 'type': filetype, 'materials': materials} self.append(library)
[docs] def export_to_xml(self, path='cross_sections.xml'): """Export cross section data library to an XML file. Parameters ---------- path : str Path to file to write. Defaults to 'cross_sections.xml'. """ root = ET.Element('cross_sections') # Determine common directory for library paths common_dir = os.path.dirname(os.path.commonprefix( [lib['path'] for lib in self])) if common_dir == '': common_dir = '.' if os.path.relpath(common_dir, os.path.dirname(str(path))) != '.': dir_element = ET.SubElement(root, "directory") dir_element.text = os.path.realpath(common_dir) for library in self: if library['type'] == "depletion_chain": lib_element = ET.SubElement(root, "depletion_chain") else: lib_element = ET.SubElement(root, "library") lib_element.set('materials', ' '.join(library['materials'])) lib_element.set('path', os.path.relpath(library['path'], common_dir)) lib_element.set('type', library['type']) # Clean the indentation to be user-readable clean_indentation(root) # Write XML file reorder_attributes(root) # TODO: Remove when support is Python 3.8+ tree = ET.ElementTree(root) tree.write(str(path), xml_declaration=True, encoding='utf-8', method='xml')
[docs] @classmethod def from_xml(cls, path=None): """Read cross section data library from an XML file. Parameters ---------- path : str, optional Path to XML file to read. If not provided, openmc.config['cross_sections'] will be used. Returns ------- data : openmc.data.DataLibrary Data library object initialized from the provided XML """ data = cls() # If path is None, get the cross sections from the global configuration if path is None: path = openmc.config.get('cross_sections') # Check to make sure we picked up cross sections if path is None: raise ValueError("Either path or openmc.config['cross_sections'] " "must be set") tree = ET.parse(path) root = tree.getroot() if root.find('directory') is not None: directory = root.find('directory').text else: directory = os.path.dirname(path) for lib_element in root.findall('library'): filename = os.path.join(directory, lib_element.attrib['path']) filetype = lib_element.attrib['type'] materials = lib_element.attrib['materials'].split() library = {'path': filename, 'type': filetype, 'materials': materials} data.libraries.append(library) # get depletion chain data dep_node = root.find("depletion_chain") if dep_node is not None: filename = os.path.join(directory, dep_node.attrib['path']) library = {'path': filename, 'type': 'depletion_chain', 'materials': []} data.libraries.append(library) return data