Пример #1
0
    def deform_swarm(self, update_owners=True):
        """
            Updating positions of either of the fixed or lagrangian swarms
            must be done with this context manager to ensure the triangulation
            information is properly populated
        """
        self.fixedSwarm._locked = True
        self.fixedSwarm._particleCoordinates.data.flags.writeable = True
        self.lagrSwarm._locked = True
        self.lagrSwarm._particleCoordinates.data.flags.writeable = True

        try:
            yield
        except Exception as e:
            raise uw._prepend_message_to_exception(e, "An exception was encountered during meshSwarm deformation."
                                                     +"Particle locations may not be correctly modified." )

        finally:

            self.fixedSwarm._locked = False
            self.fixedSwarm._particleCoordinates.data.flags.writeable = False
            self.lagrSwarm._locked = False
            self.lagrSwarm._particleCoordinates.data.flags.writeable = False

            self.fixedSwarm.update_particle_owners()
            self.lagrSwarm.update_particle_owners()
            self.update_triangulation()
Пример #2
0
    def deform_swarm(self, update_owners=True):
        """
            Updating positions of either of the fixed or lagrangian swarms
            must be done with this context manager to ensure the triangulation
            information is properly populated
        """
        self.fixedSwarm._locked = True
        self.fixedSwarm._particleCoordinates.data.flags.writeable = True
        self.lagrSwarm._locked = True
        self.lagrSwarm._particleCoordinates.data.flags.writeable = True

        try:
            yield
        except Exception as e:
            raise uw._prepend_message_to_exception(
                e,
                "An exception was encountered during meshSwarm deformation." +
                "Particle locations may not be correctly modified.")

        finally:

            self.fixedSwarm._locked = False
            self.fixedSwarm._particleCoordinates.data.flags.writeable = False
            self.lagrSwarm._locked = False
            self.lagrSwarm._particleCoordinates.data.flags.writeable = False

            self.fixedSwarm.update_particle_owners()
            self.lagrSwarm.update_particle_owners()
            self.update_triangulation()
Пример #3
0
    def deform_swarm(self, update_owners=True):
        """
        Any particle location modifications must occur within this python 
        context manager. This is necessary as it is critical that certain
        internal objects are updated when particle locations are modified.

        Parameters
        ----------
        update_owners : bool, default=True
            If this is set to False, particle ownership (which element owns a 
            particular particle) is not updated at the conclusion of the context
            manager. This is often necessary when both the mesh and particles 
            are advecting simutaneously.

        Example
        -------
        >>> mesh = uw.mesh.FeMesh_Cartesian( elementType='Q1/dQ0', elementRes=(16,16), minCoord=(0.,0.), maxCoord=(1.,1.) )
        >>> swarm = uw.swarm.Swarm(mesh)
        >>> layout = uw.swarm.layouts.PerCellGaussLayout(swarm,2)
        >>> swarm.populate_using_layout(layout)
        >>> swarm.data[0]
        array([ 0.0132078,  0.0132078])
        
        Attempted modification without using deform_swarm() should fail:
        
        >>> swarm.data[0] = [0.2,0.2]
        Traceback (most recent call last):
        ...
        ValueError: assignment destination is read-only
        
        Within the deform_swarm() context manager, modification is allowed:
        
        >>> with swarm.deform_swarm():
        ...     swarm.data[0] = [0.2,0.2]
        >>> swarm.data[0]
        array([ 0.2,  0.2])

        """
        # lock swarm to prevent particle addition etc
        self._locked = True
        # enable writeable array
        self._particleCoordinates.data.flags.writeable = True
        try:
            yield
        except Exception as e:
            raise uw._prepend_message_to_exception(
                e,
                "An exception was encountered during particle deformation." +
                "Particle locations may not be correctly modified.")
        finally:
            # disable writeable array
            self._particleCoordinates.data.flags.writeable = False
            # unlock swarm
            self._locked = False
            # update owners
            if update_owners:
                self.update_particle_owners()
Пример #4
0
    def deform_swarm(self, update_owners=True):
        """
        Any particle location modifications must occur within this python 
        context manager. This is necessary as it is critical that certain
        internal objects are updated when particle locations are modified.

        Parameters
        ----------
        update_owners : bool, default=True
            If this is set to False, particle ownership (which element owns a 
            particular particle) is not updated at the conclusion of the context
            manager. This is often necessary when both the mesh and particles 
            are advecting simutaneously.

        Example
        -------
        >>> mesh = uw.mesh.FeMesh_Cartesian( elementType='Q1/dQ0', elementRes=(16,16), minCoord=(0.,0.), maxCoord=(1.,1.) )
        >>> swarm = uw.swarm.Swarm(mesh)
        >>> layout = uw.swarm.layouts.PerCellGaussLayout(swarm,2)
        >>> swarm.populate_using_layout(layout)
        >>> swarm.data[0]
        array([ 0.0132078,  0.0132078])
        
        Attempted modification without using deform_swarm() should fail:
        
        >>> swarm.data[0] = [0.2,0.2]
        Traceback (most recent call last):
        ...
        ValueError: assignment destination is read-only
        
        Within the deform_swarm() context manager, modification is allowed:
        
        >>> with swarm.deform_swarm():
        ...     swarm.data[0] = [0.2,0.2]
        >>> swarm.data[0]
        array([ 0.2,  0.2])

        """
        # lock swarm to prevent particle addition etc
        self._locked = True
        # enable writeable array
        self._particleCoordinates.data.flags.writeable = True
        try:
            yield
        except Exception as e:
            raise uw._prepend_message_to_exception(e, "An exception was encountered during particle deformation."
                                                     +"Particle locations may not be correctly modified." )
        finally:
            # disable writeable array
            self._particleCoordinates.data.flags.writeable = False
            # unlock swarm
            self._locked = False
            # update owners
            if update_owners:
                self.update_particle_owners()
Пример #5
0
    def deform_mesh(self):
        """
        Any mesh deformation should occur within this context manager. Note that
        certain algorithms may be switched to their irregular mesh equivalents
        (if not already set this way).
        
        Any submesh will also be appropriately updated on return from the context
        manager.
        
        Example
        -------
        >>> import underworld as uw
        >>> someMesh = uw.mesh.FeMesh_Cartesian()
        >>> with someMesh.deform_mesh():
        ...     someMesh.data[0] = [0.1,0.1]
        >>> someMesh.data[0]
        array([ 0.1,  0.1])


        """
        # set the general mesh algorithm now
        uw.libUnderworld.StgDomain.Mesh_SetAlgorithms(self._cself, None)
        self._cself.isRegular = False
        self._dataWriteable = True
        try:
            yield
        except Exception as e:
            raise uw._prepend_message_to_exception(
                e, "An exception was raised during mesh deformation. " +
                "Your mesh may only be partially deformed. " +
                "You can reset your mesh using the 'reset' method. " +
                "Note that any submesh should not be modified directly, " +
                "but will instead be updated automatically on return from " +
                "the 'deform_mesh' context manager. \nEncountered exception message:\n"
            )
        finally:
            self._dataWriteable = False
            # call deformupdate, which updates various mesh metrics
            uw.libUnderworld.StgDomain.Mesh_DeformationUpdate(self._cself)
            if hasattr(self, "subMesh") and self.subMesh:
                # remesh the submesh based on the new primary
                self.subMesh.reset()
