你已经派生过 gprMax
镜像自地址
https://gitee.com/sunhf/gprMax.git
已同步 2025-08-07 04:56:51 +08:00
Added more informative messages (via analysis) on numerical dispersion.
这个提交包含在:
@@ -38,7 +38,7 @@ from .constants import c, e0, m0, z0
|
|||||||
from .exceptions import GeneralError
|
from .exceptions import GeneralError
|
||||||
from .fields_outputs import write_hdf5_outputfile
|
from .fields_outputs import write_hdf5_outputfile
|
||||||
from .fields_update import update_electric, update_magnetic, update_electric_dispersive_multipole_A, update_electric_dispersive_multipole_B, update_electric_dispersive_1pole_A, update_electric_dispersive_1pole_B
|
from .fields_update import update_electric, update_magnetic, update_electric_dispersive_multipole_A, update_electric_dispersive_multipole_B, update_electric_dispersive_1pole_A, update_electric_dispersive_1pole_B
|
||||||
from .grid import FDTDGrid, dispersion_check
|
from .grid import FDTDGrid, dispersion_analysis
|
||||||
from .input_cmds_geometry import process_geometrycmds
|
from .input_cmds_geometry import process_geometrycmds
|
||||||
from .input_cmds_file import process_python_include_code, write_processed_file, check_cmd_names
|
from .input_cmds_file import process_python_include_code, write_processed_file, check_cmd_names
|
||||||
from .input_cmds_multiuse import process_multicmds
|
from .input_cmds_multiuse import process_multicmds
|
||||||
@@ -46,7 +46,7 @@ from .input_cmds_singleuse import process_singlecmds
|
|||||||
from .materials import Material, process_materials
|
from .materials import Material, process_materials
|
||||||
from .pml import build_pmls
|
from .pml import build_pmls
|
||||||
from .receivers import store_outputs
|
from .receivers import store_outputs
|
||||||
from .utilities import logo, human_size, get_machine_cpu_os, get_terminal_width
|
from .utilities import logo, human_size, get_machine_cpu_os, get_terminal_width, round_value
|
||||||
from .yee_cell_build import build_electric_components, build_magnetic_components
|
from .yee_cell_build import build_electric_components, build_magnetic_components
|
||||||
|
|
||||||
|
|
||||||
@@ -418,9 +418,11 @@ def run_model(args, modelrun, numbermodelruns, inputfile, usernamespace):
|
|||||||
print(materialstable.table)
|
print(materialstable.table)
|
||||||
|
|
||||||
# Check to see if numerical dispersion might be a problem
|
# Check to see if numerical dispersion might be a problem
|
||||||
resolution = dispersion_check(G)
|
deltavp, N, material, maxfreq = dispersion_analysis(G)
|
||||||
if resolution and max((G.dx, G.dy, G.dz)) > resolution:
|
if deltavp and np.abs(deltavp) > G.maxnumericaldisp:
|
||||||
print(Fore.RED + '\nWARNING: Potential numerical dispersion in the simulation. Check the spatial discretisation against the smallest wavelength present. Suggested resolution <{:g}m'.format(resolution) + Style.RESET_ALL)
|
print(Fore.RED + "\nWARNING: Potentially significant numerical dispersion. Largest physical phase-velocity error is {:.2f}% in material '{}' with wavelength sampled by {} cells (maximum significant frequency {:g}Hz)".format(deltavp, material.ID, round_value(N), maxfreq) + Style.RESET_ALL)
|
||||||
|
elif deltavp:
|
||||||
|
print("\nNumerical dispersion analysis: largest physical phase-velocity error is {:.2f}% in material '{}' with wavelength sampled by {} cells (maximum significant frequency {:g}Hz)".format(deltavp, material.ID, round_value(N), maxfreq))
|
||||||
|
|
||||||
# If geometry information to be reused between model runs
|
# If geometry information to be reused between model runs
|
||||||
else:
|
else:
|
||||||
|
@@ -75,6 +75,12 @@ class FDTDGrid(Grid):
|
|||||||
self.title = ''
|
self.title = ''
|
||||||
self.messages = True
|
self.messages = True
|
||||||
self.tqdmdisable = False
|
self.tqdmdisable = False
|
||||||
|
|
||||||
|
# Threshold (dB) down from maximum power (0dB) of main frequency used to calculate highest frequency for disperion analysis
|
||||||
|
self.highestfreqthres = 60
|
||||||
|
# Maximum allowable percentage physical phase-velocity phase error
|
||||||
|
self.maxnumericaldisp = 2
|
||||||
|
|
||||||
self.nx = 0
|
self.nx = 0
|
||||||
self.ny = 0
|
self.ny = 0
|
||||||
self.nz = 0
|
self.nz = 0
|
||||||
@@ -136,19 +142,16 @@ class FDTDGrid(Grid):
|
|||||||
self.updatecoeffsdispersive = np.zeros((len(self.materials), 3 * Material.maxpoles), dtype=complextype)
|
self.updatecoeffsdispersive = np.zeros((len(self.materials), 3 * Material.maxpoles), dtype=complextype)
|
||||||
|
|
||||||
|
|
||||||
def dispersion_check(G):
|
def dispersion_analysis(G):
|
||||||
"""Check for potential numerical dispersion. Is the smallest wavelength present in the simulation discretised by at least a factor of 10
|
"""Analysis of numerical dispersion (Taflove et al, 2005, p112) - worse case of maximum frequency and minimum wavelength
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
G (class): Grid class instance - holds essential parameters describing the model.
|
G (class): Grid class instance - holds essential parameters describing the model.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
resolution (float): Potential numerical dispersion
|
deltavp (float): Percentage difference between true and numerical phase velocity
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Minimum number of spatial steps to resolve smallest wavelength
|
|
||||||
resolvedsteps = 10
|
|
||||||
|
|
||||||
# Find maximum frequency
|
# Find maximum frequency
|
||||||
maxfreqs = []
|
maxfreqs = []
|
||||||
for waveform in G.waveforms:
|
for waveform in G.waveforms:
|
||||||
@@ -185,7 +188,7 @@ def dispersion_check(G):
|
|||||||
power -= np.amax(power)
|
power -= np.amax(power)
|
||||||
|
|
||||||
# Set maximum frequency to -60dB from maximum power, ignoring DC value
|
# Set maximum frequency to -60dB from maximum power, ignoring DC value
|
||||||
freq = np.where((np.amax(power[1::]) - power[1::]) > 60)[0][0] + 1
|
freq = np.where((np.amax(power[1::]) - power[1::]) > G.highestfreqthres)[0][0] + 1
|
||||||
maxfreqs.append(freqs[freq])
|
maxfreqs.append(freqs[freq])
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@@ -194,23 +197,36 @@ def dispersion_check(G):
|
|||||||
if maxfreqs:
|
if maxfreqs:
|
||||||
maxfreq = max(maxfreqs)
|
maxfreq = max(maxfreqs)
|
||||||
|
|
||||||
# Find minimum wavelength
|
# Find minimum wavelength (material with maximum permittivity)
|
||||||
ers = [material.er for material in G.materials]
|
ers = [x.er for x in G.materials if x.ID != 'pec']
|
||||||
maxer = max(ers)
|
maxer = max(ers)
|
||||||
|
material = next(x for x in G.materials if x.er == maxer and x.ID != 'pec')
|
||||||
|
|
||||||
# Minimum velocity
|
# Minimum velocity
|
||||||
minvelocity = c / np.sqrt(maxer)
|
minvelocity = c / np.sqrt(maxer)
|
||||||
|
|
||||||
# Minimum wavelength
|
# Minimum wavelength
|
||||||
minwavelength = minvelocity / maxfreq
|
minwavelength = minvelocity / maxfreq
|
||||||
|
|
||||||
# Resolution of minimum wavelength
|
# Maximum spatial step
|
||||||
resolution = minwavelength / resolvedsteps
|
delta = max(G.dx, G.dy, G.dz)
|
||||||
|
|
||||||
|
# Courant stability factor
|
||||||
|
S = (c * G.dt) / delta
|
||||||
|
|
||||||
|
# Grid sampling density
|
||||||
|
N = minwavelength / delta
|
||||||
|
|
||||||
|
# Numerical phase velocity
|
||||||
|
vp = np.pi / (N * np.arcsin((1 / S) * np.sin((np.pi * S) / N)))
|
||||||
|
|
||||||
|
# Physical phase velocity error (percentage)
|
||||||
|
deltavp = (((vp * c) - c) / c) * 100
|
||||||
|
|
||||||
else:
|
else:
|
||||||
resolution = False
|
deltavp, N, material, maxfreq = False
|
||||||
|
|
||||||
return resolution
|
return deltavp, N, material, maxfreq
|
||||||
|
|
||||||
|
|
||||||
def get_other_directions(direction):
|
def get_other_directions(direction):
|
||||||
|
在新工单中引用
屏蔽一个用户