コード例 #1
0
ファイル: meshVariable.py プロジェクト: calbaker/FiPy-2.1.3
    def allequal(self, other):
         if self.getMesh().communicator.Nproc > 1:
             def allequalParallel(a, b):
                 return self.getMesh().communicator.allequal(a, b)

             operatorClass = Variable._OperatorVariableClass(self, baseClass=Variable)
             return self._BinaryOperatorVariable(allequalParallel,
                                                 other, 
                                                 operatorClass=operatorClass,
                                                 opShape=(),
                                                 canInline=False)            
         else:
             return Variable.allequal(self, other)
コード例 #2
0
ファイル: meshVariable.py プロジェクト: calbaker/FiPy-2.1.3
    def allclose(self, other, rtol=1.e-5, atol=1.e-8):
         if self.getMesh().communicator.Nproc > 1:
             def allcloseParallel(a, b):
                 return self.getMesh().communicator.allclose(a, b, rtol=rtol, atol=atol)

             operatorClass = Variable._OperatorVariableClass(self, baseClass=Variable)
             return self._BinaryOperatorVariable(allcloseParallel,
                                                 other, 
                                                 operatorClass=operatorClass,
                                                 opShape=(),
                                                 canInline=False)            
         else:
             return Variable.allclose(self, other, rtol=rtol, atol=atol)
コード例 #3
0
ファイル: meshVariable.py プロジェクト: regmi/fipy
    def allequal(self, other):
         if parallel.Nproc > 1:
             from mpi4py import MPI
             def allequalParallel(a, b):
                 return MPI.COMM_WORLD.allreduce(numerix.allequal(a, b), op=MPI.LAND)

             operatorClass = Variable._OperatorVariableClass(self, baseClass=Variable)
             return self._BinaryOperatorVariable(allequalParallel,
                                                 other, 
                                                 operatorClass=operatorClass,
                                                 opShape=(),
                                                 canInline=False)            
         else:
             return Variable.allequal(self, other)
コード例 #4
0
    def allequal(self, other):
        if self.mesh.communicator.Nproc > 1:

            def allequalParallel(a, b):
                return self.mesh.communicator.allequal(a, b)

            operatorClass = Variable._OperatorVariableClass(self,
                                                            baseClass=Variable)
            return self._BinaryOperatorVariable(allequalParallel,
                                                other,
                                                operatorClass=operatorClass,
                                                opShape=(),
                                                canInline=False)
        else:
            return Variable.allequal(self, other)
コード例 #5
0
    def std(self, axis=None, **kwargs):
        """Evaluate standard deviation of all the elements of a `MeshVariable`.

        Adapted from http://mpitutorial.com/tutorials/mpi-reduce-and-allreduce/

        >>> import fipy as fp
        >>> mesh = fp.Grid2D(nx=2, ny=2, dx=2., dy=5.)
        >>> var = fp.CellVariable(value=(1., 2., 3., 4.), mesh=mesh)
        >>> print (var.std()**2).allclose(1.25)
        True
        """
        if self.mesh.communicator.Nproc > 1 and (axis is None or axis
                                                 == len(self.shape) - 1):

            def stdParallel(a):
                N = self.mesh.globalNumberOfCells
                mean = self.sum(axis=axis).value / N
                sq_diff = (self - mean)**2

                return numerix.sqrt(sq_diff.sum(axis=axis).value / N)

            return self._axisOperator(opname="stdVar",
                                      op=stdParallel,
                                      axis=axis)
        else:
            return Variable.std(self, axis=axis)
コード例 #6
0
    def __init__(self,
                 surfactantVar = None,
                 distanceVar = None,
                 bulkVar = None,
                 rateConstant = None,
                 otherVar = None,
                 otherBulkVar = None,
                 otherRateConstant = None,
                 consumptionCoeff = None):
        """
        Create a `AdsorbingSurfactantEquation` object.

        :Parameters:
          - `surfactantVar`: The `SurfactantVariable` to be solved for.
          - `distanceVar`: The `DistanceVariable` that marks the interface.
          - `bulkVar`: The value of the `surfactantVar` in the bulk.
          - `rateConstant`: The adsorption rate of the `surfactantVar`.
          - `otherVar`: Another `SurfactantVariable` with more surface affinity.
          - `otherBulkVar`: The value of the `otherVar` in the bulk.
          - `otherRateConstant`: The adsorption rate of the `otherVar`.
          - `consumptionCoeff`: The rate that the `surfactantVar` is consumed during deposition.
                             
        """

        self.eq = TransientTerm(coeff = 1) - ExplicitUpwindConvectionTerm(SurfactantConvectionVariable(distanceVar))

        self.dt = Variable(0.)
        mesh = distanceVar.mesh
        adsorptionCoeff = self.dt * bulkVar * rateConstant
        spCoeff = adsorptionCoeff * distanceVar._cellInterfaceFlag
        scCoeff = adsorptionCoeff * distanceVar.cellInterfaceAreas / mesh.cellVolumes

        self.eq += ImplicitSourceTerm(spCoeff) - scCoeff

        if otherVar is not None:
            otherSpCoeff = self.dt * otherBulkVar * otherRateConstant * distanceVar._cellInterfaceFlag
            otherScCoeff = -otherVar.interfaceVar * scCoeff

            self.eq += ImplicitSourceTerm(otherSpCoeff) - otherScCoeff

            vars = (surfactantVar, otherVar)
        else:
            vars = (surfactantVar,)

        total = 0
        for var in vars:
            total += var.interfaceVar
        maxVar = (total > 1) * distanceVar._cellInterfaceFlag

        val = distanceVar.cellInterfaceAreas / mesh.cellVolumes
        for var in vars[1:]:
            val -= distanceVar._cellInterfaceFlag * var
        
        spMaxCoeff = 1e20 * maxVar
        scMaxCoeff = spMaxCoeff * val * (val > 0)
            
        self.eq += ImplicitSourceTerm(spMaxCoeff) - scMaxCoeff - 1e-40

        if consumptionCoeff is not None:
            self.eq += ImplicitSourceTerm(consumptionCoeff)
コード例 #7
0
    def shape(self):
        """
        >>> from fipy.meshes import Grid2D
        >>> from fipy.variables.cellVariable import CellVariable
        >>> mesh = Grid2D(nx=2, ny=3)
        >>> var = CellVariable(mesh=mesh)
        >>> print numerix.allequal(var.shape, (6,)) # doctest: +PROCESSOR_0
        True
        >>> print numerix.allequal(var.arithmeticFaceValue.shape, (17,)) # doctest: +PROCESSOR_0
        True
        >>> print numerix.allequal(var.grad.shape, (2, 6)) # doctest: +PROCESSOR_0
        True
        >>> print numerix.allequal(var.faceGrad.shape, (2, 17)) # doctest: +PROCESSOR_0
        True

        Have to account for zero length arrays

        >>> from fipy import Grid1D
        >>> m = Grid1D(nx=0)
        >>> v = CellVariable(mesh=m, elementshape=(2,))
        >>> (v * 1).shape
        (2, 0)
        
        """
        return (Variable._getShape(self)
                or (self.elementshape + self._getShapeFromMesh(self.mesh))
                or ())
コード例 #8
0
    def __init__(self, coeff=(1., ), var=None):
        if self.__class__ is _AbstractDiffusionTerm:
            raise AbstractBaseClassError

        if type(coeff) not in (type(()), type([])):
            coeff = [coeff]

        self.order = len(coeff) * 2

        if len(coeff) > 0:
            self.nthCoeff = coeff[0]

            from fipy.variables.variable import Variable
            if not isinstance(self.nthCoeff, Variable):
                self.nthCoeff = Variable(value=self.nthCoeff)

            from fipy.variables.cellVariable import CellVariable
            if isinstance(self.nthCoeff, CellVariable):
                self.nthCoeff = self.nthCoeff.arithmeticFaceValue

        else:
            self.nthCoeff = None

        _UnaryTerm.__init__(self, coeff=coeff, var=var)

        if self.order > 0:
            self.lowerOrderDiffusionTerm = self.__class__(coeff=coeff[1:])
コード例 #9
0
ファイル: diffusionTerm.py プロジェクト: calbaker/FiPy-2.1.3
    def __init__(self, coeff = (1.,)):
        """
        Create a `DiffusionTerm`.

        :Parameters:
          - `coeff`: `Tuple` or `list` of `FaceVariables` or numbers.
          
        """
        if type(coeff) not in (type(()), type([])):
            coeff = (coeff,)

        self.order = len(coeff) * 2


        if len(coeff) > 0:
            self.nthCoeff = coeff[0]

            from fipy.variables.variable import Variable
            if not isinstance(self.nthCoeff, Variable):
                self.nthCoeff = Variable(value = self.nthCoeff)

            from fipy.variables.cellVariable import CellVariable
            if isinstance(self.nthCoeff, CellVariable):
                self.nthCoeff = self.nthCoeff.getArithmeticFaceValue()

        else:
            self.nthCoeff = None

        Term.__init__(self, coeff = coeff)
        
        if self.order > 0:
            self.lowerOrderDiffusionTerm = DiffusionTerm(coeff = coeff[1:])
コード例 #10
0
ファイル: meshVariable.py プロジェクト: LWhitson2/fipy
    def shape(self):
        """
        >>> from fipy.meshes import Grid2D
        >>> from fipy.variables.cellVariable import CellVariable
        >>> mesh = Grid2D(nx=2, ny=3)
        >>> var = CellVariable(mesh=mesh)
        >>> print numerix.allequal(var.shape, (6,)) # doctest: +PROCESSOR_0
        True
        >>> print numerix.allequal(var.arithmeticFaceValue.shape, (17,)) # doctest: +PROCESSOR_0
        True
        >>> print numerix.allequal(var.grad.shape, (2, 6)) # doctest: +PROCESSOR_0
        True
        >>> print numerix.allequal(var.faceGrad.shape, (2, 17)) # doctest: +PROCESSOR_0
        True

        Have to account for zero length arrays

        >>> from fipy import Grid1D
        >>> m = Grid1D(nx=0)
        >>> v = CellVariable(mesh=m, elementshape=(2,))
        >>> (v * 1).shape
        (2, 0)
        
        """
        return (Variable._getShape(self)
                or (self.elementshape + self._getShapeFromMesh(self.mesh)) 
                or ())
コード例 #11
0
ファイル: meshVariable.py プロジェクト: calbaker/FiPy-2.1.3
    def _OperatorVariableClass(self, baseClass=None):
        baseClass = Variable._OperatorVariableClass(self, baseClass=baseClass)
                                     
        class _MeshOperatorVariable(baseClass):
            def __init__(self, op, var, opShape=None, canInline=True,
                         *args, **kwargs):
                mesh = reduce(lambda a, b: a or b, 
                              [getattr(v, "mesh", None) for v in var])
                for shape in [opShape] + [getattr(v, "opShape", None) for v in var]:
                    if shape is not None:
                        opShape = shape
                        break
