def _adjacentCellIDs(self): Hids = numerix.zeros((self.numberOfHorizontalRows, self.nx, 2), 'l') indices = numerix.indices((self.numberOfHorizontalRows, self.nx)) Hids[..., 1] = indices[1] + indices[0] * self.nx Hids[..., 0] = Hids[..., 1] - self.nx if self.numberOfHorizontalRows > 0: Hids[0, ..., 0] = Hids[0, ..., 1] Hids[0, ..., 1] = Hids[0, ..., 0] Hids[-1, ..., 1] = Hids[-1, ..., 0] Vids = numerix.zeros((self.ny, self.numberOfVerticalColumns, 2), 'l') indices = numerix.indices((self.ny, self.numberOfVerticalColumns)) Vids[..., 1] = indices[1] + indices[0] * self.nx Vids[..., 0] = Vids[..., 1] - 1 if self.numberOfVerticalColumns > 0: Vids[..., 0, 0] = Vids[..., 0, 1] Vids[..., 0, 1] = Vids[..., 0, 0] Vids[..., -1, 1] = Vids[..., -1, 0] faceCellIDs = numerix.concatenate( (numerix.reshape(Hids, (self.numberOfHorizontalFaces, 2)), numerix.reshape( Vids, (self.numberOfFaces - self.numberOfHorizontalFaces, 2)))) return (faceCellIDs[:, 0], faceCellIDs[:, 1])
def extendVariable(self, extensionVariable, order=2): """ Calculates the extension of `extensionVariable` from the zero level set. :Parameters: - `extensionVariable`: The variable to extend from the zero level set. """ dx, shape = self.getLSMshape() extensionValue = numerix.reshape(extensionVariable, shape) phi = numerix.reshape(self._value, shape) if LSM_SOLVER == 'lsmlib': from pylsmlib import computeExtensionFields as extension_velocities elif LSM_SOLVER == 'skfmm': from skfmm import extension_velocities else: raise Exception, "Neither `lsmlib` nor `skfmm` can be found on the $PATH" tmp, extensionValue = extension_velocities(phi, extensionValue, ext_mask=phi < 0., dx=dx, order=order) extensionVariable[:] = extensionValue.flatten()
def _adjacentCellIDs(self): Hids = numerix.zeros((self.numberOfHorizontalRows, self.nx, 2), 'l') indices = numerix.indices((self.numberOfHorizontalRows, self.nx)) Hids[..., 1] = indices[1] + indices[0] * self.nx Hids[..., 0] = Hids[..., 1] - self.nx if self.numberOfHorizontalRows > 0: Hids[0, ..., 0] = Hids[0, ..., 1] Hids[0, ..., 1] = Hids[0, ..., 0] Hids[-1, ..., 1] = Hids[-1, ..., 0] Vids = numerix.zeros((self.ny, self.numberOfVerticalColumns, 2), 'l') indices = numerix.indices((self.ny, self.numberOfVerticalColumns)) Vids[..., 1] = indices[1] + indices[0] * self.nx Vids[..., 0] = Vids[..., 1] - 1 if self.numberOfVerticalColumns > 0: Vids[..., 0, 0] = Vids[..., 0, 1] Vids[..., 0, 1] = Vids[..., 0, 0] Vids[..., -1, 1] = Vids[..., -1, 0] faceCellIDs = numerix.concatenate((numerix.reshape(Hids, (self.numberOfHorizontalFaces, 2)), numerix.reshape(Vids, (self.numberOfFaces - self.numberOfHorizontalFaces, 2)))) return (faceCellIDs[:, 0], faceCellIDs[:, 1])
def _faceCenters(self): XYcen = numerix.zeros((3, self.nx, self.ny, self.nz + 1), 'd') indices = numerix.indices((self.nx, self.ny, self.nz + 1)) XYcen[0] = (indices[0] + 0.5) * self.dx XYcen[1] = (indices[1] + 0.5) * self.dy XYcen[2] = indices[2] * self.dz XZcen = numerix.zeros((3, self.nx, self.ny + 1, self.nz), 'd') indices = numerix.indices((self.nx, self.ny + 1, self.nz)) XZcen[0] = (indices[0] + 0.5) * self.dx XZcen[1] = indices[1] * self.dy XZcen[2] = (indices[2] + 0.5) * self.dz YZcen = numerix.zeros((3, self.nx + 1, self.ny, self.nz), 'd') indices = numerix.indices((self.nx + 1, self.ny, self.nz)) YZcen[0] = indices[0] * self.dx YZcen[1] = (indices[1] + 0.5) * self.dy YZcen[2] = (indices[2] + 0.5) * self.dz return numerix.concatenate( (numerix.reshape(XYcen.swapaxes(1, 3), (3, self.numberOfXYFaces)), numerix.reshape(XZcen.swapaxes(1, 3), (3, self.numberOfXZFaces)), numerix.reshape(YZcen.swapaxes(1, 3), (3, self.numberOfYZFaces))), axis=1) + self.origin
def _faceTangents2(self): XYtan = numerix.zeros((3, self.nx, self.ny, self.nz + 1), 'l') XYtan[1, ...] = 1 XZtan = numerix.zeros((3, self.nx, self.ny + 1, self.nz), 'l') XZtan[0, ...] = 1 YZtan = numerix.zeros((3, self.nx + 1, self.ny, self.nz), 'l') YZtan[0, ...] = 1 return numerix.concatenate((numerix.reshape(XYtan[::-1].swapaxes(1, 3), (3, self.numberOfXYFaces)), numerix.reshape(XZtan[::-1].swapaxes(1, 3), (3, self.numberOfXZFaces)), numerix.reshape(YZtan[::-1].swapaxes(1, 3), (3, self.numberOfYZFaces))), axis=1)
def _faceTangents2(self): XYtan = numerix.zeros((3, self.nx, self.ny, self.nz + 1), 'l') XYtan[1, ...] = 1 XZtan = numerix.zeros((3, self.nx, self.ny + 1, self.nz), 'l') XZtan[0, ...] = 1 YZtan = numerix.zeros((3, self.nx + 1, self.ny, self.nz), 'l') YZtan[0, ...] = 1 return numerix.concatenate((numerix.reshape(XYtan[::-1].swapaxes(1,3), (3, self.numberOfXYFaces)), numerix.reshape(XZtan[::-1].swapaxes(1,3), (3, self.numberOfXZFaces)), numerix.reshape(YZtan[::-1].swapaxes(1,3), (3, self.numberOfYZFaces))), axis=1)
def _cellDistances(self): Hdis = numerix.repeat((self.dy,), self.numberOfHorizontalFaces) Hdis = numerix.reshape(Hdis, (self.nx, self.numberOfHorizontalRows)) if self.numberOfHorizontalRows > 0: Hdis[..., 0] = self.dy / 2. Hdis[..., -1] = self.dy / 2. Vdis = numerix.repeat((self.dx,), self.numberOfFaces - self.numberOfHorizontalFaces) Vdis = numerix.reshape(Vdis, (self.numberOfVerticalColumns, self.ny)) if self.numberOfVerticalColumns > 0: Vdis[0, ...] = self.dx / 2. Vdis[-1, ...] = self.dx / 2. return numerix.concatenate((numerix.reshape(numerix.swapaxes(Hdis, 0, 1), (self.numberOfHorizontalFaces,)), numerix.reshape(numerix.swapaxes(Vdis, 0, 1), (self.numberOfFaces - self.numberOfHorizontalFaces,))))
def _globalMatrixAndVectors(self): if not hasattr(self, 'globalVectors'): globalMatrix = self.matrix.asTrilinosMeshMatrix() mesh = self.var.mesh localNonOverlappingCellIDs = mesh._localNonOverlappingCellIDs ## The following conditional is required because empty indexing is not altogether functional. ## This numpy.empty((0,))[[]] and this numpy.empty((0,))[...,[]] both work, but this ## numpy.empty((3, 0))[...,[]] is broken. if self.var.shape[-1] != 0: s = (Ellipsis, localNonOverlappingCellIDs) else: s = (localNonOverlappingCellIDs,) nonOverlappingVector = Epetra.Vector(globalMatrix.domainMap, self.var[s].ravel()) from fipy.variables.coupledCellVariable import _CoupledCellVariable if isinstance(self.RHSvector, _CoupledCellVariable): RHSvector = self.RHSvector[localNonOverlappingCellIDs] else: RHSvector = numerix.reshape(numerix.array(self.RHSvector), self.var.shape)[s].ravel() nonOverlappingRHSvector = Epetra.Vector(globalMatrix.rangeMap, RHSvector) del RHSvector overlappingVector = Epetra.Vector(globalMatrix.colMap, self.var) self.globalVectors = (globalMatrix, nonOverlappingVector, nonOverlappingRHSvector, overlappingVector) return self.globalVectors
def faceNormals(self): XYnor = numerix.zeros((3, self.nx, self.ny, self.nz + 1), 'l') XYnor[0, ...] = 1 XYnor[0, ..., 0] = -1 XZnor = numerix.zeros((3, self.nx, self.ny + 1, self.nz), 'l') XZnor[1, ...] = 1 XZnor[1, :, 0, :] = -1 YZnor = numerix.zeros((3, self.nx + 1, self.ny, self.nz), 'l') YZnor[2, ...] = 1 YZnor[2, 0, ...] = -1 return numerix.concatenate((numerix.reshape(XYnor[::-1].swapaxes(1,3), (3, self.numberOfXYFaces)), numerix.reshape(XZnor[::-1].swapaxes(1,3), (3, self.numberOfXZFaces)), numerix.reshape(YZnor[::-1].swapaxes(1,3), (3, self.numberOfYZFaces))), axis=1)
def _buildMatrix(self, var, SparseMatrix, boundaryConditions=(), dt=None, transientGeomCoeff=None, diffusionGeomCoeff=None): var, L, b = FaceTerm._buildMatrix(self, var, SparseMatrix, boundaryConditions=boundaryConditions, dt=dt, transientGeomCoeff=transientGeomCoeff, diffusionGeomCoeff=diffusionGeomCoeff) ## if var.rank != 1: mesh = var.mesh if (not hasattr(self, 'constraintL')) or (not hasattr(self, 'constraintB')): constraintMask = var.faceGrad.constraintMask | var.arithmeticFaceValue.constraintMask weight = self._getWeight(var, transientGeomCoeff, diffusionGeomCoeff) if 'implicit' in weight: alpha = weight['implicit']['cell 1 diag'] else: alpha = 0.0 exteriorCoeff = self.coeff * mesh.exteriorFaces self.constraintL = (alpha * constraintMask * exteriorCoeff).divergence * mesh.cellVolumes self.constraintB = -((1 - alpha) * var.arithmeticFaceValue * constraintMask * exteriorCoeff).divergence * mesh.cellVolumes ids = self._reshapeIDs(var, numerix.arange(mesh.numberOfCells)) L.addAt(numerix.array(self.constraintL).ravel(), ids.ravel(), ids.swapaxes(0, 1).ravel()) b += numerix.reshape(self.constraintB.value, ids.shape).sum(0).ravel() return (var, L, b)
def _getGhostedValues(self, var): """Obtain current ghost values from across processes Returns ------- ndarray Ghosted values """ mesh = var.mesh localNonOverlappingCellIDs = mesh._localNonOverlappingCellIDs ## The following conditional is required because empty indexing is ## not altogether functional. This numpy.empty((0,))[[]] and this ## numpy.empty((0,))[...,[]] both work, but this numpy.empty((3, ## 0))[...,[]] is broken. if var.shape[-1] != 0: s = (Ellipsis, localNonOverlappingCellIDs) else: s = (localNonOverlappingCellIDs, ) nonOverlappingVector = Epetra.Vector(self.domainMap, var[s].ravel()) overlappingVector = Epetra.Vector(self.colMap) overlappingVector.Import(nonOverlappingVector, Epetra.Import(self.colMap, self.domainMap), Epetra.Insert) return numerix.reshape(numerix.asarray(overlappingVector), var.shape)
def faceNormals(self): XYnor = numerix.zeros((3, self.nx, self.ny, self.nz + 1), 'l') XYnor[0, ...] = 1 XYnor[0, ..., 0] = -1 XZnor = numerix.zeros((3, self.nx, self.ny + 1, self.nz), 'l') XZnor[1, ...] = 1 XZnor[1,:, 0,:] = -1 YZnor = numerix.zeros((3, self.nx + 1, self.ny, self.nz), 'l') YZnor[2, ...] = 1 YZnor[2, 0, ...] = -1 return numerix.concatenate((numerix.reshape(XYnor[::-1].swapaxes(1, 3), (3, self.numberOfXYFaces)), numerix.reshape(XZnor[::-1].swapaxes(1, 3), (3, self.numberOfXZFaces)), numerix.reshape(YZnor[::-1].swapaxes(1, 3), (3, self.numberOfYZFaces))), axis=1)
def _cellValueOverFaces(self): """ Returns the cells values at the faces. >>> from fipy.meshes import Grid2D >>> from fipy.variables.cellVariable import CellVariable >>> mesh = Grid2D(dx = .5, dy = .5, nx = 2, ny = 2) >>> distanceVariable = DistanceVariable(mesh = mesh, ... value = (-0.5, 0.5, 0.5, 1.5)) >>> answer = CellVariable(mesh=mesh, ... value=((-.5, .5, .5, 1.5), ... (-.5, .5, .5, 1.5), ... (-.5, .5, .5, 1.5), ... (-.5, .5, .5, 1.5))) >>> print numerix.allclose(distanceVariable._cellValueOverFaces, answer) True """ M = self.mesh._maxFacesPerCell N = self.mesh.numberOfCells return numerix.reshape( numerix.repeat(numerix.array(self._value)[numerix.newaxis, ...], M, axis=0), (M, N))
def _cellCenters(self): centers = numerix.zeros((3, self.nx, self.ny, self.nz), 'd') indices = numerix.indices((self.nx, self.ny, self.nz)) centers[0] = (indices[0] + 0.5) * self.dx centers[1] = (indices[1] + 0.5) * self.dy centers[2] = (indices[2] + 0.5) * self.dz ccs = numerix.reshape(centers.swapaxes(1, 3), (3, self.numberOfCells)) + self.origin return ccs
def _cellCenters(self): centers = numerix.zeros((3, self.nx, self.ny, self.nz), 'd') indices = numerix.indices((self.nx, self.ny, self.nz)) centers[0] = (indices[0] + 0.5) * self.dx centers[1] = (indices[1] + 0.5) * self.dy centers[2] = (indices[2] + 0.5) * self.dz ccs = numerix.reshape(centers.swapaxes(1,3), (3, self.numberOfCells)) + self.origin return ccs
def _solve(self): if self.var.mesh.communicator.Nproc > 1: raise Exception( "SciPy solvers cannot be used with multiple processors") self.var[:] = numerix.reshape( self._solve_(self.matrix, self.var.ravel(), numerix.array(self.RHSvector)), self.var.shape)
def _getCellVertexIDs(self): ids = numerix.zeros((4, self.nx, self.ny)) indices = numerix.indices((self.nx, self.ny)) ids[1] = indices[0] + (indices[1] + 1) * self.numberOfVerticalColumns ids[0] = ids[1] + 1 ids[3] = indices[0] + indices[1] * self.numberOfVerticalColumns ids[2] = ids[3] + 1 return numerix.reshape(ids, (4, self.numberOfCells))
def _buildMatrix(self, var, SparseMatrix, boundaryConditions=(), dt=None, transientGeomCoeff=None, diffusionGeomCoeff=None): var, L, b = FaceTerm._buildMatrix( self, var, SparseMatrix, boundaryConditions=boundaryConditions, dt=dt, transientGeomCoeff=transientGeomCoeff, diffusionGeomCoeff=diffusionGeomCoeff) ## if var.rank != 1: mesh = var.mesh if (not hasattr(self, 'constraintL')) or (not hasattr( self, 'constraintB')): weight = self._getWeight(var, transientGeomCoeff, diffusionGeomCoeff) if 'implicit' in weight: alpha = weight['implicit']['cell 1 diag'] else: alpha = 0.0 alpha_constraint = numerix.where(var.faceGrad.constraintMask, 1.0, alpha) def divergence(face_value): return ( face_value * \ (var.faceGrad.constraintMask | var.arithmeticFaceValue.constraintMask) * \ self.coeff * mesh.exteriorFaces ).divergence * mesh.cellVolumes self.constraintL = divergence(alpha_constraint) dvar = (var.faceGrad * mesh._cellDistances * mesh.faceNormals).sum(axis=0) self.constraintB = divergence( (alpha_constraint - 1) * var.arithmeticFaceValue + (alpha - 1) * dvar * var.faceGrad.constraintMask) ids = self._reshapeIDs(var, numerix.arange(mesh.numberOfCells)) L.addAt( numerix.array(self.constraintL).ravel(), ids.ravel(), ids.swapaxes(0, 1).ravel()) b += numerix.reshape(self.constraintB.value, ids.shape).sum(0).ravel() return (var, L, b)
def _calcBaseFaceVertexIDs(self): cellVertexIDs = self.cellVertexIDs ## compute the face vertex IDs. ### this assumes triangular grid #cellFaceVertexIDs = numerix.ones((self.dimensions, self.dimensions + 1, self.numCells)) cellFaceVertexIDs = numerix.ones((self.dimensions,len(cellVertexIDs), self.numCells)) cellFaceVertexIDs = -1 * cellFaceVertexIDs if (self.dimensions == 3): cellFaceVertexIDs[:, 0, :] = cellVertexIDs[:3] cellFaceVertexIDs[:, 1, :] = numerix.concatenate((cellVertexIDs[:2], cellVertexIDs[3:]), axis = 0) cellFaceVertexIDs[:, 2, :] = numerix.concatenate((cellVertexIDs[:1], cellVertexIDs[2:]), axis = 0) cellFaceVertexIDs[:, 3, :] = cellVertexIDs[1:] elif (self.dimensions == 2):#define face with vertex pairs ###This isn't very general. ###Would be nice to allow cells with different number of faces. if len(cellVertexIDs)==3: cellFaceVertexIDs[:, 0, :] = cellVertexIDs[:2] cellFaceVertexIDs[:, 1, :] = numerix.concatenate((cellVertexIDs[2:], cellVertexIDs[:1]), axis = 0) cellFaceVertexIDs[:, 2, :] = cellVertexIDs[1:] elif len(cellVertexIDs)==4: cellFaceVertexIDs[:, 0, :] = cellVertexIDs[0:2] cellFaceVertexIDs[:, 1, :] = cellVertexIDs[1:3] cellFaceVertexIDs[:, 2, :] = cellVertexIDs[2:4] cellFaceVertexIDs[:, 3, :] = numerix.concatenate((cellVertexIDs[3:], cellVertexIDs[:1]), axis = 0) cellFaceVertexIDs = cellFaceVertexIDs[::-1]#reverses order of vertex pair #self.unsortedBaseIDs = numerix.reshape(cellFaceVertexIDs.swapaxes(1,2), # (self.dimensions, # self.numCells * (self.dimensions + 1))) self.unsortedBaseIDs = numerix.reshape(cellFaceVertexIDs.swapaxes(1,2), (self.dimensions, self.numCells * (len(cellVertexIDs)))) cellFaceVertexIDs = numerix.sort(cellFaceVertexIDs, axis=0) baseFaceVertexIDs = numerix.reshape(cellFaceVertexIDs.swapaxes(1,2), (self.dimensions, self.numCells * (len(cellVertexIDs)))) self.baseFaceVertexIDs = baseFaceVertexIDs self.cellFaceVertexIDs = cellFaceVertexIDs
def _interiorFaces(self): """ Return only the faces that have two neighboring cells. """ Hids = numerix.arange(0, self.numberOfHorizontalFaces) Hids = numerix.reshape(Hids, (self.numberOfHorizontalRows, self.nx)) Hids = Hids[1:-1, ...] Vids = numerix.arange(self.numberOfHorizontalFaces, self.numberOfFaces) Vids = numerix.reshape(Vids, (self.ny, self.numberOfVerticalColumns)) Vids = Vids[..., 1:-1] interiorIDs = numerix.concatenate((numerix.reshape(Hids, (self.nx * (self.ny - 1),)), numerix.reshape(Vids, ((self.nx - 1) * self.ny,)))) from fipy.variables.faceVariable import FaceVariable interiorFaces = FaceVariable(mesh=self, value=False) interiorFaces[interiorIDs] = True return interiorFaces
def _calcCellToFaceOrientations(self): cells = self.getCells() N = len(cells) M = self._getMaxFacesPerCell() self.cellToFaceOrientations = numerix.zeros((N,M,1)) for i in range(N): orientations = cells[i].getFaceOrientations() orientations = numerix.reshape(orientations,(len(cells[i].getFaces()),)) for j in range(len(orientations)): self.cellToFaceOrientations[i,j,0] = orientations[j]
def _petsc2fipyGhost(self, vec): """Convert a PETSc `GhostVec` to a FiPy Variable (form) Moves the ghosts from the end, as necessary. The return Variable may be coupled/vector and so moving the ghosts is a bit subtle. Given an 8-element `GhostVec` `vj` ``` v0 v1 v2 v3 (v4) (v6) [4, 6] processor 0 v4 v5 v6 v7 (v1) (v3) [1, 3] processor 1 ``` where j is the global index and the `[a, b]` are the global ghost indices. Elements in () are ghosted We end up with the (2x4) FiPy Variable ``` v0 v1 (v4) processor 0 v2 v3 (v6) (v1) v4 v4 processor 1 (v3) v6 v7 ``` """ N = len(self.mesh._globalOverlappingCellIDs) M = self.numberOfEquations var = numerix.empty((M, N)) bodies = numerix.array(vec) if M > 1: bodies = numerix.reshape(bodies, (M, -1)) var[..., self._bodies] = bodies vec.ghostUpdate() with vec.localForm() as lf: if len(self._ghosts) > 0: ids = numerix.arange(-len(self._ghosts), 0) ghosts = numerix.reshape(numerix.array(lf)[ids], (M, -1)) var[..., ~self._bodies] = ghosts return var.flatten()
def _calcCellFaceIDs(self): cells = self.getCells() for cell in cells: cell._calcCenter() self.cellFaceIDs = () self.cellFaceIDIndices = () for i in range(len(cells)): cell = cells[i] ids = cell.getFaceIDs() self.cellFaceIDs += ids self.cellFaceIDs = numerix.array(self.cellFaceIDs) self.cellFaceIDs = numerix.reshape(self.cellFaceIDs, (len(cells), self._getMaxFacesPerCell()))
def _calcOrderedCellVertexIDs(self): from fipy.tools.numerix import take NFac = self._maxFacesPerCell # numpy 1.1's MA.take doesn't like FlatIter. Call ravel() instead. cellVertexIDs0 = take(self.faceVertexIDs[0], self.cellFaceIDs.ravel()) cellVertexIDs1 = take(self.faceVertexIDs[1], self.cellFaceIDs.ravel()) cellVertexIDs = MA.where(self._cellToFaceOrientations.ravel() > 0, cellVertexIDs0, cellVertexIDs1) cellVertexIDs = numerix.reshape(cellVertexIDs, (NFac, -1)) return cellVertexIDs
def _calcFaceAreas(self): faceVertexIDs = MA.filled(self.faceVertexIDs, -1) substitute = numerix.repeat(faceVertexIDs[numerix.newaxis, 0], faceVertexIDs.shape[0], axis=0) faceVertexIDs = numerix.where(MA.getmaskarray(self.faceVertexIDs), substitute, faceVertexIDs) faceVertexCoords = numerix.take(self.vertexCoords, faceVertexIDs, axis=1) faceOrigins = numerix.repeat(faceVertexCoords[:,0], faceVertexIDs.shape[0], axis=0) faceOrigins = numerix.reshape(faceOrigins, MA.shape(faceVertexCoords)) faceVertexCoords = faceVertexCoords - faceOrigins left = range(faceVertexIDs.shape[0]) right = left[1:] + [left[0]] cross = numerix.sum(numerix.cross(faceVertexCoords, numerix.take(faceVertexCoords, right, 1), axis=0), 1) self.faceAreas = numerix.sqrtDot(cross, cross) / 2.
def _calcOrderedCellVertexIDs(self): """Correct ordering for VTK_VOXEL""" ids = numerix.zeros((8, self.nx, self.ny, self.nz), 'l') indices = numerix.indices((self.nx, self.ny, self.nz)) ids[1] = indices[0] + (indices[1] + (indices[2] + 1) * (self.ny + 1) + 1) * (self.nx + 1) ids[0] = ids[1] + 1 ids[3] = indices[0] + (indices[1] + (indices[2] + 1) * (self.ny + 1)) * (self.nx + 1) ids[2] = ids[3] + 1 ids[5] = indices[0] + (indices[1] + indices[2] * (self.ny + 1) + 1) * (self.nx + 1) ids[4] = ids[5] + 1 ids[7] = indices[0] + (indices[1] + indices[2] * (self.ny + 1)) * (self.nx + 1) ids[6] = ids[7] + 1 return numerix.reshape(ids.swapaxes(1,3), (8, self.numberOfCells))
def _calcOrderedCellVertexIDs(self): """Correct ordering for VTK_VOXEL""" ids = numerix.zeros((8, self.nx, self.ny, self.nz), 'l') indices = numerix.indices((self.nx, self.ny, self.nz)) ids[1] = indices[0] + (indices[1] + (indices[2] + 1) * (self.ny + 1) + 1) * (self.nx + 1) ids[0] = ids[1] + 1 ids[3] = indices[0] + (indices[1] + (indices[2] + 1) * (self.ny + 1)) * (self.nx + 1) ids[2] = ids[3] + 1 ids[5] = indices[0] + (indices[1] + indices[2] * (self.ny + 1) + 1) * (self.nx + 1) ids[4] = ids[5] + 1 ids[7] = indices[0] + (indices[1] + indices[2] * (self.ny + 1)) * (self.nx + 1) ids[6] = ids[7] + 1 return numerix.reshape(ids.swapaxes(1, 3), (8, self.numberOfCells))
def _faceCenters(self): XYcen = numerix.zeros((3, self.nx, self.ny, self.nz + 1), 'd') indices = numerix.indices((self.nx, self.ny, self.nz + 1)) XYcen[0] = (indices[0] + 0.5) * self.dx XYcen[1] = (indices[1] + 0.5) * self.dy XYcen[2] = indices[2] * self.dz XZcen = numerix.zeros((3, self.nx, self.ny + 1, self.nz), 'd') indices = numerix.indices((self.nx, self.ny + 1, self.nz)) XZcen[0] = (indices[0] + 0.5) * self.dx XZcen[1] = indices[1] * self.dy XZcen[2] = (indices[2] + 0.5) * self.dz YZcen = numerix.zeros((3, self.nx + 1, self.ny, self.nz), 'd') indices = numerix.indices((self.nx + 1, self.ny, self.nz)) YZcen[0] = indices[0] * self.dx YZcen[1] = (indices[1] + 0.5) * self.dy YZcen[2] = (indices[2] + 0.5) * self.dz return numerix.concatenate((numerix.reshape(XYcen.swapaxes(1, 3), (3, self.numberOfXYFaces)), numerix.reshape(XZcen.swapaxes(1, 3), (3, self.numberOfXZFaces)), numerix.reshape(YZcen.swapaxes(1, 3), (3, self.numberOfYZFaces))), axis=1) + self.origin
def _calcFaceAreas(self): faceVertexIDs = MA.filled(self.faceVertexIDs, -1) substitute = numerix.repeat(faceVertexIDs[numerix.newaxis, 0], faceVertexIDs.shape[0], axis=0) faceVertexIDs = numerix.where(MA.getmaskarray(self.faceVertexIDs), substitute, faceVertexIDs) faceVertexCoords = numerix.take(self.vertexCoords, faceVertexIDs, axis=1) faceOrigins = numerix.repeat(faceVertexCoords[:,0], faceVertexIDs.shape[0], axis=0) faceOrigins = numerix.reshape(faceOrigins, MA.shape(faceVertexCoords)) faceVertexCoords = faceVertexCoords - faceOrigins left = range(faceVertexIDs.shape[0]) right = left[1:] + [left[0]] cross = numerix.sum(numerix.cross(faceVertexCoords, numerix.take(faceVertexCoords, right, 1), axis=0), 1) return numerix.sqrtDot(cross, cross) / 2.
def _cellToCellDistances(self): distances = numerix.zeros((6, self.nx, self.ny, self.nz), 'd') distances[0] = self.dx distances[1] = self.dx distances[2] = self.dy distances[3] = self.dy distances[4] = self.dz distances[5] = self.dz distances[0, 0, ... ] = self.dx / 2. distances[1, -1, ... ] = self.dx / 2. distances[2,:, 0,:] = self.dy / 2. distances[3,:, -1,:] = self.dy / 2. distances[4, ..., 0] = self.dz / 2. distances[5, ..., -1] = self.dz / 2. return numerix.reshape(distances.swapaxes(1, 3), (6, self.numberOfCells))
def _cellToCellDistances(self): distances = numerix.zeros((6, self.nx, self.ny, self.nz), 'd') distances[0] = self.dx distances[1] = self.dx distances[2] = self.dy distances[3] = self.dy distances[4] = self.dz distances[5] = self.dz distances[0, 0,... ] = self.dx / 2. distances[1, -1,... ] = self.dx / 2. distances[2, :, 0, :] = self.dy / 2. distances[3, :, -1, :] = self.dy / 2. distances[4,..., 0] = self.dz / 2. distances[5,..., -1] = self.dz / 2. return numerix.reshape(distances.swapaxes(1,3), (6, self.numberOfCells))
def _initialize(self): ##{{{ """ Initializes after signaling species have been added """ ##------ Signaling Species Specific self.img={} #Dictionary referencing the plot for ind,spec in enumerate(self.solspace.species.itervalues()): data=fnumerix.reshape(fnumerix.array(spec), spec.mesh.shape[::-1])[::-1] kwargs=spec.kwargs datamin = kwargs['datamin'] if 'datamin' in kwargs else 0 datamax = kwargs['datamax'] if 'datamax' in kwargs else 1 color = kwargs['color'] if 'color' in kwargs else "#0000FF" self.img[spec.name]=self.ax.imshow(data,extent=self.extent,alpha=1*0.5**ind,vmin=datamin,vmax=datamax,cmap=gen_cmap(color)) self.gui.add_switch(spec.name) # Add switch to GUI self.gui._initialize() self.init_state=True
def _plot_sol(self): ##{{{ """ Plots the solution layer plots based on GUI ticks """ #Update for spec in self.solspace.species.itervalues(): if self.gui.form[spec.name].value: #Checks the checkbox/gui/switch status data=fnumerix.reshape(fnumerix.array(spec), spec.mesh.shape[::-1])[::-1] self.img[spec.name].set_data(data) else: self.img[spec.name].set_data(np.array([[0],[0]])) self.canvas.draw() renderer = self.canvas.get_renderer() raw_data = renderer.tostring_rgb() surf = pg.image.fromstring(raw_data, self.size, "RGB") self.screen.blit(surf, (0,0))
def _globalMatrixAndVectors(self): if not hasattr(self, 'globalVectors'): globalMatrix = self.matrix overlappingVector = self.matrix._fipy2petscGhost(var=self.var) from fipy.variables.coupledCellVariable import _CoupledCellVariable if isinstance(self.RHSvector, _CoupledCellVariable): RHSvector = self.RHSvector else: RHSvector = numerix.reshape(numerix.asarray(self.RHSvector), self.var.shape) overlappingRHSvector = self.matrix._fipy2petscGhost(var=RHSvector) self.globalVectors = (globalMatrix, overlappingVector, overlappingRHSvector) return self.globalVectors
def _solve(self): from fipy.terms import SolutionVariableNumberError globalMatrix, overlappingVector, overlappingRHSvector = self._globalMatrixAndVectors if ((self.matrix == 0) or (self.matrix.matrix.sizes[0][1] != self.matrix.matrix.sizes[1][1]) or (self.matrix.matrix.sizes[0][1] != overlappingVector.size)): raise SolutionVariableNumberError self._solve_(globalMatrix.matrix, overlappingVector, overlappingRHSvector) value = self.matrix._petsc2fipyGhost(vec=overlappingVector) self.var.value = numerix.reshape(value, self.var.shape) self._deleteGlobalMatrixAndVectors() del self.var del self.RHSvector
def _cellVertexIDs(self): ## Get all the vertices from all the faces for each cell cellFaceVertices = numerix.take(self.faceVertexIDs, self.cellFaceIDs, axis=1) ## get a sorted list of vertices for each cell cellVertexIDs = numerix.reshape(cellFaceVertices, (-1, self.numberOfCells)) cellVertexIDs = MA.sort(cellVertexIDs, axis=0, fill_value=-1) cellVertexIDs = MA.sort(MA.concatenate((cellVertexIDs[-1, numerix.newaxis], MA.masked_where(cellVertexIDs[:-1] == cellVertexIDs[1:], cellVertexIDs[:-1]))), axis=0, fill_value=-1) ## resize the array to remove extra masked values if cellVertexIDs.shape[-1] == 0: length = 0 else: length = min(numerix.sum(MA.getmaskarray(cellVertexIDs), axis=0)) return cellVertexIDs[length:][::-1]
def calcDistanceFunction(self, order=2): """ Calculates the `distanceVariable` as a distance function. Parameters ---------- order : {`1`, `2`} The order of accuracy for the distance function calculation """ dx, shape = self.getLSMshape() if LSM_SOLVER == 'lsmlib': from pylsmlib import distance elif LSM_SOLVER == 'skfmm': from skfmm import distance else: raise Exception("Neither `lsmlib` nor `skfmm` can be found on the $PATH") self._value = distance(numerix.reshape(self._value, shape), dx=dx, order=order).flatten() self._markFresh()
def calcDistanceFunction(self, order=2): """ Calculates the `distanceVariable` as a distance function. :Parameters: - `order`: The order of accuracy for the distance funtion calculation, either 1 or 2. """ dx, shape = self.getLSMshape() if LSM_SOLVER == 'lsmlib': from pylsmlib import distance elif LSM_SOLVER == 'skfmm': from skfmm import distance else: raise Exception, "Neither `lsmlib` nor `skfmm` can be found on the $PATH" self._value = distance(numerix.reshape(self._value, shape), dx=dx, order=order).flatten() self._markFresh()
def __init__(self, faces, faceOrientations, id): """`Cell` is initialized by `Mesh` :Parameters: - `faces`: `list` or `tuple` of bounding faces that define the cell - `faceOrientations`: `list`, `tuple`, or `numerix.array` of orientations (+/-1) to indicate whether a face points into this face or out of it. Can be calculated, but the mesh typically knows this information already. - `id`: unique identifier """ self.faces = faces self.faceOrientations = numerix.array(faceOrientations) self.faceOrientations = numerix.reshape(faceOrientations,(len(faces),1)) self.id = id self.center = self._calcCenter() self.volume = self._calcVolume() for i in range(len(self.faces)): self.faces[i].addBoundingCell(self,faceOrientations[i])
def _cellValueOverFaces(self): """ Returns the cells values at the faces. >>> from fipy.meshes import Grid2D >>> from fipy.variables.cellVariable import CellVariable >>> mesh = Grid2D(dx = .5, dy = .5, nx = 2, ny = 2) >>> distanceVariable = DistanceVariable(mesh = mesh, ... value = (-0.5, 0.5, 0.5, 1.5)) >>> answer = CellVariable(mesh=mesh, ... value=((-.5, .5, .5, 1.5), ... (-.5, .5, .5, 1.5), ... (-.5, .5, .5, 1.5), ... (-.5, .5, .5, 1.5))) >>> print numerix.allclose(distanceVariable._cellValueOverFaces, answer) True """ M = self.mesh._maxFacesPerCell N = self.mesh.numberOfCells return numerix.reshape(numerix.repeat(numerix.array(self._value)[numerix.newaxis, ...], M, axis=0), (M, N))
def _solve(self): from fipy.terms import SolutionVariableNumberError globalMatrix, nonOverlappingVector, nonOverlappingRHSvector, overlappingVector = self._globalMatrixAndVectors if not (globalMatrix.rangeMap.SameAs(globalMatrix.domainMap) and globalMatrix.rangeMap.SameAs(nonOverlappingVector.Map())): raise SolutionVariableNumberError self._solve_(globalMatrix.matrix, nonOverlappingVector, nonOverlappingRHSvector) overlappingVector.Import(nonOverlappingVector, Epetra.Import(globalMatrix.colMap, globalMatrix.domainMap), Epetra.Insert) self.var.value = numerix.reshape(numerix.array(overlappingVector), self.var.shape) self._deleteGlobalMatrixAndVectors() del self.var del self.RHSvector
def _extrude(self, mesh, extrudeFunc, layers): ## should extrude cnahe self rather than creating a new mesh? ## the following allows the 2D mesh to be in 3D space, this can be the case for a ## Gmsh2DIn3DSpace which would then be extruded. oldVertices = mesh.vertexCoords if oldVertices.shape[0] == 2: oldVertices = numerix.resize(oldVertices, (3, len(oldVertices[0]))) oldVertices[2] = 0 NCells = mesh.numberOfCells NFac = mesh.numberOfFaces NFacPerCell = mesh._maxFacesPerCell ## set up the initial data arrays new_shape = (max(NFacPerCell, 4), (1 + layers)*NCells + layers*NFac) faces = numerix.MA.masked_values(-numerix.ones(new_shape, 'l'), value = -1) orderedVertices = mesh._orderedCellVertexIDs faces[:NFacPerCell, :NCells] = orderedVertices vertices = oldVertices vert0 = mesh.faceVertexIDs faceCount = NCells for layer in range(layers): ## need this later initialFaceCount = faceCount ## build the vertices newVertices = extrudeFunc(oldVertices) vertices = numerix.concatenate((vertices, newVertices), axis=1) ## build the faces along the layers faces[:NFacPerCell, faceCount: faceCount + NCells] = orderedVertices + len(oldVertices[0]) * (layer + 1) try: # numpy 1.1 doesn't copy right side before assigning slice # See: http://www.mail-archive.com/[email protected]/msg09843.html faces[:NFacPerCell, faceCount: faceCount + NCells] = faces[:NFacPerCell, faceCount: faceCount + NCells][::-1,:].copy() except: faces[:NFacPerCell, faceCount: faceCount + NCells] = faces[:NFacPerCell, faceCount: faceCount + NCells][::-1,:] faceCount = faceCount + NCells vert1 = (vert0 + len(oldVertices[0]))[::-1,:] ## build the faces between the layers faces[:4, faceCount: faceCount + NFac] = numerix.concatenate((vert0, vert1), axis = 0)[::-1,:] vert0 = vert0 + len(oldVertices[0]) NCells = mesh.numberOfCells ## build the cells, the first layer has slightly different ordering if layer == 0: c0 = numerix.reshape(numerix.arange(NCells), (1, NCells)) cells = numerix.concatenate((c0, c0 + NCells, mesh.cellFaceIDs + 2 * NCells), axis = 0) else: newCells = numerix.concatenate((c0, c0 + initialFaceCount, mesh.cellFaceIDs + faceCount), axis=0) newCells[0] = cells[1,-NCells:] cells = numerix.concatenate((cells, newCells), axis=1) ## keep a count of things for the next layer faceCount = faceCount + NFac oldVertices = newVertices ## return a new mesh, extrude could just as easily act on self return Mesh(vertices, faces, cells, communicator=mesh.communicator)
def _execInline(self, comment=None): """ Gets the stack from _getCstring() which calls _getRepresentation() >>> (Variable((1,2,3,4)) * Variable((5,6,7,8)))._getCstring() '(var0[i] * var1[i])' >>> (Variable(((1,2),(3,4))) * Variable(((5,6),(7,8))))._getCstring() '(var0[i + j * ni] * var1[i + j * ni])' >>> (Variable((1,2)) * Variable((5,6)) * Variable((7,8)))._getCstring() '((var00[i] * var01[i]) * var1[i])' The following test was implemented due to a problem with contiguous arrays. The `mesh.getCellCenters()[1]` command introduces a non-contiguous array into the `Variable` and this causes the inline routine to return senseless results. >>> from fipy import Grid2D, CellVariable >>> mesh = Grid2D(dx=1., dy=1., nx=2, ny=2) >>> var = CellVariable(mesh=mesh, value=0.) >>> Y = mesh.getCellCenters()[1] >>> var.setValue(Y + 1.0) >>> print var - Y [ 1. 1. 1. 1.] """ from fipy.tools import inline argDict = {} string = self._getCstring(argDict=argDict, freshen=True) + ';' try: shape = self.opShape except AttributeError: shape = self.shape dimensions = len(shape) if dimensions == 0: string = 'result[0] = ' + string dim = () else: string = 'result' + self._getCIndexString(shape) + ' = ' + string ni = self.opShape[-1] argDict['ni'] = ni if dimensions == 1: dim = (ni) else: nj = self.opShape[-2] argDict['nj'] = nj if dimensions == 2: dim =(nj,ni) elif dimensions == 3: nk = self.opShape[-3] dim = (nk,nj,ni) argDict['nk'] = nk else: raise DimensionError, 'Impossible Dimensions' ## Following section makes sure that the result array has a ## valid typecode. If self.value is None then a typecode is ## assigned to the Variable by running the calculation without ## inlining. The non-inlined result is thus used the first ## time through. if self.value is None and not hasattr(self, 'typecode'): self.canInline = False argDict['result'] = self.getValue() self.canInline = True self.typecode = numerix.obj2sctype(argDict['result']) else: if self.value is None: if self.getsctype() == numerix.bool_: argDict['result'] = numerix.empty(dim, numerix.int8) else: argDict['result'] = numerix.empty(dim, self.getsctype()) else: argDict['result'] = self.value resultShape = argDict['result'].shape if resultShape == (): argDict['result'] = numerix.reshape(argDict['result'], (1,)) inline._runInline(string, converters=None, comment=comment, **argDict) if resultShape == (): argDict['result'] = numerix.reshape(argDict['result'], resultShape) return argDict['result']
def _data(self): from fipy.tools.numerix import array, reshape return reshape(array(self.vars[0]), self.vars[0].mesh.shape[::-1])[::-1]
def _buildMatrix(self, var, SparseMatrix, boundaryConditions=(), dt=None, transientGeomCoeff=None, diffusionGeomCoeff=None): """ Test to ensure that a changing coefficient influences the boundary conditions. >>> from fipy import * >>> m = Grid2D(nx=2, ny=2) >>> v = CellVariable(mesh=m) >>> c0 = Variable(1.) >>> v.constrain(c0, where=m.facesLeft) Diffusion will only be in the y-direction >>> coeff = Variable([[0. , 0.], [0. , 1.]]) >>> eq = DiffusionTerm(coeff) >>> eq.solve(v, solver=DummySolver()) >>> print v [ 0. 0. 0. 0.] Change the coefficient. >>> coeff[0, 0] = 1. >>> eq.solve(v) >>> print v [ 1. 1. 1. 1.] Change the constraints. >>> c0.setValue(2.) >>> v.constrain(3., where=m.facesRight) >>> print v.faceValue.constraintMask [False False False False False False True False True True False True] >>> eq.solve(v) >>> print v [ 2.25 2.75 2.25 2.75] """ var, L, b = self.__higherOrderbuildMatrix( var, SparseMatrix, boundaryConditions=boundaryConditions, dt=dt, transientGeomCoeff=transientGeomCoeff, diffusionGeomCoeff=diffusionGeomCoeff) mesh = var.mesh if self.order == 2: if (not hasattr(self, 'constraintL')) or (not hasattr( self, 'constraintB')): normals = FaceVariable(mesh=mesh, rank=1, value=mesh._orientedFaceNormals) if len(var.shape) == 1 and len(self.nthCoeff.shape) > 1: nthCoeffFaceGrad = var.faceGrad.dot(self.nthCoeff) normalsNthCoeff = normals.dot(self.nthCoeff) else: if self.nthCoeff.shape != () and not isinstance( self.nthCoeff, FaceVariable): coeff = self.nthCoeff[..., numerix.newaxis] else: coeff = self.nthCoeff nthCoeffFaceGrad = coeff[ numerix.newaxis] * var.faceGrad[:, numerix.newaxis] s = (slice(0, None, None), ) + (numerix.newaxis, ) * ( len(coeff.shape) - 1) + (slice(0, None, None), ) normalsNthCoeff = coeff[numerix.newaxis] * normals[s] self.constraintB = -( var.faceGrad.constraintMask * nthCoeffFaceGrad).divergence * mesh.cellVolumes constrainedNormalsDotCoeffOverdAP = var.arithmeticFaceValue.constraintMask * \ normalsNthCoeff / mesh._cellDistances self.constraintB -= ( constrainedNormalsDotCoeffOverdAP * var.arithmeticFaceValue).divergence * mesh.cellVolumes ids = self._reshapeIDs(var, numerix.arange(mesh.numberOfCells)) self.constraintL = -constrainedNormalsDotCoeffOverdAP.divergence * mesh.cellVolumes ids = self._reshapeIDs(var, numerix.arange(mesh.numberOfCells)) L.addAt(self.constraintL.ravel(), ids.ravel(), ids.swapaxes(0, 1).ravel()) b += numerix.reshape(self.constraintB.ravel(), ids.shape).sum(-2).ravel() return (var, L, b)
def getNumpyArray(self): shape = self._getShape() indices = numerix.indices(shape) numMatrix = self.take(indices[0].ravel(), indices[1].ravel()) return numerix.reshape(numMatrix, shape)
def numpyArray(self): shape = self._shape indices = numerix.indices(shape) numMatrix = self.take(indices[0].ravel(), indices[1].ravel()) return numerix.reshape(numMatrix, shape)
def _extrude(self, mesh, extrudeFunc, layers): ## should extrude self rather than creating a new mesh? ## the following allows the 2D mesh to be in 3D space, this can be the case for a ## Gmsh2DIn3DSpace which would then be extruded. oldVertices = mesh.vertexCoords if oldVertices.shape[0] == 2: oldVertices = numerix.resize(oldVertices, (3, len(oldVertices[0]))) oldVertices[2] = 0 NCells = mesh.numberOfCells NFac = mesh.numberOfFaces NFacPerCell = mesh._maxFacesPerCell ## set up the initial data arrays new_shape = (max(NFacPerCell, 4), (1 + layers)*NCells + layers*NFac) faces = numerix.MA.masked_values(-numerix.ones(new_shape, 'l'), value = -1) orderedVertices = mesh._orderedCellVertexIDs faces[:NFacPerCell, :NCells] = orderedVertices vertices = oldVertices vert0 = mesh.faceVertexIDs faceCount = NCells for layer in range(layers): ## need this later initialFaceCount = faceCount ## build the vertices newVertices = extrudeFunc(oldVertices) vertices = numerix.concatenate((vertices, newVertices), axis=1) ## build the faces along the layers faces[:NFacPerCell, faceCount: faceCount + NCells] = orderedVertices + len(oldVertices[0]) * (layer + 1) try: # numpy 1.1 doesn't copy right side before assigning slice # See: http://www.mail-archive.com/[email protected]/msg09843.html faces[:NFacPerCell, faceCount: faceCount + NCells] = faces[:NFacPerCell, faceCount: faceCount + NCells][::-1,:].copy() except: faces[:NFacPerCell, faceCount: faceCount + NCells] = faces[:NFacPerCell, faceCount: faceCount + NCells][::-1,:] faceCount = faceCount + NCells vert1 = (vert0 + len(oldVertices[0]))[::-1,:] ## build the faces between the layers faces[:4, faceCount: faceCount + NFac] = numerix.concatenate((vert0, vert1), axis = 0)[::-1,:] vert0 = vert0 + len(oldVertices[0]) NCells = mesh.numberOfCells ## build the cells, the first layer has slightly different ordering if layer == 0: c0 = numerix.reshape(numerix.arange(NCells), (1, NCells)) cells = numerix.concatenate((c0, c0 + NCells, mesh.cellFaceIDs + 2 * NCells), axis = 0) else: newCells = numerix.concatenate((c0, c0 + initialFaceCount, mesh.cellFaceIDs + faceCount), axis=0) newCells[0] = cells[1, -NCells:] cells = numerix.concatenate((cells, newCells), axis=1) ## keep a count of things for the next layer faceCount = faceCount + NFac oldVertices = newVertices ## return a new mesh, extrude could just as easily act on self return Mesh(vertices, faces, cells, communicator=mesh.communicator)
def _getData(self): from fipy.tools.numerix import array, reshape return reshape(array(self.vars[0]), self.vars[0].getMesh().getShape()[::-1])[::-1]
phi_value = phi_value + delta # phi is increased by delta at end of each loop print('Total number of cells covered = ' + str(total_size)) #type(m_cell_sph) ######## Converted the spherical polar coordinates back to cartesian coordinate ##################### m_x = (m_cell_sph[0, :] * numerix.sin(m_cell_sph[2, :]) * numerix.cos(m_cell_sph[1, :])) m_y = (m_cell_sph[0, :] * numerix.sin(m_cell_sph[2, :]) * numerix.sin(m_cell_sph[1, :])) m_z = m_cell_sph[0, :] * numerix.cos(m_cell_sph[2, :]) m_cellcenters_cart_modified = numerix.array([[m_x], [m_y], [m_z]]) #numerix.shape(m_cellcenters_cart_modified) m_cellcenters_cart_modified = numerix.reshape(m_cellcenters_cart_modified, (3, total_size)) #mcell_new=m_cellcenters_cart_modified*CellVariable([1.0]) mcell_new = CellVariable(mesh=mesh, value=m_cellcenters_cart_modified) #type(mcell_new) #mcell_new.shape #type(rho) print('Calculation starts') interpolated_rho = rho(mcell_new.globalValue, order=1) pickle.dump(interpolated_rho, open("interpolated rho.p", "wb"))