Source code for pyne.xs.cache

"""This module provides a cross section cache which automatically extracts 
cross-sections from provided nuclear data sets."""
import sys
import inspect
from warnings import warn

from itertools import product
from collections import MutableMapping

import numpy as np
import tables as tb

from pyne import nucname
from pyne.pyne_config import pyne_conf
from pyne.xs.models import partial_energy_matrix, phi_g, same_arr_or_none
from pyne.xs import data_source
from pyne.utils import QAWarning

warn(__name__ + " is not yet QA compliant.", QAWarning)

if sys.version_info[0] > 2:
  basestring = str

def _valid_group_struct(E_g):
    if E_g is None:
        return None
    E_g = np.asarray(E_g, dtype='f8')
    if E_g[0] < E_g[-1]:
        E_g = E_g[::-1]
    return E_g


###############################################################################
### Set up a cross-section cache so the same data isn't loaded repetitively ###
###############################################################################

[docs]class XSCache(MutableMapping): """A lightweight multigroup cross section cache based off of python dictionaries. This relies on a list of cross section data source from which discretized group constants may be computed from raw, underlying data. Normally this requires that some cross section data be built into nuc_data. A default instance of this class is provided (pyne.xs.cache.xs_cache). Parameters ---------- group_struct : array-like of floats, optional Energy group structure E_g [MeV] from highest-to-lowest energy, length G+1. If the group structure is not present in the cache or is None, all cross sections pulled from the sources will not be discretized or collapsed. data_sources : list of DataSources and DataSource classes, optional Sequence of DataSource obejects or classes from which to grab cross section data. Data from a source earlier in the sequence (eg, index 1) will take precednce over data later in the sequence (eg, index 5). If a class is given rather than an object, the class is instantiated. """ def __init__(self, group_struct=None, data_sources=(data_source.CinderDataSource, data_source.OpenMCDataSource, data_source.SimpleDataSource, data_source.EAFDataSource, data_source.NullDataSource,)): self._cache = {} self.data_sources = [] for ds in data_sources: if inspect.isclass(ds): ds = ds(dst_group_struct=group_struct) if ds.exists: self.data_sources.append(ds) self._cache['E_g'] = _valid_group_struct(group_struct) self._cache['phi_g'] = None # # Mutable mapping pass-through interface # def __len__(self): return len(self._cache) def __iter__(self): return iter(self._cache) def __contains__(self, key): return (key in self._cache) def __delitem__(self, key): del self._cache[key] # # Explicit overrides # def __getitem__(self, key): """Key lookup by via custom loading from the nuc_data database file.""" if (key not in self._cache) and not isinstance(key, basestring): E_g = self._cache['E_g'] if E_g is None: for ds in self.data_sources: xsdata = ds.reaction(*key) if xsdata is not None: self._cache[key] = xsdata break else: kw = dict(zip(['nuc', 'rx', 'temp'], key)) kw['dst_phi_g'] = self._cache['phi_g'] for ds in self.data_sources: xsdata = ds.discretize(**kw) if xsdata is not None: self._cache[key] = xsdata break else: raise KeyError # Return the value requested return self._cache[key] def __setitem__(self, key, value): """Key setting via custom cache functionality.""" # Set the E_g if (key == 'E_g'): value = _valid_group_struct(value) cache_value = self._cache['E_g'] self.clear() self._cache['phi_g'] = None for ds in self.data_sources: ds.dst_group_struct = value elif (key == 'phi_g'): value = value if value is None else np.asarray(value, dtype='f8') cache_value = self._cache['phi_g'] if same_arr_or_none(value, cache_value): return E_g = self._cache['E_g'] if len(value) + 1 == len(E_g): self.clear() else: raise ValueError("phi_g does not match existing group structure E_g!") # Set the value normally self._cache[key] = value
[docs] def clear(self): """Clears the cache, retaining E_g and phi_g.""" E_g, phi_g = self._cache['E_g'], self._cache['phi_g'] self._cache.clear() self._cache['E_g'], self._cache['phi_g'] = E_g, phi_g
[docs] def load(self, temp=300.0): """Loads the cross sections from all data sources.""" for ds in self.data_sources: ds.load(temp=temp)
# Make a singleton of the cross-section cache xs_cache = XSCache()