Пример #6
0
    def convert(obj):
        """
        This method will attempt to convert the provided input into an equivalent
        underworld function. If the provided input is already of Function type,
        it is immediately returned. Likewise, if the input is of None type, it is
        also returned.
        
        Parameters
        ----------
        obj: fn_like
            The object to be converted. Note that if obj is of type None or
            Function, it is simply returned immediately.
            Where obj is of type int/float/double, a Constant type function 
            is returned which evaluates to the provided object's value.
            Where obj is of type list/tuple, a function will be returned
            which evaluates to a vector of the provided list/tuple's values 
            (where possible).

        Returns
        -------
        Fn.Function or None.

        Examples
        --------
        >>> import underworld as uw
        >>> import underworld.function as fn
        
        >>> fn_const = fn.Function.convert( 3 )
        >>> fn_const.evaluate(0.) # eval anywhere for constant
        array([[3]], dtype=int32)

        >>> fn_const == fn.Function.convert( fn_const )
        True

        >>> fn.Function.convert( None )

        >>> fn1 = fn.input()
        >>> fn2 = 10.*fn.input()
        >>> fn3 = 100.*fn.input()
        >>> vec = (fn1,fn2,fn3)
        >>> fn_vec = fn.Function.convert(vec)
        >>> fn_vec.evaluate([3.])
        array([[   3.,   30.,  300.]])

        """
        if isinstance(obj, (Function, type(None))):
            return obj
        else:
            import underworld.function.misc as misc
            try:
                # first try convert directly to const type object
                return misc.constant(obj)
            except Exception as e:
                # ok, that failed, let's now try convert to vector of function type object
                # first check that it is of type tuple or list
                if isinstance(obj, (tuple, list)):
                    # now check that it contains things that are convertible. recurse.
                    objlist = []
                    for item in obj:
                        objlist.append(Function.convert(item))
                    # create identity matrix for basis vectors
                    import numpy as np
                    basisvecs = np.identity(len(obj))
                    # convert these to uw functions
                    basisfns = []
                    for vec in basisvecs:
                        basisfns.append(Function.convert(vec))
                    # now return final object summed
                    vecfn = basisfns[0] * objlist[0]
                    for index in range(1, len(obj)):
                        vecfn = vecfn + basisfns[index] * objlist[index]
                    return vecfn

                import underworld as uw
                raise uw._prepend_message_to_exception(
                    e, "An exception was raised while try to convert an " +
                    "object to an Underworld2 function. Usually this " +
                    "occurs because you didn't pass in the correct " +
                    "object. Please check your function arguments! " +
                    "Note that only python types 'int', 'float' or " +
                    "'bool' (and iterables of these types) are convertible " +
                    "to functions.\n\n" +
                    "Original encountered exception message:\n")
Пример #7
0
    def __init__(self,
                 temperatureField,
                 fn_diffusivity,
                 fn_heating=0.,
                 voronoi_swarm=None,
                 conditions=[],
                 _removeBCs=True,
                 **kwargs):

        if not isinstance(temperatureField, uw.mesh.MeshVariable):
            raise TypeError(
                "Provided 'temperatureField' must be of 'MeshVariable' class.")
        self._temperatureField = temperatureField

        try:
            _fn_diffusivity = uw.function.Function.convert(fn_diffusivity)
        except Exception as e:
            raise uw._prepend_message_to_exception(
                e,
                "Exception encountered. Note that provided 'fn_diffusivity' must be of or convertible to 'Function' class.\nEncountered exception message:\n"
            )

        try:
            _fn_heating = uw.function.Function.convert(fn_heating)
        except Exception as e:
            raise uw._prepend_message_to_exception(
                e,
                "Exception encountered. Note that provided 'fn_heating' must be of or convertible to 'Function' class.\nEncountered exception message:\n"
            )

        if voronoi_swarm and not isinstance(voronoi_swarm, uw.swarm.Swarm):
            raise TypeError("Provided 'swarm' must be of 'Swarm' class.")
        self._swarm = voronoi_swarm
        if voronoi_swarm and temperatureField.mesh.elementType == 'Q2':
            import warnings
            warnings.warn(
                "Voronoi integration may yield unsatisfactory results for Q2 element types."
            )

        if not isinstance(_removeBCs, bool):
            raise TypeError("Provided '_removeBCs' must be of type bool.")
        self._removeBCs = _removeBCs

        # error check dcs 'dirichlet conditions' and ncs 'neumann cond.' FeMesh_IndexSets
        nbc = None
        mesh = temperatureField.mesh

        if not isinstance(conditions, (list, tuple)):
            conditionslist = []
            conditionslist.append(conditions)
            conditions = conditionslist
        for cond in conditions:
            if not isinstance(cond, uw.conditions.SystemCondition):
                raise TypeError(
                    "Provided 'conditions' must be a list 'SystemCondition' objects."
                )
            # set the bcs on here
            if type(cond) == uw.conditions.DirichletCondition:
                if cond.variable == temperatureField:
                    libUnderworld.StgFEM.FeVariable_SetBC(
                        temperatureField._cself, cond._cself)
            elif type(cond) == uw.conditions.NeumannCondition:
                nbc = cond
            else:
                raise RuntimeError("Can't decide on input condition")

        # build the equation numbering for the temperature field discretisation
        tEqNums = self._tEqNums = sle.EqNumber(temperatureField,
                                               removeBCs=self._removeBCs)

        # create solutions vector
        self._solutionVector = sle.SolutionVector(temperatureField, tEqNums)
        libUnderworld.StgFEM.SolutionVector_LoadCurrentFeVariableValuesOntoVector(
            self._solutionVector._cself)

        # create force vectors
        self._fvector = sle.AssembledVector(temperatureField, tEqNums)

        # and matrices
        self._kmatrix = sle.AssembledMatrix(self._solutionVector,
                                            self._solutionVector,
                                            rhs=self._fvector)

        # we will use voronoi if that has been requested by the user, else use
        # gauss integration.
        if self._swarm:
            intswarm = self._swarm._voronoi_swarm
            # need to ensure voronoi is populated now, as assembly terms will call
            # initial test functions which may require a valid voronoi swarm
            self._swarm._voronoi_swarm.repopulate()
        else:
            intswarm = uw.swarm.GaussIntegrationSwarm(mesh)

        self._kMatTerm = sle.MatrixAssemblyTerm_NA_i__NB_i__Fn(
            integrationSwarm=intswarm,
            assembledObject=self._kmatrix,
            fn=_fn_diffusivity)
        self._forceVecTerm = sle.VectorAssemblyTerm_NA__Fn(
            integrationSwarm=intswarm,
            assembledObject=self._fvector,
            fn=fn_heating)
        # search for neumann conditions
        for cond in conditions:
            if isinstance(cond, uw.conditions.NeumannCondition):
                #NOTE many NeumannConditions can be used but the _sufaceFluxTerm only records the last

                ### -VE flux because of the FEM discretisation method of the initial equation
                negativeCond = uw.conditions.NeumannCondition(
                    fn_flux=cond.fn_flux,
                    variable=cond.variable,
                    indexSetsPerDof=cond.indexSetsPerDof)

                self._surfaceFluxTerm = sle.VectorSurfaceAssemblyTerm_NA__Fn__ni(
                    assembledObject=self._fvector,
                    surfaceGaussPoints=2,
                    nbc=negativeCond)
        super(SteadyStateHeat, self).__init__(**kwargs)
