def __init__(self, mesh, name = '', value = 0., unit = None, hasOld = 0, narrowBandWidth = 1e+10): """ Creates a `distanceVariable` object. :Parameters: - `mesh`: The mesh that defines the geometry of this variable. - `name`: The name of the variable. - `value`: The initial value. - `unit`: the physical units of the variable - `hasOld`: Whether the variable maintains an old value. - `narrowBandWidth`: The width of the region about the zero level set within which the distance function is evaluated. """ CellVariable.__init__(self, mesh, name = name, value = value, unit = unit, hasOld = hasOld) self._markStale() self.narrowBandWidth = narrowBandWidth self.cellToCellDistances = MA.filled(self.mesh._getCellToCellDistances(), 0) self.cellNormals = MA.filled(self.mesh._getCellNormals(), 0) self.cellAreas = MA.filled(self.mesh._getCellAreas(), 0) ## self.cellToCellDistances = numerix.array(MA.array(self.mesh._getCellToCellDistances()).filled(0)) ## self.cellNormals = numerix.array(MA.array(self.mesh._getCellNormals()).filled(0)) ## self.cellAreas = numerix.array(MA.array(self.mesh._getCellAreas()).filled(0)) self.cellToCellIDs = numerix.array(self.mesh._getCellToCellIDsFilled()) self.adjacentCellIDs = self.mesh._getAdjacentCellIDs() self.exteriorFaces = self.mesh.getExteriorFaces() self.cellFaceIDs = self.mesh._getCellFaceIDs()
def _calcCellDistAndVec(self): tmp = numerix.take(self._cellCenters, self.faceCellIDs, axis=1) tmp = tmp[...,1,:] - tmp[...,0,:] tmp = MA.filled(MA.where(MA.getmaskarray(tmp), self._cellToFaceDistanceVectors[:,0], tmp)) cellDistanceVectors = tmp cellDistances = MA.filled(MA.sqrt(MA.sum(tmp * tmp, 0))) return cellDistances, cellDistanceVectors
def _calcValue(self): Nfaces = self.mesh.numberOfFaces M = self.mesh._maxFacesPerCell dim = self.mesh.dim cellFaceIDs = self.mesh.cellFaceIDs faceNormalAreas = self.distanceVar._levelSetNormals * self.mesh._faceAreas cellFaceNormalAreas = numerix.array(MA.filled(numerix.take(faceNormalAreas, cellFaceIDs, axis=-1), 0)) norms = numerix.array(MA.filled(MA.array(self.mesh._cellNormals), 0)) alpha = numerix.dot(cellFaceNormalAreas, norms) alpha = numerix.where(alpha > 0, alpha, 0) alphasum = numerix.sum(alpha, axis=0) alphasum += (alphasum < 1e-100) * 1.0 alpha = alpha / alphasum phi = numerix.repeat(self.distanceVar[numerix.newaxis, ...], M, axis=0) alpha = numerix.where(phi > 0., 0, alpha) volumes = numerix.array(self.mesh.cellVolumes) alpha = alpha * volumes * norms value = numerix.zeros((dim, Nfaces), 'd') vector._putAdd(value, cellFaceIDs, alpha, mask=MA.getmask(MA.array(cellFaceIDs))) ## value = numerix.reshape(value, (dim, Nfaces, dim)) return -value / self.mesh._faceAreas
def getCellInterfaceAreas(self): """ Returns the length of the interface that crosses the cell A simple 1D test: >>> from fipy.meshes.grid1D import Grid1D >>> mesh = Grid1D(dx = 1., nx = 4) >>> distanceVariable = DistanceVariable(mesh = mesh, ... value = (-1.5, -0.5, 0.5, 1.5)) >>> answer = CellVariable(mesh=mesh, value=(0, 0., 1., 0)) >>> print numerix.allclose(distanceVariable.getCellInterfaceAreas(), ... answer) True A 2D test case: >>> from fipy.meshes.grid2D import Grid2D >>> from fipy.variables.cellVariable import CellVariable >>> mesh = Grid2D(dx = 1., dy = 1., nx = 3, ny = 3) >>> distanceVariable = DistanceVariable(mesh = mesh, ... value = (1.5, 0.5, 1.5, ... 0.5,-0.5, 0.5, ... 1.5, 0.5, 1.5)) >>> answer = CellVariable(mesh=mesh, ... value=(0, 1, 0, 1, 0, 1, 0, 1, 0)) >>> print numerix.allclose(distanceVariable.getCellInterfaceAreas(), answer) True Another 2D test case: >>> mesh = Grid2D(dx = .5, dy = .5, nx = 2, ny = 2) >>> from fipy.variables.cellVariable import CellVariable >>> distanceVariable = DistanceVariable(mesh = mesh, ... value = (-0.5, 0.5, 0.5, 1.5)) >>> answer = CellVariable(mesh=mesh, ... value=(0, numerix.sqrt(2) / 4, numerix.sqrt(2) / 4, 0)) >>> print numerix.allclose(distanceVariable.getCellInterfaceAreas(), ... answer) True Test to check that the circumfrence of a circle is, in fact, :math:`2\pi r`. >>> mesh = Grid2D(dx = 0.05, dy = 0.05, nx = 20, ny = 20) >>> r = 0.25 >>> x, y = mesh.getCellCenters() >>> rad = numerix.sqrt((x - .5)**2 + (y - .5)**2) - r >>> distanceVariable = DistanceVariable(mesh = mesh, value = rad) >>> print distanceVariable.getCellInterfaceAreas().sum() 1.57984690073 """ normals = numerix.array(MA.filled(self._getCellInterfaceNormals(), 0)) areas = numerix.array(MA.filled(self.mesh._getCellAreaProjections(), 0)) return CellVariable(mesh=self.mesh, value=numerix.sum(abs(numerix.dot(normals, areas)), axis=0))
def _calcFaceCenters(self): maskedFaceVertexIDs = MA.filled(self.faceVertexIDs, 0) faceVertexCoords = numerix.take(self.vertexCoords, maskedFaceVertexIDs, axis=1) if MA.getmask(self.faceVertexIDs) is False: faceVertexCoordsMask = numerix.zeros(numerix.shape(faceVertexCoords), 'l') else: faceVertexCoordsMask = \ numerix.repeat(MA.getmaskarray(self.faceVertexIDs)[numerix.newaxis,...], self.dim, axis=0) faceVertexCoords = MA.array(data=faceVertexCoords, mask=faceVertexCoordsMask) return MA.filled(MA.average(faceVertexCoords, axis=1))
def _calcValue(self): flag = MA.filled( numerix.take(self.distanceVar._interfaceFlag, self.mesh.cellFaceIDs), 0) flag = numerix.sum(flag, axis=0) return numerix.where( numerix.logical_and(self.distanceVar.value > 0, flag > 0), 1, 0)
def _buildMatrix(self, var, SparseMatrix, boundaryConditions=(), dt=None, equation=None, transientGeomCoeff=None, diffusionGeomCoeff=None): oldArray = var.old mesh = var.mesh NCells = mesh.numberOfCells NCellFaces = mesh._maxFacesPerCell cellValues = numerix.repeat(oldArray[numerix.newaxis, ...], NCellFaces, axis = 0) cellIDs = numerix.repeat(numerix.arange(NCells)[numerix.newaxis, ...], NCellFaces, axis = 0) cellToCellIDs = mesh._cellToCellIDs if NCells > 0: cellToCellIDs = MA.where(MA.getmask(cellToCellIDs), cellIDs, cellToCellIDs) adjacentValues = numerix.take(oldArray, cellToCellIDs) differences = self._getDifferences(adjacentValues, cellValues, oldArray, cellToCellIDs, mesh) differences = MA.filled(differences, 0) minsq = numerix.sqrt(numerix.sum(numerix.minimum(differences, numerix.zeros((NCellFaces, NCells), 'l'))**2, axis=0)) maxsq = numerix.sqrt(numerix.sum(numerix.maximum(differences, numerix.zeros((NCellFaces, NCells), 'l'))**2, axis=0)) coeff = numerix.array(self._getGeomCoeff(var)) coeffXdifferences = coeff * ((coeff > 0.) * minsq + (coeff < 0.) * maxsq) else: coeffXdifferences = 0. return (var, SparseMatrix(mesh=var.mesh), -coeffXdifferences * mesh.cellVolumes)
def _buildMatrix(self, var, SparseMatrix, boundaryConditions=(), dt=None, equation=None, transientGeomCoeff=None, diffusionGeomCoeff=None): oldArray = var.old mesh = var.mesh NCells = mesh.numberOfCells NCellFaces = mesh._maxFacesPerCell cellValues = numerix.repeat(oldArray[numerix.newaxis, ...], NCellFaces, axis = 0) cellIDs = numerix.repeat(numerix.arange(NCells)[numerix.newaxis, ...], NCellFaces, axis = 0) cellToCellIDs = mesh._cellToCellIDs if NCells > 0: cellToCellIDs = MA.where(MA.getmask(cellToCellIDs), cellIDs, cellToCellIDs) adjacentValues = numerix.take(oldArray, cellToCellIDs) differences = self._getDifferences(adjacentValues, cellValues, oldArray, cellToCellIDs, mesh) differences = MA.filled(differences, 0) minsq = numerix.sqrt(numerix.sum(numerix.minimum(differences, numerix.zeros((NCellFaces, NCells), 'l'))**2, axis=0)) maxsq = numerix.sqrt(numerix.sum(numerix.maximum(differences, numerix.zeros((NCellFaces, NCells), 'l'))**2, axis=0)) coeff = numerix.array(self._getGeomCoeff(var)) coeffXdiffereneces = coeff * ((coeff > 0.) * minsq + (coeff < 0.) * maxsq) else: coeffXdiffereneces = 0. return (var, SparseMatrix(mesh=var.mesh), -coeffXdiffereneces * mesh.cellVolumes)
def _buildMatrix(self, var, SparseMatrix, boundaryCondtions=(), dt=None, equation=None): oldArray = var.getOld() mesh = var.getMesh() NCells = mesh.getNumberOfCells() NCellFaces = mesh._getMaxFacesPerCell() cellValues = numerix.repeat(oldArray[numerix.newaxis, ...], NCellFaces, axis = 0) cellIDs = numerix.repeat(numerix.arange(NCells)[numerix.newaxis, ...], NCellFaces, axis = 0) cellToCellIDs = mesh._getCellToCellIDs() if NCells > 0: cellToCellIDs = MA.where(MA.getmask(cellToCellIDs), cellIDs, cellToCellIDs) adjacentValues = numerix.take(oldArray, cellToCellIDs) differences = self._getDifferences(adjacentValues, cellValues, oldArray, cellToCellIDs, mesh) differences = MA.filled(differences, 0) minsq = numerix.sqrt(numerix.sum(numerix.minimum(differences, numerix.zeros((NCellFaces, NCells)))**2, axis=0)) maxsq = numerix.sqrt(numerix.sum(numerix.maximum(differences, numerix.zeros((NCellFaces, NCells)))**2, axis=0)) coeff = numerix.array(self._getGeomCoeff(mesh)) coeffXdiffereneces = coeff * ((coeff > 0.) * minsq + (coeff < 0.) * maxsq) else: coeffXdiffereneces = 0. return (SparseMatrix(mesh=var.getMesh()), -coeffXdiffereneces * mesh.getCellVolumes())
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 _rightHandOrientation(self): faceVertexIDs = MA.filled(self.faceVertexIDs, 0) faceVertexCoords = numerix.take(self.vertexCoords, faceVertexIDs, axis=1) t1 = faceVertexCoords[:,1,:] - faceVertexCoords[:,0,:] t2 = faceVertexCoords[:,2,:] - faceVertexCoords[:,1,:] norm = numerix.cross(t1, t2, axis=0) ## reordering norm's internal memory for inlining norm = norm.copy() norm = norm / numerix.sqrtDot(norm, norm) faceNormals = -norm return 1 - 2 * (numerix.dot(faceNormals, self.cellDistanceVectors) < 0)
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 _getNonOrthogonality(self): exteriorFaceArray = numerix.zeros((self.faceCellIDs.shape[1],)) numerix.put(exteriorFaceArray, numerix.nonzero(self.getExteriorFaces()), 1) unmaskedFaceCellIDs = MA.filled(self.faceCellIDs, 0) ## what we put in for the "fill" doesn't matter because only exterior faces have anything masked, and exterior faces have their displacement vectors set to zero. ## if it's an exterior face, make the "displacement vector" equal to zero so the cross product will be zero. faceDisplacementVectors = numerix.where(numerix.array(zip(exteriorFaceArray, exteriorFaceArray)), 0.0, numerix.take(self._getCellCenters().swapaxes(0,1), unmaskedFaceCellIDs[1, :]) - numerix.take(self._getCellCenters().swapaxes(0,1), unmaskedFaceCellIDs[0, :])).swapaxes(0,1) faceCrossProducts = (faceDisplacementVectors[0, :] * self.faceNormals[1, :]) - (faceDisplacementVectors[1, :] * self.faceNormals[0, :]) faceDisplacementVectorLengths = numerix.maximum(((faceDisplacementVectors[0, :] ** 2) + (faceDisplacementVectors[1, :] ** 2)) ** 0.5, 1.e-100) faceWeightedNonOrthogonalities = abs(faceCrossProducts / faceDisplacementVectorLengths) * self.faceAreas cellFaceWeightedNonOrthogonalities = numerix.take(faceWeightedNonOrthogonalities, self.cellFaceIDs) cellFaceAreas = numerix.take(self.faceAreas, self.cellFaceIDs) cellTotalWeightedValues = numerix.add.reduce(cellFaceWeightedNonOrthogonalities, axis = 0) cellTotalFaceAreas = numerix.add.reduce(cellFaceAreas, axis = 0) return (cellTotalWeightedValues / cellTotalFaceAreas)
def _getCellInterfaceFlag(self): """ Returns 1 for those cells on the interface: >>> from fipy.meshes.grid2D 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=(0, 1, 1, 0)) >>> print numerix.allclose(distanceVariable._getCellInterfaceFlag(), answer) True """ flag = MA.filled(numerix.take(self._getInterfaceFlag(), self.cellFaceIDs), 0) flag = numerix.sum(flag, axis=0) return numerix.where(numerix.logical_and(self.value > 0, flag > 0), 1, 0)
def _nonOrthogonality(self): exteriorFaceArray = numerix.zeros((self.faceCellIDs.shape[1], ), 'l') numerix.put(exteriorFaceArray, numerix.nonzero(self.exteriorFaces), 1) unmaskedFaceCellIDs = MA.filled(self.faceCellIDs, 0) # what we put in for the "fill" doesn't matter because only exterior # faces have anything masked, and exterior faces have their displacement # vectors set to zero. # # if it's an exterior face, make the "displacement vector" equal to zero # so the cross product will be zero. faceDisplacementVectors = \ numerix.where(numerix.array(zip(exteriorFaceArray, exteriorFaceArray)), 0.0, numerix.take(self._scaledCellCenters.swapaxes(0,1), unmaskedFaceCellIDs[1, :]) \ - numerix.take(self._scaledCellCenters.swapaxes(0,1), unmaskedFaceCellIDs[0, :])) faceDisplacementVectors = faceDisplacementVectors.swapaxes(0, 1) faceCrossProducts = (faceDisplacementVectors[0, :] * self.faceNormals[1,:]) \ - (faceDisplacementVectors[1, :] * self.faceNormals[0, :]) faceDisplacementVectorLengths = numerix.maximum(((faceDisplacementVectors[0, :] ** 2) \ + (faceDisplacementVectors[1, :] ** 2)) ** 0.5, 1.e-100) faceWeightedNonOrthogonalities = abs( faceCrossProducts / faceDisplacementVectorLengths) * self._faceAreas cellFaceWeightedNonOrthogonalities = numerix.take( faceWeightedNonOrthogonalities, self.cellFaceIDs) cellFaceAreas = numerix.take(self._faceAreas, self.cellFaceIDs) cellTotalWeightedValues = numerix.add.reduce( cellFaceWeightedNonOrthogonalities, axis=0) cellTotalFaceAreas = numerix.add.reduce(cellFaceAreas, axis=0) return (cellTotalWeightedValues / cellTotalFaceAreas)
def _calcCellCenters( self ): #cell center from bot1 and top1 (ignore coordinates of eventual bot2 and top2) tmp = numerix.take(self._faceCenters, self.cellFaceIDs[:2, :], axis=1) return MA.filled(MA.average(tmp, 1))
def _calcValue(self): normals = numerix.array( MA.filled(self.distanceVar._cellInterfaceNormals, 0)) areas = numerix.array(MA.filled(self.mesh._cellAreaProjections, 0)) return numerix.sum(abs(numerix.dot(normals, areas)), axis=0)
def _calcFaceToCellDistanceRatio(self): dAP = self._cellDistances dFP = self._faceToCellDistances[0] return MA.filled(dFP / dAP)
def _calcCellVolumes(self): tmp = self._faceCenters[0] * self._faceAreas * self.faceNormals[0] tmp = numerix.take(tmp, self.cellFaceIDs) * self._cellToFaceOrientations return MA.filled(MA.sum(tmp, 0))
def _calcCellCenters(self): tmp = numerix.take(self._faceCenters, self.cellFaceIDs, axis=1) return MA.filled(MA.average(tmp, 1))
def _calcFaceToCellDistanceRatio(self): dAP = self._getCellDistances() dFP = self._getFaceToCellDistances()[0] self.faceToCellDistanceRatio = MA.filled(dFP / dAP)
def _calcValue(self): normals = numerix.array(MA.filled(self.distanceVar._cellInterfaceNormals, 0)) areas = numerix.array(MA.filled(self.mesh._cellAreaProjections, 0)) return numerix.sum(abs(numerix.dot(normals, areas)), axis=0)
def _calcAdjacentCellIDs(self): return (MA.filled(self.faceCellIDs[0]), MA.filled(MA.where(MA.getmaskarray(self.faceCellIDs[1]), self.faceCellIDs[0], self.faceCellIDs[1])))
def _calcDistanceFunction(self, extensionVariable = None, narrowBandWidth = None, deleteIslands = False): if narrowBandWidth == None: narrowBandWidth = self.narrowBandWidth ## calculate interface values cellToCellIDs = self.mesh._getCellToCellIDs() if deleteIslands: adjVals = numerix.take(self.value, cellToCellIDs) adjInterfaceValues = MA.masked_array(adjVals, mask = (adjVals * self.value) > 0) masksum = numerix.sum(numerix.logical_not(MA.getmask(adjInterfaceValues)), 0) tmp = MA.logical_and(masksum == 4, self.value > 0) self.value = MA.where(tmp, -1, self.value) adjVals = numerix.take(self.value, cellToCellIDs) adjInterfaceValues = MA.masked_array(adjVals, mask = (adjVals * self.value) > 0) dAP = self.mesh._getCellToCellDistances() distances = abs(self.value * dAP / (self.value - adjInterfaceValues)) indices = MA.argsort(distances, 0) sign = (self.value > 0) * 2 - 1 s = distances[indices[0], numerix.arange(indices.shape[1])] if self.mesh.getDim() == 2: t = distances[indices[1], numerix.arange(indices.shape[1])] u = distances[indices[2], numerix.arange(indices.shape[1])] if indices.shape[1] > 0: ns = self.cellNormals[..., indices[0], numerix.arange(indices.shape[1])] nt = self.cellNormals[..., indices[1], numerix.arange(indices.shape[1])] else: ns = MA.zeros(self.cellNormals.shape[:-1] + (0,)) nt = MA.zeros(self.cellNormals.shape[:-1] + (0,)) signedDistance = MA.where(MA.getmask(s), self.value, MA.where(MA.getmask(t), sign * s, MA.where(abs(numerix.dot(ns,nt)) < 0.9, sign * s * t / MA.sqrt(s**2 + t**2), MA.where(MA.getmask(u), sign * s, sign * s * u / MA.sqrt(s**2 + u**2) ) ) ) ) else: signedDistance = MA.where(MA.getmask(s), self.value, sign * s) self.value = signedDistance ## calculate interface flag masksum = numerix.sum(numerix.logical_not(MA.getmask(distances)), 0) interfaceFlag = (masksum > 0).astype('l') ## spread the extensionVariable to the whole interface flag = True if extensionVariable is None: extensionVariable = numerix.zeros(self.mesh.getNumberOfCells(), 'd') flag = False ext = numerix.zeros(self.mesh.getNumberOfCells(), 'd') positiveInterfaceFlag = numerix.where(self.value > 0, interfaceFlag, 0) negativeInterfaceIDs = numerix.nonzero(numerix.where(self.value < 0, interfaceFlag, 0))[0] for id in negativeInterfaceIDs: tmp, extensionVariable[...,id] = self._calcTrialValue(id, positiveInterfaceFlag, extensionVariable) if flag: self.value = self.tmpValue.copy() ## evaluate the trialIDs adjInterfaceFlag = numerix.take(interfaceFlag, cellToCellIDs) hasAdjInterface = (numerix.sum(MA.filled(adjInterfaceFlag, 0), 0) > 0).astype('l') trialFlag = numerix.logical_and(numerix.logical_not(interfaceFlag), hasAdjInterface).astype('l') trialIDs = list(numerix.nonzero(trialFlag)[0]) evaluatedFlag = interfaceFlag for id in trialIDs: self.value[...,id], extensionVariable[id] = self._calcTrialValue(id, evaluatedFlag, extensionVariable) while len(trialIDs): id = trialIDs[numerix.argmin(abs(numerix.take(self.value, trialIDs)))] if abs(self.value[...,id]) > narrowBandWidth / 2: break trialIDs.remove(id) evaluatedFlag[...,id] = 1 for adjID in MA.filled(cellToCellIDs[...,id], -1): if adjID != -1: if not evaluatedFlag[...,adjID]: self.value[...,adjID], extensionVariable[...,adjID] = self._calcTrialValue(adjID, evaluatedFlag, extensionVariable) if adjID not in trialIDs: trialIDs.append(adjID) self.value = numerix.array(self.value)
def _calcValue(self): flag = MA.filled(numerix.take(self.distance._interfaceFlag, self.mesh.cellFaceIDs), 0) flag = numerix.sum(flag, axis=0) corner_flag = numerix.where(numerix.logical_and(self.distance.value > 0, flag > 1), 1, 0) return corner_flag | self.mask
def _calcAdjacentCellIDs(self): return (MA.filled(self.faceCellIDs[0]), MA.filled( MA.where(MA.getmaskarray(self.faceCellIDs[1]), self.faceCellIDs[0], self.faceCellIDs[1])))