Restructured CFS and CFS parameters in PML. Corrected bug with kappa parameters scaling when not set to constant.

这个提交包含在:
Craig Warren
2015-12-22 10:57:24 +00:00
父节点 a42dacb938
当前提交 ebd2bc4b86

查看文件

@@ -21,34 +21,46 @@ import numpy as np
from gprMax.constants import e0, z0, floattype from gprMax.constants import e0, z0, floattype
class CFS(): class CFSParameter():
"""PML CFS parameters.""" """CFS parameter for PML."""
# Allowable scaling types # Allowable scaling profiles and directions
scalingtypes = {'constant': 0, 'linear': 1, 'inverselinear': -1, 'quadratic': 2, 'cubic': 3, 'quartic': 4} scalingprofiles = {'constant': 0, 'linear': 1, 'quadratic': 2, 'cubic': 3, 'quartic': 4}
scalingdirections = ['forward', 'reverse']
def __init__(self, alphascaling='constant', alphamin=0, alphamax=0, kappascaling='constant', kappamin=1, kappamax=1, sigmascaling='quartic', sigmamin=0, sigmamax=None): def __init__(self, ID=None, scaling='polynomial', scalingprofile=None, scalingdirection='forward', min=0, max=0):
""" """
Args: Args:
alphascaling (str): Type of scaling used for alpha parameter. Can be: 'constant', 'linear', 'inverselinear', 'quadratic', 'cubic', 'quartic'. ID (str): Identifier for CFS parameter, can be: 'alpha', 'kappa' or 'sigma'.
alphamin (float): Minimum value for alpha parameter. scaling (str): Type of scaling, can be: 'polynomial'.
alphamax (float): Maximum value for alpha parameter. scalingprofile (str): Type of scaling profile from scalingprofiles.
kappascaling (str): Type of scaling used for kappa parameter. Can be: 'constant', 'linear', 'inverselinear', 'quadratic', 'cubic', 'quartic'. scalingdirection (str): Direction of scaling profile from scalingdirections.
kappamin (float): Minimum value for kappa parameter. min (float): Minimum value for parameter.
kappamax (float): Maximum value for kappa parameter. max (float): Maximum value for parameter.
sigmascaling (str): Type of scaling used for sigma parameter. Can be: 'constant', 'linear', 'inverselinear', 'quadratic', 'cubic', 'quartic'.
sigmamin (float): Minimum value for sigma parameter.
sigmamax (float): Maximum value for sigma parameter.
""" """
self.alphascaling = alphascaling
self.alphamin = alphamin self.ID = ID
self.alphamax = alphamax self.scaling = scaling
self.kappascaling = kappascaling self.scalingprofile = scalingprofile
self.kappamin = kappamin self.scalingdirection = scalingdirection
self.kappamax = kappamax self.min = min
self.sigmascaling = sigmascaling self.max = max
self.sigmamin = sigmamin
self.sigmamax = sigmamax
class CFS():
"""CFS term for PML."""
def __init__(self):
"""
Args:
alpha (CFSParameter): alpha parameter for CFS.
kappa (CFSParameter): kappa parameter for CFS.
sigma (CFSParameter): sigma parameter for CFS.
"""
self.alpha = CFSParameter(ID='alpha', scalingprofile='constant')
self.kappa = CFSParameter(ID='kappa', scalingprofile='constant', min=1, max=1)
self.sigma = CFSParameter(ID='sigma', scalingprofile='quartic', min=0, max=None)
def calculate_sigmamax(self, direction, er, mr, G): def calculate_sigmamax(self, direction, er, mr, G):
"""Calculates an optimum value for sigma max based on underlying material properties. """Calculates an optimum value for sigma max based on underlying material properties.
@@ -59,61 +71,70 @@ class CFS():
mr (float): Average permeability of underlying material. mr (float): Average permeability of underlying material.
G (class): Grid class instance - holds essential parameters describing the model. G (class): Grid class instance - holds essential parameters describing the model.
""" """
# Get general direction from first letter of PML direction
if direction[0] == 'x': if direction == 'xminus' or direction == 'xplus':
d = G.dx d = G.dx
elif direction[0] == 'y': elif direction == 'yminus' or direction == 'yplus':
d = G.dy d = G.dy
elif direction[0] == 'z': elif direction == 'zminus' or direction == 'zplus':
d = G.dz d = G.dz
# Calculation of the maximum value of sigma from http://dx.doi.org/10.1109/8.546249 # Calculation of the maximum value of sigma from http://dx.doi.org/10.1109/8.546249
m = CFS.scalingtypes[self.sigmascaling] m = CFSParameter.scalingprofiles[self.sigma.scalingprofile]
self.sigmamax = (0.8 * (m + 1)) / (z0 * d * np.sqrt(er * mr)) self.sigma.max = (0.8 * (m + 1)) / (z0 * d * np.sqrt(er * mr))
def scaling_polynomial(self, min, max, order, Evalues, Hvalues): def scaling_polynomial(self, order, Evalues, Hvalues):
"""Applies the polynomial to be used for scaling for electric and magnetic PML updates based on scaling type and minimum and maximum values. """Applies the polynomial to be used for the scaling profile for electric and magnetic PML updates.
Args: Args:
min (float): Minimum value for scaling. order (int): Order of polynomial for scaling profile.
max (float): Maximum value for scaling. Evalues (float): numpy array holding scaling profile values for electric PML update.
order (int): Order of polynomial for scaling. Hvalues (float): numpy array holding scaling profile values for magnetic PML update.
Evalues (float): numpy array holding scaling value for electric PML update.
Hvalues (float): numpy array holding scaling value for magnetic PML update.
Returns: Returns:
Evalues (float): numpy array holding scaling value for electric PML update. Evalues (float): numpy array holding scaling profile values for electric PML update.
Hvalues (float): numpy array holding scaling value for magnetic PML update. Hvalues (float): numpy array holding scaling profile values for magnetic PML update.
""" """
tmp = max * ((np.linspace(0, (len(Evalues) - 1) + 0.5, num=2*len(Evalues))) / (len(Evalues) - 1)) ** order
tmp = (np.linspace(0, (len(Evalues) - 1) + 0.5, num=2*len(Evalues)) / (len(Evalues) - 1)) ** order
Evalues = tmp[0:-1:2] Evalues = tmp[0:-1:2]
Hvalues = tmp[1::2] Hvalues = tmp[1::2]
return Evalues, Hvalues return Evalues, Hvalues
def calculate_values(self, min, max, scaling, Evalues, Hvalues): def calculate_values(self, thickness, parameter):
"""Calculates values for electric and magnetic PML updates based on scaling type and minimum and maximum values. """Calculates values for electric and magnetic PML updates based on profile type and minimum and maximum values.
Args: Args:
min (float): Minimum value for scaling. thickness (int): Thickness of PML in cells.
max (float): Maximum value for scaling. parameter (CFSParameter): Instance of CFSParameter
scaling (int): Type of scaling, can be: 'constant', 'linear', 'inverselinear', 'quadratic', 'cubic', 'quartic'.
Evalues (float): numpy array holding scaling value for electric PML update.
Hvalues (float): numpy array holding scaling value for magnetic PML update.
Returns: Returns:
Evalues (float): numpy array holding scaling value for electric PML update. Evalues (float): numpy array holding profile value for electric PML update.
Hvalues (float): numpy array holding scaling value for magnetic PML update. Hvalues (float): numpy array holding profile value for magnetic PML update.
""" """
if scaling == 'constant':
Evalues += max
Hvalues += max
else:
Evalues, Hvalues = self.scaling_polynomial(min, max, CFS.scalingtypes[scaling], Evalues, Hvalues)
if scaling == 'inverselinear': Evalues= np.zeros(thickness + 1, dtype=floattype)
Hvalues = np.zeros(thickness + 1, dtype=floattype)
if parameter.scalingprofile == 'constant':
Evalues += parameter.max
Hvalues += parameter.max
elif parameter.scaling == 'polynomial':
Evalues, Hvalues = self.scaling_polynomial(CFSParameter.scalingprofiles[parameter.scalingprofile], Evalues, Hvalues)
if parameter.ID == 'alpha':
pass
elif parameter.ID == 'kappa':
Evalues = Evalues * (self.kappa.max - 1) + 1
Hvalues = Hvalues * (self.kappa.max - 1) + 1
elif parameter.ID == 'sigma':
Evalues *= self.sigma.max
Hvalues *= self.sigma.max
if parameter.scalingdirection == 'reverse':
Evalues = Evalues[::-1] Evalues = Evalues[::-1]
Hvalues = Hvalues[::-1] Hvalues = Hvalues[::-1]
# print('Evalues: scaling {}, {}'.format(scaling, Evalues))
# print('Hvalues: scaling {}, {}'.format(scaling, Hvalues))
return Evalues, Hvalues return Evalues, Hvalues
@@ -126,6 +147,7 @@ class PML():
xs, xf, ys, yf, zs, zf (float): Extent of the PML volume. xs, xf, ys, yf, zs, zf (float): Extent of the PML volume.
cfs (list): CFS class instances associated with the PML. cfs (list): CFS class instances associated with the PML.
""" """
self.direction = direction self.direction = direction
self.xs = xs self.xs = xs
self.xf = xf self.xf = xf
@@ -181,17 +203,11 @@ class PML():
""" """
for x, cfs in enumerate(self.CFS): for x, cfs in enumerate(self.CFS):
Ealpha = np.zeros(self.thickness + 1, dtype=floattype) if not cfs.sigma.max:
Halpha = np.zeros(self.thickness + 1, dtype=floattype)
Ekappa = np.zeros(self.thickness + 1, dtype=floattype)
Hkappa = np.zeros(self.thickness + 1, dtype=floattype)
Esigma = np.zeros(self.thickness + 1, dtype=floattype)
Hsigma = np.zeros(self.thickness + 1, dtype=floattype)
if not cfs.sigmamax:
cfs.calculate_sigmamax(self.direction, er, mr, G) cfs.calculate_sigmamax(self.direction, er, mr, G)
Ealpha, Halpha = cfs.calculate_values(cfs.alphamin, cfs.alphamax, cfs.alphascaling, Ealpha, Halpha) Ealpha, Halpha = cfs.calculate_values(self.thickness, cfs.alpha)
Ekappa, Hkappa = cfs.calculate_values(cfs.kappamin, cfs.kappamax, cfs.kappascaling, Ekappa, Hkappa) Ekappa, Hkappa = cfs.calculate_values(self.thickness, cfs.kappa)
Esigma, Hsigma = cfs.calculate_values(cfs.sigmamin, cfs.sigmamax, cfs.sigmascaling, Esigma, Hsigma) Esigma, Hsigma = cfs.calculate_values(self.thickness, cfs.sigma)
# print('Ealpha {}'.format(Ealpha)) # print('Ealpha {}'.format(Ealpha))
# print('Halpha {}'.format(Halpha)) # print('Halpha {}'.format(Halpha))
@@ -268,9 +284,9 @@ def build_pml(G):
def calculate_initial_pml_params(G): def calculate_initial_pml_params(G):
""" This function calculates the initial parameters and coefficients for PML including setting scaling """ This function calculates the initial parameters and coefficients for PML including setting profile
(based on underlying material er and mr from solid array). (based on underlying material er and mr from solid array).
""" """
for pml in G.pmls: for pml in G.pmls:
sumer = 0 sumer = 0