Пример #8
0
    def __init__(self,
                 pressureField,
                 fn_diffusivity,
                 fn_bodyforce=None,
                 voronoi_swarm=None,
                 conditions=[],
                 velocityField=None,
                 swarmVarVelocity=None,
                 _removeBCs=True,
                 **kwargs):

        if not isinstance(pressureField, uw.mesh.MeshVariable):
            raise TypeError(
                "Provided 'pressureField' must be of 'MeshVariable' class.")
        self._pressureField = pressureField

        try:
            _fn_diffusivity = uw.function.Function.convert(fn_diffusivity)
        except Exception as e:
            raise uw._prepend_message_to_exception(
                e,
                "Exception encountered. Note that provided 'fn_diffusivity' must be of or convertible to 'Function' class.\nEncountered exception message:\n"
            )

        if not fn_bodyforce:
            if pressureField.mesh.dim == 2:
                fn_bodyforce = (0., 0.)
            else:
                fn_bodyforce = (0., 0., 0.)
        try:
            _fn_bodyforce = uw.function.Function.convert(fn_bodyforce)
        except Exception as e:
            raise uw._prepend_message_to_exception(
                e,
                "Exception encountered. Note that provided 'fn_bodyforce' must be of or convertible to 'Function' class.\nEncountered exception message:\n"
            )

        if voronoi_swarm and not isinstance(voronoi_swarm, uw.swarm.Swarm):
            raise TypeError("Provided 'swarm' must be of 'Swarm' class.")
        self._swarm = voronoi_swarm
        if len(numpy.unique(voronoi_swarm.owningCell.data[:])) != len(
                voronoi_swarm.owningCell.data[:]):
            import warnings
            warnings.warn(
                "It is not advised to fill any cell with more than one particle, as the Q1 shape function cannot capture material interfaces. Use at your own risk."
            )

        if velocityField and not isinstance(velocityField,
                                            uw.mesh.MeshVariable):
            raise TypeError(
                "Provided 'velocityField' must be of 'MeshVariable' class.")
        self._velocityField = velocityField

        if swarmVarVelocity and not isinstance(swarmVarVelocity,
                                               uw.swarm.SwarmVariable):
            raise TypeError(
                "Provided 'swarmVarVelocity' must be of 'SwarmVariable' class."
            )
        self._swarmVarVelocity = swarmVarVelocity

        if voronoi_swarm and pressureField.mesh.elementType == 'Q2':
            import warnings
            warnings.warn(
                "Voronoi integration may yield unsatisfactory results for Q2 element types. Q2 element types can also result in spurious velocity calculations."
            )

        if not isinstance(_removeBCs, bool):
            raise TypeError("Provided '_removeBCs' must be of type bool.")
        self._removeBCs = _removeBCs

        # error check dcs 'dirichlet conditions' and ncs 'neumann cond.' FeMesh_IndexSets
        nbc = None
        mesh = pressureField.mesh

        if not isinstance(conditions, (list, tuple)):
            conditionslist = []
            conditionslist.append(conditions)
            conditions = conditionslist
        for cond in conditions:
            if not isinstance(cond, uw.conditions.SystemCondition):
                raise TypeError(
                    "Provided 'conditions' must be a list 'SystemCondition' objects."
                )
            # set the bcs on here
            if type(cond) == uw.conditions.DirichletCondition:
                if cond.variable == pressureField:
                    libUnderworld.StgFEM.FeVariable_SetBC(
                        pressureField._cself, cond._cself)
            elif type(cond) == uw.conditions.NeumannCondition:
                nbc = cond
            else:
                raise RuntimeError("Can't decide on input condition")

        # build the equation numbering for the temperature field discretisation
        tEqNums = self._tEqNums = sle.EqNumber(pressureField,
                                               removeBCs=self._removeBCs)

        # create solutions vector
        self._solutionVector = sle.SolutionVector(pressureField, tEqNums)
        libUnderworld.StgFEM.SolutionVector_LoadCurrentFeVariableValuesOntoVector(
            self._solutionVector._cself)

        # create force vectors
        self._fvector = sle.AssembledVector(pressureField, tEqNums)

        # and matrices
        self._kmatrix = sle.AssembledMatrix(self._solutionVector,
                                            self._solutionVector,
                                            rhs=self._fvector)

        # we will use voronoi if that has been requested by the user, else use
        # gauss integration.
        if self._swarm:
            intswarm = self._swarm._voronoi_swarm
            # need to ensure voronoi is populated now, as assembly terms will call
            # initial test functions which may require a valid voronoi swarm
            self._swarm._voronoi_swarm.repopulate()
        else:
            intswarm = uw.swarm.GaussIntegrationSwarm(mesh)

        self._kMatTerm = sle.MatrixAssemblyTerm_NA_i__NB_i__Fn(
            integrationSwarm=intswarm,
            assembledObject=self._kmatrix,
            fn=_fn_diffusivity)

        self._forceVecTerm = sle.VectorAssemblyTerm_NA_i__Fn_i(
            integrationSwarm=intswarm,
            assembledObject=self._fvector,
            fn=fn_bodyforce * fn_diffusivity)

        # search for neumann conditions
        for cond in conditions:
            if isinstance(cond, uw.conditions.NeumannCondition):
                #NOTE many NeumannConditions can be used but the _sufaceFluxTerm only records the last

                ### -VE flux because of Energy_SLE_Solver ###
                negativeCond = uw.conditions.NeumannCondition(
                    fn_flux=-1.0 * cond.fn_flux,
                    variable=cond.variable,
                    indexSetsPerDof=cond.indexSet)

                self._surfaceFluxTerm = sle.VectorSurfaceAssemblyTerm_NA__Fn__ni(
                    assembledObject=self._fvector,
                    surfaceGaussPoints=2,
                    nbc=negativeCond)
        super(SteadyStateDarcyFlow, self).__init__(**kwargs)
