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()
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()
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()
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()
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()
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")
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)
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 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()
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)
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)
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)
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)
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)
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()