##                 opShape = reduce(lambda a, b: a or b, 
##                                  [opShape] + [getattr(v, "opShape", None) for v in var])
                if opShape is not None:
                    elementshape = opShape[:-1]
                else:
                    elementshape = reduce(lambda a, b: a or b, 
                                          [getattr(v, "elementshape", None) for v in var])

                baseClass.__init__(self, mesh=mesh, op=op, var=var, 
                                   opShape=opShape, canInline=canInline,
                                   elementshape=elementshape,
                                   *args, **kwargs)
                                 
            def getRank(self):
                return len(self.opShape) - 1
                
        return _MeshOperatorVariable
コード例 #12
0
    def min(self, axis=None):
        """
        >>> from fipy import Grid2D, CellVariable
        >>> mesh = Grid2D(nx=5, ny=5)
        >>> x, y = mesh.cellCenters
        >>> v = CellVariable(mesh=mesh, value=x*y)
        >>> print v.min()
        0.25
        """
        if self.mesh.communicator.Nproc > 1 and (axis is None or axis
                                                 == len(self.shape) - 1):

            def minParallel(a):
                return self._maxminparallel_(
                    a=a,
                    axis=axis,
                    default=numerix.inf,
                    fn=a.min,
                    fnParallel=self.mesh.communicator.MinAll)

            return self._axisOperator(opname="minVar",
                                      op=minParallel,
                                      axis=axis)
        else:
            return Variable.min(self, axis=axis)
コード例 #13
0
    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)
コード例 #14
0
    def allclose(self, other, rtol=1.e-5, atol=1.e-8):
        if self.mesh.communicator.Nproc > 1:

            def allcloseParallel(a, b):
                return self.mesh.communicator.allclose(a,
                                                       b,
                                                       rtol=rtol,
                                                       atol=atol)

            operatorClass = Variable._OperatorVariableClass(self,
                                                            baseClass=Variable)
            return self._BinaryOperatorVariable(allcloseParallel,
                                                other,
                                                operatorClass=operatorClass,
                                                opShape=(),
                                                canInline=False)
        else:
            return Variable.allclose(self, other, rtol=rtol, atol=atol)
コード例 #15
0
ファイル: meshVariable.py プロジェクト: calbaker/FiPy-2.1.3
 def setValue(self, value, unit = None, where = None):
     if where is not None:
         shape = numerix.getShape(where)
         if shape != self.shape \
           and shape == self._getShapeFromMesh(mesh=self.getMesh()):
             for dim in self.elementshape:
                 where = numerix.repeat(where[numerix.newaxis, ...], repeats=dim, axis=0)
     
     return Variable.setValue(self, value=value, unit=unit, where=where)
コード例 #16
0
ファイル: meshVariable.py プロジェクト: calbaker/FiPy-2.1.3
 def _axisClass(self, axis):
     """
     if we operate along the mesh elements, then this is no longer a
     `_MeshVariable`, otherwise we get back a `_MeshVariable` of the same
     class, but lower rank.
     """
     if axis is None or axis == len(self.shape) - 1 or axis == -1:
         return Variable._OperatorVariableClass(self, baseClass=Variable)
     else:
         return self._OperatorVariableClass()
コード例 #17
0
 def _axisClass(self, axis):
     """
     if we operate along the mesh elements, then this is no longer a
     `_MeshVariable`, otherwise we get back a `_MeshVariable` of the same
     class, but lower rank.
     """
     if axis is None or axis == len(self.shape) - 1 or axis == -1:
         return Variable._OperatorVariableClass(self, baseClass=Variable)
     else:
         return self._OperatorVariableClass()
コード例 #18
0
ファイル: meshVariable.py プロジェクト: LWhitson2/fipy
    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)
コード例 #19
0
ファイル: meshVariable.py プロジェクト: LWhitson2/fipy
 def max(self, axis=None):
     if self.mesh.communicator.Nproc > 1 and (axis is None or axis == len(self.shape) - 1):
         def maxParallel(a):
             return self._maxminparallel_(a=a, axis=axis, default=-numerix.inf, 
                                          fn=a.max, fnParallel=self.mesh.communicator.MaxAll)
             
         return self._axisOperator(opname="maxVar", 
                                   op=maxParallel, 
                                   axis=axis)
     else:
         return Variable.max(self, axis=axis)
コード例 #20
0
ファイル: meshVariable.py プロジェクト: LWhitson2/fipy
 def sum(self, axis=None):
     if self.mesh.communicator.Nproc > 1 and (axis is None or axis == len(self.shape) - 1):
         def sumParallel(a):
             a = a[..., self._localNonOverlappingIDs]
             return self.mesh.communicator.sum(a, axis=axis)
             
         return self._axisOperator(opname="sumVar", 
                                   op=sumParallel, 
                                   axis=axis)
     else:
         return Variable.sum(self, axis=axis)
コード例 #21
0
ファイル: meshVariable.py プロジェクト: calbaker/FiPy-2.1.3
 def min(self, axis=None):
     if self.getMesh().communicator.Nproc > 1 and (axis is None or axis == len(self.getShape()) - 1):
         def minParallel(a):
             return self._maxminparallel_(a=a, axis=axis, default=numerix.inf, 
                                          fn=a.min, fnParallel=self.getMesh().communicator.epetra_comm.MinAll)
             
         return self._axisOperator(opname="minVar", 
                                   op=minParallel, 
                                   axis=axis)
     else:
         return Variable.min(self, axis=axis)
コード例 #22
0
ファイル: meshVariable.py プロジェクト: calbaker/FiPy-2.1.3
 def sum(self, axis=None):
     if self.getMesh().communicator.Nproc > 1 and (axis is None or axis == len(self.getShape()) - 1):
         def sumParallel(a):
             a = a[self._getLocalNonOverlappingIDs()]
             return self.getMesh().communicator.sum(a, axis=axis)
             
         return self._axisOperator(opname="sumVar", 
                                   op=sumParallel, 
                                   axis=axis)
     else:
         return Variable.sum(self, axis=axis)
コード例 #23
0
    def setValue(self, value, unit=None, where=None):
        if where is not None:
            shape = numerix.getShape(where)
            if shape != self.shape \
              and shape == self._getShapeFromMesh(mesh=self.mesh):
                for dim in self.elementshape:
                    where = numerix.repeat(where[numerix.newaxis, ...],
                                           repeats=dim,
                                           axis=0)

        return Variable.setValue(self, value=value, unit=unit, where=where)
コード例 #24
0
ファイル: meshVariable.py プロジェクト: regmi/fipy
 def any(self, axis=None):
     if parallel.Nproc > 1 and (axis is None or axis == len(self.getShape()) - 1):
         from mpi4py import MPI
         def anyParallel(a):
             a = a[self._getLocalNonOverlappingIDs()]
             return MPI.COMM_WORLD.allreduce(a.any(axis=axis), op=MPI.LOR)
             
         return self._axisOperator(opname="anyVar", 
                                   op=anyParallel, 
                                   axis=axis)
     else:
         return Variable.any(self, axis=axis)
コード例 #25
0
ファイル: meshVariable.py プロジェクト: regmi/fipy
 def sum(self, axis=None):
     if parallel.Nproc > 1 and (axis is None or axis == len(self.getShape()) - 1):
         from PyTrilinos import Epetra
         def sumParallel(a):
             a = a[self._getLocalNonOverlappingIDs()]
             return Epetra.PyComm().SumAll(a.sum(axis=axis))
             
         return self._axisOperator(opname="sumVar", 
                                   op=sumParallel, 
                                   axis=axis)
     else:
         return Variable.sum(self, axis=axis)
コード例 #26
0
 def _getitemClass(self, index):
     if not isinstance(index, tuple):
         if isinstance(index, list):
             index = tuple(index)
         else:
             index = (index, )
     indexshape = numerix._indexShape(index=index, arrayShape=self.shape)
     if (len(indexshape) > 0 and indexshape[-1] == self.shape[-1]
             and numerix.obj2sctype(index[-1]) != numerix.obj2sctype(bool)):
         return self._OperatorVariableClass()
     else:
         return Variable._OperatorVariableClass(self, baseClass=Variable)
コード例 #27
0
ファイル: meshVariable.py プロジェクト: regmi/fipy
 def min(self, axis=None):
     if parallel.Nproc > 1 and (axis is None or axis == len(self.getShape()) - 1):
         from PyTrilinos import Epetra
         def minParallel(a):
             return self._maxminparallel_(a=a, axis=axis, default=numerix.inf, 
                                          fn=a.min, fnParallel=Epetra.PyComm().MinAll)
             
         return self._axisOperator(opname="minVar", 
                                   op=minParallel, 
                                   axis=axis)
     else:
         return Variable.min(self, axis=axis)
コード例 #28
0
    def sum(self, axis=None):
        if self.mesh.communicator.Nproc > 1 and (axis is None or axis
                                                 == len(self.shape) - 1):

            def sumParallel(a):
                a = a[..., self._localNonOverlappingIDs]
                return self.mesh.communicator.sum(a, axis=axis)

            return self._axisOperator(opname="sumVar",
                                      op=sumParallel,
                                      axis=axis)
        else:
            return Variable.sum(self, axis=axis)
コード例 #29
0
ファイル: meshVariable.py プロジェクト: calbaker/FiPy-2.1.3
 def _getitemClass(self, index):
     if not isinstance(index, tuple):
         if isinstance(index, list):
             index = tuple(index)
         else:
             index = (index,)
     indexshape = numerix._indexShape(index=index, arrayShape=self.shape)
     if (len(indexshape) > 0
         and indexshape[-1] == self.shape[-1]
         and numerix.obj2sctype(index[-1]) != numerix.obj2sctype(bool)):
         return self._OperatorVariableClass()
     else:
         return Variable._OperatorVariableClass(self, baseClass=Variable)
コード例 #30
0
ファイル: meshVariable.py プロジェクト: calbaker/FiPy-2.1.3
    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)
コード例 #31
0
    def _OperatorVariableClass(self, baseClass=None):
        baseClass = Variable._OperatorVariableClass(self, baseClass=baseClass)

        class _MeshOperatorVariable(baseClass):
            def __init__(self,
                         op,
                         var,
                         opShape=None,
                         canInline=True,
                         *args,
                         **kwargs):
                mesh = reduce(lambda a, b: a or b,
                              [getattr(v, "mesh", None) for v in var])
                for shape in [opShape
                              ] + [getattr(v, "opShape", None) for v in var]:
                    if shape is not None:
                        opShape = shape
                        break