Пример #9
0
    def deform_mesh(self, remainsRegular=False):
        """
        Any mesh deformation must occur within this python context manager. Note
        that certain algorithms may be switched to their irregular mesh equivalents
        (if not already set this way). This may have performance implications.

        Any submesh will also be appropriately updated on return from the context
        manager, as will various mesh metrics.

        Parameters
        ----------
        remainsRegular : bool, default=False
            The general assumption is that the deformed mesh will no longer be regular
            (orthonormal), and more general but less efficient algorithms will be
            selected via this context manager. To over-ride this behaviour, set
            this parameter to True.


        Example
        -------
        >>> import underworld as uw
        >>> someMesh = uw.mesh.FeMesh_Cartesian()
        >>> with someMesh.deform_mesh():
        ...     someMesh.data[0] = [0.1,0.1]
        >>> someMesh.data[0]
        array([ 0.1,  0.1])


        """
        # set the general mesh algorithm now
        if not remainsRegular:
            #            if uw.rank() == 0: print("Switching to irregular mesh algorithms.")
            uw.libUnderworld.StgDomain.Mesh_SetAlgorithms(self._cself, None)
            self._cself.isRegular = False

        # execute any pre deform functions
        for function in self._pre_deform_functions:
            function()

        self.data.flags.writeable = True
        try:
            yield
        except Exception as e:
            raise uw._prepend_message_to_exception(
                e, "An exception was raised during mesh deformation. " +
                "Your mesh may only be partially deformed. " +
                "You can reset your mesh using the 'reset' method. " +
                "Note that any submesh should not be modified directly, " +
                "but will instead be updated automatically on return from " +
                "the 'deform_mesh' context manager. \nEncountered exception message:\n"
            )
        finally:
            self.data.flags.writeable = False
            # call deformupdate, which updates various mesh metrics
            #            if uw.rank() == 0: print("Updating mesh metrics.")
            uw.libUnderworld.StgDomain.Mesh_DeformationUpdate(self._cself)
            if hasattr(self, "subMesh") and self.subMesh:
                # remesh the submesh based on the new primary
                #                if uw.rank() == 0: print("Updating submesh for primary mesh changes.")
                self.subMesh.reset()

            # execute any post deform functions
            for function in self._post_deform_functions:
                function()
Пример #10
0
    def __init__(self, temperatureField, fn_diffusivity, fn_heating=0., voronoi_swarm=None, conditions=[], _removeBCs=True, **kwargs):

        if not isinstance( temperatureField, uw.mesh.MeshVariable):
            raise TypeError( "Provided 'temperatureField' must be of 'MeshVariable' class." )
        self._temperatureField = temperatureField

        try:
            _fn_diffusivity = uw.function.Function.convert(fn_diffusivity)
        except Exception as e:
            raise uw._prepend_message_to_exception(e, "Exception encountered. Note that provided 'fn_diffusivity' must be of or convertible to 'Function' class.\nEncountered exception message:\n")

        try:
            _fn_heating = uw.function.Function.convert(fn_heating)
        except Exception as e:
            raise uw._prepend_message_to_exception(e, "Exception encountered. Note that provided 'fn_heating' must be of or convertible to 'Function' class.\nEncountered exception message:\n")

        if voronoi_swarm and not isinstance(voronoi_swarm, uw.swarm.Swarm):
            raise TypeError( "Provided 'swarm' must be of 'Swarm' class." )
        self._swarm = voronoi_swarm
        if voronoi_swarm and temperatureField.mesh.elementType=='Q2':
            import warnings
            warnings.warn("Voronoi integration may yield unsatisfactory results for Q2 element types.")

        if not isinstance( _removeBCs, bool):
            raise TypeError( "Provided '_removeBCs' must be of type bool." )
        self._removeBCs = _removeBCs

        # error check dcs 'dirichlet conditions' and ncs 'neumann cond.' FeMesh_IndexSets
        nbc  = None
        mesh = temperatureField.mesh

        if not isinstance(conditions,(list,tuple)):
            conditionslist = []
            conditionslist.append(conditions)
            conditions = conditionslist
        for cond in conditions:
            if not isinstance( cond, uw.conditions.SystemCondition ):
                raise TypeError( "Provided 'conditions' must be a list 'SystemCondition' objects." )
            # set the bcs on here
            if type( cond ) == uw.conditions.DirichletCondition:
                if cond.variable == temperatureField:
                    libUnderworld.StgFEM.FeVariable_SetBC( temperatureField._cself, cond._cself )
            elif type( cond ) == uw.conditions.NeumannCondition:
                nbc=cond
            else:
                raise RuntimeError("Can't decide on input condition")

        # build the equation numbering for the temperature field discretisation
        tEqNums = self._tEqNums = sle.EqNumber( temperatureField, removeBCs=self._removeBCs )

        # create solutions vector
        self._solutionVector = sle.SolutionVector(temperatureField, tEqNums )
        libUnderworld.StgFEM.SolutionVector_LoadCurrentFeVariableValuesOntoVector( self._solutionVector._cself )

        # create force vectors
        self._fvector = sle.AssembledVector(temperatureField, tEqNums )

        # and matrices
        self._kmatrix = sle.AssembledMatrix( self._solutionVector, self._solutionVector, rhs=self._fvector )

        # we will use voronoi if that has been requested by the user, else use
        # gauss integration.
        if self._swarm:
            intswarm = self._swarm._voronoi_swarm
            # need to ensure voronoi is populated now, as assembly terms will call
            # initial test functions which may require a valid voronoi swarm
            self._swarm._voronoi_swarm.repopulate()
        else:
            intswarm = uw.swarm.GaussIntegrationSwarm(mesh)


        self._kMatTerm = sle.MatrixAssemblyTerm_NA_i__NB_i__Fn(  integrationSwarm=intswarm,
                                                                 assembledObject=self._kmatrix,
                                                                 fn=_fn_diffusivity)
        self._forceVecTerm = sle.VectorAssemblyTerm_NA__Fn(   integrationSwarm=intswarm,
                                                              assembledObject=self._fvector,
                                                              fn=fn_heating)
        # search for neumann conditions
        for cond in conditions:
            if isinstance( cond, uw.conditions.NeumannCondition ):
                #NOTE many NeumannConditions can be used but the _sufaceFluxTerm only records the last

                ### -VE flux because of the FEM discretisation method of the initial equation
                negativeCond = uw.conditions.NeumannCondition( fn_flux=-1.0*cond.fn_flux,
                                                               variable=cond.variable,
                                                               indexSetsPerDof=cond.indexSetsPerDof )

                self._surfaceFluxTerm = sle.VectorSurfaceAssemblyTerm_NA__Fn__ni(
                                                                assembledObject  = self._fvector,
                                                                surfaceGaussPoints = 2,
                                                                nbc         = negativeCond )
        super(SteadyStateHeat, self).__init__(**kwargs)
