"""
functions for initialising particle distribution
"""
import logging
import pathlib
import numpy as np
# Local imports
import avaframe.com1DFA.DFAfunctionsCython as DFAfunC
from avaframe.in3Utils import cfgUtils
import avaframe.com1DFA.particleTools as particleTools
import avaframe.out3Plot.outDebugPlots as debPlot
import avaframe.in3Utils.geoTrans as geoTrans
# create local logger
log = logging.getLogger(__name__)
cfgAVA = cfgUtils.getGeneralConfig()
debugPlot = cfgAVA['FLAGS'].getboolean('debugPlot')
[docs]def getIniPosition(cfg, particles, dem, fields, inputSimLines, relThField):
""" Redistribute particles so that SPH force reduces with fixed particles as boundaries
Parameters
------------
cfg: configparser object
configuration settings
particles: dict
dictionary with particle properties
dem: dict
dictionary with dem header and data
fields: dict
dictionary with fields of result types
inputSimLines: dict
info on input files
relThField: numpy array
release thickness field
Returns
--------
particles: dict
updated particles dict with new positions
fields: fields
updated fields dictionary
"""
particles['iterate'] = True
particles['dt'] = cfg['GENERAL'].getfloat('dtIni')
particlesList = [particles.copy()]
countIterations = 0
# load relRaster from buffered release line
relRaster = inputSimLines['releaseLineBuffer']['rasterData']
# redistribute particles to reduce SPH force
while particles['iterate'] and countIterations < cfg['GENERAL'].getint('maxIterations'):
# compute artificial viscosity effect on velocity
particles, force = DFAfunC.computeIniMovement(cfg['GENERAL'], particles, dem, cfg['GENERAL'].getfloat('dtIni'),
fields)
# compute SPH force
particles, force = DFAfunC.computeForceSPHC(cfg['GENERAL'], particles, force, dem,
cfg['GENERAL'].getint('sphOptionIni'), gradient=0)
# update position as a result of SPH force and artifical viscosity
particles = DFAfunC.updatePositionC(cfg['GENERAL'], particles, dem, force, fields, typeStop=1)
particlesList.append(particles.copy())
# compute neighbours and update fields
particles = DFAfunC.getNeighborsC(particles, dem)
particles, fields = DFAfunC.updateFieldsC(cfg['GENERAL'], particles, dem, fields)
# count iterations
countIterations = countIterations + 1
# reset iterate for performing ava simulations
particles['iterate'] = True
# remove particles that lie outside of release polygons
if len(relThField) != 0:
relRaster = relThField
particles = resetMassPerParticle(cfg, particles, dem, relRaster, relThField)
particles = geoTrans.checkParticlesInRelease(particles, inputSimLines['releaseLine'],
cfg['GENERAL'].getfloat('thresholdPointInPoly'))
# adjust mass of particles in order to match good final mass
if len(relThField) != 0:
particles['m'] = particles['mIni']
particles['mTot'] = np.sum(particles['m'])
else:
newMass = np.sum(particles['mIni'])
oldMass = np.sum(particles['m'])
particles['m'] = particles['m'] * (newMass / oldMass)
particles['mTot'] = np.sum(particles['m'])
log.debug('oldMass: %.2f and newMass: %.2f - mass factor: %.2f - total mass: %.2f' %
(oldMass, newMass, newMass/oldMass, particles['mTot']))
# save particles to file for visualisation
particlesList.append(particles.copy())
# reset particles IDs
particles['ID'] = np.arange(particles['nPart'])
particles['nID'] = particles['nPart']
particles['parentID'] = np.arange(particles['nPart'])
# reset particle properties
nPart = particles['nPart']
particles['ux'] = np.zeros(nPart)
particles['uy'] = np.zeros(nPart)
particles['uz'] = np.zeros(nPart)
particles['uAcc'] = np.zeros(nPart)
particles['velocityMag'] = np.zeros(nPart)
particles['trajectoryLengthXY'] = np.zeros(nPart)
particles['trajectoryLengthXYZ'] = np.zeros(nPart)
particles['stoppCriteria'] = False
particles['kineticEne'] = 0.0
particles['peakKinEne'] = 0.0
particles['peakMassFlowing'] = 0.0
particles['potentialEne'] = np.sum(cfg['GENERAL'].getfloat('gravAcc') * particles['m'] * particles['z'])
particles['peakForceSPH'] = 0.0
particles['forceSPHIni'] = 0.0
# delete mIni and areaIni key from dict
del particles['mIni']
del particles['areaIni']
# TODO: note particle flow thickness is not updated- this is done in updateFieldsC in the next step as the flow
# thickness is currently computed from the mass and an interpolation on the grid
# for final configuration get neighbors and update fields
particles = DFAfunC.getNeighborsC(particles, dem)
particles, fields = DFAfunC.updateFieldsC(cfg['GENERAL'], particles, dem, fields)
fields['pft'] = fields['FT']
fields['ppr'] = fields['P']
fields['pfv'] = fields['FV']
# save particles to file for visualisation
if cfg['GENERAL'].getboolean('saveParticlesIni'):
avaDir = pathlib.Path(cfg['GENERAL']['avalancheDir'])
outDir = avaDir / 'Outputs' / 'com1DFA' / 'particlesIni'
particleTools.savePartToCsv(cfg['VISUALISATION']['visuParticleProperties'], particlesList, outDir)
return particles, fields
[docs]def resetMassPerParticle(cfg, particles, dem, relRaster, relThField):
""" recompute mass of particles according to their location with respect to relRaster
Parameters
------------
cfg: configparser object
configuration settings
particles: dict
dictionary with particles properties
dem: dict
dictionary with info on dem
relRaster: np.array
raster of release thickness values
Returns
---------
particles: dict
updated particles dictionary with new mass
"""
ncols = dem['header']['ncols']
nrows = dem['header']['nrows']
indPartInCell = particles['indPartInCell']
partInCell = particles['partInCell']
rho = cfg['GENERAL'].getfloat('rho')
indRelY, indRelX = np.nonzero(relRaster)
particles['mIni'] = np.zeros(particles['nPart'])
particles['areaIni'] = np.zeros(particles['nPart'])
aParticles = np.empty(0)
for indRelx, indRely in zip(indRelX, indRelY):
# compute number of particles for this cell
hCell = relRaster[indRely, indRelx]
volCell = dem['areaRaster'][indRely, indRelx] * hCell
massCell = volCell * rho
ic = indRelx + ncols * indRely
iStart = indPartInCell[ic]
iStop = indPartInCell[ic+1]
indParts = partInCell[iStart:iStop]
mNew = massCell / len(indParts)
particles['mIni'][indParts] = mNew
# compute area of particles assuming they are all located entirely within one cell
aPart = dem['areaRaster'][indRely, indRelx] / len(indParts)
particles['areaIni'][indParts] = aPart
if len(relThField) != 0 and cfg['GENERAL'].getboolean('fdOptionIni'):
hParticles = np.empty(0)
mParticles = np.empty(0)
# add option to get new mass of particles from bilinear interpolation of flow thickness
hParticles = DFAfunC.projOnRaster(particles['x'], particles['y'], relRaster, dem['header']['cellsize'], ncols,
nrows, cfg['GENERAL'].getint('interpOption'))
hParticles = np.asarray(hParticles)
particles['h'] = hParticles
mParticles = rho * particles['areaIni'] * particles['h']
particles['mIni'] = mParticles
return particles
[docs]def createReleaseBuffer(cfg, inputSimLines):
""" add a buffer around release polygons to get boundary particles
Parameters
-----------
cfg: configparser object
configuration settings
inputSimLines: dict
dictionary with input data info
Returns
--------
inputSimLines: dict
updated inputSimLines with releaseLineBuffer
"""
# Note on this import: it is purely a quickfix for github issue
# https://github.com/avaframe/QGisAF/issues/9
from shapely.geometry import Polygon
# get start indices and lengths of release polygons
lengthRels = inputSimLines['releaseLine']['Length']
startLines = inputSimLines['releaseLine']['Start']
xBuffered = np.empty(0)
yBuffered = np.empty(0)
lengthArray = []
startArray = [int(startLines[0])]
for m in range(len(lengthRels)):
# get coordinates of release line for each feature
indStart = int(startLines[m])
indStop = int(startLines[m] + lengthRels[m])
xRel = inputSimLines['releaseLine']['x'][indStart:indStop]
yRel = inputSimLines['releaseLine']['y'][indStart:indStop]
# create list of point tuples
points = []
for k in range(len(xRel)):
pointsT = xRel[k], yRel[k]
points.append(pointsT)
# create polygon
pol1 = Polygon(points)
# compute bufferZone
bufferZone = cfg['GENERAL'].getfloat('sphKernelRadius') * cfg['GENERAL'].getfloat('bufferZoneFactor')
polBuffered = pol1.buffer(bufferZone)
xnew, ynew = polBuffered.exterior.coords.xy
xnew = np.asarray(xnew)
ynew = np.asarray(ynew)
xBuffered = np.append(xBuffered, xnew)
yBuffered = np.append(yBuffered, ynew)
lengthArray.append(len(xnew))
startArray.append(int(startArray[-1]+len(xnew)))
# add buffered release lines to dictionary
releaseLineBuffer = inputSimLines['releaseLine'].copy()
releaseLineBuffer['x'] = xBuffered
releaseLineBuffer['y'] = yBuffered
releaseLineBuffer['Length'] = np.asarray(lengthArray)
releaseLineBuffer['Start'] = np.asarray(startArray)
releaseLineBuffer['z'] = np.zeros(len(xBuffered))
inputSimLines['releaseLineBuffer'] = releaseLineBuffer
if debugPlot:
debPlot.plotBufferRelease(inputSimLines, xBuffered, yBuffered)
return inputSimLines