##                 opShape = reduce(lambda a, b: a or b,
##                                  [opShape] + [getattr(v, "opShape", None) for v in var])
                if opShape is not None:
                    elementshape = opShape[:-1]
                else:
                    elementshape = reduce(
                        lambda a, b: a or b,
                        [getattr(v, "elementshape", None) for v in var])

                baseClass.__init__(self,
                                   mesh=mesh,
                                   op=op,
                                   var=var,
                                   opShape=opShape,
                                   canInline=canInline,
                                   elementshape=elementshape,
                                   *args,
                                   **kwargs)

            @getsetDeprecated
            def getRank(self):
                return self.rank

            @property
            def rank(self):
                return len(self.opShape) - 1

        return _MeshOperatorVariable
コード例 #32
0
    def max(self, axis=None):
        if self.mesh.communicator.Nproc > 1 and (axis is None or axis
                                                 == len(self.shape) - 1):

            def maxParallel(a):
                return self._maxminparallel_(
                    a=a,
                    axis=axis,
                    default=-numerix.inf,
                    fn=a.max,
                    fnParallel=self.mesh.communicator.MaxAll)

            return self._axisOperator(opname="maxVar",
                                      op=maxParallel,
                                      axis=axis)
        else:
            return Variable.max(self, axis=axis)
コード例 #33
0
ファイル: meshVariable.py プロジェクト: calbaker/FiPy-2.1.3
 def getShape(self):
     """
         >>> from fipy.meshes.grid2D import Grid2D
         >>> from fipy.variables.cellVariable import CellVariable
         >>> mesh = Grid2D(nx=2, ny=3)
         >>> var = CellVariable(mesh=mesh)
         >>> from fipy.tools import parallel
         >>> print parallel.procID > 0 or numerix.allequal(var.shape, (6,))
         True
         >>> print parallel.procID > 0 or numerix.allequal(var.getArithmeticFaceValue().shape, (17,))
         True
         >>> print parallel.procID > 0 or numerix.allequal(var.getGrad().shape, (2, 6))
         True
         >>> print parallel.procID > 0 or numerix.allequal(var.getFaceGrad().shape, (2, 17))
         True
     """
     return (Variable.getShape(self) 
             or (self.elementshape + self._getShapeFromMesh(self.getMesh())) 
             or ())
コード例 #34
0
ファイル: meshVariable.py プロジェクト: LWhitson2/fipy
 def min(self, axis=None):
     """
     >>> from fipy import Grid2D, CellVariable
     >>> mesh = Grid2D(nx=5, ny=5)
     >>> x, y = mesh.cellCenters
     >>> v = CellVariable(mesh=mesh, value=x*y)
     >>> print v.min()
     0.25
     """
     if self.mesh.communicator.Nproc > 1 and (axis is None or axis == len(self.shape) - 1):
         def minParallel(a):
             return self._maxminparallel_(a=a, axis=axis, default=numerix.inf, 
                                          fn=a.min, fnParallel=self.mesh.communicator.MinAll)
             
         return self._axisOperator(opname="minVar", 
                                   op=minParallel, 
                                   axis=axis)
     else:
         return Variable.min(self, axis=axis)
コード例 #35
0
ファイル: meshVariable.py プロジェクト: usnistgov/fipy
    def std(self, axis=None, **kwargs):
        """Evaluate standard deviation of all the elements of a `MeshVariable`.

        Adapted from http://mpitutorial.com/tutorials/mpi-reduce-and-allreduce/

        >>> import fipy as fp
        >>> mesh = fp.Grid2D(nx=2, ny=2, dx=2., dy=5.)
        >>> var = fp.CellVariable(value=(1., 2., 3., 4.), mesh=mesh)
        >>> print((var.std()**2).allclose(1.25))
        True
        """
        if self.mesh.communicator.Nproc > 1 and (axis is None or axis == len(self.shape) - 1):
            def stdParallel(a):
                N = self.mesh.globalNumberOfCells
                mean = self.sum(axis=axis).value / N
                sq_diff = (self - mean)**2

                return numerix.sqrt(sq_diff.sum(axis=axis).value / N)

            return self._axisOperator(opname="stdVar",
                                      op=stdParallel,
                                      axis=axis)
        else:
            return Variable.std(self, axis=axis)
コード例 #36
0
    def __init__(self,
                 surfactantVar=None,
                 distanceVar=None,
                 bulkVar=None,
                 rateConstant=None,
                 otherVar=None,
                 otherBulkVar=None,
                 otherRateConstant=None,
                 consumptionCoeff=None):
        """
        Create a `AdsorbingSurfactantEquation` object.

        :Parameters:
          - `surfactantVar`: The `SurfactantVariable` to be solved for.
          - `distanceVar`: The `DistanceVariable` that marks the interface.
          - `bulkVar`: The value of the `surfactantVar` in the bulk.
          - `rateConstant`: The adsorption rate of the `surfactantVar`.
          - `otherVar`: Another `SurfactantVariable` with more surface affinity.
          - `otherBulkVar`: The value of the `otherVar` in the bulk.
          - `otherRateConstant`: The adsorption rate of the `otherVar`.
          - `consumptionCoeff`: The rate that the `surfactantVar` is consumed during deposition.

        """

        self.eq = TransientTerm(coeff=1) - ExplicitUpwindConvectionTerm(
            SurfactantConvectionVariable(distanceVar))

        self.dt = Variable(0.)
        mesh = distanceVar.mesh
        adsorptionCoeff = self.dt * bulkVar * rateConstant
        spCoeff = adsorptionCoeff * distanceVar._cellInterfaceFlag
        scCoeff = adsorptionCoeff * distanceVar.cellInterfaceAreas / mesh.cellVolumes

        self.eq += ImplicitSourceTerm(spCoeff) - scCoeff

        if otherVar is not None:
            otherSpCoeff = self.dt * otherBulkVar * otherRateConstant * distanceVar._cellInterfaceFlag
            otherScCoeff = -otherVar.interfaceVar * scCoeff

            self.eq += ImplicitSourceTerm(otherSpCoeff) - otherScCoeff

            vars = (surfactantVar, otherVar)
        else:
            vars = (surfactantVar, )

        total = 0
        for var in vars:
            total += var.interfaceVar
        maxVar = (total > 1) * distanceVar._cellInterfaceFlag

        val = distanceVar.cellInterfaceAreas / mesh.cellVolumes
        for var in vars[1:]:
            val -= distanceVar._cellInterfaceFlag * var

        spMaxCoeff = 1e20 * maxVar
        scMaxCoeff = spMaxCoeff * val * (val > 0)

        self.eq += ImplicitSourceTerm(spMaxCoeff) - scMaxCoeff - 1e-40

        if consumptionCoeff is not None:
            self.eq += ImplicitSourceTerm(consumptionCoeff)