Пример #11
0
    def __init__(self, temperatureField, fn_diffusivity=None, fn_heating=0., swarm=None, conditions=[], conductivityFn=None, heatingFn=None, rtolerance=None, **kwargs):
        if conductivityFn:
            raise RuntimeError("Note that the 'conductivityFn' parameter has been renamed to 'fn_diffusivity'.")
        if heatingFn:
            raise RuntimeError("Note that the 'heatingFn' parameter has been renamed to 'fn_heating'.")
        if rtolerance:
            raise RuntimeError("Note that the 'rtolerance' parameter has been removed.\n" \
                               "All solver functionality has been moved to underworld.systems.Solver.")

        if not isinstance( temperatureField, uw.mesh.MeshVariable):
            raise TypeError( "Provided 'temperatureField' must be of 'MeshVariable' class." )
        self._temperatureField = temperatureField

        if not fn_diffusivity:
            raise ValueError("You must specify a diffusivity function via the 'fn_diffusivity' parameter.")
        try:
            _fn_diffusivity = uw.function.Function._CheckIsFnOrConvertOrThrow(fn_diffusivity)
        except Exception as e:
            raise uw._prepend_message_to_exception(e, "Exception encountered. Note that provided 'fn_diffusivity' must be of or convertible to 'Function' class.\nEncountered exception message:\n")

        try:
            _fn_heating = uw.function.Function._CheckIsFnOrConvertOrThrow(fn_heating)
        except Exception as e:
            raise uw._prepend_message_to_exception(e, "Exception encountered. Note that provided 'fn_heating' must be of or convertible to 'Function' class.\nEncountered exception message:\n")

        if swarm and not isinstance(swarm, uw.swarm.Swarm):
            raise TypeError( "Provided 'swarm' must be of 'Swarm' class." )
        self._swarm = swarm

        if not isinstance(conditions, (uw.conditions._SystemCondition, list, tuple) ):
            raise TypeError( "Provided 'conditions' must be a list '_SystemCondition' objects." )
        if len(conditions) > 1:
            raise ValueError( "Multiple conditions are not currently supported." )
        for cond in conditions:
            if not isinstance( cond, uw.conditions._SystemCondition ):
                raise TypeError( "Provided 'conditions' must be a list '_SystemCondition' objects." )
            # set the bcs on here.. will rearrange this in future. 
            if cond.variable == self._temperatureField:
                libUnderworld.StgFEM.FeVariable_SetBC( self._temperatureField._cself, cond._cself )

        # ok, we've set some bcs, lets recreate eqnumbering
        libUnderworld.StgFEM._FeVariable_CreateNewEqnNumber( self._temperatureField._cself )
        self._conditions = conditions

        # create solutions vector
        self._temperatureSol = sle.SolutionVector(temperatureField)

        # create force vectors
        self._fvector = sle.AssembledVector(temperatureField)

        # and matrices
        self._kmatrix = sle.AssembledMatrix( temperatureField, temperatureField, rhs=self._fvector )

        # create swarm
        self._gaussSwarm = uw.swarm.GaussIntegrationSwarm(self._temperatureField.mesh)
        self._PICSwarm = None
        if self._swarm:
            self._PICSwarm = uw.swarm.PICIntegrationSwarm(self._swarm)

        swarmguy = self._PICSwarm
        if not swarmguy:
            swarmguy = self._gaussSwarm
        self._kMatTerm = sle.MatrixAssemblyTerm_NA_i__NB_i__Fn(  integrationSwarm=swarmguy,
                                                                 assembledObject=self._kmatrix,
                                                                 fn=_fn_diffusivity)
        self._forceVecTerm = sle.VectorAssemblyTerm_NA__Fn(   integrationSwarm=swarmguy,
                                                              assembledObject=self._fvector,
                                                              fn=fn_heating)
        super(SteadyStateHeat, self).__init__(**kwargs)
