def _shapeClassAndOther(self, opShape, operatorClass, other): """ Determine the shape of the result, the base class of the result, and (if necessary) a modified form of `other` that is suitable for the operation. By default, returns the result of the generic `Variable._shapeClassAndOther()`, but if that fails, and if each dimension of `other` is exactly the `Mesh` dimension, do what the user probably "meant" and project `other` onto the `Mesh`. >>> from fipy import * >>> mesh = Grid1D(nx=5) >>> A = numerix.arange(5) >>> B = Variable(1.) >>> import warnings >>> savedFilters = list(warnings.filters) >>> warnings.resetwarnings() >>> warnings.simplefilter("error", UserWarning, append=True) >>> C = CellVariable(mesh=mesh) * (A * B) Traceback (most recent call last): ... UserWarning: The expression `(multiply([0 1 2 3 4], Variable(value=array(1.0))))` has been cast to a constant `CellVariable` >>> warnings.filters = savedFilters """ otherShape = numerix.getShape(other) if (not isinstance(other, _MeshVariable) and otherShape is not () and otherShape[-1] == self._globalNumberOfElements): if (isinstance(other, Variable) and len(other.requiredVariables) > 0): import warnings warnings.warn( "The expression `%s` has been cast to a constant `%s`" % (repr(other), self._variableClass.__name__), UserWarning, stacklevel=4) other = self._variableClass(value=other, mesh=self.mesh) newOpShape, baseClass, newOther = Variable._shapeClassAndOther( self, opShape, operatorClass, other) if ((newOpShape is None or baseClass is None) and numerix.alltrue( numerix.array(numerix.getShape(other)) == self.mesh.dim)): newOpShape, baseClass, newOther = Variable._shapeClassAndOther( self, opShape, operatorClass, other[..., numerix.newaxis]) return (newOpShape, baseClass, newOther)
def _shapeClassAndOther(self, opShape, operatorClass, other): """ Determine the shape of the result, the base class of the result, and (if necessary) a modified form of `other` that is suitable for the operation. By default, returns the result of the generic `Variable._shapeClassAndOther()`, but if that fails, and if each dimension of `other` is exactly the `Mesh` dimension, do what the user probably "meant" and project `other` onto the `Mesh`. >>> from fipy import * >>> mesh = Grid1D(nx=5) >>> A = numerix.arange(5) >>> B = Variable(1.) >>> import warnings >>> savedFilters = list(warnings.filters) >>> warnings.resetwarnings() >>> warnings.simplefilter("error", UserWarning, append=True) >>> C = CellVariable(mesh=mesh) * (A * B) Traceback (most recent call last): ... UserWarning: The expression `(multiply([0 1 2 3 4], Variable(value=array(1.0))))` has been cast to a constant `CellVariable` >>> warnings.filters = savedFilters """ otherShape = numerix.getShape(other) if (not isinstance(other, _MeshVariable) and otherShape is not () and otherShape[-1] == self._globalNumberOfElements): if (isinstance(other, Variable) and len(other.requiredVariables) > 0): import warnings warnings.warn("The expression `%s` has been cast to a constant `%s`" % (repr(other), self._variableClass.__name__), UserWarning, stacklevel=4) other = self._variableClass(value=other, mesh=self.mesh) newOpShape, baseClass, newOther = Variable._shapeClassAndOther(self, opShape, operatorClass, other) if ((newOpShape is None or baseClass is None) and numerix.alltrue(numerix.array(numerix.getShape(other)) == self.mesh.dim)): newOpShape, baseClass, newOther = Variable._shapeClassAndOther(self, opShape, operatorClass, other[..., numerix.newaxis]) return (newOpShape, baseClass, newOther)
def _shapeClassAndOther(self, opShape, operatorClass, other): """ Determine the shape of the result, the base class of the result, and (if necessary) a modified form of `other` that is suitable for the operation. By default, returns the result of the generic `Variable._shapeClassAndOther()`, but if that fails, and if each dimension of `other` is exactly the `Mesh` dimension, do what the user probably "meant" and project `other` onto the `Mesh`. """ otherShape = numerix.getShape(other) if (not isinstance(other, _MeshVariable) and otherShape is not () and otherShape[-1] == self._getGlobalNumberOfElements()): other = self._getVariableClass()(value=other, mesh=self.getMesh()) newOpShape, baseClass, newOther = Variable._shapeClassAndOther(self, opShape, operatorClass, other) if ((newOpShape is None or baseClass is None) and numerix.alltrue(numerix.array(numerix.getShape(other)) == self.getMesh().getDim())): newOpShape, baseClass, newOther = Variable._shapeClassAndOther(self, opShape, operatorClass, other[..., numerix.newaxis]) return (newOpShape, baseClass, newOther)
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.numMesh.grid2D import Grid2D >>> mesh = Grid2D(nx = 2, ny = 2, dx = 1., dy = 1.) >>> from fipy.tools import parallel >>> print parallel.procID != 0 or (mesh._getCellFaceIDs() == [[0, 1, 2, 3], ... [7, 8, 10, 11], ... [2, 3, 4, 5], ... [6, 7, 9, 10]]).flatten().all() True >>> mesh._connectFaces(numerix.nonzero(mesh.getFacesLeft()), numerix.nonzero(mesh.getFacesRight())) >>> print parallel.procID != 0 or (mesh._getCellFaceIDs() == [[0, 1, 2, 3], ... [7, 6, 10, 9], ... [2, 3, 4, 5], ... [6, 7, 9, 10]]).flatten().all() 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.getExteriorFaces() == self.getExteriorFaces()).all() ## following assert checks number of faces are equal, normals are opposite and areas are the same assert numerix.alltrue(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.getDim()): 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 tmp = self.cellFaceIDs[i] numerix.put(tmp, faceCellIDs, cellFaceIDs[i]) self.cellFaceIDs[i] = tmp ## calculate new topology _CommonMesh._calcTopology(self) ## calculate new geometry self._calcFaceToCellDistanceRatio() self._calcCellToCellDistances() self._calcScaledGeometry() self._calcFaceAspectRatios()