def _calcInteriorAndExteriorFaceIDs(self): from fipy.variables.faceVariable import FaceVariable mask = MA.getmask(self.faceCellIDs[1]) exteriorFaces = FaceVariable(mesh=self, value=mask) interiorFaces = FaceVariable(mesh=self, value=numerix.logical_not(mask)) return interiorFaces, exteriorFaces
def _calcGeomCoeff(self, var): mesh = var.mesh if self.nthCoeff is not None: coeff = self.nthCoeff shape = numerix.getShape(coeff) if isinstance(coeff, FaceVariable): rank = coeff.rank else: rank = len(shape) if var.rank == 0: anisotropicRank = rank elif var.rank == 1: anisotropicRank = rank - 2 else: raise IndexError('the solution variable has the wrong rank') if anisotropicRank == 0 and self._treatMeshAsOrthogonal(mesh): if coeff.shape != () and not isinstance(coeff, FaceVariable): coeff = coeff[..., numerix.newaxis] tmpBop = (coeff * FaceVariable(mesh=mesh, value=mesh._faceAreas) / mesh._cellDistances)[numerix.newaxis, :] else: if anisotropicRank == 1 or anisotropicRank == 0: coeff = coeff * numerix.identity(mesh.dim) if anisotropicRank > 0: shape = numerix.getShape(coeff) if mesh.dim != shape[0] or mesh.dim != shape[1]: raise IndexError( 'diffusion coefficient tensor is not an appropriate shape for this mesh' ) faceNormals = FaceVariable(mesh=mesh, rank=1, value=mesh.faceNormals) rotationTensor = self.__getRotationTensor(mesh) rotationTensor[:, 0] = rotationTensor[:, 0] / mesh._cellDistances tmpBop = faceNormals.dot(coeff).dot( rotationTensor) * mesh._faceAreas return tmpBop else: return None
def __getRotationTensor(self, mesh): if not hasattr(self, 'rotationTensor'): rotationTensor = FaceVariable(mesh=mesh, rank=2) rotationTensor[:, 0] = self._getNormals(mesh) if mesh.dim == 2: rotationTensor[:, 1] = rotationTensor[:, 0].dot( (((0, 1), (-1, 0)))) elif mesh.dim == 3: epsilon = 1e-20 div = numerix.sqrt(1 - rotationTensor[2, 0]**2) flag = numerix.resize(div > epsilon, (mesh.dim, mesh.numberOfFaces)) rotationTensor[0, 1] = 1 rotationTensor[:, 1] = numerix.where( flag, rotationTensor[:, 0].dot( (((0, 1, 0), (-1, 0, 0), (0, 0, 0)))) / div, rotationTensor[:, 1]) rotationTensor[1, 2] = 1 rotationTensor[:, 2] = numerix.where( flag, rotationTensor[:, 0] * rotationTensor[2, 0] / div, rotationTensor[:, 2]) rotationTensor[2, 2] = -div self.rotationTensor = rotationTensor return self.rotationTensor
def _exteriorFaces(self): """ Return only the faces that have one neighboring cell. """ exteriorIDs = numerix.concatenate((numerix.arange(0, self.nx), numerix.arange(0, self.nx) + self.nx * self.ny, numerix.arange(0, self.ny) * self.numberOfVerticalColumns + self.numberOfHorizontalFaces, numerix.arange(0, self.ny) * self.numberOfVerticalColumns + self.numberOfHorizontalFaces + self.nx)) from fipy.variables.faceVariable import FaceVariable exteriorFaces = FaceVariable(mesh=self, value=False) exteriorFaces[exteriorIDs] = True return exteriorFaces
def _calcGeomCoeff(self, var): mesh = var.mesh if not isinstance(self.coeff, FaceVariable): shape = numerix.array(self.coeff).shape if shape != () and shape != (1,) and shape[-1] == 1: shape = shape[:-1] self.coeff = FaceVariable(mesh=mesh, elementshape=shape, value=self.coeff) projectedCoefficients = self.coeff * mesh._orientedAreaProjections return projectedCoefficients.sum(0)
def _interiorFaces(self): """ Return only the faces that have two neighboring cells """ XYids = self._XYFaceIDs XZids = self._XZFaceIDs YZids = self._YZFaceIDs interiorIDs = numerix.concatenate((numerix.ravel(XYids[ ... ,1:-1]), numerix.ravel(XZids[ :, 1:-1, :]), numerix.ravel(YZids[1:-1, ...].swapaxes(0,1)))) from fipy.variables.faceVariable import FaceVariable interiorFaces = FaceVariable(mesh=self, value=False) interiorFaces[interiorIDs] = True return interiorFaces
def _exteriorFaces(self): """ Return only the faces that have one neighboring cell. """ XYids = self._XYFaceIDs XZids = self._XZFaceIDs YZids = self._YZFaceIDs exteriorIDs = numerix.concatenate( (numerix.ravel(XYids[..., 0].swapaxes(0, 1)), numerix.ravel(XYids[..., -1].swapaxes(0, 1)), numerix.ravel(XZids[:, 0, :]), numerix.ravel(XZids[:, -1, :]), numerix.ravel(YZids[0, ...]), numerix.ravel(YZids[-1, ...]))) from fipy.variables.faceVariable import FaceVariable exteriorFaces = FaceVariable(mesh=self, value=False) exteriorFaces[exteriorIDs] = True return exteriorFaces
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 _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 faceCenters(self): from fipy.variables.faceVariable import FaceVariable return FaceVariable(mesh=self, value=self._faceCenters, rank=1)
def _connectFaces(self, faces0, faces1): """ Merge faces on the same mesh. This is used to create periodic meshes. The first list of faces, `faces1`, will be the faces that are used to add to the matrix diagonals. The faces in `faces2` will not be used. They aren't deleted but their adjacent cells are made to point at `faces1`. The list `faces2` are not altered, they still remain as members of exterior faces. >>> from fipy.meshes.nonUniformGrid2D import NonUniformGrid2D >>> mesh = NonUniformGrid2D(nx = 2, ny = 2, dx = 1., dy = 1.) >>> print((mesh.cellFaceIDs == [[0, 1, 2, 3], ... [7, 8, 10, 11], ... [2, 3, 4, 5], ... [6, 7, 9, 10]]).flatten().all()) # doctest: +PROCESSOR_0 True >>> mesh._connectFaces(numerix.nonzero(mesh.facesLeft), numerix.nonzero(mesh.facesRight)) >>> print((mesh.cellFaceIDs == [[0, 1, 2, 3], ... [7, 6, 10, 9], ... [2, 3, 4, 5], ... [6, 7, 9, 10]]).flatten().all()) # doctest: +PROCESSOR_0 True """ ## check for errors ## check that faces are members of exterior faces from fipy.variables.faceVariable import FaceVariable faces = FaceVariable(mesh=self, value=False) faces[faces0] = True faces[faces1] = True assert (faces | self.exteriorFaces == self.exteriorFaces).all() ## following assert checks number of faces are equal, normals are opposite and areas are the same assert numerix.allclose(numerix.take(self._areaProjections, faces0, axis=1), numerix.take(-self._areaProjections, faces1, axis=1)) ## extract the adjacent cells for both sets of faces faceCellIDs0 = self.faceCellIDs[0] faceCellIDs1 = self.faceCellIDs[1] ## set the new adjacent cells for `faces0` MA.put(faceCellIDs1, faces0, MA.take(faceCellIDs0, faces0)) MA.put(faceCellIDs0, faces0, MA.take(faceCellIDs0, faces1)) self.faceCellIDs[0] = faceCellIDs0 self.faceCellIDs[1] = faceCellIDs1 ## extract the face to cell distances for both sets of faces faceToCellDistances0 = self._faceToCellDistances[0] faceToCellDistances1 = self._faceToCellDistances[1] ## set the new faceToCellDistances for `faces0` MA.put(faceToCellDistances1, faces0, MA.take(faceToCellDistances0, faces0)) MA.put(faceToCellDistances0, faces0, MA.take(faceToCellDistances0, faces1)) self._faceToCellDistances[0] = faceToCellDistances0 self._faceToCellDistances[1] = faceToCellDistances1 ## calculate new cell distances and add them to faces0 numerix.put(self._cellDistances, faces0, MA.take(faceToCellDistances0 + faceToCellDistances1, faces0)) ## change the direction of the face normals for faces0 for dim in range(self.dim): faceNormals = self.faceNormals[dim].copy() numerix.put(faceNormals, faces0, MA.take(faceNormals, faces1)) self.faceNormals[dim] = faceNormals ## Cells that are adjacent to faces1 are changed to point at faces0 ## get the cells adjacent to faces1 faceCellIDs = MA.take(self.faceCellIDs[0], faces1) ## get all the adjacent faces for those particular cells cellFaceIDs = numerix.take(self.cellFaceIDs, faceCellIDs, axis=1) for i in range(cellFaceIDs.shape[0]): ## if the faces is a member of faces1 then change the face to point at ## faces0 cellFaceIDs[i] = MA.where(cellFaceIDs[i] == faces1, faces0, cellFaceIDs[i]) ## add those faces back to the main self.cellFaceIDs numerix.put(self.cellFaceIDs[i], faceCellIDs, cellFaceIDs[i]) ## calculate new topology self._setTopology() ## calculate new geometry self._handleFaceConnection() self.scale = self.scale['length']
ny = 1 valueLeft = 0. fluxRight = 1. timeStepDuration = 1. L = 10. dx = L / nx dy = 1. mesh = Tri2D(dx, dy, nx, ny) var = CellVariable(name="solution variable", mesh=mesh, value=valueLeft) from fipy.variables.faceVariable import FaceVariable diffCoeff = FaceVariable(mesh=mesh, value=1.0) x = mesh.getFaceCenters()[..., 0] diffCoeff.setValue(0.1, where=(L / 4. <= x) & (x < 3. * L / 4.)) boundaryConditions = (FixedValue(mesh.getFacesLeft(), valueLeft), FixedFlux(mesh.getFacesRight(), fluxRight)) if __name__ == '__main__': ImplicitDiffusionTerm(coeff=diffCoeff).solve( var, boundaryConditions=boundaryConditions) viewer = fipy.viewers.make(vars=var) viewer.plot() raw_input('finished')
def _interiorFaces(self): from fipy.variables.faceVariable import FaceVariable interiorFaces = FaceVariable(mesh=self, value=False) interiorFaces[numerix.arange(self.numberOfFaces - 2) + 1] = True return interiorFaces