Пример #12
0
    def __init__(self,
                 temperatureField,
                 fn_diffusivity=None,
                 fn_heating=0.,
                 swarm=None,
                 conditions=[],
                 conductivityFn=None,
                 heatingFn=None,
                 rtolerance=None,
                 **kwargs):
        if conductivityFn:
            raise RuntimeError(
                "Note that the 'conductivityFn' parameter has been renamed to 'fn_diffusivity'."
            )
        if heatingFn:
            raise RuntimeError(
                "Note that the 'heatingFn' parameter has been renamed to 'fn_heating'."
            )
        if rtolerance:
            raise RuntimeError("Note that the 'rtolerance' parameter has been removed.\n" \
                               "All solver functionality has been moved to underworld.systems.Solver.")

        if not isinstance(temperatureField, uw.mesh.MeshVariable):
            raise TypeError(
                "Provided 'temperatureField' must be of 'MeshVariable' class.")
        self._temperatureField = temperatureField

        if not fn_diffusivity:
            raise ValueError(
                "You must specify a diffusivity function via the 'fn_diffusivity' parameter."
            )
        try:
            _fn_diffusivity = uw.function.Function._CheckIsFnOrConvertOrThrow(
                fn_diffusivity)
        except Exception as e:
            raise uw._prepend_message_to_exception(
                e,
                "Exception encountered. Note that provided 'fn_diffusivity' must be of or convertible to 'Function' class.\nEncountered exception message:\n"
            )

        try:
            _fn_heating = uw.function.Function._CheckIsFnOrConvertOrThrow(
                fn_heating)
        except Exception as e:
            raise uw._prepend_message_to_exception(
                e,
                "Exception encountered. Note that provided 'fn_heating' must be of or convertible to 'Function' class.\nEncountered exception message:\n"
            )

        if swarm and not isinstance(swarm, uw.swarm.Swarm):
            raise TypeError("Provided 'swarm' must be of 'Swarm' class.")
        self._swarm = swarm

        if not isinstance(conditions,
                          (uw.conditions._SystemCondition, list, tuple)):
            raise TypeError(
                "Provided 'conditions' must be a list '_SystemCondition' objects."
            )
        if len(conditions) > 1:
            raise ValueError(
                "Multiple conditions are not currently supported.")
        for cond in conditions:
            if not isinstance(cond, uw.conditions._SystemCondition):
                raise TypeError(
                    "Provided 'conditions' must be a list '_SystemCondition' objects."
                )
            # set the bcs on here.. will rearrange this in future.
            if cond.variable == self._temperatureField:
                libUnderworld.StgFEM.FeVariable_SetBC(
                    self._temperatureField._cself, cond._cself)

        # ok, we've set some bcs, lets recreate eqnumbering
        libUnderworld.StgFEM._FeVariable_CreateNewEqnNumber(
            self._temperatureField._cself)
        self._conditions = conditions

        # create solutions vector
        self._temperatureSol = sle.SolutionVector(temperatureField)

        # create force vectors
        self._fvector = sle.AssembledVector(temperatureField)

        # and matrices
        self._kmatrix = sle.AssembledMatrix(temperatureField,
                                            temperatureField,
                                            rhs=self._fvector)

        # create swarm
        self._gaussSwarm = uw.swarm.GaussIntegrationSwarm(
            self._temperatureField.mesh)
        self._PICSwarm = None
        if self._swarm:
            self._PICSwarm = uw.swarm.PICIntegrationSwarm(self._swarm)

        swarmguy = self._PICSwarm
        if not swarmguy:
            swarmguy = self._gaussSwarm
        self._kMatTerm = sle.MatrixAssemblyTerm_NA_i__NB_i__Fn(
            integrationSwarm=swarmguy,
            assembledObject=self._kmatrix,
            fn=_fn_diffusivity)
        self._forceVecTerm = sle.VectorAssemblyTerm_NA__Fn(
            integrationSwarm=swarmguy,
            assembledObject=self._fvector,
            fn=fn_heating)
        super(SteadyStateHeat, self).__init__(**kwargs)
Пример #13
0
    def convert(obj):
        """
        This method will simply check if the provided object is of Function type
        or None type. If it is, it is simply returned. Otherwise, conversion
        to a function is attempted. 
        
        Parameters
        ----------
        obj: fn_like
            The object to be converted. Note that if obj is of type None or
            Function, it is simply returned immediately.
            Where obj is of type int/float/double, a Constant type function 
            is returned which evaluates to the provided object's value.
            Where obj is of type list/tuple, a function will be returned
            which evaluates to a vector of the provided list/tuple's values 
            (where possible).

        Returns
        -------
        Fn.Function or None.

        Examples
        --------
        >>> import underworld as uw
        >>> import underworld.function as fn
        
        >>> fn_const = fn.Function.convert( 3 )
        >>> fn_const.evaluate(0.) # eval anywhere for constant
        array([[3]], dtype=int32)

        >>> fn_const == fn.Function.convert( fn_const )
        True

        >>> fn.Function.convert( None )

        >>> fn1 = fn.input()
        >>> fn2 = 10.*fn.input()
        >>> fn3 = 100.*fn.input()
        >>> vec = (fn1,fn2,fn3)
        >>> fn_vec = fn.Function.convert(vec)
        >>> fn_vec.evaluate([3.])
        array([[   3.,   30.,  300.]])

        """
        if isinstance(obj, (Function, type(None)) ):
            return obj
        else:
            import misc
            try:
                # first try convert directly to const type object
                return misc.constant(obj)
            except Exception as e:
                # ok, that failed, let's now try convert to vector of function type object
                # first check that it is of type tuple or list
                if isinstance(obj, (tuple,list)):
                    # now check that it contains things that are convertible. recurse.
                    objlist = []
                    for item in obj:
                        objlist.append( Function.convert(item) )
                    # create identity matrix for basis vectors
                    import numpy as np
                    basisvecs = np.identity(len(obj))
                    # convert these to uw functions
                    basisfns = []
                    for vec in basisvecs:
                        basisfns.append( Function.convert(vec) )
                    # now return final object summed
                    vecfn = basisfns[0]*objlist[0]
                    for index in range(1,len(obj)):
                        vecfn = vecfn + basisfns[index]*objlist[index]
                    return vecfn
                
                import underworld as uw
                raise uw._prepend_message_to_exception(e, "An exception was raised while try to convert an "
                                                         +"object to an Underworld2 function. Usually this "
                                                         +"occurs because you didn't pass in the correct "
                                                         +"object. Please check your function arguments! "
                                                         +"Note that only python types 'int', 'float' or "
                                                         +"'bool' (and iterables of these types) are convertible "
                                                         +"to functions.\n\n"
                                                         +"Original encountered exception message:\n")
    def __init__(self, meshVariable=None, fn=None, voronoi_swarm=None, type=0, **kwargs):

        if not meshVariable:
            raise ValueError("You must specify a mesh variable via the 'meshVariable' parameter.")
        if not isinstance( meshVariable, uw.mesh.MeshVariable):
            raise TypeError( "Provided 'meshVariable' must be of 'MeshVariable' class." )
        self._meshVariable = meshVariable

        if not fn:
            raise ValueError("You must specify a function via the 'fn' parameter.")
        try:
            _fn = uw.function.Function.convert(fn)
        except Exception as e:
            raise uw._prepend_message_to_exception(e, "Exception encountered. Note that provided 'fn' must be of or convertible to 'Function' class.\nEncountered exception message:\n")

        if voronoi_swarm and not isinstance(voronoi_swarm, uw.swarm.Swarm):
            raise TypeError( "Provided 'swarm' must be of 'Swarm' class." )
        self._swarm = voronoi_swarm
        if voronoi_swarm and meshVariable.mesh.elementType=='Q2':
            import warnings
            warnings.warn("Voronoi integration may yield unsatisfactory results for Q2 mesh.")
            


        if not type in [0,1]:
            raise ValueError( "Provided 'type' must take a value of 0 (weighted average) or 1 (weighted residual)." )
        self.type = type

        eqNum = sle.EqNumber(meshVariable)
        # create force vectors
        self._fvector = sle.AssembledVector(meshVariable, eqNum)

        # determine the required geometry mesh.  for submesh, use the parent mesh.
        geometryMesh = self._meshVariable.mesh
        if hasattr(self._meshVariable.mesh.generator, 'geometryMesh'):
            geometryMesh = self._meshVariable.mesh.generator.geometryMesh

        # we will use voronoi if that has been requested by the user, else use
        # gauss integration.
        if self._swarm:
            intswarm = self._swarm._voronoi_swarm
            # need to ensure voronoi is populated now, as assembly terms will call
            # initial test functions which may require a valid voronoi swarm
            self._swarm._voronoi_swarm.repopulate()
        else:
            intswarm = uw.swarm.GaussIntegrationSwarm(geometryMesh)

        self._fn = _fn

        self._forceVecTerm = sle.VectorAssemblyTerm_NA__Fn(   integrationSwarm=intswarm,
                                                              assembledObject=self._fvector,
                                                              fn=_fn,
                                                              mesh=geometryMesh )

        if self.type == 0:
            # create copy guy
            self._copyMeshVariable = meshVariable.copy()
            # create unity array of required dimensionality
            self._unityArray = []
            for ii in range(self._meshVariable.nodeDofCount):
                self._unityArray.append(1.)
            self.solve = self._solve_average
        else:
            # create solutions vector
            self._solutionVector = sle.SolutionVector(meshVariable, eqNum)
            # and matrices
            self._kmatrix = sle.AssembledMatrix( self._solutionVector, self._solutionVector, rhs=self._fvector )
            # matrix term
            self._kMatTerm = sle.MatrixAssemblyTerm_NA__NB__Fn(  integrationSwarm=intswarm,
                                                                 assembledObject=self._kmatrix,
                                                                 fn = 1.0,
                                                                 mesh=geometryMesh )
            self._solver = None
            self.solve = self._solve_residual

        super(MeshVariable_Projection, self).__init__(**kwargs)
