Source code for underworld.swarm.layouts

##~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~##
##                                                                                   ##
##  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.                             ##
##                                                                                   ##
##~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~##
'''
This module contains classes for populating swarms with particles across
the domain.
'''
import underworld._stgermain as _stgermain
import _swarm
import abc as _abc

[docs]class ParticleLayoutAbstract(_stgermain.StgCompoundComponent): """ Abstract class. Children classes are responsible for populating swarms with particles, generally across the entire domain. Parameters ---------- swarm : underworld.swarm.Swarm The swarm this layout will act upon """ _objectsDict = { "_layout": None } _selfObjectName = "_layout" __metaclass__ = _abc.ABCMeta def __init__(self, swarm, **kwargs ): if not isinstance(swarm, _swarm.Swarm): raise TypeError("'swarm' object passed in must be of type 'Swarm'") self._swarm = swarm # build parent super(ParticleLayoutAbstract,self).__init__(**kwargs) @property def swarm(self): """ Returns ------- underworld.swarm.Swarm Swarm this layout will act to fill with particlces. """ return self._swarm
[docs]class PerCellGaussLayout(ParticleLayoutAbstract): """ This layout populates the domain with particles located at gauss locations within each element of the swarm's associated finite element mesh. Parameters ---------- swarm : underworld.swarm.Swarm The swarm this layout will act upon gaussPointCount : int Per cell, the number of gauss points in each dimensional direction. Must take an int value between 1 and 5 inclusive. Example ------- >>> import underworld as uw >>> # choose mesh to coincide with global element >>> mesh = uw.mesh.FeMesh_Cartesian('Q1/dQ0', (1,1), (-1.,-1.), (1.,1.)) >>> swarm = uw.swarm.Swarm(mesh) >>> layout = uw.swarm.layouts.PerCellGaussLayout(swarm,gaussPointCount=2) >>> swarm.populate_using_layout(layout) >>> swarm.particleLocalCount 4 >>> swarm.particleCoordinates.data array([[-0.57735027, -0.57735027], [ 0.57735027, -0.57735027], [-0.57735027, 0.57735027], [ 0.57735027, 0.57735027]]) >>> import math >>> # lets check one of these gauss points >>> ( swarm.particleCoordinates.data[3][0] - math.sqrt(1./3.) ) < 1.e-10 True """ _objectsDict = { "_layout": "IrregularMeshGaussLayout" } def __init__(self, swarm, gaussPointCount, **kwargs ): if not isinstance(gaussPointCount, int): raise TypeError("'gaussPointCount' object passed in must be of type 'int'") if gaussPointCount not in [1,2,3,4,5]: raise ValueError("'gaussPointCount' object passed in must take a value between \n between 1 and 5 inclusive.") self._gaussPointCount = gaussPointCount # build parent super(PerCellGaussLayout,self).__init__(swarm=swarm, **kwargs) def _add_to_stg_dict(self,componentDictionary): # call parents method super(PerCellGaussLayout,self)._add_to_stg_dict(componentDictionary) componentDictionary[ self._layout.name ][ "dim"] = self.swarm.mesh.dim componentDictionary[ self._layout.name ][ "FeMesh"] = self.swarm.mesh._cself.name componentDictionary[ self._layout.name ]["gaussParticles"] = self._gaussPointCount
[docs]class GlobalSpaceFillerLayout(ParticleLayoutAbstract): """ This layout fills the domain with particles in a quasi-random pattern. It utilises sobol sequences to generate global particle locations which are more uniform than that achieved by a purely random generator. This layout is mostly useful where populating particles across a rectangular domain. Parameters ---------- swarm : underworld.swarm.Swarm The swarm this layout will act upon particlesPerCell : float The average number of particles per element that this layout will generate. Example ------- >>> import underworld as uw >>> mesh = uw.mesh.FeMesh_Cartesian('Q1/dQ0', (1,1), (0.,0.), (1.,1.)) >>> swarm = uw.swarm.Swarm(mesh) >>> layout = uw.swarm.layouts.GlobalSpaceFillerLayout(swarm,particlesPerCell=4) >>> swarm.populate_using_layout(layout) >>> swarm.particleLocalCount 4 >>> swarm.particleCoordinates.data array([[ 0.5 , 0.5 ], [ 0.25 , 0.75 ], [ 0.75 , 0.25 ], [ 0.375, 0.625]]) """ _objectsDict = { "_layout": "SpaceFillerParticleLayout" } def __init__(self, swarm, particlesPerCell, **kwargs ): if not isinstance(particlesPerCell, (int,float)): raise TypeError("'particlesPerCell' object passed in must be of type 'float' or 'int'.") if particlesPerCell<=0: raise ValueError("'particlesPerCell' object passed in must take a value greater than zero.") self._particlesPerCell = float(particlesPerCell) # build parent super(GlobalSpaceFillerLayout,self).__init__(swarm=swarm, **kwargs) def _add_to_stg_dict(self,componentDictionary): # call parents method super(GlobalSpaceFillerLayout,self)._add_to_stg_dict(componentDictionary) componentDictionary[ self._layout.name ][ "dim"] = self.swarm.mesh.dim componentDictionary[ self._layout.name ]["averageInitialParticlesPerCell"] = self._particlesPerCell
class _PerCellMeshParticleLayout(ParticleLayoutAbstract): """ This layout fills the domain with particles on a per cell basis. It should not be directly invoked with instead one of its child classes being used. Parameters ---------- swarm : underworld.swarm.Swarm The swarm this layout will act upon particlesPerCell : int The number of particles per element/cell that this layout will generate. """ _objectsDict = { "_layout": "MeshParticleLayout" } def __init__(self, swarm, particlesPerCell, **kwargs ): if not isinstance(particlesPerCell, int): raise TypeError("'particlesPerCell' object passed in must be of type 'int'.") if particlesPerCell<1: raise ValueError("'particlesPerCell' object passed in must take a value greater than zero.") self._particlesPerCell = particlesPerCell # build parent super(_PerCellMeshParticleLayout,self).__init__(swarm=swarm, **kwargs) def _add_to_stg_dict(self,componentDictionary): # call parents method super(_PerCellMeshParticleLayout,self)._add_to_stg_dict(componentDictionary) componentDictionary[ self._layout.name ]["cellParticleCount"] = self._particlesPerCell componentDictionary[ self._layout.name ][ "FeMesh"] = self.swarm.mesh._cself.name componentDictionary[ self._layout.name ][ "filltype"] = self._filltype
[docs]class PerCellSpaceFillerLayout(_PerCellMeshParticleLayout): """ This layout fills the domain with particles in a quasi-random pattern. It utilises sobol sequences to generate per element particle locations which are more uniform than that achieved by a purely random generator. Parameters ---------- swarm : underworld.swarm.Swarm The swarm this layout will act upon particlesPerCell : int The number of particles per element that this layout will generate. Example ------- >>> import underworld as uw >>> mesh = uw.mesh.FeMesh_Cartesian('Q1/dQ0', (1,1), (0.,0.), (1.,1.)) >>> swarm = uw.swarm.Swarm(mesh) >>> layout = uw.swarm.layouts.PerCellSpaceFillerLayout(swarm,particlesPerCell=4) >>> swarm.populate_using_layout(layout) >>> swarm.particleLocalCount 4 >>> swarm.particleCoordinates.data array([[ 0.5 , 0.5 ], [ 0.25 , 0.75 ], [ 0.75 , 0.25 ], [ 0.375, 0.625]]) """ def __init__(self, swarm, particlesPerCell, **kwargs ): self._filltype = 0 # this sets sobol # build parent super(PerCellSpaceFillerLayout,self).__init__(swarm=swarm, particlesPerCell=particlesPerCell, **kwargs)
[docs]class PerCellRandomLayout(_PerCellMeshParticleLayout): """ This layout fills the domain with particles in a random (per element) pattern. Parameters ---------- swarm : underworld.swarm.Swarm The swarm this layout will act upon particlesPerCell : int The number of particles per element that this layout will generate. seed : int Seed for random generator. Default is 13. Example ------- >>> import underworld as uw >>> mesh = uw.mesh.FeMesh_Cartesian('Q1/dQ0', (1,1), (0.,0.), (1.,1.)) >>> swarm = uw.swarm.Swarm(mesh) >>> layout = uw.swarm.layouts.PerCellRandomLayout(swarm,particlesPerCell=4) >>> swarm.populate_using_layout(layout) >>> swarm.particleLocalCount 4 >>> swarm.particleCoordinates.data array([[ 0.24261743, 0.67115852], [ 0.16116546, 0.70790335], [ 0.73160516, 0.08792286], [ 0.71953113, 0.15966135]]) """ def __init__(self, swarm, particlesPerCell, seed=13, **kwargs ): self._filltype = 1 # this sets random self._seed = seed # build parent super(PerCellRandomLayout,self).__init__(swarm=swarm, particlesPerCell=particlesPerCell, **kwargs) def _add_to_stg_dict(self,componentDictionary): # call parents method super(PerCellRandomLayout,self)._add_to_stg_dict(componentDictionary) componentDictionary[ self._layout.name ]["seed"] = self._seed