コード例 #37
0
class AdsorbingSurfactantEquation():
    r"""

    The `AdsorbingSurfactantEquation` object solves the
    `SurfactantEquation` but with an adsorbing species from some bulk
    value. The equation that describes the surfactant adsorbing is
    given by,

    .. math::

       \dot{\theta} = J v \theta + k c (1 - \theta - \theta_{\text{other}}) - \theta c_{\text{other}} k_{\text{other}} - k^- \theta

    where :math:`\theta`, :math:`J`, :math:`v`, :math:`k`, :math:`c`,
    :math:`k^-` and :math:`n` represent the surfactant coverage, the curvature,
    the interface normal velocity, the adsorption rate, the concentration in the
    bulk at the interface, the consumption rate and an exponent of consumption,
    respectively. The :math:`\text{other}` subscript refers to another
    surfactant with greater surface affinity.

    The terms on the RHS of the above equation represent conservation of
    surfactant on a non-uniform surface, Langmuir adsorption, removal of
    surfactant due to adsorption of the other surfactant onto non-vacant sites
    and consumption of the surfactant respectively. The adsorption term is added
    to the source by setting :math:` S_c = k c (1 - \theta_{\text{other}})` and
    :math:`S_p = -k c`. The other terms are added to the source in a similar
    way.

    The following is a test case:

    >>> from fipy.variables.distanceVariable \
    ...     import DistanceVariable
    >>> from fipy import SurfactantVariable
    >>> from fipy.meshes import Grid2D
    >>> from fipy.tools import numerix
    >>> from fipy.variables.cellVariable import CellVariable
    >>> dx = .5
    >>> dy = 2.3
    >>> dt = 0.25
    >>> k = 0.56
    >>> initialValue = 0.1
    >>> c = 0.2
    
    >>> from fipy.meshes import Grid2D
    >>> from fipy import serialComm
    >>> mesh = Grid2D(dx = dx, dy = dy, nx = 5, ny = 1, communicator=serialComm)
    >>> distanceVar = DistanceVariable(mesh = mesh, 
    ...                                value = (-dx*3/2, -dx/2, dx/2, 
    ...                                          3*dx/2,  5*dx/2),
    ...                                hasOld = 1)
    >>> surfactantVar = SurfactantVariable(value = (0, 0, initialValue, 0 ,0), 
    ...                                    distanceVar = distanceVar)
    >>> bulkVar = CellVariable(mesh = mesh, value = (c , c, c, c, c))
    >>> eqn = AdsorbingSurfactantEquation(surfactantVar = surfactantVar,
    ...                                   distanceVar = distanceVar,
    ...                                   bulkVar = bulkVar,
    ...                                   rateConstant = k)
    >>> eqn.solve(surfactantVar, dt = dt)
    >>> answer = (initialValue + dt * k * c) / (1 + dt * k * c)
    >>> print numerix.allclose(surfactantVar.interfaceVar, 
    ...                  numerix.array((0, 0, answer, 0, 0)))
    1

    The following test case is for two surfactant variables. One has more
    surface affinity than the other.

    >>> from fipy.variables.distanceVariable \
    ...     import DistanceVariable
    >>> from fipy import SurfactantVariable
    >>> from fipy.meshes import Grid2D
    >>> dx = 0.5
    >>> dy = 2.73
    >>> dt = 0.001
    >>> k0 = 1.
    >>> k1 = 10.
    >>> theta0 = 0.
    >>> theta1 = 0.
    >>> c0 = 1.
    >>> c1 = 1.
    >>> totalSteps = 10
    >>> mesh = Grid2D(dx = dx, dy = dy, nx = 5, ny = 1, communicator=serialComm)
    >>> distanceVar = DistanceVariable(mesh = mesh, 
    ...                                value = dx * (numerix.arange(5) - 1.5),
    ...                                hasOld = 1)
    >>> var0 = SurfactantVariable(value = (0, 0, theta0, 0 ,0), 
    ...                           distanceVar = distanceVar)
    >>> var1 = SurfactantVariable(value = (0, 0, theta1, 0 ,0), 
    ...                           distanceVar = distanceVar)
    >>> bulkVar0 = CellVariable(mesh = mesh, value = (c0, c0, c0, c0, c0))
    >>> bulkVar1 = CellVariable(mesh = mesh, value = (c1, c1, c1, c1, c1))

    >>> eqn0 = AdsorbingSurfactantEquation(surfactantVar = var0,
    ...                                    distanceVar = distanceVar,
    ...                                    bulkVar = bulkVar0,
    ...                                    rateConstant = k0)

    >>> eqn1 = AdsorbingSurfactantEquation(surfactantVar = var1,
    ...                                    distanceVar = distanceVar,
    ...                                    bulkVar = bulkVar1,
    ...                                    rateConstant = k1,
    ...                                    otherVar = var0,
    ...                                    otherBulkVar = bulkVar0,
    ...                                    otherRateConstant = k0)

    >>> for step in range(totalSteps):
    ...     eqn0.solve(var0, dt = dt)
    ...     eqn1.solve(var1, dt = dt)
    >>> answer0 = 1 - numerix.exp(-k0 * c0 * dt * totalSteps)
    >>> answer1 = (1 - numerix.exp(-k1 * c1 * dt * totalSteps)) * (1 - answer0)
    >>> print numerix.allclose(var0.interfaceVar, 
    ...                  numerix.array((0, 0, answer0, 0, 0)), rtol = 1e-2)
    1
    >>> print numerix.allclose(var1.interfaceVar, 
    ...                  numerix.array((0, 0, answer1, 0, 0)), rtol = 1e-2)
    1
    >>> dt = 0.1
    >>> for step in range(10):
    ...     eqn0.solve(var0, dt = dt)
    ...     eqn1.solve(var1, dt = dt)

    >>> x, y = mesh.cellCenters
    >>> check = var0.interfaceVar + var1.interfaceVar
    >>> answer = CellVariable(mesh=mesh, value=check)
    >>> answer[x==1.25] = 1.
    >>> print check.allequal(answer)
    True

    The following test case is to fix a bug where setting the adosrbtion
    coefficient to zero leads to the solver not converging and an eventual
    failure.

    >>> var0 = SurfactantVariable(value = (0, 0, theta0, 0 ,0), 
    ...                           distanceVar = distanceVar)
    >>> bulkVar0 = CellVariable(mesh = mesh, value = (c0, c0, c0, c0, c0))

    >>> eqn0 = AdsorbingSurfactantEquation(surfactantVar = var0,
    ...                                    distanceVar = distanceVar,
    ...                                    bulkVar = bulkVar0,
    ...                                    rateConstant = 0)

    >>> eqn0.solve(var0, dt = dt)
    >>> eqn0.solve(var0, dt = dt)
    >>> answer = CellVariable(mesh=mesh, value=var0.interfaceVar)
    >>> answer[x==1.25] = 0.
    
    >>> print var0.interfaceVar.allclose(answer)
    True

    The following test case is to fix a bug that allows the accelerator to
    become negative.

    >>> nx = 5
    >>> ny = 5
    >>> dx = 1.
    >>> dy = 1.
    >>> mesh = Grid2D(dx=dx, dy=dy, nx = nx, ny = ny, communicator=serialComm)
    >>> x, y = mesh.cellCenters

    >>> disVar = DistanceVariable(mesh=mesh, value=1., hasOld=True)
    >>> disVar[y < dy] = -1
    >>> disVar[x < dx] = -1
    >>> disVar.calcDistanceFunction() #doctest: +LSM

    >>> levVar = SurfactantVariable(value = 0.5, distanceVar = disVar)
    >>> accVar = SurfactantVariable(value = 0.5, distanceVar = disVar)

    >>> levEq = AdsorbingSurfactantEquation(levVar,
    ...                                     distanceVar = disVar,
    ...                                     bulkVar = 0,
    ...                                     rateConstant = 0)

    >>> accEq = AdsorbingSurfactantEquation(accVar,
    ...                                     distanceVar = disVar,
    ...                                     bulkVar = 0,
    ...                                     rateConstant = 0,
    ...                                     otherVar = levVar,
    ...                                     otherBulkVar = 0,
    ...                                     otherRateConstant = 0)

    >>> extVar = CellVariable(mesh = mesh, value = accVar.interfaceVar)

    >>> from fipy import TransientTerm, AdvectionTerm
    >>> advEq = TransientTerm() + AdvectionTerm(extVar)

    >>> dt = 0.1

    >>> for i in range(50):
    ...     disVar.calcDistanceFunction()
    ...     extVar.value = (numerix.array(accVar.interfaceVar))
    ...     disVar.extendVariable(extVar)
    ...     disVar.updateOld()
    ...     advEq.solve(disVar, dt = dt)
    ...     levEq.solve(levVar, dt = dt)
    ...     accEq.solve(accVar, dt = dt) #doctest: +LSM

    >>> print (accVar >= -1e-10).all()
    True
    """
    def __init__(self,
                 surfactantVar = None,
                 distanceVar = None,
                 bulkVar = None,
                 rateConstant = None,
                 otherVar = None,
                 otherBulkVar = None,
                 otherRateConstant = None,
                 consumptionCoeff = None):
        """
        Create a `AdsorbingSurfactantEquation` object.

        :Parameters:
          - `surfactantVar`: The `SurfactantVariable` to be solved for.
          - `distanceVar`: The `DistanceVariable` that marks the interface.
          - `bulkVar`: The value of the `surfactantVar` in the bulk.
          - `rateConstant`: The adsorption rate of the `surfactantVar`.
          - `otherVar`: Another `SurfactantVariable` with more surface affinity.
          - `otherBulkVar`: The value of the `otherVar` in the bulk.
          - `otherRateConstant`: The adsorption rate of the `otherVar`.
          - `consumptionCoeff`: The rate that the `surfactantVar` is consumed during deposition.
                             
        """

        self.eq = TransientTerm(coeff = 1) - ExplicitUpwindConvectionTerm(SurfactantConvectionVariable(distanceVar))

        self.dt = Variable(0.)
        mesh = distanceVar.mesh
        adsorptionCoeff = self.dt * bulkVar * rateConstant
        spCoeff = adsorptionCoeff * distanceVar._cellInterfaceFlag
        scCoeff = adsorptionCoeff * distanceVar.cellInterfaceAreas / mesh.cellVolumes

        self.eq += ImplicitSourceTerm(spCoeff) - scCoeff

        if otherVar is not None:
            otherSpCoeff = self.dt * otherBulkVar * otherRateConstant * distanceVar._cellInterfaceFlag
            otherScCoeff = -otherVar.interfaceVar * scCoeff

            self.eq += ImplicitSourceTerm(otherSpCoeff) - otherScCoeff

            vars = (surfactantVar, otherVar)
        else:
            vars = (surfactantVar,)

        total = 0
        for var in vars:
            total += var.interfaceVar
        maxVar = (total > 1) * distanceVar._cellInterfaceFlag

        val = distanceVar.cellInterfaceAreas / mesh.cellVolumes
        for var in vars[1:]:
            val -= distanceVar._cellInterfaceFlag * var
        
        spMaxCoeff = 1e20 * maxVar
        scMaxCoeff = spMaxCoeff * val * (val > 0)
            
        self.eq += ImplicitSourceTerm(spMaxCoeff) - scMaxCoeff - 1e-40

        if consumptionCoeff is not None:
            self.eq += ImplicitSourceTerm(consumptionCoeff)

    def solve(self, var, boundaryConditions=(), solver=None, dt=None):
        """
        Builds and solves the `AdsorbingSurfactantEquation`'s linear system once.
        	
        :Parameters:
           - `var`: A `SurfactantVariable` to be solved for. Provides the initial condition, the old value and holds the solution on completion.
           - `solver`: The iterative solver to be used to solve the linear system of equations.
           - `boundaryConditions`: A tuple of boundaryConditions.
           - `dt`: The time step size.
           
	"""
        self.dt.setValue(dt)
        if solver is None:
            import fipy.solvers.solver
            if fipy.solvers.solver == 'pyamg':
                from fipy.solvers.pyAMG.linearGeneralSolver import LinearGeneralSolver
                solver = LinearGeneralSolver(tolerance=1e-15, iterations=2000)
            else:
                from fipy.solvers import LinearPCGSolver
                solver = LinearPCGSolver()
            
        if type(boundaryConditions) not in (type(()), type([])):
            boundaryConditions = (boundaryConditions,)
        
        var.constrain(0, var.mesh.exteriorFaces)
        
        self.eq.solve(var,
                      boundaryConditions=boundaryConditions,
                      solver = solver,
                      dt=1.)
        
    def sweep(self, var, solver=None, boundaryConditions=(), dt=None, underRelaxation=None, residualFn=None):
        r"""
        Builds and solves the `AdsorbingSurfactantEquation`'s linear
        system once. This method also recalculates and returns the
        residual as well as applying under-relaxation.

        :Parameters:

           - `var`: The variable to be solved for. Provides the initial condition, the old value and holds the solution on completion.
           - `solver`: The iterative solver to be used to solve the linear system of equations. 
           - `boundaryConditions`: A tuple of boundaryConditions.
           - `dt`: The time step size.
           - `underRelaxation`: Usually a value between `0` and `1` or `None` in the case of no under-relaxation

	"""
        self.dt.setValue(dt)
        if solver is None:
            from fipy.solvers import DefaultAsymmetricSolver
            solver = DefaultAsymmetricSolver()
        
        if type(boundaryConditions) not in (type(()), type([])):
            boundaryConditions = (boundaryConditions,)
        
        var.constrain(0, var.mesh.exteriorFaces)

        return self.eq.sweep(var, solver=solver, boundaryConditions=boundaryConditions, underRelaxation=underRelaxation, residualFn=residualFn, dt=1.)
コード例 #38
0
ファイル: meshVariable.py プロジェクト: calbaker/FiPy-2.1.3
    def __init__(self, mesh, name='', value=0., rank=None, elementshape=None, 
                 unit=None, cached=1):
        """
        :Parameters:
          - `mesh`: the mesh that defines the geometry of this `Variable`
          - `name`: the user-readable name of the `Variable`
          - `value`: the initial value
          - `rank`: the rank (number of dimensions) of each element of this 
            `Variable`. Default: 0
          - `elementshape`: the shape of each element of this variable
             Default: `rank * (mesh.getDim(),)`
          - `unit`: the physical units of the `Variable`
        """
        from fipy.tools import debug

        if isinstance(value, (list, tuple)):
            value = numerix.array(value)
            
        if isinstance(value, _MeshVariable):
            if mesh is None:
                mesh = value.mesh
            elif mesh != value.mesh:
                raise ValueError, "The new 'Variable' must use the same mesh as the supplied value"

        self.mesh = mesh
        value = self._globalToLocalValue(value)
        
        if value is None:
            array = None
        elif not isinstance(value, _Constant) and isinstance(value, Variable):
            name = name or value.name
            unit = None
            if isinstance(value, _MeshVariable):
                if not isinstance(value, self._getVariableClass()):
                    raise TypeError, "A '%s' cannot be cast to a '%s'" % (value._getVariableClass().__name__, 
                                                                          self._getVariableClass().__name__)
                if elementshape is not None and elementshape != value.shape[:-1]:
                    raise ValueError, "'elementshape' != shape of elements of 'value'"

                if rank is not None and rank != value.getRank():
                    raise ValueError, "'rank' != rank of 'value'"

                elementshape = value.shape[:-1]
                array = None

