你已经派生过 gprMax
镜像自地址
https://gitee.com/sunhf/gprMax.git
已同步 2025-08-07 15:10:13 +08:00
Tidy ups and remove n_built_in_materials
这个提交包含在:
@@ -213,6 +213,373 @@ class DispersiveMaterial(Material):
|
||||
er -= ersum
|
||||
|
||||
return er
|
||||
|
||||
|
||||
class PeplinskiSoil:
|
||||
"""Soil objects that are characterised according to a mixing model
|
||||
by Peplinski (http://dx.doi.org/10.1109/36.387598).
|
||||
"""
|
||||
|
||||
def __init__(self, ID, sandfraction, clayfraction, bulkdensity,
|
||||
sandpartdensity, watervolfraction):
|
||||
"""
|
||||
Args:
|
||||
ID: string for name of the soil.
|
||||
sandfraction: float of sand fraction of the soil.
|
||||
clayfraction: float of clay fraction of the soil.
|
||||
bulkdensity: float of bulk density of the soil (g/cm3).
|
||||
sandpartdensity: float of density of the sand particles in the
|
||||
soil (g/cm3).
|
||||
watervolfraction: tuple of floats of two numbers that specify a
|
||||
range for the volumetric water fraction of the
|
||||
soil.
|
||||
"""
|
||||
|
||||
self.ID = ID
|
||||
self.S = sandfraction
|
||||
self.C = clayfraction
|
||||
self.rb = bulkdensity
|
||||
self.rs = sandpartdensity
|
||||
self.mu = watervolfraction
|
||||
self.startmaterialnum = 0 #This is not used anymore and code that uses it can be removed
|
||||
# store all of the material IDs in a list instead of storing only the first number of the material
|
||||
# and assume that all must be sequentially numbered. This allows for more general mixing models
|
||||
self.matID = []
|
||||
|
||||
def calculate_properties(self, nbins, G):
|
||||
"""Calculates the real and imaginery part of a Debye model for the soil
|
||||
as well as a conductivity. It uses an approximation to a semi-empirical
|
||||
model (http://dx.doi.org/10.1109/36.387598).
|
||||
|
||||
Args:
|
||||
nbins: int for number of bins to use to create the different materials.
|
||||
G: FDTDGrid class describing a grid in a model.
|
||||
"""
|
||||
|
||||
# Debye model properties of water at 25C & zero salinity
|
||||
T = 25
|
||||
S = 0
|
||||
watereri, waterer, watertau, watersig = calculate_water_properties(T, S)
|
||||
f = 1.3e9
|
||||
w = 2 * np.pi * f
|
||||
erealw = watereri + ((waterer - watereri) / (1 + (w * watertau)**2))
|
||||
|
||||
a = 0.65 # Experimentally derived constant
|
||||
es = (1.01 + 0.44 * self.rs)**2 - 0.062 # Relative permittivity of sand particles
|
||||
b1 = 1.2748 - 0.519 * self.S - 0.152 * self.C
|
||||
b2 = 1.33797 - 0.603 * self.S - 0.166 * self.C
|
||||
|
||||
# For frequencies in the range 0.3GHz to 1.3GHz
|
||||
sigf = 0.0467 + 0.2204 * self.rb - 0.411 * self.S + 0.6614 * self.C
|
||||
# For frequencies in the range 1.4GHz to 18GHz
|
||||
# sigf = -1.645 + 1.939 * self.rb - 2.25622 * self.S + 1.594 * self.C
|
||||
|
||||
# Generate a set of bins based on the given volumetric water fraction
|
||||
# values. Changed to make sure mid points are contained completely within the ranges.
|
||||
# The limiting values of the ranges are not included in this.
|
||||
|
||||
#mubins = np.linspace(self.mu[0], self.mu[1], nbins)
|
||||
mubins = np.linspace(self.mu[0], self.mu[1], nbins + 1)
|
||||
# Generate a range of volumetric water fraction values the mid-point of
|
||||
# each bin to make materials from
|
||||
#mumaterials = mubins + (mubins[1] - mubins[0]) / 2
|
||||
mumaterials = 0.5 * (mubins[1:nbins+1] + mubins[0:nbins])
|
||||
|
||||
# Create an iterator
|
||||
muiter = np.nditer(mumaterials, flags=['c_index'])
|
||||
while not muiter.finished:
|
||||
# Real part for frequencies in the range 1.4GHz to 18GHz
|
||||
er = (1 + (self.rb / self.rs) * ((es**a) - 1) + (muiter[0]**b1 * erealw**a)
|
||||
- muiter[0]) ** (1 / a)
|
||||
# Real part for frequencies in the range 0.3GHz to 1.3GHz (linear
|
||||
# correction to 1.4-18GHz value)
|
||||
er = 1.15 * er - 0.68
|
||||
|
||||
# Permittivity at infinite frequency
|
||||
eri = er - (muiter[0]**(b2 / a) * DispersiveMaterial.waterdeltaer)
|
||||
|
||||
# Effective conductivity
|
||||
sig = muiter[0]**(b2 / a) * ((sigf * (self.rs - self.rb)) / (self.rs * muiter[0]))
|
||||
|
||||
# Check to see if the material already exists before creating a new one
|
||||
requiredID = '|{:.4f}|'.format(float(muiter[0]))
|
||||
material = next((x for x in G.materials if x.ID == requiredID), None)
|
||||
if muiter.index == 0:
|
||||
if material:
|
||||
self.startmaterialnum = material.numID
|
||||
self.matID.append(material.numID)
|
||||
else:
|
||||
self.startmaterialnum = len(G.materials)
|
||||
if not material:
|
||||
m = DispersiveMaterial(len(G.materials), requiredID)
|
||||
m.type = 'debye'
|
||||
m.averagable = False
|
||||
m.poles = 1
|
||||
if m.poles > config.get_model_config().materials['maxpoles']:
|
||||
config.get_model_config().materials['maxpoles'] = m.poles
|
||||
m.er = eri
|
||||
m.se = sig
|
||||
m.deltaer.append(er - eri)
|
||||
m.tau.append(DispersiveMaterial.watertau)
|
||||
G.materials.append(m)
|
||||
self.matID.append(m.numID)
|
||||
|
||||
muiter.iternext()
|
||||
|
||||
|
||||
class RangeMaterial:
|
||||
"""Material defined with a given range of parameters to be used for fractal
|
||||
spatial distributions.
|
||||
"""
|
||||
|
||||
def __init__(self, ID, er_range, sigma_range, mu_range, ro_range):
|
||||
"""
|
||||
Args:
|
||||
ID: string for name of the material.
|
||||
er_range: tuple of floats for relative permittivity range of the
|
||||
material.
|
||||
sigma_range: tuple of floats for electric conductivity range of the
|
||||
material.
|
||||
mu_range: tuple of floats for magnetic permeability of material.
|
||||
ro_range: tuple of floats for magnetic loss range of material.
|
||||
"""
|
||||
|
||||
self.ID = ID
|
||||
self.er = er_range
|
||||
self.sig = sigma_range
|
||||
self.mu = mu_range
|
||||
self.ro = ro_range
|
||||
self.startmaterialnum = 0 #This is not really needed anymore and code that uses it can be removed.
|
||||
# store all of the material IDs in a list instead of storing only the first number of the material
|
||||
# and assume that all must be sequentially numbered. This allows for more general mixing models
|
||||
self.matID = []
|
||||
|
||||
def calculate_properties(self, nbins, G):
|
||||
"""Calculates the properties of the materials.
|
||||
|
||||
Args:
|
||||
nbins: int for number of bins to use to create the different materials.
|
||||
G: FDTDGrid class describing a grid in a model.
|
||||
"""
|
||||
|
||||
# Generate a set of relative permittivity bins based on the given range
|
||||
erbins = np.linspace(self.er[0], self.er[1], nbins+1)
|
||||
|
||||
# Generate a range of relative permittivity values the mid-point of
|
||||
# each bin to make materials from
|
||||
#ermaterials = erbins + np.abs((erbins[1] - erbins[0])) / 2
|
||||
ermaterials = 0.5 * (erbins[1:nbins+1] + erbins[0:nbins])
|
||||
|
||||
# Generate a set of conductivity bins based on the given range
|
||||
sigmabins = np.linspace(self.sig[0], self.sig[1], nbins + 1)
|
||||
|
||||
# Generate a range of conductivity values the mid-point of
|
||||
# each bin to make materials from
|
||||
#sigmamaterials = sigmabins + (sigmabins[1] - sigmabins[0]) / 2
|
||||
sigmamaterials = 0.5 * (sigmabins[1:nbins+1] + sigmabins[0:nbins])
|
||||
|
||||
# Generate a set of magnetic permeability bins based on the given range
|
||||
mubins = np.linspace(self.mu[0], self.mu[1], nbins + 1)
|
||||
|
||||
# Generate a range of magnetic permeability values the mid-point of
|
||||
# each bin to make materials from
|
||||
#mumaterials = mubins + np.abs((mubins[1] - mubins[0])) / 2
|
||||
mumaterials = 0.5 * (mubins[1:nbins+1] + mubins[0:nbins])
|
||||
|
||||
# Generate a set of magnetic loss bins based on the given range
|
||||
robins = np.linspace(self.ro[0], self.ro[1], nbins + 1)
|
||||
|
||||
# Generate a range of magnetic loss values the mid-point of each bin to
|
||||
# make materials from
|
||||
#romaterials = robins + np.abs((robins[1] - robins[0])) / 2
|
||||
romaterials = 0.5 * (robins[1:nbins+1] + robins[0:nbins])
|
||||
|
||||
|
||||
# Iterate over the bins
|
||||
for iter in np.arange(nbins):
|
||||
# Relative permittivity
|
||||
er = ermaterials[iter]
|
||||
# Effective conductivity
|
||||
se = sigmamaterials[iter]
|
||||
# Magnetic permeability
|
||||
mr = mumaterials[iter]
|
||||
# Magnetic loss
|
||||
sm = romaterials[iter]
|
||||
|
||||
# Check to see if the material already exists before creating a new one
|
||||
requiredID = f'|{float(er):.4f}+{float(se):.4f}+{float(mr):.4f}+{float(sm):.4f}|'
|
||||
material = next((x for x in G.materials if x.ID == requiredID), None)
|
||||
if iter == 0:
|
||||
if material:
|
||||
self.startmaterialnum = material.numID
|
||||
self.matID.append(material.numID)
|
||||
else:
|
||||
self.startmaterialnum = len(G.materials)
|
||||
if not material:
|
||||
m = Material(len(G.materials), requiredID)
|
||||
m.type = ''
|
||||
m.averagable = True
|
||||
m.er = er
|
||||
m.se = se
|
||||
m.mr = mr
|
||||
m.sm = sm
|
||||
G.materials.append(m)
|
||||
self.matID.append(m.numID)
|
||||
|
||||
|
||||
class ListMaterial:
|
||||
"""A list of predefined materials to be used for fractal spatial
|
||||
distributions. This command does not create new materials but collects
|
||||
them to be used in a stochastic distribution by a fractal box.
|
||||
"""
|
||||
|
||||
def __init__(self, ID, listofmaterials):
|
||||
"""
|
||||
Args:
|
||||
ID: string for name of the material.
|
||||
listofmaterials: A list of material IDs.
|
||||
|
||||
"""
|
||||
|
||||
self.ID = ID
|
||||
self.mat = listofmaterials
|
||||
self.startmaterialnum = 0 #This is not really needed anymore
|
||||
# store all of the material IDs in a list instead of storing only the first number of the material
|
||||
# and assume that all must be sequentially numbered. This allows for more general mixing models
|
||||
# this is important here as this model assumes predefined materials.
|
||||
self.matID = []
|
||||
|
||||
|
||||
def calculate_properties(self, nbins, G):
|
||||
"""Calculates the properties of the materials.
|
||||
|
||||
Args:
|
||||
nbins: int for number of bins to use to create the different materials.
|
||||
G: FDTDGrid class describing a grid in a model.
|
||||
"""
|
||||
|
||||
# Iterate over the bins
|
||||
for iter in np.arange(nbins):
|
||||
#requiredID = '|{:}_in_{:}|'.format((self.mat[iter]),(self.ID))
|
||||
requiredID = self.mat[iter]
|
||||
# Check if the material already exists before creating a new one
|
||||
material = next((x for x in G.materials if x.ID == requiredID), None)
|
||||
self.matID.append(material.numID)
|
||||
|
||||
#if iter == 0:
|
||||
# if material:
|
||||
# self.startmaterialnum = material.numID
|
||||
# else:
|
||||
# self.startmaterialnum = len(G.materials)
|
||||
|
||||
#if not material:
|
||||
# temp = next((x for x in G.materials if x.ID == self.mat[iter]), None)
|
||||
# m = copy.deepcopy(temp) #This needs to import copy in order to work
|
||||
# m.ID = requiredID
|
||||
# m.numID = len(G.materials)
|
||||
# G.materials.append(m)
|
||||
|
||||
if not material:
|
||||
logger.exception(self.__str__() + f' material(s) {material} do not exist')
|
||||
raise ValueError
|
||||
|
||||
|
||||
def create_built_in_materials(G):
|
||||
"""Creates pre-defined (built-in) materials.
|
||||
|
||||
Args:
|
||||
G: FDTDGrid class describing a grid in a model.
|
||||
"""
|
||||
|
||||
m = Material(0, 'pec')
|
||||
m.se = float('inf')
|
||||
m.type = 'builtin'
|
||||
m.averagable = False
|
||||
G.materials.append(m)
|
||||
|
||||
m = Material(1, 'free_space')
|
||||
m.type = 'builtin'
|
||||
G.materials.append(m)
|
||||
|
||||
|
||||
def calculate_water_properties(T=25, S=0):
|
||||
"""Get extended Debye model properties for water.
|
||||
|
||||
Args:
|
||||
T: float for emperature of water (degrees centigrade).
|
||||
S: float for salinity of water (part per thousand).
|
||||
|
||||
Returns:
|
||||
eri: float for relative permittivity at infinite frequency.
|
||||
er: float for static relative permittivity.
|
||||
tau: float for relaxation time (s).
|
||||
sig: float for conductivity (Siemens/m).
|
||||
"""
|
||||
|
||||
# Properties of water from: https://doi.org/10.1109/JOE.1977.1145319
|
||||
eri = 4.9
|
||||
er = 88.045 - 0.4147 * T + 6.295e-4 * T**2 + 1.075e-5 * T**3
|
||||
tau = (1 / (2 * np.pi)) * (1.1109e-10 - 3.824e-12 * T + 6.938e-14 * T**2 -
|
||||
5.096e-16 * T**3)
|
||||
|
||||
delta = 25 - T
|
||||
beta = (2.033e-2 + 1.266e-4 * delta + 2.464e-6 * delta**2 - S *
|
||||
(1.849e-5 - 2.551e-7 * delta + 2.551e-8 * delta**2))
|
||||
sig_25s = S * (0.182521 - 1.46192e-3 * S + 2.09324e-5 * S**2 - 1.28205e-7 * S**3)
|
||||
sig = sig_25s * np.exp(-delta * beta)
|
||||
|
||||
return eri, er, tau, sig
|
||||
|
||||
|
||||
def create_water(G, T=25, S=0):
|
||||
"""Creates single-pole Debye model for water with specified temperature and
|
||||
salinity.
|
||||
|
||||
Args:
|
||||
T: float for temperature of water (degrees centigrade).
|
||||
S: float for salinity of water (part per thousand).
|
||||
G: FDTDGrid class describing a grid in a model.
|
||||
"""
|
||||
|
||||
eri, er, tau, sig = calculate_water_properties(T, S)
|
||||
|
||||
m = DispersiveMaterial(len(G.materials), 'water')
|
||||
m.averagable = False
|
||||
m.type = 'builtin, debye'
|
||||
m.poles = 1
|
||||
m.er = eri
|
||||
m.se = sig
|
||||
m.deltaer.append(er - eri)
|
||||
m.tau.append(tau)
|
||||
G.materials.append(m)
|
||||
if config.get_model_config().materials['maxpoles'] == 0:
|
||||
config.get_model_config().materials['maxpoles'] = 1
|
||||
|
||||
|
||||
def create_grass(G):
|
||||
"""Creates single-pole Debye model for grass
|
||||
|
||||
Args:
|
||||
G: FDTDGrid class describing a grid in a model.
|
||||
"""
|
||||
|
||||
# Properties of grass from: http://dx.doi.org/10.1007/BF00902994
|
||||
er = 18.5087
|
||||
eri = 12.7174
|
||||
tau = 1.0793e-11
|
||||
sig = 0
|
||||
|
||||
m = DispersiveMaterial(len(G.materials), 'grass')
|
||||
m.averagable = False
|
||||
m.type = 'builtin, debye'
|
||||
m.poles = 1
|
||||
m.er = eri
|
||||
m.se = sig
|
||||
m.deltaer.append(er - eri)
|
||||
m.tau.append(tau)
|
||||
G.materials.append(m)
|
||||
if config.get_model_config().materials['maxpoles'] == 0:
|
||||
config.get_model_config().materials['maxpoles'] = 1
|
||||
|
||||
|
||||
def process_materials(G):
|
||||
@@ -283,392 +650,4 @@ def process_materials(G):
|
||||
materialtext.append(material.averagable)
|
||||
materialsdata.append(materialtext)
|
||||
|
||||
return materialsdata
|
||||
|
||||
|
||||
class PeplinskiSoil:
|
||||
"""Soil objects that are characterised according to a mixing model
|
||||
by Peplinski (http://dx.doi.org/10.1109/36.387598).
|
||||
"""
|
||||
|
||||
def __init__(self, ID, sandfraction, clayfraction, bulkdensity,
|
||||
sandpartdensity, watervolfraction):
|
||||
"""
|
||||
Args:
|
||||
ID: string for name of the soil.
|
||||
sandfraction: float of sand fraction of the soil.
|
||||
clayfraction: float of clay fraction of the soil.
|
||||
bulkdensity: float of bulk density of the soil (g/cm3).
|
||||
sandpartdensity: float of density of the sand particles in the
|
||||
soil (g/cm3).
|
||||
watervolfraction: tuple of floats of two numbers that specify a
|
||||
range for the volumetric water fraction of the
|
||||
soil.
|
||||
"""
|
||||
|
||||
self.ID = ID
|
||||
self.S = sandfraction
|
||||
self.C = clayfraction
|
||||
self.rb = bulkdensity
|
||||
self.rs = sandpartdensity
|
||||
self.mu = watervolfraction
|
||||
self.startmaterialnum = 0 #This is not used anymore and code that uses it can be removed
|
||||
# store all of the material IDs in a list instead of storing only the first number of the material
|
||||
# and assume that all must be sequentially numbered. This allows for more general mixing models
|
||||
self.matID = []
|
||||
|
||||
def calculate_properties(self, nbins, G):
|
||||
"""Calculates the real and imaginery part of a Debye model for the soil
|
||||
as well as a conductivity. It uses an approximation to a semi-empirical
|
||||
model (http://dx.doi.org/10.1109/36.387598).
|
||||
|
||||
Args:
|
||||
nbins: int for number of bins to use to create the different materials.
|
||||
G: FDTDGrid class describing a grid in a model.
|
||||
"""
|
||||
|
||||
# Debye model properties of water at 25C & zero salinity
|
||||
T = 25
|
||||
S = 0
|
||||
watereri, waterer, watertau, watersig = calculate_water_properties(T, S)
|
||||
f = 1.3e9
|
||||
w = 2 * np.pi * f
|
||||
erealw = watereri + ((waterer - watereri) / (1 + (w * watertau)**2))
|
||||
|
||||
a = 0.65 # Experimentally derived constant
|
||||
es = (1.01 + 0.44 * self.rs)**2 - 0.062 # Relative permittivity of sand particles
|
||||
b1 = 1.2748 - 0.519 * self.S - 0.152 * self.C
|
||||
b2 = 1.33797 - 0.603 * self.S - 0.166 * self.C
|
||||
|
||||
# For frequencies in the range 0.3GHz to 1.3GHz
|
||||
sigf = 0.0467 + 0.2204 * self.rb - 0.411 * self.S + 0.6614 * self.C
|
||||
# For frequencies in the range 1.4GHz to 18GHz
|
||||
# sigf = -1.645 + 1.939 * self.rb - 2.25622 * self.S + 1.594 * self.C
|
||||
|
||||
# Generate a set of bins based on the given volumetric water fraction
|
||||
# values. Changed to make sure mid points are contained completely within the ranges.
|
||||
# The limiting values of the ranges are not included in this.
|
||||
|
||||
#mubins = np.linspace(self.mu[0], self.mu[1], nbins)
|
||||
mubins = np.linspace(self.mu[0], self.mu[1], nbins+1)
|
||||
# Generate a range of volumetric water fraction values the mid-point of
|
||||
# each bin to make materials from
|
||||
#mumaterials = mubins + (mubins[1] - mubins[0]) / 2
|
||||
mumaterials = 0.5*(mubins[1:nbins+1] + mubins[0:nbins])
|
||||
|
||||
|
||||
# Create an iterator
|
||||
muiter = np.nditer(mumaterials, flags=['c_index'])
|
||||
while not muiter.finished:
|
||||
# Real part for frequencies in the range 1.4GHz to 18GHz
|
||||
er = (1 + (self.rb / self.rs) * ((es**a) - 1) + (muiter[0]**b1 * erealw**a)
|
||||
- muiter[0]) ** (1 / a)
|
||||
# Real part for frequencies in the range 0.3GHz to 1.3GHz (linear
|
||||
# correction to 1.4-18GHz value)
|
||||
er = 1.15 * er - 0.68
|
||||
|
||||
# Permittivity at infinite frequency
|
||||
eri = er - (muiter[0]**(b2 / a) * DispersiveMaterial.waterdeltaer)
|
||||
|
||||
# Effective conductivity
|
||||
sig = muiter[0]**(b2 / a) * ((sigf * (self.rs - self.rb)) / (self.rs * muiter[0]))
|
||||
|
||||
# Check to see if the material already exists before creating a new one
|
||||
requiredID = '|{:.4f}|'.format(float(muiter[0]))
|
||||
material = next((x for x in G.materials if x.ID == requiredID), None)
|
||||
if muiter.index == 0:
|
||||
if material:
|
||||
self.startmaterialnum = material.numID
|
||||
self.matID.append(material.numID)
|
||||
else:
|
||||
self.startmaterialnum = len(G.materials)
|
||||
if not material:
|
||||
m = DispersiveMaterial(len(G.materials), requiredID)
|
||||
m.type = 'debye'
|
||||
m.averagable = False
|
||||
m.poles = 1
|
||||
if m.poles > config.get_model_config().materials['maxpoles']:
|
||||
config.get_model_config().materials['maxpoles'] = m.poles
|
||||
m.er = eri
|
||||
m.se = sig
|
||||
m.deltaer.append(er - eri)
|
||||
m.tau.append(DispersiveMaterial.watertau)
|
||||
G.materials.append(m)
|
||||
self.matID.append(m.numID)
|
||||
|
||||
muiter.iternext()
|
||||
|
||||
|
||||
|
||||
class RangeMaterial:
|
||||
"""Material defined with a given range of parameters to be used for
|
||||
factal spatial disttibutions
|
||||
"""
|
||||
|
||||
def __init__(self, ID, er_range, sigma_range, mu_range, ro_range):
|
||||
"""
|
||||
Args:
|
||||
ID: string for name of the material.
|
||||
er_range: tuple of floats for relative permittivity range of the material.
|
||||
sigma_range: tuple of floats for electric conductivity range of the material.
|
||||
mu_range: tuple of floats for magnetic permeability of material.
|
||||
ro_range: tuple of floats for magnetic loss range of material.
|
||||
"""
|
||||
|
||||
self.ID = ID
|
||||
self.er = er_range
|
||||
self.sig = sigma_range
|
||||
self.mu = mu_range
|
||||
self.ro = ro_range
|
||||
self.startmaterialnum = 0 #This is not really needed anymore and code that uses it can be removed.
|
||||
# store all of the material IDs in a list instead of storing only the first number of the material
|
||||
# and assume that all must be sequentially numbered. This allows for more general mixing models
|
||||
self.matID = []
|
||||
|
||||
|
||||
def calculate_properties(self, nbins, G):
|
||||
"""Calculates the properties of the materials.
|
||||
|
||||
Args:
|
||||
nbins: int for number of bins to use to create the different materials.
|
||||
G: FDTDGrid class describing a grid in a model.
|
||||
"""
|
||||
|
||||
# Generate a set of relative permittivity bins based on the given range
|
||||
erbins = np.linspace(self.er[0], self.er[1], nbins+1)
|
||||
# Generate a range of relative permittivity values the mid-point of
|
||||
# each bin to make materials from
|
||||
#ermaterials = erbins + np.abs((erbins[1] - erbins[0])) / 2
|
||||
ermaterials = 0.5*(erbins[1:nbins+1] + erbins[0:nbins])
|
||||
|
||||
# Generate a set of conductivity bins based on the given range
|
||||
sigmabins = np.linspace(self.sig[0], self.sig[1], nbins+1)
|
||||
# Generate a range of conductivity values the mid-point of
|
||||
# each bin to make materials from
|
||||
#sigmamaterials = sigmabins + (sigmabins[1] - sigmabins[0]) / 2
|
||||
sigmamaterials = 0.5*(sigmabins[1:nbins+1] + sigmabins[0:nbins])
|
||||
|
||||
# Generate a set of magnetic permeability bins based on the given range
|
||||
mubins = np.linspace(self.mu[0], self.mu[1], nbins+1)
|
||||
# Generate a range of magnetic permeability values the mid-point of
|
||||
# each bin to make materials from
|
||||
#mumaterials = mubins + np.abs((mubins[1] - mubins[0])) / 2
|
||||
mumaterials = 0.5*(mubins[1:nbins+1] + mubins[0:nbins])
|
||||
|
||||
# Generate a set of magnetic loss bins based on the given range
|
||||
robins = np.linspace(self.ro[0], self.ro[1], nbins+1)
|
||||
# Generate a range of magnetic loss values the mid-point of
|
||||
# each bin to make materials from
|
||||
#romaterials = robins + np.abs((robins[1] - robins[0])) / 2
|
||||
romaterials = 0.5*(robins[1:nbins+1] + robins[0:nbins])
|
||||
|
||||
|
||||
# Iterate over the bins
|
||||
for iter in np.arange(0,nbins):
|
||||
|
||||
# Relative permittivity
|
||||
er = ermaterials[iter]
|
||||
|
||||
# Effective conductivity
|
||||
se = sigmamaterials[iter]
|
||||
|
||||
# magnetic permeability
|
||||
mr = mumaterials[iter]
|
||||
|
||||
# magnetic loss
|
||||
sm = romaterials[iter]
|
||||
|
||||
# Check to see if the material already exists before creating a new one
|
||||
requiredID = '|{:.4f}+{:.4f}+{:.4f}+{:.4f}|'.format(float(er),float(se),float(mr),float(sm))
|
||||
material = next((x for x in G.materials if x.ID == requiredID), None)
|
||||
if iter == 0:
|
||||
if material:
|
||||
self.startmaterialnum = material.numID
|
||||
self.matID.append(material.numID)
|
||||
else:
|
||||
self.startmaterialnum = len(G.materials)
|
||||
if not material:
|
||||
m = Material(len(G.materials), requiredID)
|
||||
m.type = ''
|
||||
m.averagable = True
|
||||
m.er = er
|
||||
m.se = se
|
||||
m.mr = mr
|
||||
m.sm = sm
|
||||
G.materials.append(m)
|
||||
self.matID.append(m.numID)
|
||||
|
||||
|
||||
|
||||
class ListMaterial:
|
||||
"""A list of predefined materials to be used for
|
||||
factal spatial disttibutions. This command does not create new materials but collects them to be used in a
|
||||
stochastic distribution by a fractal box.
|
||||
"""
|
||||
|
||||
def __init__(self, ID, listofmaterials):
|
||||
"""
|
||||
Args:
|
||||
ID: string for name of the material.
|
||||
listofmaterials: A list of material IDs.
|
||||
|
||||
"""
|
||||
|
||||
self.ID = ID
|
||||
self.mat = listofmaterials
|
||||
self.startmaterialnum = 0 #This is not really needed anymore
|
||||
# store all of the material IDs in a list instead of storing only the first number of the material
|
||||
# and assume that all must be sequentially numbered. This allows for more general mixing models
|
||||
# this is important here as this model assumes predefined materials.
|
||||
self.matID = []
|
||||
|
||||
|
||||
def calculate_properties(self, nbins, G):
|
||||
"""Calculates the properties of the materials. No Debye is used but name kept the same as used in other
|
||||
class that needs Debye
|
||||
|
||||
Args:
|
||||
nbins: int for number of bins to use to create the different materials.
|
||||
G: FDTDGrid class describing a grid in a model.
|
||||
"""
|
||||
|
||||
|
||||
# Iterate over the bins
|
||||
for iter in np.arange(0,nbins):
|
||||
|
||||
# Check to see if the material already exists before creating a new one
|
||||
#requiredID = '|{:}_in_{:}|'.format((self.mat[iter]),(self.ID))
|
||||
requiredID = self.mat[iter]
|
||||
material = next((x for x in G.materials if x.ID == requiredID), None)
|
||||
self.matID.append(material.numID)
|
||||
|
||||
#if iter == 0:
|
||||
# if material:
|
||||
# self.startmaterialnum = material.numID
|
||||
# else:
|
||||
# self.startmaterialnum = len(G.materials)
|
||||
|
||||
#if not material:
|
||||
# temp = next((x for x in G.materials if x.ID == self.mat[iter]), None)
|
||||
# m = copy.deepcopy(temp) #This needs to import copy in order to work
|
||||
# m.ID = requiredID
|
||||
# m.numID = len(G.materials)
|
||||
# G.materials.append(m)
|
||||
|
||||
|
||||
if not material:
|
||||
logger.exception(self.__str__() + f' material(s) {material} do not exist')
|
||||
raise ValueError
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def create_built_in_materials(G):
|
||||
"""Creates pre-defined (built-in) materials.
|
||||
|
||||
Args:
|
||||
G: FDTDGrid class describing a grid in a model.
|
||||
"""
|
||||
|
||||
G.n_built_in_materials = len(G.materials)
|
||||
|
||||
m = Material(0, 'pec')
|
||||
m.se = float('inf')
|
||||
m.type = 'builtin'
|
||||
m.averagable = False
|
||||
G.materials.append(m)
|
||||
|
||||
m = Material(1, 'free_space')
|
||||
m.type = 'builtin'
|
||||
G.materials.append(m)
|
||||
|
||||
G.n_built_in_materials = len(G.materials)
|
||||
|
||||
|
||||
def calculate_water_properties(T=25, S=0):
|
||||
"""Get extended Debye model properties for water.
|
||||
|
||||
Args:
|
||||
T: float for emperature of water (degrees centigrade).
|
||||
S: float for salinity of water (part per thousand).
|
||||
|
||||
Returns:
|
||||
eri: float for relative permittivity at infinite frequency.
|
||||
er: float for static relative permittivity.
|
||||
tau: float for relaxation time (s).
|
||||
sig: float for conductivity (Siemens/m).
|
||||
"""
|
||||
|
||||
# Properties of water from: https://doi.org/10.1109/JOE.1977.1145319
|
||||
eri = 4.9
|
||||
er = 88.045 - 0.4147 * T + 6.295e-4 * T**2 + 1.075e-5 * T**3
|
||||
tau = (1 / (2 * np.pi)) * (1.1109e-10 - 3.824e-12 * T + 6.938e-14 * T**2 -
|
||||
5.096e-16 * T**3)
|
||||
|
||||
delta = 25 - T
|
||||
beta = (2.033e-2 + 1.266e-4 * delta + 2.464e-6 * delta**2 - S *
|
||||
(1.849e-5 - 2.551e-7 * delta + 2.551e-8 * delta**2))
|
||||
sig_25s = S * (0.182521 - 1.46192e-3 * S + 2.09324e-5 * S**2 - 1.28205e-7 * S**3)
|
||||
sig = sig_25s * np.exp(-delta * beta)
|
||||
|
||||
return eri, er, tau, sig
|
||||
|
||||
|
||||
def create_water(G, T=25, S=0):
|
||||
"""Creates single-pole Debye model for water with specified temperature and
|
||||
salinity.
|
||||
|
||||
Args:
|
||||
T: float for temperature of water (degrees centigrade).
|
||||
S: float for salinity of water (part per thousand).
|
||||
G: FDTDGrid class describing a grid in a model.
|
||||
"""
|
||||
|
||||
eri, er, tau, sig = calculate_water_properties(T, S)
|
||||
|
||||
G.n_built_in_materials = len(G.materials)
|
||||
|
||||
m = DispersiveMaterial(len(G.materials), 'water')
|
||||
m.averagable = False
|
||||
m.type = 'builtin, debye'
|
||||
m.poles = 1
|
||||
m.er = eri
|
||||
m.se = sig
|
||||
m.deltaer.append(er - eri)
|
||||
m.tau.append(tau)
|
||||
G.materials.append(m)
|
||||
if config.get_model_config().materials['maxpoles'] == 0:
|
||||
config.get_model_config().materials['maxpoles'] = 1
|
||||
|
||||
G.n_built_in_materials = len(G.materials)
|
||||
|
||||
|
||||
def create_grass(G):
|
||||
"""Creates single-pole Debye model for grass
|
||||
|
||||
Args:
|
||||
G: FDTDGrid class describing a grid in a model.
|
||||
"""
|
||||
|
||||
# Properties of grass from: http://dx.doi.org/10.1007/BF00902994
|
||||
er = 18.5087
|
||||
eri = 12.7174
|
||||
tau = 1.0793e-11
|
||||
sig = 0
|
||||
|
||||
G.n_built_in_materials = len(G.materials)
|
||||
|
||||
m = DispersiveMaterial(len(G.materials), 'grass')
|
||||
m.averagable = False
|
||||
m.type = 'builtin, debye'
|
||||
m.poles = 1
|
||||
m.er = eri
|
||||
m.se = sig
|
||||
m.deltaer.append(er - eri)
|
||||
m.tau.append(tau)
|
||||
G.materials.append(m)
|
||||
if config.get_model_config().materials['maxpoles'] == 0:
|
||||
config.get_model_config().materials['maxpoles'] = 1
|
||||
|
||||
G.n_built_in_materials = len(G.materials)
|
||||
return materialsdata
|
@@ -123,7 +123,7 @@ class SubGridBase(UserObjectMulti):
|
||||
self.subgrid = sg
|
||||
|
||||
# Copy over built in materials
|
||||
sg.materials = [copy(m) for m in grid.materials if m.numID in range(0, grid.n_built_in_materials + 1)]
|
||||
sg.materials = [copy(m) for m in grid.materials if m.type == 'builtin']
|
||||
|
||||
# Don't mix and match different subgrid types
|
||||
for sg_made in grid.subgrids:
|
||||
|
在新工单中引用
屏蔽一个用户