def _processIndexChunk(self, what, chunk): key = what.lower() if key not in self._indxMap: raise SerpentToolsException( 'Could not find proper index map for quantity ' '{}'.format(what) ) datum = self._indxMap[key] indx = 0 store = False for line in chunk: if 'SENS' in line: store = True continue if '];' in line: return if store: start = line.index('\'') + 1 if '\'' in line else 0 stop = -1 key = line[start:stop].replace('\'', '').strip() if '%' in key: key = key.split('% ')[1] datum[key] = indx indx += 1 raise SerpentToolsException( "Unexpected index chunk {}".format(chunk))
def getFY(self, parent, energy, daughter, flagEnergy=True): """ Return a specific fission yield given the parent ID, neutron energy and daughter ID If the energy does not exist in the results, the fission yield corresponding to the closest energy is returned Parameters ---------- parent: int or float ID of the parent undergoing fission energy: float neutron energy in MeV daughter: int or float ID of the fission product flagEnergy: boolean If set to true, the function will return the fission yield that matches to the closest energy given by the user Returns ------- indYield: float Independent fission yield cumYield: float Cumulative fission yield Raises ------ SerpentToolsException: If energy is a negative number If parent or fission product are not found """ if energy < 0: raise SerpentToolsException("Energy entry {0} must be positive" " in {1}".format( energy, self.filePath)) if flagEnergy: # obtain the different energies for a specific parent eneList = [ items[1] for items in self.nfy.keys() if parent == items[0] ] # obtain the closest energy value energy = min(eneList, key=lambda x: abs(x - energy)) if eneList else energy if (parent, energy) not in self.nfy.keys(): raise SerpentToolsException("There is no parent {0} with energy " "{1} in {2}".format( parent, energy, self.filePath)) FP = self.nfy[(parent, energy)]['fissProd'] IndYield = self.nfy[(parent, energy)]['indYield'] CumYield = self.nfy[(parent, energy)]['cumYield'] if daughter in FP: return (float(IndYield[FP == daughter]), float(CumYield[FP == daughter])) raise SerpentToolsException( "There is no fission product {0} for parent {1} at energy {2} in " "{3}".format(daughter, parent, energy, self.filePath))
def addUniverse(self, univID, burnup=0, burnIndex=0, burnDays=0): """ Add a universe to this branch. Data for the universes are produced at specific points in time. The additional arguments help track of when the data for this universe were created. A negative value of ``burnup`` indicates the units on burnup are really ``days``. Therefore, the value of ``burnDays`` and ``burnup`` will be swapped. .. warning:: This method will overwrite data for universes that already exist Parameters ---------- univID: int or str Identifier for this universe burnup: float or int Value of burnup [MWd/kgU]. A negative value here indicates the value is really in units of days. burnIndex: int Point in the depletion schedule burnDays: int or float Point in time Returns ------- serpentTools.objects.containers.HomogUniv Empty new universe """ if self.__hasDays is None and burnup: self.__hasDays = burnup < 0 if burnup < 0: if not self.__hasDays: raise SerpentToolsException( self.__mismatchedBurnup.format('negative', 'MWd/kgU')) burnup, burnDays = None if burnup else 0, -burnup else: if self.__hasDays and not burnDays: raise SerpentToolsException( self.__mismatchedBurnup.format('positive', 'days')) burnDays = None if burnup else 0 newUniv = HomogUniv(univID, burnup, burnIndex, burnDays) key = (univID, burnup or burnDays, burnIndex) if key in self.__keys: warning('Overwriting existing universe {} in {}'.format( key, str(self))) else: self.__keys.add(key) self.universes[key] = newUniv return newUniv
def inferReader(filePath): """ Attempt to infer the correct reader type. Parameters ---------- filePath: str or path-like File to be read. Raises ------ SerpentToolsException If a reader cannot be inferred """ filePath = str(filePath) for reg, reader in REGEXES.items(): match = re.match(reg, filePath) if match and match.group() == filePath: debug('Inferred reader for {}: {}' .format(filePath, reader.__name__)) return reader raise SerpentToolsException( 'Failed to infer filetype and thus accurate reader from' 'file path {}. Pass one of the below options to ensure ' 'a specific reader:\n{}'.format(filePath, SUPPORTED_READER_MSG) )
def __init__(self, name, bu, step, day): if not all(xx is None or xx >= 0 for xx in (bu, step, day)): tail = [ '{}: {}'.format(valName, val) for valName, val in zip(('burnup', 'index', 'days'), (bu, step, day)) ] raise SerpentToolsException( "Will not create universe with negative burnup\n{}".format( ', '.join(tail))) NamedObject.__init__(self, name) if step == 0: bu = bu if bu is not None else 0.0 day = day if day is not None else 0.0 self.bu = bu self.step = step self.day = day # Dictionaries: self.b1Exp = {} self.infExp = {} self.b1Unc = {} self.infUnc = {} self.gc = {} self.gcUnc = {} self.__reshaped = rc['xs.reshapeScatter'] self._numGroups = None self.groups = None self.microGroups = None self._numMicroGroups = None
def _gather_univdata(self, func): numAppearances = {} for key in self.universes: if key.universe not in numAppearances: numAppearances[key.universe] = 1 continue numAppearances[key.universe] += 1 # check to make sure all universes appear an identical # number of times burnupVals = set(numAppearances.values()) if len(burnupVals) != 1: raise SerpentToolsException( "Universes appear a different number of times:\n{}".format( numAppearances)) shapeStart = burnupVals.pop(), len(numAppearances) univOrder = tuple(sorted(numAppearances)) univData = {func('universes'): univOrder} for univKey, univ in self.universes.items(): # position in matrix uIndex = univOrder.index(univKey.universe) bIndex = univKey.step for expName, uncName in zip(('infExp', 'b1Exp', 'gc'), ('infUnc', 'b1Unc', 'gcUnc')): expD = getattr(univ, expName) uncD = getattr(univ, uncName) gatherPairedUnivData(univ, uIndex, bIndex, shapeStart, func, expD, uncD, univData) return univData
def _getMatch(self, line, regex, desc): match = regex.search(line) if match is not None: return match raise SerpentToolsException( "Depmtx reader failed to match {} from {}:\n{}".format( desc, self.filePath, line))
def spreadPlot(self, xdim=None, fixed=None, sampleKwargs=None, meanKwargs=None, ax=None, xlabel=None, ylabel=None, logx=False, logy=False, loglog=False, legend=True): """ Plot the mean tally value against all sampled detector data. Parameters ---------- xdim: str Bin index to place on the x-axis fixed: None or dict Dictionary controlling the reduction in data down to one dimension sampleKwargs : dict, optional Additional matplotlib-acceptable arguments to be passed into the plot when plotting data from unique runs, e.g. ``{"c": k, "alpha": 0.5}``. meanKwargs : dict, optional Additional matplotlib-acceptable argumentst to be used when plotting the mean value, e.g. ``{"c": "b", "marker": "o"}`` {ax} {xlabel} {ylabel} {logx} {logy} {loglog} {legend} Returns ------- {rax} """ if self.allTallies is None: raise AttributeError( "allTallies is None, cannot plot all tally data") samplerData = self.slice(fixed, 'tallies') slices = self._getSlices(fixed) if len(samplerData.shape) != 1: raise SerpentToolsException( 'Data must be constrained to 1D, not {}'.format( samplerData.shape)) xdata, autoX = self._getPlotXData(xdim, samplerData) xlabel = xlabel or autoX if sampleKwargs is None: sampleKwargs = {"c": "k", "alpha": 0.5, "marker": ""} if meanKwargs is None: meanKwargs = {"c": "#0173b2", "marker": "o"} ax = ax or pyplot.gca() for data in self.allTallies: ax.plot(xdata, data[slices], **sampleKwargs) ax.plot(xdata, samplerData, label='Mean value', **meanKwargs) formatPlot(ax, logx=logx, logy=logy, loglog=loglog, xlabel=xlabel, ylabel=ylabel, legend=legend) return ax
def getXS(self, universe, isotope, reaction, isomeric=0): """ Return the group-wise micro cross-sections for a specific isotope, and reaction Parameters ---------- universe: string universe ID, e.g., `0` isotope: int or float ID of the isotope (ZZAAA0/1) reaction: int MT reaction, e.g., 102 --> (n,gamma) Special flag: int or float Isomeric state or fission yield distribution number Default is zero Returns ------- xsVal: numpy.ndarray Group-wise cross-section values xsUnc: numpy.ndarray Group-wise uncertainty values Raises ------ SerpentToolsException: If the universe does not exist If the isotope's format is incorrect (not ZZAAA0/1) """ if universe not in self.xsVal.keys(): raise SerpentToolsException( "Universe {0} does not exist in {1}".format( universe, self.filePath)) if isotope < 10010 or isotope > 1000000: raise SerpentToolsException("Isotope {0} is not properly formatted" " ZZAAA0/1 in {1}".format( isotope, self.filePath)) key = (isotope, reaction, isomeric) if key in self.xsVal[universe]: return (self.xsVal[universe][key], self.xsUnc[universe][key]) raise SerpentToolsException("There is no isotope {0} with reaction {1}" " and isomeric flag {2} in {3}".format( isotope, reaction, isomeric, self.filePath))
def orderedUniv(self): """Universe keys sorted by ID and by burnup""" if not any(self): raise SerpentToolsException( 'No universes stored on branch {}'.format(str(self))) if self._orderedUniverses is None: self._orderedUniverses = tuple( sorted(self, key=lambda tpl: (tpl.universe, tpl.step))) return self._orderedUniverses
def _inspectData(self): """ensure the parser grabbed expected materials.""" obtainedRes = (self._counter['meta'] // self._numUniv if self._numUniv else self._counter['meta']) if obtainedRes != self._counter['rslt']: raise SerpentToolsException( "The file {} is not complete. The reader found {} universes, " "{} time-points, and {} overall result points ".format( self.filePath, self._numUniv, self._counter['rslt'], self._counter['meta'])) if not self.resdata and not self.metadata: for keys, dictUniv in self.universes.items(): if dictUniv.hasData(): return raise SerpentToolsException( "metadata, resdata and universes are all empty " "from {} and <results.expectGcu> is True".format( self.filePath))
def slice(self, fixed, data='tallies'): """ Return a view of the reshaped array where certain axes are fixed Parameters ---------- fixed: dict dictionary to aid in the restriction on the multidimensional array. Keys correspond to the various grids present in ``indexes`` while the values are used to data: {'tallies', 'errors', 'scores'} Which data set to slice Returns ------- :class:`numpy.ndarray` View into the respective data where certain dimensions have been removed Raises ------ SerpentToolsException If the data has not been reshaped or is None [e.g. scores] KeyError If the data set to slice not in the allowed selection """ if not self._isReshaped(): raise SerpentToolsException( 'Slicing requires detector to be reshaped') if data not in self._map: raise KeyError( 'Data argument {} not in allowed options' '\n{}'.format(data, ', '.join(self._map.keys()))) work = self._map[data] if work is None: raise SerpentToolsException( '{} data for detector {} is None. ' 'Cannot perform slicing'.format(data, self.name)) if not fixed: return work return work[self._getSlices(fixed)]
def _processNumChunk(self, chunk): chunk = [line for line in chunk if 'SENS' in line] for line in chunk: split = line.split() attrN = 'n' + split[0].split('_')[-1].capitalize() if hasattr(self, attrN): setattr(self, attrN, int(split[-1][:-1])) else: raise SerpentToolsException( 'Attempted to set attribute {} from number block'.format( attrN))
def _precheck(self): """do a quick scan to ensure this looks like mdx file.""" with open(self.filePath) as fid: if fid is None: raise IOError("Attempting to read on a closed file.\n" "Parser: {}\nFile: {}".format( self, self.filePath)) for tline in fid: if 'NFY' in tline: return raise SerpentToolsException("Fission yields values were not " "found in {}".format(self.filePath))
def reshape(self): """ Reshape the tally data into a multidimensional array This method reshapes the tally and uncertainty data into arrays where the array axes correspond to specific bin types. If a detector was set up to tally two group flux in a 5 x 5 xy mesh, then the resulting tally data would be in a 50 x 12/13 matrix in the original ``detN.m`` file. The tally data and relative error would be rebroadcasted into 2 x 5 x 5 arrays, and the indexing information is stored in ``self.indexes`` Returns ------- shape: list Dimensionality of the resulting array Raises ------ SerpentToolsException: If the bin data has not been loaded """ if self.bins is None: raise SerpentToolsException('Tally data for detector {} has not ' 'been loaded'.format(self.name)) if self.__reshaped: warning('Data has already been reshaped') return shape = [] self.indexes = OrderedDict() hasScores = self.bins.shape[1] == 13 if self.bins.shape[0] == 1: self.tallies = self.bins[0, 10] self.errors = self.bins[0, 11] if hasScores: self.scores = self.bins[0, 12] else: for index in range(1, 10): uniqueVals = unique(self.bins[:, index]) if len(uniqueVals) > 1: indexName = self._indexName(index) self.indexes[indexName] = array(uniqueVals, dtype=int) - 1 shape.append(len(uniqueVals)) self.tallies = self.bins[:, 10].reshape(shape) self.errors = self.bins[:, 11].reshape(shape) if hasScores: self.scores = self.bins[:, 12].reshape(shape) self._map = {'tallies': self.tallies, 'errors': self.errors, 'scores': self.scores} self.__reshaped = True return shape
def getUniv(self, univ, burnup=None, index=None, timeDays=None): """ Return a specific universe given the ID and time of interest If more than one time parameter is given, the hierarchy of search is: index (highest priority), burnup, timeDays (lowest priority) Parameters ---------- univ: str Unique str for the desired universe burnup: float or int Burnup [MWd/kgU] of the desired universe timeDays: float or int Time [days] of the desired universe index: int Point of interest in the burnup/days index Returns ------- :py:class:`~serpentTools.objects.containers.HomogUniv` Requested universe Raises ------ KeyError: If the requested universe could not be found SerpentToolsException: If burnup, days and index are not given """ if index is None and burnup is None and timeDays is None: raise SerpentToolsException( 'Burnup, time or index are required inputs') searchIndex = (2 if index is not None else 1 if burnup is not None else 3) searchValue = (index if index is not None else burnup if burnup is not None else timeDays) if searchIndex == 2 and searchValue < 1: # index must be non-zero raise KeyError( 'Index read is {}, however only integers above zero are ' 'allowed'.format(searchValue)) for key, dictUniv in iteritems(self.universes): if key[0] == univ and key[searchIndex] == searchValue: debug('Found universe that matches with keys {}'.format(key)) return self.universes[key] searchName = ('index ' if index else 'burnup ' if burnup else 'timeDays ') raise KeyError( 'Could not find a universe that matched requested universe {} and ' '{} {}'.format(univ, searchName, searchValue))
def getUniv(self, univ, burnup=None, index=None, timeDays=None): """ Return a specific universe given the ID and time of interest Parameters ---------- univ: str Unique str for the desired universe burnup: float or int, optional Burnup [MWd/kgU] of the desired universe timeDays: float or int, optional Time [days] of the desired universe index: int, optinal Point of interest in the burnup/days index Returns ------- :class:`~serpentTools.objects.HomogUniv` Requested universe Raises ------ KeyError: If the requested universe could not be found :class:`~serpentTools.SerpentToolsException` If burnup, days and index are not given """ if index is None and burnup is None and timeDays is None: raise SerpentToolsException( 'Burnup, time or index are required inputs') searchKey = UnivTuple(univ, burnup, index, timeDays) # check if key is exactly present universe = self.universes.get(searchKey) if universe is not None: return universe for key, universe in iteritems(self.universes): for uItem, sItem in zip(key, searchKey): if sItem is None: continue elif uItem != sItem: break else: return universe raise KeyError( "Could not find a universe that matches {}".format(searchKey))
def _storeResData(self, varNamePy, varVals): """Process time-dependent results data""" vals = str2vec(varVals) # convert the string to float numbers stored = self._tempArrays.get(varNamePy) if stored is None: self._tempArrays[varNamePy] = ListOfArrays(vals) elif len(stored) < self._counter['rslt']: # append this data only once! try: stored.append(vals) except Exception as ee: raise SerpentToolsException( "Error in appending {} into {} of resdata:\n{}".format( varNamePy, vals, str(ee)))
def __processEnergyChunk(self, chunk): for line in chunk: if 'SENS' == line[:4]: break else: raise SerpentToolsException("Could not find SENS parameter " "in energy chunk {}".format(chunk[:3])) splitLine = line.split() varName = splitLine[0].split('_')[1:] varValues = str2vec(splitLine[3:-1]) if varName[0] == 'E': self.energies = varValues elif varName == ['LETHARGY', 'WIDTHS']: self.lethargyWidths = varValues else: warning("Unanticipated energy setting {}".format(splitLine[0]))
def _storeResData(self, varNamePy, varVals): """Process time-dependent results data""" vals = str2vec(varVals) # convert the string to float numbers if varNamePy in self.resdata.keys(): # extend existing matrix currVar = self.resdata[varNamePy] ndim = 1 if len(currVar.shape) == 2: ndim = currVar.shape[0] if ndim < self._counter['rslt']: # append this data only once! try: stacked = vstack([self.resdata[varNamePy], vals]) self.resdata[varNamePy] = stacked except Exception as ee: raise SerpentToolsException( "Error in appending {} into {} of resdata:\n{}". format(varNamePy, vals, str(ee))) else: self.resdata[varNamePy] = array(vals) # define a new matrix
def getUniv(self, univID, burnup=None, index=None, days=None): """ Return a specific universe given the ID and time of interest Parameters ---------- univID: str Unique ID for the desired universe burnup: float, optional Burnup [MWd/kgU] of the desired universe index: int, optional Point of interest in the burnup index days : float, optional Point in time [d] for the desired universe Returns ------- :class:`~serpentTools.objects.HomogUniv` Requested universe Raises ------ KeyError If the requested universe could not be found :class:`serpentTools.SerpentToolsException` If neither burnup nor index are given """ if burnup is None and index is None: raise SerpentToolsException('Burnup or index are required inputs') searchKey = UnivTuple(univID, burnup, index, days) for key, universe in self.items(): for uItem, sItem in zip(key, searchKey): if sItem is None: continue if uItem != sItem: break else: return universe raise KeyError( "Could not find a universe matching {}".format(searchKey))
def getUniv(self, univID, burnup=None, index=None): """ Return a specific universe given the ID and time of interest If burnup and index are given, burnup is used to search Parameters ---------- univID: int Unique ID for the desired universe burnup: float or int Burnup [MWd/kgU] of the desired universe index: int Point of interest in the burnup index Returns ------- :py:class:`~serpentTools.objects.containers.HomogUniv` Requested universe Raises ------ KeyError: If the requested universe could not be found SerpentToolsException: If neither burnup nor index are given """ if burnup is None and index is None: raise SerpentToolsException('Burnup or index are required inputs') searchIndex = 2 if index is not None else 1 searchValue = index if index is not None else burnup for key in self.__keys: if key[0] == univID and key[searchIndex] == searchValue: debug('Found universe that matches with keys {}'.format(key)) return self.universes[key] searchName = 'burnup' + ('' if index is None else ' index') raise KeyError( 'Could not find a universe that matched requested universe {} and ' '{} {}'.format(univID, searchName, searchValue))
def inferReader(filePath): """ Attempt to infer the correct reader type. Parameters ---------- filePath: str File to be read. Raises ------ SerpentToolsException If a reader cannot be inferred """ for reg, reader in six.iteritems(REGEXES): match = re.match(reg, filePath) if match and match.group() == filePath: debug('Inferred reader for {}: {}'.format(filePath, reader.__name__)) return reader raise SerpentToolsException( 'Failed to infer filetype and thus accurate reader from' 'file path {}'.format(filePath))
def __init__(self, name, bu, step, day): if not all(isNonNeg(xx) for xx in (bu, step, day)): tail = [ '{}: {}'.format(name, val) for name, val in zip(('burnup', 'index', 'days'), (bu, step, day)) ] raise SerpentToolsException( "Will not create universe with negative burnup\n{}".format( ', '.join(tail))) NamedObject.__init__(self, name) if step is not None and step == 0: bu = bu if bu is not None else 0.0 day = day if day is not None else 0.0 self.bu = bu self.step = step self.day = day # Dictionaries: self.b1Exp = {} self.infExp = {} self.b1Unc = {} self.infUnc = {} self.metadata = {}
def cleanDetChunk(chunk): """ Return the name of the detector [grid] and the array of data. Parameters ---------- chunk: list Chunk of text from the output file pertaining to this section. Should begin with ``DET<name>[<grid>] = [`` with array data on the subsequent lines Returns ------- str: Name of the detector including grid characters numpy.ndarray: Array containing numeric data from the chunk Raises ------ SerpentToolsException: If the name of the detector could not be determined """ if chunk[0][:3] != 'DET': raise SerpentToolsException( "Could not determine name of detector from chunk: {}".format( chunk[0])) leader = chunk.pop(0) name = leader.split()[0][3:] if chunk[-1][:2] == '];': chunk.pop(-1) nCols = len(chunk[0].split()) data = empty((len(chunk), nCols), order='F') for indx, row in enumerate(chunk): data[indx] = str2vec(row) return name, data
def meshPlot(self, xdim, ydim, what='tallies', fixed=None, ax=None, cmap=None, logColor=False, xlabel=None, ylabel=None, logx=False, logy=False, loglog=False, **kwargs): """ Plot tally data as a function of two mesh dimensions Parameters ---------- xdim: str Primary dimension - will correspond to x-axis on plot ydim: str Secondary dimension - will correspond to y-axis on plot what: {'tallies', 'errors', 'scores'} Color meshes from tally data, uncertainties, or scores fixed: None or dict Dictionary controlling the reduction in data down to one dimension {ax} {cmap} logColor: bool If true, apply a logarithmic coloring to the data positive data {xlabel} {ylabel} {logx} {logy} {loglog} {kwargs} :py:func:`~matplotlib.pyplot.pcolormesh` Returns ------- {rax} Raises ------ SerpentToolsException If data to be plotted, with or without constraints, is not 1D KeyError If the data set by ``what`` not in the allowed selection ValueError If the data contains negative quantities and ``logColor`` is ``True`` See Also -------- * :py:meth:`~serpentTools.objects.containers.DetectorBase.slice` * :py:func:`matplotlib.pyplot.pcolormesh` * :py:func:`~serpentTools.plot.cartMeshPlot` """ if fixed: for qty, name in zip((xdim, ydim), ('x', 'y')): if qty in fixed: raise SerpentToolsException( 'Requested {} dimension {} is one of the axis to be constrained. ' .format(name, qty)) data = self.slice(fixed, what) dShape = data.shape if len(dShape) != 2: raise SerpentToolsException( 'Data must be 2D for mesh plot, currently is {}.\nConstraints:' '{}'.format(dShape, fixed)) xgrid = self._getGrid(xdim) ygrid = self._getGrid(ydim) if data.shape != (ygrid.size - 1, xgrid.size - 1): data = data.T ax = cartMeshPlot(data, xgrid, ygrid, ax, cmap, logColor, **kwargs) ax.set_xlabel(xlabel or xdim) ax.set_ylabel(ylabel or ydim) if loglog or logx: ax.set_xscale('log') if loglog or logy: ax.set_yscale('log') return ax
def plot(self, xUnits, yUnits=None, timePoints=None, names=None, zai=None, materials=None, ax=None, legend=None, logx=False, logy=False, loglog=False, labelFmt=None, xlabel=None, ylabel=None, ncol=1, **kwargs): """ Plot properties for all materials in this file together. Parameters ---------- xUnits: str If ``xUnits`` is given and ``yUnits`` is ``None``, then the plotted data will be ``xUnits`` against ``'days'`` name of x value to obtain, e.g. ``'days'``, ``'burnup'`` yUnits: str name of y value to return, e.g. ``'adens'``, ``'ingTox'`` timePoints: list or None If given, select the time points according to those specified here. Otherwise, select all points .. deprecated:: 0.7.0 Will plot against all time points names: str or list or None If given, plot values corresponding to these isotope names. Otherwise, plot values for all isotopes. zai: int or list or None If given, plot values corresponding to these isotope ``ZZAAAI`` values. Otherwise, plot for all isotopes .. versionadded:: 0.5.1 materials: None or list Selection of materials from ``self.materials`` to plot. If None, plot all materials, potentially including ``tot`` {ax} {legend} {xlabel} Otherwise, use ``xUnits`` {ylabel} Otherwise, use ``yUnits`` {logx} {logy} {loglog} {matLabelFmt} {ncol} {kwargs} :py:func:`matplotlib.pyplot.plot` Returns ------- {rax} See Also -------- * :py:func:`~serpentTools.objects.materials.DepletedMaterial.getValues` * :py:func:`matplotlib.pyplot.plot` * :py:meth:`str.format` - used for formatting labels * :py:func:`~serpentTools.objects.materials.DepletedMaterial.plot` Raises ------ KeyError If x axis units are not ``'days'`` nor ``'burnup'`` SerpentToolsException If the materials dictionary does not contain any items """ if yUnits is None: yUnits = xUnits xUnits = 'days' if not self.materials: raise SerpentToolsException("Material dictionary is empty") if xUnits not in ('days', 'burnup'): raise KeyError("Plot method only uses x-axis data from <days> and " "<burnup>, not {}".format(xUnits)) missing = set() ax = ax or pyplot.gca() materials = materials or self.materials.keys() labelFmt = labelFmt or '{mat} {iso}' for mat in materials: if mat not in self.materials: missing.add(mat) continue ax = self.materials[mat].plot( xUnits, yUnits, timePoints, names, zai, ax, legend=False, xlabel=xlabel, ylabel=ylabel, logx=False, logy=False, loglog=False, labelFmt=labelFmt, **kwargs) if missing: warning("The following materials were not found in materials " "dictionary: {}".format(', '.join(missing))) formatPlot(ax, legend=legend, legendcols=ncol, logx=logx, logy=logy, loglog=loglog, xlabel=xlabel or DEPLETION_PLOT_LABELS[xUnits], ylabel=ylabel or DEPLETION_PLOT_LABELS[yUnits], ) return ax
def read(filePath, reader='infer'): """ Simple entry point to read a file and obtain the processed reader. Parameters ---------- filePath: str Path to the file to be reader reader: str or callable Type of reader to use. If a string is given, then the actions described below will happen. If callable, then that function will be used with the file path as the first argument. =============== ========================================== String argument Action =============== ========================================== infer Infer the correct reader based on the file branch ``BranchingReader`` bumat ``BumatReader`` dep ``DepletionReader`` det ``DetectorReader`` fission ``FissionMatrixReader`` history ``HistoryReader`` microxs ``MdxReader`` results ``ResultsReader`` sensitivity ``SensitivityReader`` xsplot ``XSPlotReader`` =============== ========================================== Returns ------- serpentTools.objects.base.BaseReader Correct subclass corresponding to the file type Raises ------ AttributeError If the object created by the reader through ``reader(filePath)`` does not have a ``read`` method. SerpentToolsException If the reader could not be inferred or if the requested reader string is not supported NotImplementedError This has the ability to load in readers that may not be complete, and thus the ``read`` method may raise this error. """ if isinstance(reader, str): if reader == 'infer': loader = inferReader(filePath) else: if reader in READERS: loader = READERS[reader] else: raise SerpentToolsException( 'Reader type {} not supported. Try one of the below:\n{}'. format(reader, SUPPORTED_READER_MSG)) else: assert callable(reader), ('Reader {} is not callable'.format( str(reader))) loader = reader returnedFromLoader = loader(filePath) returnedFromLoader.read() return returnedFromLoader
def _precheck(self): with open(self.filePath) as stream: line = stream.readline().strip() if line[:4] != 't = ': raise SerpentToolsException( "File does not appear to be a depmtx file")
def _postcheck(self): if not self.sensitivities: raise SerpentToolsException("No sensitivity data stored on reader") if not self.energyIntegratedSens: raise SerpentToolsException("No energy integrated sensitivities " "stored on reader")