#             value = value._copyValue()

        if elementshape is None:
            valueShape = numerix.getShape(value)
            if valueShape != () and valueShape[-1] == self._getShapeFromMesh(mesh)[-1]:
                if elementshape is not None and elementshape != valueShape[:-1]:
                    raise ValueError, "'elementshape' != shape of elements of 'value'"

                if rank is not None and rank != len(valueShape[:-1]):
                    raise ValueError, "'rank' != rank of 'value'"
                elementshape = valueShape[:-1]
            elif rank is None and elementshape is None:
                elementshape = valueShape

        if rank is None:
            if elementshape is None:
                elementshape = ()
        elif elementshape is None:
            elementshape = rank * (mesh.getDim(),)
        elif len(elementshape) != rank:
            raise ValueError, 'len(elementshape) != rank'
                
        self.elementshape = elementshape
        
        if not locals().has_key("array"):
            if numerix._isPhysical(value):
                dtype = numerix.obj2sctype(value.value)
            else:
                dtype = numerix.obj2sctype(value)
            array = numerix.zeros(self.elementshape 
                                  + self._getShapeFromMesh(mesh),
                                  dtype)
            if numerix._broadcastShape(array.shape, numerix.shape(value)) is None:
                if not isinstance(value, Variable):
                    value = _Constant(value)
                value = value[..., numerix.newaxis]
                                  
        Variable.__init__(self, name=name, value=value, unit=unit, 
                          array=array, cached=cached)
コード例 #39
0
    def __init__(self,
                 mesh,
                 name='',
                 value=0.,
                 rank=None,
                 elementshape=None,
                 unit=None,
                 cached=1):
        """
        :Parameters:
          - `mesh`: the mesh that defines the geometry of this `Variable`
          - `name`: the user-readable name of the `Variable`
          - `value`: the initial value
          - `rank`: the rank (number of dimensions) of each element of this 
            `Variable`. Default: 0
          - `elementshape`: the shape of each element of this variable
             Default: `rank * (mesh.dim,)`
          - `unit`: the physical units of the `Variable`
        """
        if isinstance(value, (list, tuple)):
            value = numerix.array(value)

        if isinstance(value, _MeshVariable):
            if mesh is None:
                mesh = value.mesh
            elif mesh != value.mesh:
                raise ValueError, "The new 'Variable' must use the same mesh as the supplied value"

        self.mesh = mesh
        value = self._globalToLocalValue(value)

        if value is None:
            array = None
        elif not isinstance(value, _Constant) and isinstance(value, Variable):
            name = name or value.name
            unit = None
            if isinstance(value, _MeshVariable):
                if not isinstance(value, self._variableClass):
                    raise TypeError, "A '%s' cannot be cast to a '%s'" % (
                        value._variableClass.__name__,
                        self._variableClass.__name__)
                if elementshape is not None and elementshape != value.shape[:
                                                                            -1]:
                    raise ValueError, "'elementshape' != shape of elements of 'value'"

                if rank is not None and rank != value.rank:
                    raise ValueError, "'rank' != rank of 'value'"

                elementshape = value.shape[:-1]
                array = None

#             value = value._copyValue()

        if elementshape is None:
            valueShape = numerix.getShape(value)
            if valueShape != () and valueShape[-1] == self._getShapeFromMesh(
                    mesh)[-1]:
                if elementshape is not None and elementshape != valueShape[:-1]:
                    raise ValueError, "'elementshape' != shape of elements of 'value'"

                if rank is not None and rank != len(valueShape[:-1]):
                    raise ValueError, "'rank' != rank of 'value'"
                elementshape = valueShape[:-1]
            elif rank is None and elementshape is None:
                elementshape = valueShape

        if rank is None:
            if elementshape is None:
                elementshape = ()
        elif elementshape is None:
            elementshape = rank * (mesh.dim, )
        elif len(elementshape) != rank:
            raise ValueError, 'len(elementshape) != rank'

        self.elementshape = elementshape

        if not "array" in locals():
            if numerix._isPhysical(value):
                dtype = numerix.obj2sctype(value.value)
            else:
                dtype = numerix.obj2sctype(value)
            #print "meshvariable elshape: ",self.elementshape
            #print "meshvariable _getShapeFromMesh: ",self._getShapeFromMesh(mesh)
            array = numerix.zeros(
                self.elementshape + self._getShapeFromMesh(mesh), dtype)
            if numerix._broadcastShape(array.shape,
                                       numerix.shape(value)) is None:
                if not isinstance(value, Variable):
                    value = _Constant(value)
                value = value[..., numerix.newaxis]

        Variable.__init__(self,
                          name=name,
                          value=value,
                          unit=unit,
                          array=array,
                          cached=cached)
