__all__ = [
# OcTree
'OcTreeReader',
'OcTreeAppender',
]
__displayname__ = 'OcTree Mesh'
import vtk
from vtk.util import numpy_support as nps
from .. import _helpers, interface
from .two_file_base import ModelAppenderBase, ubcMeshReaderBase
with _helpers.HiddenPrints():
import discretize
[docs]
class OcTreeReader(ubcMeshReaderBase):
"""This class reads a UBC OcTree Mesh file and builds a
``vtkUnstructuredGrid`` of the data in the file. Model File is optional.
Reader will still construct ``vtkUnstructuredGrid`` safely.
"""
__displayname__ = 'UBC OcTree Mesh Reader'
__category__ = 'reader'
description = 'PVGeo: UBC OcTree Mesh'
def __init__(self, nOutputPorts=1, outputType='vtkUnstructuredGrid', **kwargs):
ubcMeshReaderBase.__init__(
self, nOutputPorts=nOutputPorts, outputType=outputType, **kwargs
)
self.__mesh = None
self.__models = []
[docs]
def ubc_octree_mesh(self, FileName, pdo=None):
"""This method reads a UBC OcTree Mesh file and builds a
``vtkUnstructuredGrid`` of the data in the file. This method generates
the ``vtkUnstructuredGrid`` without any data attributes.
Args:
FileName (str): The mesh filename as an absolute path for the input
mesh file in UBC OcTree format.
pdo (vtkUnstructuredGrid): A pointer to the output data object.
Return:
vtkUnstructuredGrid:
a ``vtkUnstructuredGrid`` generated from the UBCMesh grid.
Mesh is defined by the input mesh file.
No data attributes here, simply an empty mesh. Use the
``place_model_on_octree_mesh()`` method to associate with model data.
"""
try:
self.__mesh = discretize.TreeMesh.read_UBC(FileName)
except (IOError, OSError) as fe:
raise _helpers.PVGeoError(str(fe))
if pdo is None:
pdo = self.__mesh.to_vtk()
else:
pdo.DeepCopy(self.__mesh.to_vtk())
return pdo
[docs]
@staticmethod
def place_model_on_octree_mesh(mesh, model, data_name='Data'):
"""Places model data onto a mesh. This is for the UBC Grid data readers
to associate model data with the mesh grid.
Args:
mesh (vtkUnstructuredGrid): The ``vtkUnstructuredGrid`` that is the
mesh to place the model data upon. Needs to have been read in by ubcOcTree
model (np.ndarray): A NumPy float array that holds all of the data
to place inside of the mesh's cells.
data_name (str): The name of the model data array once placed on the
``vtkUnstructuredGrid``.
Return:
vtkUnstructuredGrid:
The input ``vtkUnstructuredGrid`` with model data appended.
"""
if isinstance(model, dict):
for key in model.keys():
mesh = OcTreeReader.place_model_on_octree_mesh(
mesh, model[key], data_name=key
)
return mesh
# Make sure this model file fits the dimensions of the mesh
numCells = mesh.GetNumberOfCells()
if numCells < len(model):
raise _helpers.PVGeoError(
'This model file has more data than the given mesh has cells to hold.'
)
elif numCells > len(model):
raise _helpers.PVGeoError(
'This model file does not have enough data to fill the given mesh\'s cells.'
)
# This is absolutely crucial!
# Do not play with unless you know what you are doing!
# Also note that this assumes ``discretize`` handles addin this array
ind_reorder = nps.vtk_to_numpy(mesh.GetCellData().GetArray('index_cell_corner'))
model = model[ind_reorder]
# Convert data to VTK data structure and append to output
c = interface.convert_array(model, name=data_name, deep=True)
# THIS IS CELL DATA! Add the model data to CELL data:
mesh.GetCellData().AddArray(c)
return mesh
def __ubc_octree(self, filename_mesh, filename_models, output):
"""Wrapper to Read UBC GIF OcTree mesh and model file pairs. UBC OcTree
models are defined using a 2-file format. The "mesh" file describes how
the data is descritized. The "model" file lists the physical property
values for all cells in a mesh. A model file is meaningless without an
associated mesh file. This only handles OcTree formats
Args:
filename_mesh (str): The OcTree Mesh filename as an absolute path
for the input mesh file in UBC OcTree Mesh Format
filename_models (list(str)): The model filenames as absolute paths for
the input model timesteps in UBC OcTree Model Format.
output (vtkUnstructuredGrid): The output data object
Return:
vtkUnstructuredGrid:
A ``vtkUnstructuredGrid`` generated from the UBC 2D/3D Mesh grid.
Mesh is defined by the input mesh file. Cell data is defined by
the input model file.
"""
if self.need_to_readMesh():
# Construct/read the mesh
self.ubc_octree_mesh(filename_mesh, pdo=output)
self.need_to_readMesh(flag=False)
output.DeepCopy(self.__mesh.to_vtk())
if self.need_to_readModels() and self.this_has_models():
# Read the model data
self.__models = []
for f in filename_models:
# Read the model data
self.__models.append(ubcMeshReaderBase.ubc_model_3d(f))
self.need_to_readModels(flag=False)
return output
[docs]
def RequestData(self, request, inInfo, outInfo):
"""Used by pipeline to generate output"""
# Get output:
output = self.GetOutputData(outInfo, 0)
# Get requested time index
i = _helpers.get_requested_time(self, outInfo)
self.__ubc_octree(self.get_mesh_filename(), self.get_model_filenames(), output)
# Place the model data for given timestep onto the mesh
if len(self.__models) > i:
self.place_model_on_octree_mesh(
output, self.__models[i], self.get_data_name()
)
return 1
[docs]
def clear_mesh(self):
"""Use to clean/rebuild the mesh."""
self.__mesh = vtk.vtkUnstructuredGrid()
ubcMeshReaderBase.clear_models(self)
[docs]
def clear_models(self):
"""Use to clean the models and reread the data"""
self.__models = []
ubcMeshReaderBase.clear_models(self)
###############################################################################
[docs]
class OcTreeAppender(ModelAppenderBase):
"""This filter reads a timeseries of models and appends it to an input
``vtkUnstructuredGrid``
"""
__displayname__ = 'UBC OcTree Mesh Appender'
__category__ = 'filter'
def __init__(self, **kwargs):
ModelAppenderBase.__init__(
self,
inputType='vtkUnstructuredGrid',
outputType='vtkUnstructuredGrid',
**kwargs
)
[docs]
def _read_up_front(self):
"""Internal helper to read all data at start"""
reader = ubcMeshReaderBase.ubc_model_3d
self._models = []
for f in self._model_filenames:
# Read the model data
self._models.append(reader(f))
self.need_to_read(flag=False)
return
[docs]
def _place_on_mesh(self, output, idx=0):
"""Internal helper to place a model on the mesh for a given index"""
OcTreeReader.place_model_on_octree_mesh(
output, self._models[idx], self.get_data_name()
)
return