def Map(self, coord): if optimise.DebuggingEnabled(): assert (len(coord) == 3) assert (coord[2] <= self._maxZ) assert (coord[2] >= self._minZ) distanceFromBottom = coord[2] - self._minZ r = calc.L2Norm(coord[:2]) if optimise.DebuggingEnabled(): assert (r >= self._a and r <= self._b) distanceFromInnerWall = r - self._a distanceFromOuterWall = self._b - r if calc.AlmostEquals(self._phiTop, 0.0): localMaxZ = self._maxZ elif self._phiTop > 0.0: localMaxZ = self._maxZ - distanceFromOuterWall * math.tan( self._phiTop) else: localMaxZ = self._maxZ + distanceFromInnerWall * math.tan( self._phiTop) if calc.AlmostEquals(self._phiBottom, 0.0): localMinZ = self._minZ elif self._phiBottom > 0.0: localMinZ = self._minZ + distanceFromInnerWall * math.tan( self._phiBottom) else: localMinZ = self._minZ - distanceFromOuterWall * math.tan( self._phiBottom) newZ = localMinZ + (distanceFromBottom / (self._maxZ - self._minZ)) * (localMaxZ - localMinZ) return [coord[0], coord[1], newZ]
def ToVtu(self, axis=(0.0, 1.0, 0.0), quadMesh=False): assert (not self._shape is None) vtu = self.Mesh(quadMesh=quadMesh).ToVtu() name = self.GetName() if name is None: name = "UnknownField" data = [] for i in range(self.YCoordsCount()): for j in range(self.XCoordsCount()): data.append(self.GetVal(j, i)) data = numpy.array(data) data.shape = (self.XCoordsCount() * self.YCoordsCount(), self._DataLen()) vtu.AddField(name, data) if not calc.AlmostEquals(axis[0], 0.0) or not calc.AlmostEquals( axis[1], 1.0) or not calc.AlmostEquals(axis[2], 0.0): transform = vtk.vtkTransform() transform.Identity() # Find the rotation axis # (0, 1, 0) x axis rotationAxis = [-axis[2], 0.0, -axis[0]] # Normalise rotationAxisMagnitude = calc.L2Norm(rotationAxis) rotationAxis = [ val / rotationAxisMagnitude for val in rotationAxis ] # Find the rotation angle angle = calc.Rad2Deg(math.acos(axis[1] / calc.L2Norm(axis))) # Rotation transform.RotateWXYZ(angle, rotationAxis[0], rotationAxis[1], rotationAxis[2]) transform.Update() newPoints = vtk.vtkPoints() transform.TransformPoints(vtu.ugrid.GetPoints(), newPoints) vtu.ugrid.SetPoints(newPoints) return vtu
def CylinderVtuCut(inputVtu, radius, origin=(0.0, 0.0, 0.0), axis=(0.0, 0.0, 1.0)): """ Perform a 3D cylinder cut of a vtu """ assert (len(origin) == 3) assert (len(axis) == 3) # An implicit function with which to cut cylinder = vtk.vtkCylinder() cylinder.SetRadius(radius) cylinder.SetCenter((0.0, 0.0, 0.0)) # Generate the transform transform = vtk.vtkTransform() transform.Identity() if not calc.AlmostEquals(axis[0], 0.0) or not calc.AlmostEquals( axis[1], 1.0) or not calc.AlmostEquals(axis[2], 0.0): # Find the rotation axis # (0, 1, 0) x axis rotationAxis = [-axis[2], 0.0, -axis[0]] # Normalise rotationAxisMagnitude = calc.L2Norm(rotationAxis) rotationAxis = [val / rotationAxisMagnitude for val in rotationAxis] # Find the rotation angle angle = calc.Rad2Deg(math.acos(axis[1] / calc.L2Norm(axis))) # Rotation transform.RotateWXYZ(angle, rotationAxis[0], rotationAxis[1], rotationAxis[2]) # Translation transform.Translate(origin[0], origin[1], origin[2]) # Set the transform cylinder.SetTransform(transform) return ImplicitFunctionVtuCut(inputVtu, cylinder)
def Map(self, coord): if optimise.DebuggingEnabled(): assert (len(coord) == 3) assert (coord[2] <= self._maxZ) assert (coord[2] >= self._minZ) r = calc.L2Norm(coord[:2]) phi = math.atan2(coord[1], coord[0]) phi += self._phi * ((coord[2] - self._minZ) / (self._maxZ - self._minZ)) newX = r * math.cos(phi) newY = r * math.sin(phi) return [newX, newY, coord[2]]
def LineVtuCut(inputVtu, origin=(0.0, 0.0, 0.0), direction=(1.0, 0.0, 0.0)): """ Perform a plane-plane double cut to form a 1D line (in 3D space) """ assert (len(origin) == 3) assert (len(direction) == 3) # Copy the input line direction x0 = direction[0] y0 = direction[1] z0 = direction[2] # To form the line from two planar cuts, we need two normal vectors at right # angles to the line direction. # Form the first normal vector by imposing x0 dot x1 = 0, with one component # of x1 equal to one and one equal to zero, where the component in x0 # corresponding to the remaining third component is non-zero if calc.AlmostEquals(z0, 0.0): if calc.AlmostEquals(y0, 0.0): if calc.AlmostEquals(x0, 0.0): raise Exception("Direction has zero length") y1 = 1.0 z1 = 0.0 # x1 = -(y0 y1 + z0 z1) / x0 x1 = -y0 / x0 else: x1 = 1.0 z1 = 0.0 # y1 = -(x0 x1 + z0 z1) / y0 y1 = -x0 / y0 else: x1 = 1.0 y1 = 0.0 # z1 = -(x0 x1 + y0 y1) / z0 z1 = -x0 / z0 # Normalise the first normal vector mag = calc.L2Norm([x1, y1, z1]) x1 /= mag y1 /= mag z1 /= mag # Form the second normal vector via a cross product x2 = y0 * z1 - z0 * y1 y2 = z0 * x1 - x0 * z1 z2 = x0 * y1 - y0 * x1 # Normalise the second normal vector mag = calc.L2Norm([x2, y2, z2]) x2 /= mag y2 /= mag z2 /= mag normal1 = (x1, y1, z1) normal2 = (x2, y2, z2) debug.dprint("Normal 1 = " + str(normal1)) debug.dprint("Normal 2 = " + str(normal2)) # Perform the cuts cutVtu = PlanarVtuCut(inputVtu, origin, normal1) cutVtu = PlanarVtuCut(cutVtu, origin, normal2) return cutVtu
def ModelPvtuToVtu(pvtu): """ Convert a parallel vtu to a serial vtu but without any fields. Does nothing (except generate a copy) if the supplied vtu is already a serial vtu. """ # Step 1: Extract the ghost levels, and check that we have a parallel vtu result = vtu() ghostLevel = pvtu.ugrid.GetCellData().GetArray("vtkGhostLevels") if ghostLevel is None: # We have a serial vtu debug.deprint("Warning: VtuFromPvtu passed a serial vtu") ghostLevel = [0 for i in range(vtu.ugrid.GetNumberOfCells())] else: # We have a parallel vtu ghostLevel = [ ghostLevel.GetValue(i) for i in range(ghostLevel.GetNumberOfComponents() * ghostLevel.GetNumberOfTuples()) ] # Step 2: Collect the non-ghost cell IDs debug.dprint("Input cells: " + str(pvtu.ugrid.GetNumberOfCells())) cellIds = [] keepCell = [False for i in range(pvtu.ugrid.GetNumberOfCells())] oldCellIdToNew = [None for i in range(pvtu.ugrid.GetNumberOfCells())] # Collect the new non-ghost cell IDs and generate the cell renumbering map index = 0 for i, level in enumerate(ghostLevel): if calc.AlmostEquals(level, 0.0): cellIds.append(i) keepCell[i] = True oldCellIdToNew[i] = index index += 1 debug.dprint("Non-ghost cells: " + str(len(cellIds))) # Step 3: Collect the non-ghost node IDs debug.dprint("Input points: " + str(pvtu.ugrid.GetNumberOfPoints())) nodeIds = [] keepNode = [False for i in range(pvtu.ugrid.GetNumberOfPoints())] oldNodeIdToNew = [None for i in range(pvtu.ugrid.GetNumberOfPoints())] # Find a list of candidate non-ghost node IDs, based on nodes attached to # non-ghost cells for cellId in cellIds: cellNodeIds = pvtu.ugrid.GetCell(cellId).GetPointIds() cellNodeIds = [ cellNodeIds.GetId(i) for i in range(cellNodeIds.GetNumberOfIds()) ] for nodeId in cellNodeIds: keepNode[nodeId] = True debug.dprint("Non-ghost nodes (pass 1): " + str(keepNode.count(True))) # Detect duplicate nodes # Jumping through Python 2.3 hoops for cx1 - in >= 2.4, can just pass a cmp # argument to list.sort class LocationSorter(utils.Sorter): def __init__(self, x, y, order=[0, 1, 2]): utils.Sorter.__init__(self, x, y) self._order = order return def __cmp__(self, val): def cmp(x, y, order): for comp in order: if x[comp] > y[comp]: return 1 elif x[comp] < y[comp]: return -1 return 0 return cmp(self._key, val.GetKey(), self._order) def Dup(x, y, tol): for i, xVal in enumerate(x): if abs(xVal - y[i]) > tol: return False return True locations = pvtu.GetLocations() lbound, ubound = VtuBoundingBox(pvtu).GetBounds() tol = calc.L2Norm([ubound[i] - lbound[i] for i in range(len(lbound))]) / 1.0e12 debug.dprint("Duplicate node tolerance: " + str(tol)) duplicateNodeMap = [None for i in range(pvtu.ugrid.GetNumberOfPoints())] duplicateNodeMapInverse = [[] for i in range(len(duplicateNodeMap))] # We need to sort the locations using all possible combinations of component # order, to take account of all possible floating point errors. orders = [[0], [[0, 1], [1, 0]], [[0, 1, 2], [0, 2, 1], [1, 0, 2], [1, 2, 0], [2, 0, 1], [2, 1, 0]]][VtuDim(pvtu) - 1] for order in orders: debug.dprint("Processing component order: " + str(order)) # Generate a sorted list of locations, with their node IDs sortPack = [ LocationSorter(location.tolist(), i, order) for i, location in enumerate(locations) ] sortPack.sort() permutedLocations = [pack.GetKey() for pack in sortPack] permutedNodeIds = [pack.GetValue() for pack in sortPack] # This rather horrible construction maps all except the first node in each set # of duplicate nodes to the first node in the set of duplicate nodes, for the # sorted current non-ghost locations i = 0 while i < len(permutedLocations) - 1: j = i while j < len(permutedLocations) - 1: if Dup(permutedLocations[i], permutedLocations[j + 1], tol): if keepNode[permutedNodeIds[j + 1]]: oldNodeId = permutedNodeIds[j + 1] newNodeId = permutedNodeIds[i] while not duplicateNodeMap[newNodeId] is None: newNodeId = duplicateNodeMap[newNodeId] if newNodeId == oldNodeId: # This is already mapped the other way break if newNodeId == oldNodeId: # Can only occur from early exit of the above loop j += 1 continue def MapInverses(oldNodeId, newNodeId): for nodeId in duplicateNodeMapInverse[oldNodeId]: assert (not nodeId == newNodeId) assert (keepNode[newNodeId]) keepNode[nodeId] = False duplicateNodeMap[nodeId] = newNodeId duplicateNodeMapInverse[newNodeId].append( nodeId) MapInverses(nodeId, newNodeId) duplicateNodeMapInverse[oldNodeId] = [] return keepNode[newNodeId] = True keepNode[oldNodeId] = False # Map everything mapped to the old node ID to the new node ID MapInverses(oldNodeId, newNodeId) duplicateNodeMap[oldNodeId] = newNodeId duplicateNodeMapInverse[newNodeId].append(oldNodeId) j += 1 else: break i = j i += 1 debug.dprint("Non-ghost nodes: " + str(keepNode.count(True))) # Collect the final non-ghost node IDs and generate the node renumbering map nodeIds = [] index = 0 for i, keep in enumerate(keepNode): if keep: nodeIds.append(i) oldNodeIdToNew[i] = index index += 1 for i, nodeId in enumerate(duplicateNodeMap): if not nodeId is None: assert (oldNodeIdToNew[i] is None) assert (not oldNodeIdToNew[nodeId] is None) oldNodeIdToNew[i] = oldNodeIdToNew[nodeId] debug.dprint("Non-ghost nodes (pass 2): " + str(len(nodeIds))) # Step 4: Generate the new locations locations = pvtu.GetLocations() locations = numpy.array([locations[i] for i in nodeIds]) points = vtk.vtkPoints() points.SetDataTypeToDouble() for location in locations: points.InsertNextPoint(location) result.ugrid.SetPoints(points) # Step 5: Generate the new cells for cellId in cellIds: cell = pvtu.ugrid.GetCell(cellId) cellNodeIds = cell.GetPointIds() cellNodeIds = [ cellNodeIds.GetId(i) for i in range(cellNodeIds.GetNumberOfIds()) ] idList = vtk.vtkIdList() for nodeId in cellNodeIds: oldNodeId = nodeId nodeId = oldNodeIdToNew[nodeId] assert (not nodeId is None) assert (nodeId >= 0) assert (nodeId <= len(nodeIds)) idList.InsertNextId(nodeId) result.ugrid.InsertNextCell(cell.GetCellType(), idList) return result, oldNodeIdToNew, oldCellIdToNew
def PvtuToVtuRemoveDuplicateNodes(pvtu, keepNode): # Detect duplicate nodes and remove them # Jumping through Python 2.3 hoops for cx1 - in >= 2.4, can just pass a cmp # argument to list.sort class LocationSorter(utils.Sorter): def __init__(self, x, y, order=[0, 1, 2]): utils.Sorter.__init__(self, x, y) self._order = order return def __cmp__(self, val): def cmp(x, y, order): for comp in order: if x[comp] > y[comp]: return 1 elif x[comp] < y[comp]: return -1 return 0 return cmp(self._key, val.GetKey(), self._order) def Dup(x, y, tol): for i, xVal in enumerate(x): if abs(xVal - y[i]) > tol: return False return True nodeIds = [] oldNodeIdToNew = [None] * pvtu.ugrid.GetNumberOfPoints() locations = pvtu.GetLocations() lbound, ubound = VtuBoundingBox(pvtu).GetBounds() tol = calc.L2Norm([ubound[i] - lbound[i] for i in range(len(lbound))]) / 1.0e12 debug.dprint("Duplicate node tolerance: " + str(tol)) duplicateNodeMap = [None for i in range(pvtu.ugrid.GetNumberOfPoints())] duplicateNodeMapInverse = [[] for i in range(len(duplicateNodeMap))] # We need to sort the locations using all possible combinations of component # order, to take account of all possible floating point errors. orders = [[0], [[0, 1], [1, 0]], [[0, 1, 2], [0, 2, 1], [1, 0, 2], [1, 2, 0], [2, 0, 1], [2, 1, 0]]][VtuDim(pvtu) - 1] for order in orders: debug.dprint("Processing component order: " + str(order)) # Generate a sorted list of locations, with their node IDs sortPack = [ LocationSorter(location.tolist(), i, order) for i, location in enumerate(locations) ] sortPack.sort() permutedLocations = [pack.GetKey() for pack in sortPack] permutedNodeIds = [pack.GetValue() for pack in sortPack] # This rather horrible construction maps all except the first node in each set # of duplicate nodes to the first node in the set of duplicate nodes, for the # sorted current non-ghost locations i = 0 while i < len(permutedLocations) - 1: j = i while j < len(permutedLocations) - 1: if Dup(permutedLocations[i], permutedLocations[j + 1], tol): if keepNode[permutedNodeIds[j + 1]]: oldNodeId = permutedNodeIds[j + 1] newNodeId = permutedNodeIds[i] while not duplicateNodeMap[newNodeId] is None: newNodeId = duplicateNodeMap[newNodeId] if newNodeId == oldNodeId: # This is already mapped the other way break if newNodeId == oldNodeId: # Can only occur from early exit of the above loop j += 1 continue def MapInverses(oldNodeId, newNodeId): for nodeId in duplicateNodeMapInverse[oldNodeId]: assert (not nodeId == newNodeId) assert (keepNode[newNodeId]) keepNode[nodeId] = False duplicateNodeMap[nodeId] = newNodeId duplicateNodeMapInverse[newNodeId].append( nodeId) MapInverses(nodeId, newNodeId) duplicateNodeMapInverse[oldNodeId] = [] return keepNode[newNodeId] = True keepNode[oldNodeId] = False # Map everything mapped to the old node ID to the new node ID MapInverses(oldNodeId, newNodeId) duplicateNodeMap[oldNodeId] = newNodeId duplicateNodeMapInverse[newNodeId].append(oldNodeId) j += 1 else: break i = j i += 1 debug.dprint("Non-ghost nodes: " + str(keepNode.count(True))) # Collect the final non-ghost node IDs and generate the node renumbering map nodeIds = [] index = 0 for i, keep in enumerate(keepNode): if keep: nodeIds.append(i) oldNodeIdToNew[i] = index index += 1 for i, nodeId in enumerate(duplicateNodeMap): if not nodeId is None: assert (oldNodeIdToNew[i] is None) assert (not oldNodeIdToNew[nodeId] is None) oldNodeIdToNew[i] = oldNodeIdToNew[nodeId] debug.dprint("Non-ghost nodes (pass 2): " + str(len(nodeIds))) return oldNodeIdToNew, nodeIds