Пример #15
0
    def __init__(self, pressureField, fn_diffusivity, fn_bodyforce=None, voronoi_swarm=None, conditions=[], velocityField=None, swarmVarVelocity=None, _removeBCs=True, **kwargs):

        if not isinstance( pressureField, uw.mesh.MeshVariable):
            raise TypeError( "Provided 'pressureField' must be of 'MeshVariable' class." )
        self._pressureField = pressureField

        try:
            _fn_diffusivity = uw.function.Function.convert(fn_diffusivity)
        except Exception as e:
            raise uw._prepend_message_to_exception(e, "Exception encountered. Note that provided 'fn_diffusivity' must be of or convertible to 'Function' class.\nEncountered exception message:\n")

        if not fn_bodyforce:
            if pressureField.mesh.dim == 2:
                fn_bodyforce = (0.,0.)
            else:
                fn_bodyforce = (0.,0.,0.)
        try:
            _fn_bodyforce = uw.function.Function.convert(fn_bodyforce)
        except Exception as e:
            raise uw._prepend_message_to_exception(e, "Exception encountered. Note that provided 'fn_bodyforce' must be of or convertible to 'Function' class.\nEncountered exception message:\n")

        if voronoi_swarm and not isinstance(voronoi_swarm, uw.swarm.Swarm):
            raise TypeError( "Provided 'swarm' must be of 'Swarm' class." )
        self._swarm = voronoi_swarm
        if len(numpy.unique(voronoi_swarm.owningCell.data[:])) != len(voronoi_swarm.owningCell.data[:]):
            import warnings
            warnings.warn("It is not advised to fill any cell with more than one particle, as the Q1 shape function cannot capture material interfaces. Use at your own risk.")

        if velocityField and not isinstance( velocityField, uw.mesh.MeshVariable):
            raise TypeError( "Provided 'velocityField' must be of 'MeshVariable' class." )
        self._velocityField = velocityField

        if swarmVarVelocity and not isinstance(swarmVarVelocity, uw.swarm.SwarmVariable):
            raise TypeError("Provided 'swarmVarVelocity' must be of 'SwarmVariable' class.")
        self._swarmVarVelocity = swarmVarVelocity

        if voronoi_swarm and pressureField.mesh.elementType=='Q2':
            import warnings
            warnings.warn("Voronoi integration may yield unsatisfactory results for Q2 element types. Q2 element types can also result in spurious velocity calculations.")

        if not isinstance( _removeBCs, bool):
            raise TypeError( "Provided '_removeBCs' must be of type bool." )
        self._removeBCs = _removeBCs

        # error check dcs 'dirichlet conditions' and ncs 'neumann cond.' FeMesh_IndexSets
        nbc  = None
        mesh = pressureField.mesh

        if not isinstance(conditions,(list,tuple)):
            conditionslist = []
            conditionslist.append(conditions)
            conditions = conditionslist
        for cond in conditions:
            if not isinstance( cond, uw.conditions.SystemCondition ):
                raise TypeError( "Provided 'conditions' must be a list 'SystemCondition' objects." )
            # set the bcs on here
            if type( cond ) == uw.conditions.DirichletCondition:
                if cond.variable == pressureField:
                    libUnderworld.StgFEM.FeVariable_SetBC( pressureField._cself, cond._cself )
            elif type( cond ) == uw.conditions.NeumannCondition:
                nbc=cond
            else:
                raise RuntimeError("Can't decide on input condition")

        # build the equation numbering for the temperature field discretisation
        tEqNums = self._tEqNums = sle.EqNumber( pressureField, removeBCs=self._removeBCs )

        # create solutions vector
        self._solutionVector = sle.SolutionVector(pressureField, tEqNums )
        libUnderworld.StgFEM.SolutionVector_LoadCurrentFeVariableValuesOntoVector( self._solutionVector._cself )

        # create force vectors
        self._fvector = sle.AssembledVector(pressureField, tEqNums )

        # and matrices
        self._kmatrix = sle.AssembledMatrix( self._solutionVector, self._solutionVector, rhs=self._fvector )


        # we will use voronoi if that has been requested by the user, else use
        # gauss integration.
        if self._swarm:
            intswarm = self._swarm._voronoi_swarm
            # need to ensure voronoi is populated now, as assembly terms will call
            # initial test functions which may require a valid voronoi swarm
            self._swarm._voronoi_swarm.repopulate()
        else:
            intswarm = uw.swarm.GaussIntegrationSwarm(mesh)


        self._kMatTerm = sle.MatrixAssemblyTerm_NA_i__NB_i__Fn(  integrationSwarm=intswarm,
                                                                 assembledObject=self._kmatrix,
                                                                 fn=_fn_diffusivity)

        self._forceVecTerm = sle.VectorAssemblyTerm_NA_i__Fn_i(   integrationSwarm=intswarm,
                                                              assembledObject=self._fvector,
                                                              fn=fn_bodyforce*fn_diffusivity)

        # search for neumann conditions
        for cond in conditions:
            if isinstance( cond, uw.conditions.NeumannCondition ):
                #NOTE many NeumannConditions can be used but the _sufaceFluxTerm only records the last

                ### -VE flux because of Energy_SLE_Solver ###
                negativeCond = uw.conditions.NeumannCondition( fn_flux=-1.0*cond.fn_flux,
                                                               variable=cond.variable,
                                                               indexSetsPerDof=cond.indexSet )

                self._surfaceFluxTerm = sle.VectorSurfaceAssemblyTerm_NA__Fn__ni(
                                                                assembledObject  = self._fvector,
                                                                surfaceGaussPoints = 2,
                                                                nbc         = negativeCond )
        super(SteadyStateDarcyFlow, self).__init__(**kwargs)
    def __init__(self,
                 meshVariable=None,
                 fn=None,
                 voronoi_swarm=None,
                 type=0,
                 gauss_swarm=None,
                 **kwargs):

        if not meshVariable:
            raise ValueError(
                "You must specify a mesh variable via the 'meshVariable' parameter."
            )
        if not isinstance(meshVariable, uw.mesh.MeshVariable):
            raise TypeError(
                "Provided 'meshVariable' must be of 'MeshVariable' class.")
        self._meshVariable = meshVariable

        if not fn:
            raise ValueError(
                "You must specify a function via the 'fn' parameter.")
        try:
            _fn = uw.function.Function.convert(fn)
        except Exception as e:
            raise uw._prepend_message_to_exception(
                e,
                "Exception encountered. Note that provided 'fn' must be of or convertible to 'Function' class.\nEncountered exception message:\n"
            )

        if voronoi_swarm and not isinstance(voronoi_swarm, uw.swarm.Swarm):
            raise TypeError("Provided 'swarm' must be of 'Swarm' class.")
        self._swarm = voronoi_swarm
        if voronoi_swarm and meshVariable.mesh.elementType == 'Q2':
            import warnings
            warnings.warn(
                "Voronoi integration may yield unsatisfactory results for Q2 mesh."
            )

        if not type in [0, 1]:
            raise ValueError(
                "Provided 'type' must take a value of 0 (weighted average) or 1 (weighted residual)."
            )
        self.type = type

        eqNum = sle.EqNumber(meshVariable)
        # create force vectors
        self._fvector = sle.AssembledVector(meshVariable, eqNum)

        # determine the required geometry mesh.  for submesh, use the parent mesh.
        geometryMesh = self._meshVariable.mesh
        if hasattr(self._meshVariable.mesh.generator, 'geometryMesh'):
            geometryMesh = self._meshVariable.mesh.generator.geometryMesh

        # setup the gauss integration swarm
        if gauss_swarm != None:
            if not isinstance(gauss_swarm, uw.swarm.GaussIntegrationSwarm):
                raise RuntimeError(
                    "Provided 'gauss_swarm' must be a GaussIntegrationSwarm object"
                )
            intswarm = gauss_swarm
        else:
            intswarm = uw.swarm.GaussIntegrationSwarm(geometryMesh)

        # we will use voronoi if that has been requested by the user, else use
        # gauss integration.
        if self._swarm:
            intswarm = self._swarm._voronoi_swarm
            # need to ensure voronoi is populated now, as assembly terms will call
            # initial test functions which may require a valid voronoi swarm
            self._swarm._voronoi_swarm.repopulate()

        self._fn = _fn

        self._forceVecTerm = sle.VectorAssemblyTerm_NA__Fn(
            integrationSwarm=intswarm,
            assembledObject=self._fvector,
            fn=_fn,
            mesh=geometryMesh)

        if self.type == 0:
            # create copy guy
            self._copyMeshVariable = meshVariable.copy()
            # create unity array of required dimensionality
            self._unityArray = []
            for ii in range(self._meshVariable.nodeDofCount):
                self._unityArray.append(1.)
            self.solve = self._solve_average
        else:
            # create solutions vector
            self._solutionVector = sle.SolutionVector(meshVariable, eqNum)
            # and matrices
            self._kmatrix = sle.AssembledMatrix(self._solutionVector,
                                                self._solutionVector,
                                                rhs=self._fvector)
            # matrix term
            self._kMatTerm = sle.MatrixAssemblyTerm_NA__NB__Fn(
                integrationSwarm=intswarm,
                assembledObject=self._kmatrix,
                fn=1.0,
                mesh=geometryMesh)
            self._solver = None
            self.solve = self._solve_residual

        super(MeshVariable_Projection, self).__init__(**kwargs)
