##~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~##
## ##
## This file forms part of the Underworld geophysics modelling application. ##
## ##
## For full license and copyright information, please refer to the LICENSE.md file ##
## located at the project root, or contact the authors. ##
## ##
##~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~##
import underworld as uw
import underworld._stgermain as _stgermain
import underworld.mesh as mesh
import underworld.libUnderworld.libUnderworldPy.Function as _cfn
from . import _assembledvector
from . import _assembledmatrix
import underworld.libUnderworld as libUnderworld
[docs]class AssemblyTerm(_stgermain.StgCompoundComponent):
_objectsDict = { "_assemblyterm": None }
_selfObjectName = "_assemblyterm"
def __init__(self, integrationSwarm, extraInfo=None, **kwargs):
super(AssemblyTerm,self).__init__(**kwargs)
if not isinstance(integrationSwarm, uw.swarm.IntegrationSwarm):
raise TypeError("'integrationSwarm' object passed in must be of type 'IntegrationSwarm'")
self._integrationSwarm = integrationSwarm
self._extraInfo = extraInfo
self._fn = None
self._set_fn_function = None
def _add_to_stg_dict(self,componentDictionary):
# call parents method
super(AssemblyTerm,self)._add_to_stg_dict(componentDictionary)
componentDictionary[ self._cself.name ][ "Swarm"] = self._integrationSwarm._cself.name
componentDictionary[ self._cself.name ]["ExtraInfo"] = self._extraInfo
@property
def fn(self):
return self._fn
@fn.setter
def fn(self, value):
if not self._set_fn_function:
raise RuntimeError("You cannot set a function for this assembly term.")
_fn = uw.function._function.Function.convert(value)
if not isinstance( _fn, uw.function.Function):
raise ValueError( "Provided 'fn' must be of, or convertible to, 'Function' class." )
self._fn = _fn
self._set_fn_function( self._cself, self._fn._fncself )
def _setup(self):
# lets setup fn tings.. note that this uses the 'property' above
if self._set_fn_function:
self.fn = self._fn
[docs]class VectorAssemblyTerm(AssemblyTerm):
def __init__(self, assembledObject, **kwargs):
super(VectorAssemblyTerm,self).__init__(**kwargs)
if not isinstance( assembledObject, _assembledvector.AssembledVector):
raise TypeError("'assembledObject' passed in must be of type 'AssembledVector'")
self._assembledObject = assembledObject
def _add_to_stg_dict(self,componentDictionary):
# call parents method
super(VectorAssemblyTerm,self)._add_to_stg_dict(componentDictionary)
componentDictionary[ self._cself.name ]["ForceVector"] = self._assembledObject._cself.name
[docs]class MatrixAssemblyTerm(AssemblyTerm):
def __init__(self, assembledObject=None, **kwargs):
super(MatrixAssemblyTerm,self).__init__(**kwargs)
if not isinstance( assembledObject, (_assembledmatrix.AssembledMatrix, type(None))):
raise TypeError("'assembledObject' passed in must be of type 'AssembledMatrix'")
self._assembledObject = assembledObject
def _add_to_stg_dict(self,componentDictionary):
# call parents method
super(MatrixAssemblyTerm,self)._add_to_stg_dict(componentDictionary)
if self._assembledObject:
componentDictionary[ self._cself.name ]["StiffnessMatrix"] = self._assembledObject._cself.name
[docs]class VectorSurfaceAssemblyTerm_NA__Fn__ni(VectorAssemblyTerm):
"""
Build an assembly term for a surface integral.
Parameters
----------
nbc : underworld.conditions.NeumannCondition
See uw.conditions.NeumannCondition for details
integrationSwarm : underworld.swarm.GaussBorderIntegrationSwarm
Optional integration swarm to be used for numerical integration.
surfaceGaussPoints : int
The number of quadrature points per element face to use in surface
integration. Will be used to create a GaussBorderIntegrationSwarm in
the case the 'swarm' input is 'None'.
"""
_objectsDict = { "_assemblyterm": "VectorSurfaceAssemblyTerm_NA__Fn__ni" }
def __init__(self, nbc, integrationSwarm=None, surfaceGaussPoints=2, **kwargs):
if not isinstance(nbc, uw.conditions.NeumannCondition):
raise ValueError( "Provided 'nbc' must be a NeumannCondition class." )
self._nbc = nbc
# use the nbc variable's mesh
mesh = self._nbc.variable.mesh
if integrationSwarm != None:
if not isinstance( integrationSwarm, uw.swarm.GaussBorderIntegrationSwarm):
raise ValueError("Provided 'borderSwarm' must be of type uw.swarm.GaussBorderIntegrationSwarm")
else: # no swarm provide, so we build one
if not isinstance(surfaceGaussPoints, int):
raise TypeError( "Provided 'surfaceGaussPoints' must be a positive integer")
if surfaceGaussPoints < 1:
raise ValueError( "Provided 'surfaceGaussPoints' must be a positive integer")
integrationSwarm = uw.swarm.GaussBorderIntegrationSwarm( mesh=mesh,
particleCount=surfaceGaussPoints )
super(VectorSurfaceAssemblyTerm_NA__Fn__ni,self).__init__( integrationSwarm=integrationSwarm, **kwargs )
# pass the NeumannConditions to the SurfaceAssemblyTerm so it knows which nodes to assemble the flux contribution
libUnderworld.Underworld._VectorSurfaceAssemblyTerm_SetBNodes( self._cself, nbc._cself )
##### Now construct the additional rhs force like term. Ingredients required for a surface integral
# 1) a gauss border swarm
# 2) a mask function to only evaluate the flux only on nodes specified in the nbc.indexSets
#####
deltaMeshVariable = uw.mesh.MeshVariable(mesh, 1)
deltaMeshVariable.data[:] = 0.
# set a value 1.0 on provided vertices
newSet = mesh.specialSets['Empty']
for i in range(len(nbc.indexSetsPerDof)):
if nbc.indexSetsPerDof[i] is None:
continue
newSet += nbc.indexSetsPerDof[i]
deltaMeshVariable.data[newSet.data] = 1.0
# note we use this condition to only capture border swarm particles
# on the surface itself. for those directly adjacent, the deltaMeshVariable will evaluate
# to non-zero (but less than 1.), so we need to remove those from the integration as well.
maskFn = uw.function.branching.conditional(
[ ( deltaMeshVariable > 0.999, 1. ),
( True, 0. ) ] )
self._fn = maskFn * nbc.fn_flux
self._set_fn_function = libUnderworld.Underworld._VectorSurfaceAssemblyTerm_NA__Fn__ni_SetFn
# Questionable code think we can remove
# if mesh:
# if not isinstance( mesh, uw.mesh.FeMesh_Cartesian ):
# raise TypeError( "The provided mesh must be of FeMesh_Cartesian class.")
# # set directly
# self._cself.geometryMesh = mesh._cself
# self._mesh = mesh
def _add_to_stg_dict(self,componentDictionary):
# call parents method
super(VectorSurfaceAssemblyTerm_NA__Fn__ni,self)._add_to_stg_dict(componentDictionary)
[docs]class VectorAssemblyTerm_NA_j__Fn_ij(VectorAssemblyTerm):
"""
Build an assembly term for a spatial gradient, used for the viscoelastic force term.
Parameters
----------
fn : underworld.function.Function
Function is a vector of size 3 (dim=2) or 6 (dim=3) representing a symetric tensor
mesh : uw.mesh.FeMesh_Cartesian
"""
_objectsDict = { "_assemblyterm": "VectorAssemblyTerm_NA_j__Fn_ij" }
def __init__(self, fn, mesh=None, **kwargs):
# build parent
super(VectorAssemblyTerm_NA_j__Fn_ij,self).__init__(**kwargs)
self._set_fn_function = libUnderworld.Underworld._VectorAssemblyTerm_NA_j__Fn_ij_SetFn
self._fn = fn
if mesh:
if not isinstance( mesh, uw.mesh.FeMesh_Cartesian ):
raise TypeError( "The provided mesh must be of FeMesh_Cartesian class.")
# set directly
self._cself.geometryMesh = mesh._cself
self._mesh = mesh
def _add_to_stg_dict(self,componentDictionary):
# call parents method
super(VectorAssemblyTerm_NA_j__Fn_ij,self)._add_to_stg_dict(componentDictionary)
[docs]class VectorAssemblyTerm_NA__Fn(VectorAssemblyTerm):
_objectsDict = { "_assemblyterm": "VectorAssemblyTerm_NA__Fn" }
def __init__(self, fn, mesh=None, **kwargs):
# build parent
super(VectorAssemblyTerm_NA__Fn,self).__init__(**kwargs)
self._set_fn_function = libUnderworld.Underworld._VectorAssemblyTerm_NA__Fn_SetFn
self._fn = fn
if mesh:
if not isinstance( mesh, uw.mesh.FeMesh_Cartesian ):
raise TypeError( "The provided mesh must be of FeMesh_Cartesian class.")
# set directly
self._cself.geometryMesh = mesh._cself
self._mesh = mesh
def _add_to_stg_dict(self,componentDictionary):
# call parents method
super(VectorAssemblyTerm_NA__Fn,self)._add_to_stg_dict(componentDictionary)
[docs]class VectorAssemblyTerm_NA_i__Fn_i(VectorAssemblyTerm):
_objectsDict = { "_assemblyterm": "VectorAssemblyTerm_NA_i__Fn_i" }
def __init__(self, fn, mesh=None, **kwargs):
# build parent
super(VectorAssemblyTerm_NA_i__Fn_i,self).__init__(**kwargs)
self._set_fn_function = libUnderworld.Underworld._VectorAssemblyTerm_NA_i__Fn_i_SetFn
self._fn = fn
if mesh:
if not isinstance( mesh, uw.mesh.FeMesh_Cartesian ):
raise TypeError( "The provided mesh must be of FeMesh_Cartesian class.")
# set directly
self._cself.geometryMesh = mesh._cself
self._mesh = mesh
def _add_to_stg_dict(self,componentDictionary):
# call parents method
super(VectorAssemblyTerm_NA_i__Fn_i,self)._add_to_stg_dict(componentDictionary)
[docs]class GradientStiffnessMatrixTerm(MatrixAssemblyTerm):
_objectsDict = { "_assemblyterm": "GradientStiffnessMatrixTerm" }
pass
[docs]class PreconditionerMatrixTerm(MatrixAssemblyTerm):
_objectsDict = { "_assemblyterm": "UzawaPreconditionerTerm" }
pass
[docs]class ConstitutiveMatrixTerm(MatrixAssemblyTerm):
_objectsDict = { "_assemblyterm": "ConstitutiveMatrixCartesian" }
def __init__(self, fn_visc1=None, fn_visc2=None, fn_director=None, **kwargs):
# build parent
super(ConstitutiveMatrixTerm,self).__init__(**kwargs)
# disable these, because this guy requires multiple functions
self._set_fn_function = None
self._fn = None
if not fn_visc1:
raise ValueError("You must provide a viscosity for the ConstitutiveMatrixTerm")
self._fn_visc1 = fn_visc1
self._fn_visc2 = fn_visc2
self._fn_director = fn_director
@property
def fn_visc1(self):
return self._fn_visc1
@fn_visc1.setter
def fn_visc1(self, value):
_fn = uw.function.Function.convert(value)
if not isinstance( _fn, uw.function.Function):
raise ValueError( "Provided 'fn' must be of or convertible to 'Function' class." )
self._fn_visc1 = _fn
libUnderworld.Underworld._ConstitutiveMatrixCartesian_Set_Fn_Visc1( self._cself, self._fn_visc1._fncself )
@property
def fn_visc2(self):
return self._fn_visc2
@fn_visc2.setter
def fn_visc2(self, value):
_fn = uw.function.Function.convert(value)
if not isinstance( _fn, uw.function.Function):
raise ValueError( "Provided 'fn' must be of or convertible to 'Function' class." )
self._fn_visc2 = _fn
libUnderworld.Underworld._ConstitutiveMatrixCartesian_Set_Fn_Visc2( self._cself, self._fn_visc2._fncself )
@property
def fn_director(self):
return self._fn_director
@fn_director.setter
def fn_director(self, value):
_fn = uw.function.Function.convert(value)
if not isinstance( _fn, uw.function.Function):
raise ValueError( "Provided 'fn' must be of or convertible to 'Function' class." )
self._fn_director = _fn
libUnderworld.Underworld._ConstitutiveMatrixCartesian_Set_Fn_Director( self._cself, self._fn_director._fncself )
def _setup(self):
# lets setup fn tings.. note that this uses the 'property' above
self.fn_visc1 = self._fn_visc1
if self._fn_visc2:
self.fn_visc2 = self._fn_visc2
if self._fn_director:
self.fn_director = self._fn_director
def _add_to_stg_dict(self,componentDictionary):
# call parents method
super(ConstitutiveMatrixTerm,self)._add_to_stg_dict(componentDictionary)
componentDictionary[ self._cself.name ]["dim"] = self._integrationSwarm._mesh.dim
[docs]class MatrixAssemblyTerm_NA_i__NB_i__Fn(MatrixAssemblyTerm):
_objectsDict = { "_assemblyterm": "MatrixAssemblyTerm_NA_i__NB_i__Fn" }
def __init__(self, fn, **kwargs):
# build parent
super(MatrixAssemblyTerm_NA_i__NB_i__Fn,self).__init__(**kwargs)
self._set_fn_function = libUnderworld.Underworld.MatrixAssemblyTerm_NA_i__NB_i__Fn_SetFn
self._fn = fn
def _add_to_stg_dict(self,componentDictionary):
# call parents method
super(MatrixAssemblyTerm_NA_i__NB_i__Fn,self)._add_to_stg_dict(componentDictionary)
[docs]class MatrixAssemblyTerm_NA__NB__Fn(MatrixAssemblyTerm):
_objectsDict = { "_assemblyterm": "MatrixAssemblyTerm_NA__NB__Fn" }
def __init__(self, fn, mesh, **kwargs):
# build parent
super(MatrixAssemblyTerm_NA__NB__Fn,self).__init__(**kwargs)
self._set_fn_function = libUnderworld.Underworld.MatrixAssemblyTerm_NA__NB__Fn_SetFn
self._fn = fn
if not isinstance( mesh, uw.mesh.FeMesh_Cartesian ):
raise TypeError( "The provided mesh must be of FeMesh_Cartesian class.")
# set mesh directly
self._cself.geometryMesh = mesh._cself
self._geometryMesh = mesh
def _add_to_stg_dict(self,componentDictionary):
# call parents method
super(MatrixAssemblyTerm_NA__NB__Fn,self)._add_to_stg_dict(componentDictionary)
[docs]class LumpedMassMatrixVectorTerm(VectorAssemblyTerm):
_objectsDict = { "_assemblyterm": "LumpedMassMatrixForceTerm" }
pass
[docs]class AdvDiffResidualVectorTerm(VectorAssemblyTerm):
_objectsDict = { "_assemblyterm": "AdvDiffResidualForceTerm" }
def __init__( self, velocityField, diffusivity, sourceTerm, **kwargs ):
# build parent
super(AdvDiffResidualVectorTerm,self).__init__(**kwargs)
if not isinstance( velocityField, uw.mesh.MeshVariable):
raise TypeError( "Provided 'velocityField' must be of 'MeshVariable' class." )
self._velocityField = velocityField
# because supg takes 2 fn we don't use the '_fn' attribute
# instead we make '_fn_diffusivity' and '_fn_source'
self._fn_diffusivity= uw.function.Function.convert(diffusivity)
if not isinstance( self._fn_diffusivity, uw.function.Function ):
raise TypeError( "Provided 'diffusivity' must be of the type, or convertible to, 'Function' class ")
# if sourceTerm is None make it 0.0 fn object
self._fn_source = uw.function.Function.convert(sourceTerm)
if self._fn_source == None:
self._fn_source = uw.function.misc.constant(0.0)
self._set_fn_function = None
self._fn = None
self._set_fn_diffusivity_function = \
libUnderworld.Underworld._SUPGVectorTerm_NA__Fn_SetDiffusivityFn
self._set_fn_source_function = \
libUnderworld.Underworld._SUPGVectorTerm_NA__Fn_SetSourceFn
def _add_to_stg_dict(self,componentDictionary):
# call parents method
super(AdvDiffResidualVectorTerm,self)._add_to_stg_dict(componentDictionary)
componentDictionary[ self._cself.name ][ "VelocityField"] = self._velocityField._cself.name
componentDictionary[ self._cself.name ][ "UpwindXiFunction"] = "DoublyAsymptoticAssumption"
@property
def fn_diffusivity(self):
return self._fn_diffusivity
@fn_diffusivity.setter
def fn_diffusivity(self, value):
if not self._set_fn_diffusivity_function:
raise RuntimeError("You cannot set a function for this assembly term.")
_fn = uw.function._function.Function.convert(value)
if not isinstance( _fn, uw.function.Function):
raise ValueError( "Provided 'fn' must be of, or convertible to, 'Function' class." )
self._fn_diffusivity = _fn
self._set_fn_diffusivity_function( self._cself, self._fn_diffusivity._fncself )
@property
def fn_source(self):
return self._sourceFn
@fn_source.setter
def fn_source(self, value):
if not self._set_fn_source_function:
raise RuntimeError("You cannot set a function for this assembly term.")
_fn = uw.function._function.Function.convert(value)
if not isinstance( _fn, uw.function.Function):
raise ValueError( "Provided 'fn' must be of, or convertible to, 'Function' class." )
self._fn_source = _fn
self._set_fn_source_function( self._cself, self._fn_source._fncself )
def _setup(self):
# lets setup fn tings.. note that this uses the 'property' above
if self._set_fn_diffusivity_function:
self.fn_diffusivity = self._fn_diffusivity
if self._set_fn_source_function:
self.fn_source = self._fn_source
[docs]class MatrixSurfaceAssemblyTerm_NA__NB__Fn__ni(MatrixAssemblyTerm):
_objectsDict = { "_assemblyterm": "MatrixSurfaceAssemblyTerm_NA__NB__Fn__ni" }
def __init__(self, fn, mesh, **kwargs):
# build parent
super(MatrixSurfaceAssemblyTerm_NA__NB__Fn__ni,self).__init__(**kwargs)
self._set_fn_function = libUnderworld.Underworld.MatrixSurfaceAssemblyTerm_NA__NB__Fn__ni_SetFn
self._fn = fn
if not isinstance( mesh, uw.mesh.FeMesh_Cartesian ):
raise TypeError( "The provided mesh must be of FeMesh_Cartesian class.")
# set mesh directly
self._cself.geometryMesh = mesh._cself
self._geometryMesh = mesh
def _add_to_stg_dict(self,componentDictionary):
# call parents method
super(MatrixSurfaceAssemblyTerm_NA__NB__Fn__ni,self)._add_to_stg_dict(componentDictionary)