你已经派生过 gprMax
镜像自地址
https://gitee.com/sunhf/gprMax.git
已同步 2025-08-07 15:10:13 +08:00
Restructured CFS and CFS parameters in PML. Corrected bug with kappa parameters scaling when not set to constant.
这个提交包含在:
152
gprMax/pml.py
152
gprMax/pml.py
@@ -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
|
||||||
|
在新工单中引用
屏蔽一个用户