Пример #17
0
    def deform_mesh(self, remainsRegular=False):
        """
        Any mesh deformation must occur within this python context manager. Note
        that certain algorithms may be switched to their irregular mesh equivalents
        (if not already set this way). This may have performance implications.

        Any submesh will also be appropriately updated on return from the context
        manager, as will various mesh metrics.

        Parameters
        ----------
        remainsRegular : bool, default=False
            The general assumption is that the deformed mesh will no longer be regular
            (orthonormal), and more general but less efficient algorithms will be
            selected via this context manager. To over-ride this behaviour, set
            this parameter to True.


        Example
        -------
        >>> import underworld as uw
        >>> someMesh = uw.mesh.FeMesh_Cartesian()
        >>> with someMesh.deform_mesh():
        ...     someMesh.data[0] = [0.1,0.1]
        >>> someMesh.data[0]
        array([ 0.1,  0.1])


        """
        # set the general mesh algorithm now
        if not remainsRegular:
#            if uw.rank() == 0: print("Switching to irregular mesh algorithms.")
            uw.libUnderworld.StgDomain.Mesh_SetAlgorithms( self._cself, None )
            self._cself.isRegular = False

        # execute any pre deform functions
        for function in self._pre_deform_functions:
            function()

        self.data.flags.writeable = True
        try:
            yield
        except Exception as e:
            raise uw._prepend_message_to_exception(e, "An exception was raised during mesh deformation. "
                                                     +"Your mesh may only be partially deformed. "
                                                     +"You can reset your mesh using the 'reset' method. "
                                                     +"Note that any submesh should not be modified directly, "
                                                     +"but will instead be updated automatically on return from "
                                                     +"the 'deform_mesh' context manager. \nEncountered exception message:\n")
        finally:
            self.data.flags.writeable = False
            # call deformupdate, which updates various mesh metrics
#            if uw.rank() == 0: print("Updating mesh metrics.")
            uw.libUnderworld.StgDomain.Mesh_DeformationUpdate( self._cself )
            if hasattr(self,"subMesh") and self.subMesh:
                # remesh the submesh based on the new primary
#                if uw.rank() == 0: print("Updating submesh for primary mesh changes.")
                self.subMesh.reset()

            # execute any post deform functions
            for function in self._post_deform_functions:
                function()