Removed OpenCG dependency for distribcell paths in Pandas DataFrames

This commit is contained in:
Will Boyd 2016-04-30 09:35:17 -04:00
parent ae083cf5d4
commit 7741b525bb
3 changed files with 208 additions and 484 deletions

File diff suppressed because one or more lines are too long

View file

@ -1,4 +1,4 @@
from collections import Iterable
from collections import Iterable, OrderedDict
import copy
from numbers import Real, Integral
import sys
@ -516,7 +516,7 @@ class Filter(object):
return filter_bin
def get_pandas_dataframe(self, data_size, summary=None):
def get_pandas_dataframe(self, data_size, distribcell_paths=False):
"""Builds a Pandas DataFrame for the Filter's bins.
This method constructs a Pandas DataFrame object for the filter with
@ -531,12 +531,10 @@ class Filter(object):
----------
data_size : Integral
The total number of bins in the tally corresponding to this filter
summary : None or openmc.Summary
An optional Summary object to be used to construct columns for
distribcell tally filters (default is None). The geometric
distribcell_paths : bool
Construct columns for distribcell tally filters. The geometric
information in the Summary object is embedded into a Multi-index
column with a geometric "path" to each distribcell instance.
NOTE: This option requires the OpenCG Python package.
Returns
-------
@ -554,7 +552,7 @@ class Filter(object):
1. a single column with the cell instance IDs (without summary info)
2. separate columns for the cell IDs, universe IDs, and lattice IDs
and x,y,z cell indices corresponding to each (with summary info).
and x,y,z cell indices corresponding to each (distribcell paths).
For 'energy' and 'energyout' filters, the DataFrame includes one
column for the lower energy bound and one column for the upper
@ -566,8 +564,7 @@ class Filter(object):
Raises
------
ImportError
When Pandas is not installed, or summary info is requested but
OpenCG is not installed.
When Pandas is not installed
See also
--------
@ -626,106 +623,108 @@ class Filter(object):
elif self.type == 'distribcell':
level_df = None
if isinstance(summary, Summary):
# Attempt to import the OpenCG package
try:
import opencg
except ImportError:
msg = 'The OpenCG package must be installed ' \
'to use a Summary for distribcell dataframes'
raise ImportError(msg)
# Create Pandas Multi-index columns for each level in CSG tree
if distribcell_paths:
# Extract the OpenCG geometry from the Summary
opencg_geometry = summary.opencg_geometry
openmc_geometry = summary.openmc_geometry
# FIXME: Make assumption that each path is the same length???
# NOTE: Just state this caveat in the docstring
# Use OpenCG to compute the number of regions
opencg_geometry.initialize_cell_offsets()
num_regions = opencg_geometry.num_regions
# Initialize a dictionary mapping OpenMC distribcell
# offsets to OpenCG LocalCoords linked lists
offsets_to_coords = {}
for offset, path in enumerate(self.distribcell_paths):
region = opencg_geometry.get_region_from_path(path)
coords = opencg_geometry.find_region(region)
offsets_to_coords[offset] = coords
# Each distribcell offset is a DataFrame bin
# Unravel the paths into DataFrame columns
num_offsets = len(offsets_to_coords)
# Initialize termination condition for while loop
distribcell_paths = copy.deepcopy(self.distribcell_paths)
num_offsets = len(distribcell_paths)
levels_remain = True
counter = 0
level_counter = 0
# Iterate over each level in the CSG tree hierarchy
# FIXME: Allocate NumPy arrays for each CSG level
while levels_remain:
levels_remain = False
level_counter += 1
level_key = 'level {}'.format(level_counter)
first_path = distribcell_paths[0]
level_dict = OrderedDict()
# Initialize dictionary to build Pandas Multi-index
# column for this level in the CSG tree hierarchy
level_dict = {}
next_index = first_path.index('-')
level = first_path[:next_index]
first_path = first_path[next_index+2:]
# Initialize prefix Multi-index keys
counter += 1
level_key = 'level {0}'.format(counter)
univ_key = (level_key, 'univ', 'id')
cell_key = (level_key, 'cell', 'id')
lat_id_key = (level_key, 'lat', 'id')
lat_x_key = (level_key, 'lat', 'x')
lat_y_key = (level_key, 'lat', 'y')
lat_z_key = (level_key, 'lat', 'z')
# This level is a lattice (e.g., ID(x,y,z))
if '(' in level:
level_type = 'lattice'
# Allocate NumPy arrays for each CSG level and
# each Multi-index column in the DataFrame
level_dict[univ_key] = np.empty(num_offsets)
level_dict[cell_key] = np.empty(num_offsets)
level_dict[lat_id_key] = np.empty(num_offsets)
level_dict[lat_x_key] = np.empty(num_offsets)
level_dict[lat_y_key] = np.empty(num_offsets)
level_dict[lat_z_key] = np.empty(num_offsets)
# Initialize prefix Multi-index keys
lat_id_key = (level_key, 'lat', 'id')
lat_x_key = (level_key, 'lat', 'x')
lat_y_key = (level_key, 'lat', 'y')
lat_z_key = (level_key, 'lat', 'z')
# Initialize Multi-index columns to NaN - this is
# necessary since some distribcell instances may
# have very different LocalCoords linked lists
level_dict[univ_key][:] = np.NAN
level_dict[cell_key][:] = np.NAN
level_dict[lat_id_key][:] = np.NAN
level_dict[lat_x_key][:] = np.NAN
level_dict[lat_y_key][:] = np.NAN
level_dict[lat_z_key][:] = np.NAN
# Allocate NumPy arrays for each CSG level and
# each Multi-index column in the DataFrame
level_dict[lat_id_key] = np.empty(num_offsets)
level_dict[lat_x_key] = np.empty(num_offsets)
level_dict[lat_y_key] = np.empty(num_offsets)
level_dict[lat_z_key] = np.empty(num_offsets)
# Iterate over all regions (distribcell instances)
for offset in range(num_offsets):
coords = offsets_to_coords[offset]
# This level is a universe / cell (e.g., ID->ID)
else:
level_type = 'universe'
# If entire LocalCoords has been unraveled into
# Multi-index columns already, continue
if coords is None:
continue
# Assign entry to Universe Multi-index column
if coords._type == 'universe':
level_dict[univ_key][offset] = coords._universe._id
level_dict[cell_key][offset] = coords._cell._id
# Assign entry to Lattice Multi-index column
# Pop off the cell ID from the path
if '-' in first_path:
next_index = first_path.index('-')
level = first_path[:next_index]
first_path = first_path[next_index+2:]
else:
# Reverse y index per lattice ordering in OpenCG
level_dict[lat_id_key][offset] = coords._lattice._id
level_dict[lat_x_key][offset] = coords._lat_x
level_dict[lat_y_key][offset] = \
coords._lattice.dimension[1] - coords._lat_y - 1
level_dict[lat_z_key][offset] = coords._lat_z
levels_remain = False
# Initialize prefix Multi-index keys
univ_key = (level_key, 'univ', 'id')
cell_key = (level_key, 'cell', 'id')
# Allocate NumPy arrays for each CSG level and
# each Multi-index column in the DataFrame
level_dict[univ_key] = np.empty(num_offsets)
level_dict[cell_key] = np.empty(num_offsets)
# Populate Multi-index arrays with all distribcell paths
for i, path in enumerate(distribcell_paths):
if level_type == 'lattice':
# Extract lattice ID, indices from path
next_index = path.index('-')
lat_id_indices = path[:next_index]
# Trim lattice info from distribcell path
distribcell_paths[i] = path[next_index+2:]
# Extract the lattice cell indices from the path
i1 = lat_id_indices.index('(')
i2 = lat_id_indices.index(')')
i3 = lat_id_indices[i1+1:i2]
# Assign entry to Lattice Multi-index column
level_dict[lat_id_key][i] = path[:i1]
level_dict[lat_x_key][i] = int(i3.split(',')[0]) - 1
level_dict[lat_y_key][i] = int(i3.split(',')[1]) - 1
level_dict[lat_z_key][i] = int(i3.split(',')[2]) - 1
# Move to next node in LocalCoords linked list
if coords._next is None:
offsets_to_coords[offset] = None
else:
offsets_to_coords[offset] = coords._next
levels_remain = True
# Extract universe ID from path
next_index = path.index('-')
universe_id = int(path[:next_index])
# Trim universe info from distribcell path
path = path[next_index+2:]
# Extract cell ID from path
if '-' in path:
next_index = path.index('-')
cell_id = int(path[:next_index])
distribcell_paths[i] = path[next_index+2:]
else:
cell_id = int(path)
distribcell_paths[i] = ''
# Assign entry to Universe, Cell Multi-index columns
level_dict[univ_key][i] = universe_id
level_dict[cell_key][i] = cell_id
# Tile the Multi-index columns
for level_key, level_bins in level_dict.items():

View file

@ -1538,8 +1538,8 @@ class Tally(object):
return data
def get_pandas_dataframe(self, filters=True, nuclides=True,
scores=True, summary=None, float_format='{:.2e}'):
def get_pandas_dataframe(self, filters=True, nuclides=True, scores=True,
distribcell_paths=False, float_format='{:.2e}'):
"""Build a Pandas DataFrame for the Tally data.
This method constructs a Pandas DataFrame object for the Tally data
@ -1557,12 +1557,10 @@ class Tally(object):
Include columns with nuclide bin information (default is True).
scores : bool
Include columns with score bin information (default is True).
summary : None or openmc.Summary
An optional Summary object to be used to construct columns for
distribcell tally filters (default is None). The geometric
distribcell_paths : bool
Construct columns for distribcell tally filters. The geometric
information in the Summary object is embedded into a Multi-index
column with a geometric "path" to each distribcell intance.
NOTE: This option requires the OpenCG Python package.
column with a geometric "path" to each distribcell instance.
float_format : str
All floats in the DataFrame will be formatted using the given
format string before printing.
@ -1588,13 +1586,15 @@ class Tally(object):
msg = 'The Tally ID="{0}" has no data to return'.format(self.id)
raise KeyError(msg)
'''
# If using Summary, ensure StatePoint.link_with_summary(...) was called
if summary and not self.with_summary:
if distribcell_pathssummary and not self.with_summary:
msg = 'The Tally ID="{0}" has not been linked with the Summary. ' \
'Call the StatePoint.link_with_summary(...) method ' \
'before using Tally.get_pandas_dataframe(...) with ' \
'Summary info'.format(self.id)
raise KeyError(msg)
'''
# Initialize a pandas dataframe for the tally data
import pandas as pd
@ -1608,7 +1608,8 @@ class Tally(object):
# Append each Filter's DataFrame to the overall DataFrame
for self_filter in self.filters:
filter_df = self_filter.get_pandas_dataframe(data_size, summary)
filter_df = self_filter.get_pandas_dataframe(
data_size, distribcell_paths)
df = pd.concat([df, filter_df], axis=1)
# Include DataFrame column for nuclides if user requested it