diff --git a/openmc/filter.py b/openmc/filter.py index bcbe61eb82..e7e527531f 100644 --- a/openmc/filter.py +++ b/openmc/filter.py @@ -282,12 +282,39 @@ class Filter(object): merged_filter = copy.deepcopy(self) # Merge unique filter bins - merged_bins = list(set(self.bins + filter.bins)) + merged_bins = list(set(list(self.bins) + list(filter.bins))) merged_filter.bins = merged_bins merged_filter.num_bins = len(merged_bins) return merged_filter + def is_subset(self, other): + """Determine if another filter is a subset of this filter. + + If all of the bins in the other filter are included as bins in this + filter, then it is a subset of this filter. + + Parameters + ---------- + other : Filter + The filter to query as a subset of this filter + + Returns + ------- + boolean + Whether or not the other filter is a subset of this filter + """ + if not isinstance(other, Filter): + return False + elif self.type != other.type: + return False + + for bin in other.bins: + if bin not in self.bins: + return False + + return True + def get_bin_index(self, filter_bin): """Returns the index in the Filter for some bin. diff --git a/openmc/mgxs/mgxs.py b/openmc/mgxs/mgxs.py index 6d975502ef..18e87bba10 100644 --- a/openmc/mgxs/mgxs.py +++ b/openmc/mgxs/mgxs.py @@ -158,6 +158,10 @@ class MultiGroupXS(object): def name(self): return self._name + @property + def xs_type(self): + return self._xs_type + @property def domain(self): return self._domain @@ -280,7 +284,9 @@ class MultiGroupXS(object): if subdomains != 'all': cv.check_type('subdomains', subdomains, Iterable, Integral) - if subdomains == 'all': + if subdomains == 'all' and self.domain_type != 'distribcell': + indices = [0] + elif subdomains == 'all' and self.domain_type == 'distribcell': tally = self.tallies.values()[0] domain_filter = tally.find_filter(self.domain_type) num_subdomains = domain_filter.num_bins @@ -331,7 +337,9 @@ class MultiGroupXS(object): if indices != 'all': cv.check_type('offsets', indices, Iterable, Integral) - if indices == 'all': + if indices == 'all' and self.domain_type != 'distribcell': + subdomains = [self.domain.id] + elif indices == 'all' and self.domain_type == 'distribcell': tally = self.tallies.values()[0] domain_filter = tally.find_filter(self.domain_type) num_subdomains = domain_filter.num_bins @@ -382,6 +390,7 @@ class MultiGroupXS(object): # Create a domain Filter object domain_filter = openmc.Filter(self.domain_type, self.domain.id) + domain_filter.num_bins = 1 for score, key, filters in zip(scores, keys, all_filters): self.tallies[key] = openmc.Tally(name=self.name) @@ -413,8 +422,14 @@ class MultiGroupXS(object): statepoint.read_results() # Create Tallies to search for in StatePoint - if self.tallies is None: - self.create_tallies() + self.create_tallies() + + if self.domain_type == 'distribcell': + filters = [] + filter_bins = [] + else: + filters = [self.domain_type] + filter_bins = [(self.domain.id,)] # Find, slice and store Tallies from StatePoint # The tally slicing is needed if tally merging was used @@ -422,7 +437,8 @@ class MultiGroupXS(object): sp_tally = statepoint.get_tally(tally.scores, tally.filters, tally.nuclides, estimator=tally.estimator) - sp_tally = sp_tally.get_slice(scores=tally.scores, nuclides=tally.nuclides) + sp_tally = sp_tally.get_slice(tally.scores, filters, + filter_bins, tally.nuclides) self.tallies[tally_type] = sp_tally def get_xs(self, groups='all', subdomains='all', value='mean'): @@ -575,7 +591,7 @@ class MultiGroupXS(object): # Append cross-section data if it has been computed if self.xs_tally is not None: if subdomains == 'all': - subdomains = self.get_subdomain_indices() + subdomains = self.get_subdomains() # Loop over all subdomains for subdomain in subdomains: @@ -697,8 +713,7 @@ class MultiGroupXS(object): import h5py raise NotImplementedError('HDF5 storage is not yet implemented') - def export_xs_data(self, filename='mgxs', directory='mgxs', format='csv', - groups='indices', summary=None): + def export_xs_data(self, filename='mgxs', directory='mgxs', format='csv'): """Export the multi-group cross-section data to a file. This routine leverages the functionality in the Pandas library to @@ -742,20 +757,41 @@ class MultiGroupXS(object): filename = filename.replace(' ', '-') # Get a Pandas DataFrame for the data - df = self.get_pandas_dataframe(groups, summary) + df = self.get_pandas_dataframe() + + # Capitalize column label strings + df.columns = map(str.title, df.columns) # Export the data using Pandas IO API if format == 'csv': - df.to_csv(filename + '.csv') + df.to_csv(filename + '.csv', index=False) elif format == 'excel': - # FIXME: Overwrite column CrossScores with scores - df.to_excel(filename + '.xls') + df.to_excel(filename + '.xls', index=False) elif format == 'pickle': df.to_pickle(filename + '.pkl') elif format == 'latex': + if self.domain_type == 'distribcell': + msg = 'Unable to export distribcell multi-group cross-section' \ + 'data to a LaTeX table' + raise NotImplementedError(msg) + # FIXME: Insert greek letters - # FIXME: Need to put document header around string - df.to_latex(filename + '.tex') + + df.to_latex(filename + '.tex', bold_rows=True, + longtable=True, index=False) + + # Surround LaTeX table with code needed to run pdflatex + with open(filename + '.tex','r') as original: + data = original.read() + with open(filename + '.tex','w') as modified: + modified.write( + '\\documentclass[preview, 12pt, border=1mm]{standalone}\n') + modified.write('\\usepackage{caption}\n') + modified.write('\\usepackage{longtable}\n') + modified.write('\\usepackage{booktabs}\n') + modified.write('\\begin{document}\n\n') + modified.write(data) + modified.write('\n\\end{document}') def get_pandas_dataframe(self, groups='indices', summary=None): """Build a Pandas DataFrame for the MultiGroupXS data. @@ -799,7 +835,7 @@ class MultiGroupXS(object): df = self.xs_tally.get_pandas_dataframe(summary=summary) # Remove the score column since it is homogeneous and redundant - if summary: + if summary and self.domain_type == 'distribcell': df = df.drop('score', level=0, axis=1) else: df = df.drop('score', axis=1) @@ -836,7 +872,7 @@ class TotalXS(MultiGroupXS): def __init__(self, domain=None, domain_type=None, groups=None, name=''): super(TotalXS, self).__init__(domain, domain_type, groups, name) - self.xs_type = 'total' + self._xs_type = 'total' def create_tallies(self): """Construct the OpenMC tallies needed to compute this cross-section.""" @@ -849,6 +885,7 @@ class TotalXS(MultiGroupXS): # Create the non-domain specific Filters for the Tallies group_edges = self.energy_groups.group_edges energy_filter = openmc.Filter('energy', group_edges) + energy_filter.num_bins = self.num_groups filters = [[energy_filter], [energy_filter]] # Initialize the Tallies @@ -867,7 +904,7 @@ class TransportXS(MultiGroupXS): def __init__(self, domain=None, domain_type=None, groups=None, name=''): super(TransportXS, self).__init__(domain, domain_type, groups, name) - self.xs_type = 'transport' + self._xs_type = 'transport' def create_tallies(self): """Construct the OpenMC tallies needed to compute this cross-section.""" @@ -881,6 +918,8 @@ class TransportXS(MultiGroupXS): group_edges = self.energy_groups.group_edges energy_filter = openmc.Filter('energy', group_edges) energyout_filter = openmc.Filter('energyout', group_edges) + energy_filter.num_bins = self.num_groups + energyout_filter.num_bins = self.num_groups filters = [[energy_filter], [energy_filter], [energyout_filter]] # Initialize the Tallies @@ -905,7 +944,7 @@ class AbsorptionXS(MultiGroupXS): def __init__(self, domain=None, domain_type=None, groups=None, name=''): super(AbsorptionXS, self).__init__(domain, domain_type, groups, name) - self.xs_type = 'absorption' + self._xs_type = 'absorption' def create_tallies(self): """Construct the OpenMC tallies needed to compute this cross-section.""" @@ -918,6 +957,7 @@ class AbsorptionXS(MultiGroupXS): # Create the non-domain specific Filters for the Tallies group_edges = self.energy_groups.group_edges energy_filter = openmc.Filter('energy', group_edges) + energy_filter.num_bins = self.num_groups filters = [[energy_filter], [energy_filter]] # Initialize the Tallies @@ -949,6 +989,7 @@ class CaptureXS(MultiGroupXS): # Create the non-domain specific Filters for the Tallies group_edges = self.energy_groups.group_edges energy_filter = openmc.Filter('energy', group_edges) + energy_filter.num_bins = self.num_groups filters = [[energy_filter], [energy_filter], [energy_filter]] # Initialize the Tallies @@ -981,6 +1022,7 @@ class FissionXS(MultiGroupXS): # Create the non-domain specific Filters for the Tallies group_edges = self.energy_groups.group_edges energy_filter = openmc.Filter('energy', group_edges) + energy_filter.num_bins = self.num_groups filters = [[energy_filter], [energy_filter]] # Initialize the Tallies @@ -1012,6 +1054,7 @@ class NuFissionXS(MultiGroupXS): # Create the non-domain specific Filters for the Tallies group_edges = self.energy_groups.group_edges energy_filter = openmc.Filter('energy', group_edges) + energy_filter.num_bins = self.num_groups filters = [[energy_filter], [energy_filter]] # Initialize the Tallies @@ -1043,6 +1086,7 @@ class ScatterXS(MultiGroupXS): # Create the non-domain specific Filters for the Tallies group_edges = self.energy_groups.group_edges energy_filter = openmc.Filter('energy', group_edges) + energy_filter.num_bins = self.num_groups filters = [[energy_filter], [energy_filter]] # Intialize the Tallies @@ -1074,6 +1118,7 @@ class NuScatterXS(MultiGroupXS): # Create the non-domain specific Filters for the Tallies group_edges = self.energy_groups.group_edges energy_filter = openmc.Filter('energy', group_edges) + energy_filter.num_bins = self.num_groups filters = [[energy_filter], [energy_filter]] # Initialize the Tallies @@ -1100,6 +1145,8 @@ class ScatterMatrixXS(MultiGroupXS): group_edges = self.energy_groups.group_edges energy = openmc.Filter('energy', group_edges) energyout = openmc.Filter('energyout', group_edges) + energy.num_bins = self.num_groups + energyout.num_bins = self.num_groups # Create a list of scores for each Tally to be created if correct: @@ -1236,7 +1283,7 @@ class ScatterMatrixXS(MultiGroupXS): string += template.format('', group, bounds[0], bounds[1]) if subdomains == 'all': - subdomains = self.get_subdomain_indices() + subdomains = self.get_subdomains() # Loop over all subdomains for subdomain in subdomains: @@ -1269,7 +1316,7 @@ class NuScatterMatrixXS(ScatterMatrixXS): def __init__(self, domain=None, domain_type=None, groups=None, name=''): super(NuScatterMatrixXS, self).__init__(domain, domain_type, groups, name) - self.xs_type = 'nu-scatter matrix' + self._xs_type = 'nu-scatter matrix' def create_tallies(self): """Construct the OpenMC tallies needed to compute this cross-section.""" @@ -1283,6 +1330,8 @@ class NuScatterMatrixXS(ScatterMatrixXS): group_edges = self.energy_groups.group_edges energy = openmc.Filter('energy', group_edges) energyout = openmc.Filter('energyout', group_edges) + energy.num_bins = self.num_groups + energyout.num_bins = self.num_groups filters = [[energy], [energy, energyout], [energyout]] # Intialize the Tallies @@ -1326,6 +1375,8 @@ class Chi(MultiGroupXS): group_edges = self.energy_groups.group_edges energy_filter = openmc.Filter('energy', group_edges) energyout_filter = openmc.Filter('energyout', group_edges) + energy_filter.num_bins = self.num_groups + energyout_filter.num_bins = self.num_groups filters = [[energy_filter], [energyout_filter]] # Intialize the Tallies diff --git a/openmc/statepoint.py b/openmc/statepoint.py index 0730c5c65c..6e6accf836 100644 --- a/openmc/statepoint.py +++ b/openmc/statepoint.py @@ -692,8 +692,8 @@ class StatePoint(object): contains_filters = True # Iterate over the Filters requested by the user - for filter in filters: - if filter not in test_tally.filters: + for filter, test_filter in zip(filters, test_tally.filters): + if not test_filter.is_subset(filter): contains_filters = False break