你已经派生过 gprMax
镜像自地址
https://gitee.com/sunhf/gprMax.git
已同步 2025-08-06 20:46:52 +08:00
Overhaul of message printing, materials table printing, and progress bars.
这个提交包含在:
@@ -29,6 +29,7 @@ import sys
|
|||||||
from time import perf_counter
|
from time import perf_counter
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
from terminaltables import AsciiTable
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
|
|
||||||
from ._version import __version__
|
from ._version import __version__
|
||||||
@@ -40,7 +41,7 @@ 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
|
||||||
from .input_cmds_singleuse import process_singlecmds
|
from .input_cmds_singleuse import process_singlecmds
|
||||||
from .materials import Material
|
from .materials import Material, process_materials
|
||||||
from .pml import build_pmls, update_electric_pml, update_magnetic_pml
|
from .pml import build_pmls, update_electric_pml, update_magnetic_pml
|
||||||
from .receivers import store_outputs
|
from .receivers import store_outputs
|
||||||
from .utilities import logo, human_size
|
from .utilities import logo, human_size
|
||||||
@@ -113,7 +114,6 @@ def run_main(args):
|
|||||||
# Process for benchmarking simulation
|
# Process for benchmarking simulation
|
||||||
elif args.benchmark:
|
elif args.benchmark:
|
||||||
run_benchmark_sim(args, inputfile, usernamespace)
|
run_benchmark_sim(args, inputfile, usernamespace)
|
||||||
print('\nSimulation completed.\n{}\n'.format('-' * get_terminal_size()[0]))
|
|
||||||
|
|
||||||
# Process for standard simulation
|
# Process for standard simulation
|
||||||
else:
|
else:
|
||||||
@@ -128,8 +128,6 @@ def run_main(args):
|
|||||||
else:
|
else:
|
||||||
run_std_sim(args, numbermodelruns, inputfile, usernamespace)
|
run_std_sim(args, numbermodelruns, inputfile, usernamespace)
|
||||||
|
|
||||||
print('\nSimulation completed.\n{}\n'.format('-' * get_terminal_size()[0]))
|
|
||||||
|
|
||||||
|
|
||||||
def run_std_sim(args, numbermodelruns, inputfile, usernamespace, optparams=None):
|
def run_std_sim(args, numbermodelruns, inputfile, usernamespace, optparams=None):
|
||||||
"""Run standard simulation - models are run one after another and each model is parallelised with OpenMP
|
"""Run standard simulation - models are run one after another and each model is parallelised with OpenMP
|
||||||
@@ -153,7 +151,8 @@ def run_std_sim(args, numbermodelruns, inputfile, usernamespace, optparams=None)
|
|||||||
modelusernamespace = usernamespace
|
modelusernamespace = usernamespace
|
||||||
run_model(args, modelrun, numbermodelruns, inputfile, modelusernamespace)
|
run_model(args, modelrun, numbermodelruns, inputfile, modelusernamespace)
|
||||||
tsimend = perf_counter()
|
tsimend = perf_counter()
|
||||||
print('\nTotal simulation time [HH:MM:SS]: {}'.format(datetime.timedelta(seconds=int(tsimend - tsimstart))))
|
print('\n{}\nSimulation completed in [HH:MM:SS]: {}'.format('-' * get_terminal_size()[0], datetime.timedelta(seconds=int(tsimend - tsimstart))))
|
||||||
|
print('{}\n'.format('=' * get_terminal_size()[0]))
|
||||||
|
|
||||||
|
|
||||||
def run_benchmark_sim(args, inputfile, usernamespace):
|
def run_benchmark_sim(args, inputfile, usernamespace):
|
||||||
@@ -173,21 +172,19 @@ def run_benchmark_sim(args, inputfile, usernamespace):
|
|||||||
threads.append(int(thread))
|
threads.append(int(thread))
|
||||||
|
|
||||||
benchtimes = np.zeros(len(threads))
|
benchtimes = np.zeros(len(threads))
|
||||||
|
|
||||||
numbermodelruns = len(threads)
|
numbermodelruns = len(threads)
|
||||||
usernamespace['number_model_runs'] = numbermodelruns
|
usernamespace['number_model_runs'] = numbermodelruns
|
||||||
tsimstart = perf_counter()
|
|
||||||
for modelrun in range(1, numbermodelruns + 1):
|
for modelrun in range(1, numbermodelruns + 1):
|
||||||
os.environ['OMP_NUM_THREADS'] = str(threads[modelrun - 1])
|
os.environ['OMP_NUM_THREADS'] = str(threads[modelrun - 1])
|
||||||
tsolve = run_model(args, modelrun, numbermodelruns, inputfile, usernamespace)
|
tsolve = run_model(args, modelrun, numbermodelruns, inputfile, usernamespace)
|
||||||
benchtimes[modelrun - 1] = tsolve
|
benchtimes[modelrun - 1] = tsolve
|
||||||
tsimend = perf_counter()
|
|
||||||
|
|
||||||
# Save number of threads and benchmarking times to NumPy archive
|
# Save number of threads and benchmarking times to NumPy archive
|
||||||
threads = np.array(threads)
|
threads = np.array(threads)
|
||||||
np.savez(os.path.splitext(inputfile)[0], threads=threads, benchtimes=benchtimes, version=__version__)
|
np.savez(os.path.splitext(inputfile)[0], threads=threads, benchtimes=benchtimes, version=__version__)
|
||||||
|
|
||||||
print('\nTotal simulation time [HH:MM:SS]: {}'.format(datetime.timedelta(seconds=int(tsimend - tsimstart))))
|
print('\nSimulation completed\n{}\n'.format('=' * get_terminal_size()[0]))
|
||||||
|
|
||||||
|
|
||||||
def run_mpi_sim(args, numbermodelruns, inputfile, usernamespace, optparams=None):
|
def run_mpi_sim(args, numbermodelruns, inputfile, usernamespace, optparams=None):
|
||||||
@@ -212,7 +209,9 @@ def run_mpi_sim(args, numbermodelruns, inputfile, usernamespace, optparams=None)
|
|||||||
rank = comm.rank # rank of this process
|
rank = comm.rank # rank of this process
|
||||||
status = MPI.Status() # get MPI status object
|
status = MPI.Status() # get MPI status object
|
||||||
name = MPI.Get_processor_name() # get name of processor/host
|
name = MPI.Get_processor_name() # get name of processor/host
|
||||||
|
|
||||||
|
tsimstart = perf_counter()
|
||||||
|
|
||||||
if rank == 0: # Master process
|
if rank == 0: # Master process
|
||||||
modelrun = 1
|
modelrun = 1
|
||||||
numworkers = size - 1
|
numworkers = size - 1
|
||||||
@@ -263,6 +262,10 @@ def run_mpi_sim(args, numbermodelruns, inputfile, usernamespace, optparams=None)
|
|||||||
|
|
||||||
comm.send(None, dest=0, tag=tags.EXIT.value)
|
comm.send(None, dest=0, tag=tags.EXIT.value)
|
||||||
|
|
||||||
|
tsimend = perf_counter()
|
||||||
|
print('\n{}\nSimulation completed in [HH:MM:SS]: {}'.format('-' * get_terminal_size()[0], datetime.timedelta(seconds=int(tsimend - tsimstart))))
|
||||||
|
print('{}\n'.format('=' * get_terminal_size()[0]))
|
||||||
|
|
||||||
|
|
||||||
def run_model(args, modelrun, numbermodelruns, inputfile, usernamespace):
|
def run_model(args, modelrun, numbermodelruns, inputfile, usernamespace):
|
||||||
"""Runs a model - processes the input file; builds the Yee cells; calculates update coefficients; runs main FDTD loop.
|
"""Runs a model - processes the input file; builds the Yee cells; calculates update coefficients; runs main FDTD loop.
|
||||||
@@ -286,7 +289,7 @@ def run_model(args, modelrun, numbermodelruns, inputfile, usernamespace):
|
|||||||
|
|
||||||
# Normal model reading/building process; bypassed if geometry information to be reused
|
# Normal model reading/building process; bypassed if geometry information to be reused
|
||||||
if 'G' not in globals():
|
if 'G' not in globals():
|
||||||
print('{}\n\nModel input file: {}\n'.format('-' * get_terminal_size()[0], inputfile))
|
print('{}\n\nInput file: {}\n'.format('-' * get_terminal_size()[0], inputfile))
|
||||||
|
|
||||||
# Add the current model run to namespace that can be accessed by user in any Python code blocks in input file
|
# Add the current model run to namespace that can be accessed by user in any Python code blocks in input file
|
||||||
usernamespace['current_model_run'] = modelrun
|
usernamespace['current_model_run'] = modelrun
|
||||||
@@ -329,20 +332,20 @@ def run_model(args, modelrun, numbermodelruns, inputfile, usernamespace):
|
|||||||
G.initialise_field_arrays()
|
G.initialise_field_arrays()
|
||||||
|
|
||||||
# Process geometry commands in the order they were given
|
# Process geometry commands in the order they were given
|
||||||
tinputprocstart = perf_counter()
|
print()
|
||||||
process_geometrycmds(geometry, G)
|
process_geometrycmds(geometry, G)
|
||||||
tinputprocend = perf_counter()
|
|
||||||
print('\nInput file processed in [HH:MM:SS]: {}'.format(datetime.timedelta(seconds=int(tinputprocend - tinputprocstart))))
|
|
||||||
|
|
||||||
# Build the PML and calculate initial coefficients
|
# Build the PML and calculate initial coefficients
|
||||||
build_pmls(G)
|
build_pmls(G)
|
||||||
|
|
||||||
# Build the model, i.e. set the material properties (ID) for every edge of every Yee cell
|
# Build the model, i.e. set the material properties (ID) for every edge of every Yee cell
|
||||||
tbuildstart = perf_counter()
|
print()
|
||||||
|
pbar = tqdm(total=2, desc='Building FDTD grid')
|
||||||
build_electric_components(G.solid, G.rigidE, G.ID, G)
|
build_electric_components(G.solid, G.rigidE, G.ID, G)
|
||||||
|
pbar.update()
|
||||||
build_magnetic_components(G.solid, G.rigidH, G.ID, G)
|
build_magnetic_components(G.solid, G.rigidH, G.ID, G)
|
||||||
tbuildend = perf_counter()
|
pbar.update()
|
||||||
print('\nModel built in [HH:MM:SS]: {}'.format(datetime.timedelta(seconds=int(tbuildend - tbuildstart))))
|
pbar.close()
|
||||||
|
|
||||||
# Process any voltage sources (that have resistance) to create a new material at the source location
|
# Process any voltage sources (that have resistance) to create a new material at the source location
|
||||||
for voltagesource in G.voltagesources:
|
for voltagesource in G.voltagesources:
|
||||||
@@ -355,38 +358,13 @@ def run_model(args, modelrun, numbermodelruns, inputfile, usernamespace):
|
|||||||
if Material.maxpoles != 0:
|
if Material.maxpoles != 0:
|
||||||
G.initialise_dispersive_arrays()
|
G.initialise_dispersive_arrays()
|
||||||
|
|
||||||
# Calculate update coefficients, store in arrays, and list materials in model
|
# Process complete list of materials - calculate update coefficients, store in arrays, and build text list of materials/properties
|
||||||
|
materialsdata = process_materials(G)
|
||||||
if G.messages:
|
if G.messages:
|
||||||
print('\nMaterials in model:\n')
|
materialstable = AsciiTable(materialsdata)
|
||||||
print('ID\tName\t\tProperties')
|
materialstable.outer_border = False
|
||||||
print('{}'.format('-' * 80))
|
materialstable.justify_columns[0] = 'right'
|
||||||
for material in G.materials:
|
print(materialstable.table)
|
||||||
|
|
||||||
# Calculate update coefficients for material
|
|
||||||
material.calculate_update_coeffsE(G)
|
|
||||||
material.calculate_update_coeffsH(G)
|
|
||||||
|
|
||||||
# Store all update coefficients together
|
|
||||||
G.updatecoeffsE[material.numID, :] = material.CA, material.CBx, material.CBy, material.CBz, material.srce
|
|
||||||
G.updatecoeffsH[material.numID, :] = material.DA, material.DBx, material.DBy, material.DBz, material.srcm
|
|
||||||
|
|
||||||
# Store coefficients for any dispersive materials
|
|
||||||
if Material.maxpoles != 0:
|
|
||||||
z = 0
|
|
||||||
for pole in range(Material.maxpoles):
|
|
||||||
G.updatecoeffsdispersive[material.numID, z:z + 3] = e0 * material.eqt2[pole], material.eqt[pole], material.zt[pole]
|
|
||||||
z += 3
|
|
||||||
|
|
||||||
if G.messages:
|
|
||||||
if material.deltaer and material.tau:
|
|
||||||
tmp = 'delta_epsr={}, tau={} secs; '.format(', '.join('{:g}'.format(deltaer) for deltaer in material.deltaer), ', '.join('{:g}'.format(tau) for tau in material.tau))
|
|
||||||
else:
|
|
||||||
tmp = ''
|
|
||||||
if material.average:
|
|
||||||
dielectricsmoothing = 'dielectric smoothing permitted.'
|
|
||||||
else:
|
|
||||||
dielectricsmoothing = 'dielectric smoothing not permitted.'
|
|
||||||
print('{:3}\t{:12}\tepsr={:g}, sig={:g} S/m; mur={:g}, sig*={:g} S/m; '.format(material.numID, material.ID, material.er, material.se, material.mr, material.sm) + tmp + dielectricsmoothing)
|
|
||||||
|
|
||||||
# Check to see if numerical dispersion might be a problem
|
# Check to see if numerical dispersion might be a problem
|
||||||
resolution = dispersion_check(G)
|
resolution = dispersion_check(G)
|
||||||
@@ -395,6 +373,8 @@ def run_model(args, modelrun, numbermodelruns, inputfile, usernamespace):
|
|||||||
|
|
||||||
# If geometry information to be reused between model runs
|
# If geometry information to be reused between model runs
|
||||||
else:
|
else:
|
||||||
|
print('{}\nInput not re-processed.'.format('-' * get_terminal_size()[0]))
|
||||||
|
|
||||||
# Clear arrays for field components
|
# Clear arrays for field components
|
||||||
G.initialise_field_arrays()
|
G.initialise_field_arrays()
|
||||||
|
|
||||||
@@ -424,12 +404,10 @@ def run_model(args, modelrun, numbermodelruns, inputfile, usernamespace):
|
|||||||
if not G.geometryviews and args.geometry_only:
|
if not G.geometryviews and args.geometry_only:
|
||||||
raise GeneralError('No geometry views found.')
|
raise GeneralError('No geometry views found.')
|
||||||
elif G.geometryviews:
|
elif G.geometryviews:
|
||||||
tgeostart = perf_counter()
|
print()
|
||||||
for geometryview in G.geometryviews:
|
for geometryview in tqdm(G.geometryviews, desc='Writing geometry file(s)'):
|
||||||
geometryview.write_vtk(modelrun, numbermodelruns, G)
|
geometryview.write_vtk(modelrun, numbermodelruns, G)
|
||||||
# geometryview.write_xdmf(modelrun, numbermodelruns, G)
|
# geometryview.write_xdmf(modelrun, numbermodelruns, G)
|
||||||
tgeoend = perf_counter()
|
|
||||||
print('\nGeometry file(s) written in [HH:MM:SS]: {}'.format(datetime.timedelta(seconds=int(tgeoend - tgeostart))))
|
|
||||||
|
|
||||||
# Run simulation (if not doing geometry only)
|
# Run simulation (if not doing geometry only)
|
||||||
if not args.geometry_only:
|
if not args.geometry_only:
|
||||||
@@ -438,13 +416,13 @@ def run_model(args, modelrun, numbermodelruns, inputfile, usernamespace):
|
|||||||
for snapshot in G.snapshots:
|
for snapshot in G.snapshots:
|
||||||
snapshot.prepare_vtk_imagedata(modelrun, numbermodelruns, G)
|
snapshot.prepare_vtk_imagedata(modelrun, numbermodelruns, G)
|
||||||
|
|
||||||
# Prepare output file
|
# Output filename
|
||||||
inputfileparts = os.path.splitext(inputfile)
|
inputfileparts = os.path.splitext(inputfile)
|
||||||
if numbermodelruns == 1:
|
if numbermodelruns == 1:
|
||||||
outputfile = inputfileparts[0] + '.out'
|
outputfile = inputfileparts[0] + '.out'
|
||||||
else:
|
else:
|
||||||
outputfile = inputfileparts[0] + str(modelrun) + '.out'
|
outputfile = inputfileparts[0] + str(modelrun) + '.out'
|
||||||
print('\nOutput to file: {}\n'.format(outputfile))
|
print('\nOutput file: {}\n'.format(outputfile))
|
||||||
|
|
||||||
####################################
|
####################################
|
||||||
# Start - Main FDTD calculations #
|
# Start - Main FDTD calculations #
|
||||||
@@ -454,7 +432,7 @@ def run_model(args, modelrun, numbermodelruns, inputfile, usernamespace):
|
|||||||
# Absolute time
|
# Absolute time
|
||||||
abstime = 0
|
abstime = 0
|
||||||
|
|
||||||
for timestep in tqdm(range(G.iterations)):
|
for timestep in tqdm(range(G.iterations), desc='Running simulation, model ' + str(modelrun) + ' of ' + str(numbermodelruns)):
|
||||||
# Store field component values for every receiver and transmission line
|
# Store field component values for every receiver and transmission line
|
||||||
store_outputs(timestep, G.Ex, G.Ey, G.Ez, G.Hx, G.Hy, G.Hz, G)
|
store_outputs(timestep, G.Ex, G.Ey, G.Ez, G.Hx, G.Hy, G.Hz, G)
|
||||||
|
|
||||||
@@ -505,7 +483,8 @@ def run_model(args, modelrun, numbermodelruns, inputfile, usernamespace):
|
|||||||
# Write an output file in HDF5 format
|
# Write an output file in HDF5 format
|
||||||
write_hdf5(outputfile, G.Ex, G.Ey, G.Ez, G.Hx, G.Hy, G.Hz, G)
|
write_hdf5(outputfile, G.Ex, G.Ey, G.Ez, G.Hx, G.Hy, G.Hz, G)
|
||||||
|
|
||||||
print('Memory (RAM) usage: ~{}'.format(human_size(p.memory_info().rss)))
|
if G.messages:
|
||||||
|
print('\nMemory (RAM) used: ~{}'.format(human_size(p.memory_info().rss)))
|
||||||
|
|
||||||
##################################
|
##################################
|
||||||
# End - Main FDTD calculations #
|
# End - Main FDTD calculations #
|
||||||
|
在新工单中引用
屏蔽一个用户