コード例 #40
0
class AdsorbingSurfactantEquation():
    r"""

    The `AdsorbingSurfactantEquation` object solves the
    `SurfactantEquation` but with an adsorbing species from some bulk
    value. The equation that describes the surfactant adsorbing is
    given by,

    .. math::

       \dot{\theta} = J v \theta + k c (1 - \theta - \theta_{\text{other}}) - \theta c_{\text{other}} k_{\text{other}} - k^- \theta

    where :math:`\theta`, :math:`J`, :math:`v`, :math:`k`, :math:`c`,
    :math:`k^-` and :math:`n` represent the surfactant coverage, the curvature,
    the interface normal velocity, the adsorption rate, the concentration in the
    bulk at the interface, the consumption rate and an exponent of consumption,
    respectively. The :math:`\text{other}` subscript refers to another
    surfactant with greater surface affinity.

    The terms on the RHS of the above equation represent conservation of
    surfactant on a non-uniform surface, Langmuir adsorption, removal of
    surfactant due to adsorption of the other surfactant onto non-vacant sites
    and consumption of the surfactant respectively. The adsorption term is added
    to the source by setting :math:` S_c = k c (1 - \theta_{\text{other}})` and
    :math:`S_p = -k c`. The other terms are added to the source in a similar
    way.

    The following is a test case:

    >>> from fipy.variables.distanceVariable \
    ...     import DistanceVariable
    >>> from fipy import SurfactantVariable
    >>> from fipy.meshes import Grid2D
    >>> from fipy.tools import numerix
    >>> from fipy.variables.cellVariable import CellVariable
    >>> dx = .5
    >>> dy = 2.3
    >>> dt = 0.25
    >>> k = 0.56
    >>> initialValue = 0.1
    >>> c = 0.2

    >>> from fipy.meshes import Grid2D
    >>> from fipy import serialComm
    >>> mesh = Grid2D(dx = dx, dy = dy, nx = 5, ny = 1, communicator=serialComm)
    >>> distanceVar = DistanceVariable(mesh = mesh,
    ...                                value = (-dx*3/2, -dx/2, dx/2,
    ...                                          3*dx/2,  5*dx/2),
    ...                                hasOld = 1)
    >>> surfactantVar = SurfactantVariable(value = (0, 0, initialValue, 0 ,0),
    ...                                    distanceVar = distanceVar)
    >>> bulkVar = CellVariable(mesh = mesh, value = (c , c, c, c, c))
    >>> eqn = AdsorbingSurfactantEquation(surfactantVar = surfactantVar,
    ...                                   distanceVar = distanceVar,
    ...                                   bulkVar = bulkVar,
    ...                                   rateConstant = k)
    >>> eqn.solve(surfactantVar, dt = dt)
    >>> answer = (initialValue + dt * k * c) / (1 + dt * k * c)
    >>> print numerix.allclose(surfactantVar.interfaceVar,
    ...                  numerix.array((0, 0, answer, 0, 0)))
    1

    The following test case is for two surfactant variables. One has more
    surface affinity than the other.

    >>> from fipy.variables.distanceVariable \
    ...     import DistanceVariable
    >>> from fipy import SurfactantVariable
    >>> from fipy.meshes import Grid2D
    >>> dx = 0.5
    >>> dy = 2.73
    >>> dt = 0.001
    >>> k0 = 1.
    >>> k1 = 10.
    >>> theta0 = 0.
    >>> theta1 = 0.
    >>> c0 = 1.
    >>> c1 = 1.
    >>> totalSteps = 10
    >>> mesh = Grid2D(dx = dx, dy = dy, nx = 5, ny = 1, communicator=serialComm)
    >>> distanceVar = DistanceVariable(mesh = mesh,
    ...                                value = dx * (numerix.arange(5) - 1.5),
    ...                                hasOld = 1)
    >>> var0 = SurfactantVariable(value = (0, 0, theta0, 0 ,0),
    ...                           distanceVar = distanceVar)
    >>> var1 = SurfactantVariable(value = (0, 0, theta1, 0 ,0),
    ...                           distanceVar = distanceVar)
    >>> bulkVar0 = CellVariable(mesh = mesh, value = (c0, c0, c0, c0, c0))
    >>> bulkVar1 = CellVariable(mesh = mesh, value = (c1, c1, c1, c1, c1))

    >>> eqn0 = AdsorbingSurfactantEquation(surfactantVar = var0,
    ...                                    distanceVar = distanceVar,
    ...                                    bulkVar = bulkVar0,
    ...                                    rateConstant = k0)

    >>> eqn1 = AdsorbingSurfactantEquation(surfactantVar = var1,
    ...                                    distanceVar = distanceVar,
    ...                                    bulkVar = bulkVar1,
    ...                                    rateConstant = k1,
    ...                                    otherVar = var0,
    ...                                    otherBulkVar = bulkVar0,
    ...                                    otherRateConstant = k0)

    >>> for step in range(totalSteps):
    ...     eqn0.solve(var0, dt = dt)
    ...     eqn1.solve(var1, dt = dt)
    >>> answer0 = 1 - numerix.exp(-k0 * c0 * dt * totalSteps)
    >>> answer1 = (1 - numerix.exp(-k1 * c1 * dt * totalSteps)) * (1 - answer0)
    >>> print numerix.allclose(var0.interfaceVar,
    ...                  numerix.array((0, 0, answer0, 0, 0)), rtol = 1e-2)
    1
    >>> print numerix.allclose(var1.interfaceVar,
    ...                  numerix.array((0, 0, answer1, 0, 0)), rtol = 1e-2)
    1
    >>> dt = 0.1
    >>> for step in range(10):
    ...     eqn0.solve(var0, dt = dt)
    ...     eqn1.solve(var1, dt = dt)

    >>> x, y = mesh.cellCenters
    >>> check = var0.interfaceVar + var1.interfaceVar
    >>> answer = CellVariable(mesh=mesh, value=check)
    >>> answer[x==1.25] = 1.
    >>> print check.allequal(answer)
    True

    The following test case is to fix a bug where setting the adsorption
    coefficient to zero leads to the solver not converging and an eventual
    failure.

    >>> var0 = SurfactantVariable(value = (0, 0, theta0, 0 ,0),
    ...                           distanceVar = distanceVar)
    >>> bulkVar0 = CellVariable(mesh = mesh, value = (c0, c0, c0, c0, c0))

    >>> eqn0 = AdsorbingSurfactantEquation(surfactantVar = var0,
    ...                                    distanceVar = distanceVar,
    ...                                    bulkVar = bulkVar0,
    ...                                    rateConstant = 0)

    >>> eqn0.solve(var0, dt = dt)
    >>> eqn0.solve(var0, dt = dt)
    >>> answer = CellVariable(mesh=mesh, value=var0.interfaceVar)
    >>> answer[x==1.25] = 0.

    >>> print var0.interfaceVar.allclose(answer)
    True

    The following test case is to fix a bug that allows the accelerator to
    become negative.

    >>> nx = 5
    >>> ny = 5
    >>> dx = 1.
    >>> dy = 1.
    >>> mesh = Grid2D(dx=dx, dy=dy, nx = nx, ny = ny, communicator=serialComm)
    >>> x, y = mesh.cellCenters

    >>> disVar = DistanceVariable(mesh=mesh, value=1., hasOld=True)
    >>> disVar[y < dy] = -1
    >>> disVar[x < dx] = -1
    >>> disVar.calcDistanceFunction() #doctest: +LSM

    >>> levVar = SurfactantVariable(value = 0.5, distanceVar = disVar)
    >>> accVar = SurfactantVariable(value = 0.5, distanceVar = disVar)

    >>> levEq = AdsorbingSurfactantEquation(levVar,
    ...                                     distanceVar = disVar,
    ...                                     bulkVar = 0,
    ...                                     rateConstant = 0)

    >>> accEq = AdsorbingSurfactantEquation(accVar,
    ...                                     distanceVar = disVar,
    ...                                     bulkVar = 0,
    ...                                     rateConstant = 0,
    ...                                     otherVar = levVar,
    ...                                     otherBulkVar = 0,
    ...                                     otherRateConstant = 0)

    >>> extVar = CellVariable(mesh = mesh, value = accVar.interfaceVar)

    >>> from fipy import TransientTerm, AdvectionTerm
    >>> advEq = TransientTerm() + AdvectionTerm(extVar)

    >>> dt = 0.1

    >>> for i in range(50):
    ...     disVar.calcDistanceFunction()
    ...     extVar.value = (numerix.array(accVar.interfaceVar))
    ...     disVar.extendVariable(extVar)
    ...     disVar.updateOld()
    ...     advEq.solve(disVar, dt = dt)
    ...     levEq.solve(levVar, dt = dt)
    ...     accEq.solve(accVar, dt = dt) #doctest: +LSM

    >>> # The following test fails sometimes on linux with scipy solvers
    >>> # See issue #575. We ignore for now.
    >>> print (accVar >= -1e-10).all() #doctest: +NOTLINUXSCIPY
    True
    """
    def __init__(self,
                 surfactantVar=None,
                 distanceVar=None,
                 bulkVar=None,
                 rateConstant=None,
                 otherVar=None,
                 otherBulkVar=None,
                 otherRateConstant=None,
                 consumptionCoeff=None):
        """
        Create a `AdsorbingSurfactantEquation` object.

        :Parameters:
          - `surfactantVar`: The `SurfactantVariable` to be solved for.
          - `distanceVar`: The `DistanceVariable` that marks the interface.
          - `bulkVar`: The value of the `surfactantVar` in the bulk.
          - `rateConstant`: The adsorption rate of the `surfactantVar`.
          - `otherVar`: Another `SurfactantVariable` with more surface affinity.
          - `otherBulkVar`: The value of the `otherVar` in the bulk.
          - `otherRateConstant`: The adsorption rate of the `otherVar`.
          - `consumptionCoeff`: The rate that the `surfactantVar` is consumed during deposition.

        """

        self.eq = TransientTerm(coeff=1) - ExplicitUpwindConvectionTerm(
            SurfactantConvectionVariable(distanceVar))

        self.dt = Variable(0.)
        mesh = distanceVar.mesh
        adsorptionCoeff = self.dt * bulkVar * rateConstant
        spCoeff = adsorptionCoeff * distanceVar._cellInterfaceFlag
        scCoeff = adsorptionCoeff * distanceVar.cellInterfaceAreas / mesh.cellVolumes

        self.eq += ImplicitSourceTerm(spCoeff) - scCoeff

        if otherVar is not None:
            otherSpCoeff = self.dt * otherBulkVar * otherRateConstant * distanceVar._cellInterfaceFlag
            otherScCoeff = -otherVar.interfaceVar * scCoeff

            self.eq += ImplicitSourceTerm(otherSpCoeff) - otherScCoeff

            vars = (surfactantVar, otherVar)
        else:
            vars = (surfactantVar, )

        total = 0
        for var in vars:
            total += var.interfaceVar
        maxVar = (total > 1) * distanceVar._cellInterfaceFlag

        val = distanceVar.cellInterfaceAreas / mesh.cellVolumes
        for var in vars[1:]:
            val -= distanceVar._cellInterfaceFlag * var

        spMaxCoeff = 1e20 * maxVar
        scMaxCoeff = spMaxCoeff * val * (val > 0)

        self.eq += ImplicitSourceTerm(spMaxCoeff) - scMaxCoeff - 1e-40

        if consumptionCoeff is not None:
            self.eq += ImplicitSourceTerm(consumptionCoeff)

    def solve(self, var, boundaryConditions=(), solver=None, dt=None):
        """
        Builds and solves the `AdsorbingSurfactantEquation`'s linear system once.

        :Parameters:
           - `var`: A `SurfactantVariable` to be solved for. Provides the initial condition, the old value and holds the solution on completion.
           - `solver`: The iterative solver to be used to solve the linear system of equations.
           - `boundaryConditions`: A tuple of boundaryConditions.
           - `dt`: The time step size.

	"""
        self.dt.setValue(dt)
        if solver is None:
            import fipy.solvers.solver
            if fipy.solvers.solver == 'pyamg':
                from fipy.solvers.pyAMG.linearGeneralSolver import LinearGeneralSolver
                solver = LinearGeneralSolver(tolerance=1e-15, iterations=2000)
            else:
                from fipy.solvers import LinearPCGSolver
                solver = LinearPCGSolver()

        if type(boundaryConditions) not in (type(()), type([])):
            boundaryConditions = (boundaryConditions, )

        var.constrain(0, var.mesh.exteriorFaces)

        self.eq.solve(var,
                      boundaryConditions=boundaryConditions,
                      solver=solver,
                      dt=1.)

    def sweep(self,
              var,
              solver=None,
              boundaryConditions=(),
              dt=None,
              underRelaxation=None,
              residualFn=None):
        r"""
        Builds and solves the `AdsorbingSurfactantEquation`'s linear
        system once. This method also recalculates and returns the
        residual as well as applying under-relaxation.

        :Parameters:

           - `var`: The variable to be solved for. Provides the initial condition, the old value and holds the solution on completion.
           - `solver`: The iterative solver to be used to solve the linear system of equations.
           - `boundaryConditions`: A tuple of boundaryConditions.
           - `dt`: The time step size.
           - `underRelaxation`: Usually a value between `0` and `1` or `None` in the case of no under-relaxation

	"""
        self.dt.setValue(dt)
        if solver is None:
            from fipy.solvers import DefaultAsymmetricSolver
            solver = DefaultAsymmetricSolver()

        if type(boundaryConditions) not in (type(()), type([])):
            boundaryConditions = (boundaryConditions, )

        var.constrain(0, var.mesh.exteriorFaces)

        return self.eq.sweep(var,
                             solver=solver,
                             boundaryConditions=boundaryConditions,
                             underRelaxation=underRelaxation,
                             residualFn=residualFn,
                             dt=1.)
コード例 #41
0
ファイル: operatorVariable.py プロジェクト: xinxinboss/fipy
 def _isCached(self):
     return (Variable._isCached(self)
             or (len(self.subscribedVariables) > 1
                 and not self._cacheNever))
コード例 #42
0
ファイル: diffusionTerm.py プロジェクト: calbaker/FiPy-2.1.3
class DiffusionTerm(Term):

    r"""
    This term represents a higher order diffusion term. The order of the term is determined
    by the number of `coeffs`, such that::

        DiffusionTerm(D1)

    represents a typical 2nd-order diffusion term of the form

    .. math::

       \nabla\cdot\left(D_1 \nabla \phi\right)

    and::

        DiffusionTerm((D1,D2))

    represents a 4th-order Cahn-Hilliard term of the form

    .. math::

       \nabla \cdot \left\{ D_1 \nabla \left[ \nabla\cdot\left( D_2 \nabla \phi\right) \right] \right\}

    and so on.

    """

    def __init__(self, coeff = (1.,)):
        """
        Create a `DiffusionTerm`.

        :Parameters:
          - `coeff`: `Tuple` or `list` of `FaceVariables` or numbers.
          
        """
        if type(coeff) not in (type(()), type([])):
            coeff = (coeff,)

        self.order = len(coeff) * 2


        if len(coeff) > 0:
            self.nthCoeff = coeff[0]

            from fipy.variables.variable import Variable
            if not isinstance(self.nthCoeff, Variable):
                self.nthCoeff = Variable(value = self.nthCoeff)

            from fipy.variables.cellVariable import CellVariable
            if isinstance(self.nthCoeff, CellVariable):
                self.nthCoeff = self.nthCoeff.getArithmeticFaceValue()

        else:
            self.nthCoeff = None

        Term.__init__(self, coeff = coeff)
        
        if self.order > 0:
            self.lowerOrderDiffusionTerm = DiffusionTerm(coeff = coeff[1:])
        
    def __neg__(self):
        """
        Negate the term.

        >>> -DiffusionTerm(coeff=[1.])
        DiffusionTerm(coeff=[-1.0])

        >>> -DiffusionTerm()
        DiffusionTerm(coeff=[-1.0])
           
        """
        negatedCoeff = list(self.coeff)
        negatedCoeff[0] = -negatedCoeff[0]
        return self.__class__(coeff = negatedCoeff)
            
    def _getBoundaryConditions(self, boundaryConditions):
        higherOrderBCs = []
        lowerOrderBCs = []

        for bc in boundaryConditions:
            bcDeriv = bc._getDerivative(self.order - 2)
            if bcDeriv:
                higherOrderBCs.append(bcDeriv)
            else:
                lowerOrderBCs.append(bc)
                
        return higherOrderBCs, lowerOrderBCs

    def _getNormals(self, mesh):
        return mesh._getFaceCellToCellNormals()

    def _getRotationTensor(self, mesh):
        if not hasattr(self, 'rotationTensor'):

            from fipy.variables.faceVariable import FaceVariable
            rotationTensor = FaceVariable(mesh=mesh, rank=2)
            
            rotationTensor[:, 0] = self._getNormals(mesh)

            if mesh.getDim() == 2:
                rotationTensor[:,1] = rotationTensor[:,0].dot((((0, 1), (-1, 0))))
            elif mesh.getDim() ==3:
                epsilon = 1e-20

                div = numerix.sqrt(1 - rotationTensor[2,0]**2)
                flag = numerix.resize(div > epsilon, (mesh.getDim(), mesh._getNumberOfFaces()))

                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 _treatMeshAsOrthogonal(self, mesh):
        return mesh._isOrthogonal()

    def _calcAnisotropySource(self, coeff, mesh, var):

        if not hasattr(self, 'anisotropySource'):
            if len(coeff) > 1:
                gradients = var.getGrad().getHarmonicFaceValue().dot(self._getRotationTensor(mesh))
                from fipy.variables.addOverFacesVariable import _AddOverFacesVariable
                self.anisotropySource = _AddOverFacesVariable(gradients[1:].dot(coeff[1:])) * mesh.getCellVolumes()

    def _calcGeomCoeff(self, mesh):
        if self.nthCoeff is not None:
          
            coeff = self.nthCoeff
            shape = numerix.getShape(coeff)

            from fipy.variables.faceVariable import FaceVariable
            if isinstance(coeff, FaceVariable):
                rank = coeff.getRank()
            else:
                rank = len(shape)

            if rank == 0 and self._treatMeshAsOrthogonal(mesh):
                tmpBop = (coeff * mesh._getFaceAreas() / mesh._getCellDistances())[numerix.newaxis, :]

            else:

                if rank == 1 or rank == 0:
                    coeff = coeff * numerix.identity(mesh.getDim())

                if rank > 0:
                    shape = numerix.getShape(coeff)
                    if mesh.getDim() != shape[0] or mesh.getDim() != shape[1]:
                        raise IndexError, 'diffusion coefficent tensor is not an appropriate shape for this mesh'          

                faceNormals = FaceVariable(mesh=mesh, rank=1, value=mesh._getFaceNormals())
                rotationTensor = self._getRotationTensor(mesh)
                rotationTensor[:,0] = rotationTensor[:,0] / mesh._getCellDistances()
                
                tmpBop = faceNormals.dot(coeff).dot(rotationTensor) * mesh._getFaceAreas()

            return tmpBop

        else:

            return None

    def _getCoefficientMatrix(self, SparseMatrix, mesh, coeff):
        interiorCoeff = numerix.array(coeff)
        
        interiorCoeff[mesh.getExteriorFaces().getValue()] = 0
        
        interiorCoeff = numerix.take(interiorCoeff, mesh._getCellFaceIDs())

        coefficientMatrix = SparseMatrix(mesh=mesh, bandwidth = mesh._getMaxFacesPerCell() + 1)
        coefficientMatrix.addAtDiagonal(numerix.sum(interiorCoeff, 0))
        del interiorCoeff

        interiorFaces = mesh.getInteriorFaceIDs()
        interiorFaceCellIDs = mesh.getInteriorFaceCellIDs()

        interiorCoeff = -numerix.take(coeff, interiorFaces, axis=-1)
        coefficientMatrix.addAt(interiorCoeff, interiorFaceCellIDs[0], interiorFaceCellIDs[1])
        interiorCoeff = -numerix.take(coeff, interiorFaces, axis=-1)
        coefficientMatrix.addAt(interiorCoeff, interiorFaceCellIDs[1], interiorFaceCellIDs[0])
        
        return coefficientMatrix
        
    def _bcAdd(self, coefficientMatrix, boundaryB, LLbb):
        coefficientMatrix += LLbb[0]
        boundaryB += LLbb[1]
        
    def _doBCs(self, SparseMatrix, higherOrderBCs, N, M, coeffs, coefficientMatrix, boundaryB):
        for boundaryCondition in higherOrderBCs:
            self._bcAdd(coefficientMatrix, boundaryB, boundaryCondition._buildMatrix(SparseMatrix, N, M, coeffs))
            
        return coefficientMatrix, boundaryB

    def __add__(self, other):
        if isinstance(other, DiffusionTerm):
            from fipy.terms.collectedDiffusionTerm import _CollectedDiffusionTerm
            if isinstance(other, _CollectedDiffusionTerm):
                return other + self
            elif other.order == self.order and self.order <= 2:
                if self.order == 0:
                    return self
                elif self.order == 2:
                    return self.__class__(coeff=self.coeff[0] + other.coeff[0])
            else:
                term = _CollectedDiffusionTerm()
                term += self
                term += other
                return term
        else:
            return Term.__add__(self, other)

    def _buildMatrix(self, var, SparseMatrix, boundaryConditions = (), dt = 1., equation=None):
        mesh = var.getMesh()
        
        N = mesh.getNumberOfCells()
        M = mesh._getMaxFacesPerCell()

        if self.order > 2:

            higherOrderBCs, lowerOrderBCs = self._getBoundaryConditions(boundaryConditions)
            
            lowerOrderL, lowerOrderb = self.lowerOrderDiffusionTerm._buildMatrix(var = var, SparseMatrix=SparseMatrix,
                                                                                 boundaryConditions = lowerOrderBCs, 
                                                                                 dt = dt,
                                                                                 equation=equation)
            del lowerOrderBCs
            
            lowerOrderb = lowerOrderb / mesh.getCellVolumes()
            volMatrix = SparseMatrix(mesh=var.getMesh(), bandwidth = 1)
            
            volMatrix.addAtDiagonal(1. / mesh.getCellVolumes() )
            lowerOrderL = volMatrix * lowerOrderL
            del volMatrix

            if not hasattr(self, 'coeffDict'):

                coeff = self._getGeomCoeff(mesh)[0]
                minusCoeff = -coeff
                
                coeff.dontCacheMe()
                minusCoeff.dontCacheMe()

                self.coeffDict = {
                    'cell 1 diag':     minusCoeff,
                    'cell 1 offdiag':  coeff
                    }
                del coeff
                del minusCoeff

                self.coeffDict['cell 2 offdiag'] = self.coeffDict['cell 1 offdiag']
                self.coeffDict['cell 2 diag'] = self.coeffDict['cell 1 diag']


            mm = self._getCoefficientMatrix(SparseMatrix, mesh, self.coeffDict['cell 1 diag'])
            L, b = self._doBCs(SparseMatrix, higherOrderBCs, N, M, self.coeffDict, 
                               mm, numerix.zeros(N,'d'))
                               
            del higherOrderBCs
            del mm

            b = L * lowerOrderb + b
            del lowerOrderb

            L = L * lowerOrderL
            del lowerOrderL

        elif self.order == 2:

            if not hasattr(self, 'coeffDict'):

                coeff = self._getGeomCoeff(mesh)
                minusCoeff = -coeff[0]

                coeff[0].dontCacheMe()
                minusCoeff.dontCacheMe()

                self.coeffDict = {
                    'cell 1 diag':    minusCoeff,
                    'cell 1 offdiag':  coeff[0]
                    }

                self.coeffDict['cell 2 offdiag'] = self.coeffDict['cell 1 offdiag']
                self.coeffDict['cell 2 diag'] = self.coeffDict['cell 1 diag']

                self._calcAnisotropySource(coeff, mesh, var)

                del coeff
                del minusCoeff
                
            higherOrderBCs, lowerOrderBCs = self._getBoundaryConditions(boundaryConditions)
            del lowerOrderBCs

            L, b = self._doBCs(SparseMatrix, higherOrderBCs, N, M, self.coeffDict, 
                               self._getCoefficientMatrix(SparseMatrix, mesh, self.coeffDict['cell 1 diag']), numerix.zeros(N,'d'))

            if hasattr(self, 'anisotropySource'):
                b -= self.anisotropySource
                               
            del higherOrderBCs


        else:
            
            L = SparseMatrix(mesh=mesh)
            L.addAtDiagonal(mesh.getCellVolumes())
            b = numerix.zeros((N),'d')
            
        return (L, b)
        
    def _test(self):
        r"""
        Test, 2nd order, 1 dimension, fixed flux of zero both ends.

        >>> from fipy.meshes.grid1D import Grid1D
        >>> from fipy.matrices.pysparseMatrix import _PysparseMeshMatrix as SparseMatrix
        >>> from fipy.tools import parallel
        >>> procID = parallel.procID
        >>> mesh = Grid1D(dx = 1., nx = 2)
        >>> term = DiffusionTerm(coeff = (1,))
        >>> coeff = term._getGeomCoeff(mesh)
        >>> M = term._getCoefficientMatrix(SparseMatrix, mesh, coeff[0])
        >>> print numerix.allclose(M.getNumpyArray(), 
        ...                        (( 1., -1.), 
        ...                         (-1.,  1.))) or procID != 0
        True
        >>> from fipy.variables.cellVariable import CellVariable
        >>> L,b = term._buildMatrix(var=CellVariable(mesh=mesh), SparseMatrix=SparseMatrix)
        >>> print numerix.allclose(L.getNumpyArray(), 
        ...                        ((-1.,  1.), 
        ...                         ( 1., -1.))) or procID != 0
        True
        >>> print numerix.allclose(b, (0., 0.)) or procID != 0
        True

        The coefficient must be a `FaceVariable`, a `CellVariable` (which will
        be interpolated to a `FaceVariable`), or a scalar value 
        
        >>> from fipy.variables.faceVariable import FaceVariable
        >>> term = DiffusionTerm(coeff=FaceVariable(mesh=mesh, value=1))
        >>> coeff = term._getGeomCoeff(mesh)
        >>> M = term._getCoefficientMatrix(SparseMatrix, mesh, coeff[0])
        >>> print numerix.allclose(M.getNumpyArray(), 
        ...                        (( 1., -1.), 
        ...                         (-1.,  1.))) or procID != 0
        True
        >>> L,b = term._buildMatrix(var=CellVariable(mesh=mesh), SparseMatrix=SparseMatrix)
        >>> print numerix.allclose(L.getNumpyArray(), 
        ...                        ((-1.,  1.), 
        ...                         ( 1., -1.))) or procID != 0
        True
        >>> print numerix.allclose(b, (0., 0.)) or procID != 0
        True

        >>> term = DiffusionTerm(coeff=CellVariable(mesh=mesh, value=1))
        >>> coeff = term._getGeomCoeff(mesh)
        >>> M = term._getCoefficientMatrix(SparseMatrix, mesh, coeff[0])
        >>> print numerix.allclose(M.getNumpyArray(), 
        ...                        (( 1., -1.), 
        ...                         (-1.,  1.))) or procID != 0
        True
        >>> L,b = term._buildMatrix(var=CellVariable(mesh=mesh), SparseMatrix=SparseMatrix)
        >>> print numerix.allclose(L.getNumpyArray(), 
        ...                        ((-1.,  1.), 
        ...                         ( 1., -1.))) or procID != 0
        True
        >>> print numerix.allclose(b, (0., 0.)) or procID != 0
        True

        >>> from fipy.variables.variable import Variable
        >>> term = DiffusionTerm(coeff = Variable(value = 1))
        >>> coeff = term._getGeomCoeff(mesh)
        >>> M = term._getCoefficientMatrix(SparseMatrix, mesh, coeff[0])
        >>> print numerix.allclose(M.getNumpyArray(), 
        ...                        (( 1., -1.), 
        ...                         (-1.,  1.))) or procID != 0
        True
        >>> L,b = term._buildMatrix(var=CellVariable(mesh=mesh), SparseMatrix=SparseMatrix)
        >>> print numerix.allclose(L.getNumpyArray(), 
        ...                        ((-1.,  1.), 
        ...                         ( 1., -1.))) or procID != 0
        True
        >>> print numerix.allclose(b, (0., 0.)) or procID != 0
        True
                   
        >>> term = DiffusionTerm(coeff = ((1,2),))

        >>> term = DiffusionTerm(coeff = FaceVariable(mesh = mesh, value = (1,), rank=1))
        >>> term = DiffusionTerm(coeff = CellVariable(mesh=mesh, value=(1,), rank=1))

        Test, 2nd order, 1 dimension, fixed flux 3, fixed value of 4

        >>> from fipy.boundaryConditions.fixedFlux import FixedFlux
        >>> from fipy.boundaryConditions.fixedValue import FixedValue
        >>> bcLeft = FixedFlux(mesh.getFacesLeft(), 3.)
        >>> bcRight = FixedValue(mesh.getFacesRight(), 4.)
        >>> term = DiffusionTerm(coeff = (1.,))
        >>> coeff = term._getGeomCoeff(mesh)
        >>> M = term._getCoefficientMatrix(SparseMatrix, mesh, coeff[0])
        >>> print numerix.allclose(M.getNumpyArray(), 
        ...                        (( 1., -1.), 
        ...                         (-1.,  1.))) or procID != 0
        True
        >>> L,b = term._buildMatrix(var=CellVariable(mesh=mesh), 
        ...                         SparseMatrix=SparseMatrix ,
        ...                         boundaryConditions=(bcLeft, bcRight))
        >>> print numerix.allclose(L.getNumpyArray(), 
        ...                        ((-1.,  1.), 
        ...                         ( 1., -3.))) or procID != 0
        True
        >>> print numerix.allclose(b, (-3., -8.)) or procID != 0
        True
           
        Test, 4th order, 1 dimension, x = 0; fixed flux 3, fixed curvatures 0,
        x = 2, fixed value 1, fixed curvature 0

        >>> bcLeft1 = FixedFlux(mesh.getFacesLeft(), 3.)
        >>> from fipy.boundaryConditions.nthOrderBoundaryCondition \
        ...     import NthOrderBoundaryCondition
        >>> bcLeft2 =  NthOrderBoundaryCondition(mesh.getFacesLeft(), 0., 2)
        >>> bcRight1 = FixedValue(mesh.getFacesRight(), 4.)
        >>> bcRight2 =  NthOrderBoundaryCondition(mesh.getFacesRight(), 0., 2)
        >>> term = DiffusionTerm(coeff = (1., 1.))
        >>> coeff = term._getGeomCoeff(mesh)
        >>> M = term._getCoefficientMatrix(SparseMatrix, mesh, coeff[0])
        >>> print numerix.allclose(M.getNumpyArray(), 
        ...                        (( 1., -1.), 
        ...                         (-1.,  1.))) or procID != 0
        True
        >>> L,b = term._buildMatrix(var = CellVariable(mesh = mesh), SparseMatrix=SparseMatrix,
        ...                         boundaryConditions = (bcLeft1, bcLeft2, 
        ...                                               bcRight1, bcRight2))
        >>> print numerix.allclose(L.getNumpyArray(), 
        ...                        (( 4., -6.), 
        ...                         (-4., 10.))) or procID != 0
        True
        >>> print numerix.allclose(b, (1., 21.)) or procID != 0
        True
        
        Test, 4th order, 1 dimension, x = 0; fixed flux 3, fixed curvature 2,
        x = 2, fixed value 4, fixed 3rd order -1

        >>> bcLeft1 = FixedFlux(mesh.getFacesLeft(), 3.)
        >>> bcLeft2 =  NthOrderBoundaryCondition(mesh.getFacesLeft(), 2., 2)
        >>> bcRight1 = FixedValue(mesh.getFacesRight(), 4.)
        >>> bcRight2 =  NthOrderBoundaryCondition(mesh.getFacesRight(), -1., 3)
        >>> term = DiffusionTerm(coeff = (-1., 1.))
        >>> coeff = term._getGeomCoeff(mesh)
        >>> M = term._getCoefficientMatrix(SparseMatrix, mesh, coeff[0])
        >>> print numerix.allclose(M.getNumpyArray(), 
        ...                        ((-1.,  1.), 
        ...                         ( 1., -1.))) or procID != 0
        True
        >>> L,b = term._buildMatrix(var = CellVariable(mesh = mesh), 
        ...                         SparseMatrix=SparseMatrix,
        ...                         boundaryConditions = (bcLeft1, bcLeft2, 
        ...                                               bcRight1, bcRight2))
        >>> print numerix.allclose(L.getNumpyArray(), 
        ...                        ((-4.,  6.), 
        ...                         ( 2., -4.))) or procID != 0
        True
        >>> print numerix.allclose(b, (3., -4.)) or procID != 0
        True


        Test when dx = 0.5.

        >>> mesh = Grid1D(dx = .5, nx = 2)
        >>> bcLeft1 = FixedValue(mesh.getFacesLeft(), 0.)
        >>> bcLeft2 =  NthOrderBoundaryCondition(mesh.getFacesLeft(), 1., 2)
        >>> bcRight1 = FixedFlux(mesh.getFacesRight(), 1.)
        >>> bcRight2 =  NthOrderBoundaryCondition(mesh.getFacesRight(), 0., 3)
        >>> term = DiffusionTerm(coeff = (1., 1.))
        >>> coeff = term._getGeomCoeff(mesh)
        >>> M = term._getCoefficientMatrix(SparseMatrix, mesh, coeff[0])
        >>> print numerix.allclose(M.getNumpyArray(), 
        ...                        (( 2., -2.), 
        ...                         (-2.,  2.))) or procID != 0
        True
        >>> L,b = term._buildMatrix(var = CellVariable(mesh = mesh), 
        ...                         SparseMatrix=SparseMatrix,
        ...                         boundaryConditions = (bcLeft1, bcLeft2, 
        ...                                               bcRight1, bcRight2))
        >>> print numerix.allclose(L.getNumpyArray(), 
        ...                        (( 80., -32.),
        ...                         (-32.,  16.))) or procID != 0
        True
        >>> print numerix.allclose(b, (-8., 4.)) or procID != 0
        True

        The following tests are to check that DiffusionTerm can take any of the four
        main Variable types.

        >>> from fipy.meshes.tri2D import Tri2D
        >>> mesh = Tri2D(nx = 1, ny = 1)
        >>> term = DiffusionTerm(CellVariable(value = 1, mesh = mesh))
        >>> print term._getGeomCoeff(mesh)[0]
        [ 6.   6.   6.   6.   1.5  1.5  1.5  1.5]
        >>> term = DiffusionTerm(FaceVariable(value = 1, mesh = mesh))
        >>> print term._getGeomCoeff(mesh)[0]
        [ 6.   6.   6.   6.   1.5  1.5  1.5  1.5]
        >>> term = DiffusionTerm(CellVariable(value=(0.5, 1), mesh=mesh, rank=1))
        >>> term = DiffusionTerm(CellVariable(value=((0.5,), (1,)), mesh=mesh, rank=1))
        >>> print term._getGeomCoeff(mesh)[0]
        [ 6.     6.     3.     3.     1.125  1.125  1.125  1.125]
        >>> term = DiffusionTerm(FaceVariable(value=(0.5, 1), mesh=mesh, rank=1))
        >>> term = DiffusionTerm(FaceVariable(value=((0.5,), (1,)), mesh=mesh, rank=1))
        >>> print term._getGeomCoeff(mesh)[0]
        [ 6.     6.     3.     3.     1.125  1.125  1.125  1.125]
        >>> mesh = Tri2D(nx = 1, ny = 1, dy = 0.1)
        >>> term = DiffusionTerm(FaceVariable(value=(0.5, 1), mesh=mesh, rank=1))
        >>> term = DiffusionTerm(FaceVariable(value=((0.5,), (1,)), mesh=mesh, rank=1))
        >>> val = (60., 60., 0.3, 0.3, 0.22277228, 0.22277228, 0.22277228, 0.22277228)
        >>> print numerix.allclose(term._getGeomCoeff(mesh)[0], val)
        1
        >>> term = DiffusionTerm(((0.5, 1),))
        >>> term = DiffusionTerm((((0.5,), (1,)),))
        >>> print numerix.allclose(term._getGeomCoeff(mesh)[0], val)
        Traceback (most recent call last):
            ...
        IndexError: diffusion coefficent tensor is not an appropriate shape for this mesh

        Anisotropy test

        >>> from fipy.meshes.tri2D import Tri2D
        >>> mesh = Tri2D(nx = 1, ny = 1)
        >>> term = DiffusionTerm((((1, 2), (3, 4)),))
        >>> print term._getGeomCoeff(mesh)
        [[ 24.          24.           6.           6.           0.           7.5
            7.5          0.        ]
         [ -3.          -3.           2.           2.          -1.41421356
            0.70710678   0.70710678  -1.41421356]]

        """
        pass
コード例 #43
0
 def __init__(self, var):
     Variable.__init__(self, unit=var.unit)
     self.var = self._requires(var)
コード例 #44
0
ファイル: operatorVariable.py プロジェクト: LWhitson2/fipy
 def _isCached(self):
     return (Variable._isCached(self) 
             or (len(self.subscribedVariables) > 1 and not self._cacheNever))
コード例 #45
0
 def __init__(self, var):
     Variable.__init__(self, unit = var.unit)
     self.var = self._requires(var)