你已经派生过 gprMax
镜像自地址
https://gitee.com/sunhf/gprMax.git
已同步 2025-08-07 04:56:51 +08:00
First commit
这个提交包含在:
0
gprMax/__init__.py
普通文件
0
gprMax/__init__.py
普通文件
15
gprMax/__main__.py
普通文件
15
gprMax/__main__.py
普通文件
@@ -0,0 +1,15 @@
|
||||
"""gprMax.__main__: executed when gprMax directory is called as script."""
|
||||
|
||||
from .gprMax import main
|
||||
main()
|
||||
|
||||
# Code profiling
|
||||
# Time profiling
|
||||
#import cProfile, pstats
|
||||
#cProfile.run('main()','stats')
|
||||
#p = pstats.Stats('stats')
|
||||
#p.sort_stats('time').print_stats(50)
|
||||
|
||||
# Memory profiling - use in gprMax.py
|
||||
# from memory profiler import profile
|
||||
# add @profile before function to profile
|
29
gprMax/constants.pxd
普通文件
29
gprMax/constants.pxd
普通文件
@@ -0,0 +1,29 @@
|
||||
# Copyright (C) 2015: The University of Edinburgh
|
||||
# Authors: Craig Warren and Antonis Giannopoulos
|
||||
#
|
||||
# This file is part of gprMax.
|
||||
#
|
||||
# gprMax is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gprMax is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import numpy as np
|
||||
cimport numpy as np
|
||||
|
||||
# Data types:
|
||||
# Solid and ID arrays use 32-bit integers (0 to 4294967295)
|
||||
# Rigid arrays use 8-bit integers (the smallest available type to store true/false)
|
||||
# Fractal and dispersive coefficient arrays use complex numbers (complextype) which are represented as two floats
|
||||
# Main field arrays use floats (floattype) and complex numbers (complextype)
|
||||
|
||||
ctypedef np.float32_t floattype_t
|
||||
ctypedef np.complex64_t complextype_t
|
43
gprMax/constants.py
普通文件
43
gprMax/constants.py
普通文件
@@ -0,0 +1,43 @@
|
||||
# Copyright (C) 2015: The University of Edinburgh
|
||||
# Authors: Craig Warren and Antonis Giannopoulos
|
||||
#
|
||||
# This file is part of gprMax.
|
||||
#
|
||||
# gprMax is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gprMax is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import sys
|
||||
import decimal as d
|
||||
import numpy as np
|
||||
from pyfiglet import Figlet
|
||||
|
||||
# Data types:
|
||||
# Solid and ID arrays use 32-bit integers (0 to 4294967295)
|
||||
# Rigid arrays use 8-bit integers (the smallest available type to store true/false)
|
||||
# Fractal and dispersive coefficient arrays use complex numbers (complextype) which are represented as two floats
|
||||
# Main field arrays use floats (floattype) and complex numbers (complextype)
|
||||
|
||||
floattype = np.float32
|
||||
complextype = np.complex64
|
||||
|
||||
# Speed of light in vacuum (m/s)
|
||||
c = 2.9979245e8
|
||||
|
||||
# Permittivity of free space (F/m)
|
||||
e0 = 8.854187e-12
|
||||
|
||||
# Permeability of free space (H/m)
|
||||
m0 = 1.256637e-6
|
||||
|
||||
# Impedance of free space (Ohms)
|
||||
z0 = 376.7303134
|
20
gprMax/exceptions.py
普通文件
20
gprMax/exceptions.py
普通文件
@@ -0,0 +1,20 @@
|
||||
# Copyright (C) 2015: The University of Edinburgh
|
||||
# Authors: Craig Warren and Antonis Giannopoulos
|
||||
#
|
||||
# This file is part of gprMax.
|
||||
#
|
||||
# gprMax is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gprMax is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
class CmdInputError(ValueError):
|
||||
"""Handles errors in user specified commands. Subclasses the ValueError class."""
|
112
gprMax/fields_output.py
普通文件
112
gprMax/fields_output.py
普通文件
@@ -0,0 +1,112 @@
|
||||
import numpy as np
|
||||
# Copyright (C) 2015: The University of Edinburgh
|
||||
# Authors: Craig Warren and Antonis Giannopoulos
|
||||
#
|
||||
# This file is part of gprMax.
|
||||
#
|
||||
# gprMax is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gprMax is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import h5py
|
||||
|
||||
from .constants import floattype
|
||||
|
||||
|
||||
def prepare_output_file(outputfile, G):
|
||||
"""Prepares an output file in HDF5 format for writing.
|
||||
|
||||
Args:
|
||||
outputfile (str): Name of the output file.
|
||||
G (class): Grid class instance - holds essential parameters describing the model.
|
||||
|
||||
Returns:
|
||||
f (file object): File object for the file to be written to.
|
||||
"""
|
||||
|
||||
f = h5py.File(outputfile, 'w')
|
||||
f.attrs['Title'] = G.title
|
||||
f.attrs['Iterations'] = G.iterations
|
||||
f.attrs['dx, dy, dz'] = (G.dx, G.dy, G.dz)
|
||||
f.attrs['dt'] = G.dt
|
||||
f.attrs['txsteps'] = (G.txstepx, G.txstepy, G.txstepz)
|
||||
f.attrs['rxsteps'] = (G.rxstepx, G.rxstepy, G.rxstepz)
|
||||
f.attrs['ntx'] = len(G.voltagesources) + len(G.hertziandipoles) + len(G.magneticdipoles)
|
||||
f.attrs['nrx'] = len(G.rxs)
|
||||
|
||||
# Create groups for txs, rxs
|
||||
txs = f.create_group('/txs')
|
||||
rxs = f.create_group('/rxs')
|
||||
|
||||
# Add positional data for txs
|
||||
if G.txs: # G.txs will be populated only if this is being used for converting old style output file to HDF5 format
|
||||
txlist = G.txs
|
||||
else:
|
||||
txlist = G.voltagesources + G.hertziandipoles + G.magneticdipoles
|
||||
for txindex, tx in enumerate(txlist):
|
||||
tmp = f.create_group('/txs/tx' + str(txindex + 1))
|
||||
tmp['Position'] = (tx.positionx * G.dx, tx.positiony * G.dy, tx.positionz * G.dz)
|
||||
|
||||
# Add positional data for rxs
|
||||
for rxindex, rx in enumerate(G.rxs):
|
||||
tmp = f.create_group('/rxs/rx' + str(rxindex + 1))
|
||||
tmp['Position'] = (rx.positionx * G.dx, rx.positiony * G.dy, rx.positionz * G.dz)
|
||||
tmp['Ex'] = np.zeros(G.iterations, dtype=floattype)
|
||||
tmp['Ey'] = np.zeros(G.iterations, dtype=floattype)
|
||||
tmp['Ez'] = np.zeros(G.iterations, dtype=floattype)
|
||||
tmp['Hx'] = np.zeros(G.iterations, dtype=floattype)
|
||||
tmp['Hy'] = np.zeros(G.iterations, dtype=floattype)
|
||||
tmp['Hz'] = np.zeros(G.iterations, dtype=floattype)
|
||||
|
||||
return f
|
||||
|
||||
|
||||
def write_output(f, timestep, Ex, Ey, Ez, Hx, Hy, Hz, G):
|
||||
"""Writes field component values to an output file in HDF5 format.
|
||||
|
||||
Args:
|
||||
f (file object): File object for the file to be written to.
|
||||
timestep (int): Current iteration number.
|
||||
Ex, Ey, Ez, Hx, Hy, Hz (memory view): Current electric and magnetic field values.
|
||||
G (class): Grid class instance - holds essential parameters describing the model.
|
||||
"""
|
||||
|
||||
# Normal field writing from main
|
||||
if type(timestep) is not slice:
|
||||
# For each rx, write field component values at current timestep
|
||||
for rxindex, rx in enumerate(G.rxs):
|
||||
f['/rxs/rx' + str(rxindex + 1) + '/Ex'][timestep] = Ex[rx.positionx, rx.positiony, rx.positionz]
|
||||
f['/rxs/rx' + str(rxindex + 1) + '/Ey'][timestep] = Ey[rx.positionx, rx.positiony, rx.positionz]
|
||||
f['/rxs/rx' + str(rxindex + 1) + '/Ez'][timestep] = Ez[rx.positionx, rx.positiony, rx.positionz]
|
||||
f['/rxs/rx' + str(rxindex + 1) + '/Hx'][timestep] = Hx[rx.positionx, rx.positiony, rx.positionz]
|
||||
f['/rxs/rx' + str(rxindex + 1) + '/Hy'][timestep] = Hy[rx.positionx, rx.positiony, rx.positionz]
|
||||
f['/rxs/rx' + str(rxindex + 1) + '/Hz'][timestep] = Hz[rx.positionx, rx.positiony, rx.positionz]
|
||||
|
||||
# Field writing when converting old style output file to HDF5 format
|
||||
else:
|
||||
if len(G.rxs) == 1:
|
||||
f['/rxs/rx1/Ex'][timestep] = Ex
|
||||
f['/rxs/rx1/Ey'][timestep] = Ey
|
||||
f['/rxs/rx1/Ez'][timestep] = Ez
|
||||
f['/rxs/rx1/Hx'][timestep] = Hx
|
||||
f['/rxs/rx1/Hy'][timestep] = Hy
|
||||
f['/rxs/rx1/Hz'][timestep] = Hz
|
||||
else:
|
||||
for rxindex, rx in enumerate(G.rxs):
|
||||
f['/rxs/rx' + str(rxindex + 1) + '/Ex'][timestep] = Ex[:, rxindex]
|
||||
f['/rxs/rx' + str(rxindex + 1) + '/Ey'][timestep] = Ey[:, rxindex]
|
||||
f['/rxs/rx' + str(rxindex + 1) + '/Ez'][timestep] = Ez[:, rxindex]
|
||||
f['/rxs/rx' + str(rxindex + 1) + '/Hx'][timestep] = Hx[:, rxindex]
|
||||
f['/rxs/rx' + str(rxindex + 1) + '/Hy'][timestep] = Hy[:, rxindex]
|
||||
f['/rxs/rx' + str(rxindex + 1) + '/Hz'][timestep] = Hz[:, rxindex]
|
||||
|
||||
|
397
gprMax/fields_update.pyx
普通文件
397
gprMax/fields_update.pyx
普通文件
@@ -0,0 +1,397 @@
|
||||
# Copyright (C) 2015: The University of Edinburgh
|
||||
# Authors: Craig Warren and Antonis Giannopoulos
|
||||
#
|
||||
# This file is part of gprMax.
|
||||
#
|
||||
# gprMax is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gprMax is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import numpy as np
|
||||
cimport numpy as np
|
||||
from cython.parallel import prange
|
||||
from .constants cimport floattype_t, complextype_t
|
||||
|
||||
|
||||
#########################################
|
||||
# Electric field updates - Ex component #
|
||||
#########################################
|
||||
cpdef update_ex(int nx, int ny, int nz, int nthreads, floattype_t[:, :] updatecoeffsE, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Ex, floattype_t[:, :, :] Hy, floattype_t[:, :, :] Hz):
|
||||
"""This function updates the Ex field components.
|
||||
|
||||
Args:
|
||||
nx, ny, nz (int): Grid size in cells
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
"""
|
||||
|
||||
cdef int i, j, k, listIndex
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(1, ny):
|
||||
for k in range(1, nz):
|
||||
listIndex = ID[0, i, j, k]
|
||||
Ex[i, j, k] = updatecoeffsE[listIndex, 0] * Ex[i, j, k] + updatecoeffsE[listIndex, 2] * (Hz[i, j, k] - Hz[i, j - 1, k]) - updatecoeffsE[listIndex, 3] * (Hy[i, j, k] - Hy[i, j, k - 1])
|
||||
|
||||
|
||||
cpdef update_ex_dispersive_multipole_A(int nx, int ny, int nz, int nthreads, int maxpoles, floattype_t[:, :] updatecoeffsE, complextype_t[:, :] updatecoeffsdispersive, np.uint32_t[:, :, :, :] ID, complextype_t[:, :, :, :] Tx, floattype_t[:, :, :] Ex, floattype_t[:, :, :] Hy, floattype_t[:, :, :] Hz):
|
||||
"""This function updates the Ex field components when dispersive materials (with multiple poles) are present.
|
||||
|
||||
Args:
|
||||
nx, ny, nz (int): Grid size in cells
|
||||
maxpoles (int): Maximum number of poles
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, T, ID, E, H (memoryviews): Access to update coeffients, temporary, ID and field component arrays
|
||||
"""
|
||||
|
||||
cdef int i, j, k, listIndex, p
|
||||
cdef float phi = 0.0
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(1, ny):
|
||||
for k in range(1, nz):
|
||||
listIndex = ID[0, i, j, k]
|
||||
phi = 0.0
|
||||
for p in range(0, maxpoles):
|
||||
phi = phi + updatecoeffsdispersive[listIndex, p * 3].real * Tx[p, i, j, k].real
|
||||
Tx[p, i, j, k] = updatecoeffsdispersive[listIndex, 1 + (p * 3)] * Tx[p, i, j, k] + updatecoeffsdispersive[listIndex, 2 + (p * 3)] * Ex[i, j, k]
|
||||
Ex[i, j, k] = updatecoeffsE[listIndex, 0] * Ex[i, j, k] + updatecoeffsE[listIndex, 2] * (Hz[i, j, k] - Hz[i, j - 1, k]) - updatecoeffsE[listIndex, 3] * (Hy[i, j, k] - Hy[i, j, k - 1]) - updatecoeffsE[listIndex, 4] * phi
|
||||
|
||||
cpdef update_ex_dispersive_multipole_B(int nx, int ny, int nz, int nthreads, int maxpoles, complextype_t[:, :] updatecoeffsdispersive, np.uint32_t[:, :, :, :] ID, complextype_t[:, :, :, :] Tx, floattype_t[:, :, :] Ex):
|
||||
"""This function updates the Ex field components when dispersive materials (with multiple poles) are present.
|
||||
|
||||
Args:
|
||||
nx, ny, nz (int): Grid size in cells
|
||||
maxpoles (int): Maximum number of poles
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, T, ID, E (memoryviews): Access to update coeffients, temporary, ID and field component arrays
|
||||
"""
|
||||
|
||||
cdef int i, j, k, listIndex, p
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(1, ny):
|
||||
for k in range(1, nz):
|
||||
listIndex = ID[0, i, j, k]
|
||||
for p in range(0, maxpoles):
|
||||
Tx[p, i, j, k] = Tx[p, i, j, k] - updatecoeffsdispersive[listIndex, 2 + (p * 3)] * Ex[i, j, k]
|
||||
|
||||
|
||||
cpdef update_ex_dispersive_1pole_A(int nx, int ny, int nz, int nthreads, floattype_t[:, :] updatecoeffsE, complextype_t[:, :] updatecoeffsdispersive, np.uint32_t[:, :, :, :] ID, complextype_t[:, :, :, :] Tx, floattype_t[:, :, :] Ex, floattype_t[:, :, :] Hy, floattype_t[:, :, :] Hz):
|
||||
"""This function updates the Ex field components when dispersive materials (with 1 pole) are present.
|
||||
|
||||
Args:
|
||||
nx, ny, nz (int): Grid size in cells
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, T, ID, E, H (memoryviews): Access to update coeffients, temporary, ID and field component arrays
|
||||
"""
|
||||
|
||||
cdef int i, j, k, listIndex
|
||||
cdef float phi = 0.0
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(1, ny):
|
||||
for k in range(1, nz):
|
||||
listIndex = ID[0, i, j, k]
|
||||
phi = updatecoeffsdispersive[listIndex, 0].real * Tx[0, i, j, k].real
|
||||
Tx[0, i, j, k] = updatecoeffsdispersive[listIndex, 1] * Tx[0, i, j, k] + updatecoeffsdispersive[listIndex, 2] * Ex[i, j, k]
|
||||
Ex[i, j, k] = updatecoeffsE[listIndex, 0] * Ex[i, j, k] + updatecoeffsE[listIndex, 2] * (Hz[i, j, k] - Hz[i, j - 1, k]) - updatecoeffsE[listIndex, 3] * (Hy[i, j, k] - Hy[i, j, k - 1]) - updatecoeffsE[listIndex, 4] * phi
|
||||
|
||||
|
||||
cpdef update_ex_dispersive_1pole_B(int nx, int ny, int nz, int nthreads, complextype_t[:, :] updatecoeffsdispersive, np.uint32_t[:, :, :, :] ID, complextype_t[:, :, :, :] Tx, floattype_t[:, :, :] Ex):
|
||||
"""This function updates the Ex field components when dispersive materials (with 1 pole) are present.
|
||||
|
||||
Args:
|
||||
nx, ny, nz (int): Grid size in cells
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, T, ID, E (memoryviews): Access to update coeffients, temporary, ID and field component arrays
|
||||
"""
|
||||
|
||||
cdef int i, j, k, listIndex
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(1, ny):
|
||||
for k in range(1, nz):
|
||||
listIndex = ID[0, i, j, k]
|
||||
Tx[0, i, j, k] = Tx[0, i, j, k] - updatecoeffsdispersive[listIndex, 2] * Ex[i, j, k]
|
||||
|
||||
|
||||
#########################################
|
||||
# Electric field updates - Ey component #
|
||||
#########################################
|
||||
cpdef update_ey(int nx, int ny, int nz, int nthreads, floattype_t[:, :] updatecoeffsE, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Ey, floattype_t[:, :, :] Hx, floattype_t[:, :, :] Hz):
|
||||
"""This function updates the Ey field components.
|
||||
|
||||
Args:
|
||||
nx, ny, nz (int): Grid size in cells
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
"""
|
||||
|
||||
cdef int i, j, k, listIndex
|
||||
|
||||
for i in prange(1, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(1, nz):
|
||||
listIndex = ID[1, i, j, k]
|
||||
Ey[i, j, k] = updatecoeffsE[listIndex, 0] * Ey[i, j, k] + updatecoeffsE[listIndex, 3] * (Hx[i, j, k] - Hx[i, j, k - 1]) - updatecoeffsE[listIndex, 1] * (Hz[i, j, k] - Hz[i - 1, j, k])
|
||||
|
||||
|
||||
cpdef update_ey_dispersive_multipole_A(int nx, int ny, int nz, int nthreads, int maxpoles, floattype_t[:, :] updatecoeffsE, complextype_t[:, :] updatecoeffsdispersive, np.uint32_t[:, :, :, :] ID, complextype_t[:, :, :, :] Ty, floattype_t[:, :, :] Ey, floattype_t[:, :, :] Hx, floattype_t[:, :, :] Hz):
|
||||
"""This function updates the Ey field components when dispersive materials (with multiple poles) are present.
|
||||
|
||||
Args:
|
||||
nx, ny, nz (int): Grid size in cells
|
||||
maxpoles (int): Maximum number of poles
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, T, ID, E, H (memoryviews): Access to update coeffients, temporary, ID and field component arrays
|
||||
"""
|
||||
|
||||
cdef int i, j, k, listIndex, p
|
||||
cdef float phi = 0.0
|
||||
|
||||
for i in prange(1, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(1, nz):
|
||||
listIndex = ID[1, i, j, k]
|
||||
phi = 0.0
|
||||
for p in range(0, maxpoles):
|
||||
phi = phi + updatecoeffsdispersive[listIndex, p * 3].real * Ty[p, i, j, k].real
|
||||
Ty[p, i, j, k] = updatecoeffsdispersive[listIndex, 1 + (p * 3)] * Ty[p, i, j, k] + updatecoeffsdispersive[listIndex, 2 + (p * 3)] * Ey[i, j, k]
|
||||
Ey[i, j, k] = updatecoeffsE[listIndex, 0] * Ey[i, j, k] + updatecoeffsE[listIndex, 3] * (Hx[i, j, k] - Hx[i, j, k - 1]) - updatecoeffsE[listIndex, 1] * (Hz[i, j, k] - Hz[i - 1, j, k]) - updatecoeffsE[listIndex, 4] * phi
|
||||
|
||||
|
||||
cpdef update_ey_dispersive_multipole_B(int nx, int ny, int nz, int nthreads, int maxpoles, complextype_t[:, :] updatecoeffsdispersive, np.uint32_t[:, :, :, :] ID, complextype_t[:, :, :, :] Ty, floattype_t[:, :, :] Ey):
|
||||
"""This function updates the Ey field components when dispersive materials (with multiple poles) are present.
|
||||
|
||||
Args:
|
||||
nx, ny, nz (int): Grid size in cells
|
||||
maxpoles (int): Maximum number of poles
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, T, ID, E, H (memoryviews): Access to update coeffients, temporary, ID and field component arrays
|
||||
"""
|
||||
|
||||
cdef int i, j, k, listIndex, p
|
||||
|
||||
for i in prange(1, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(1, nz):
|
||||
listIndex = ID[1, i, j, k]
|
||||
for p in range(0, maxpoles):
|
||||
Ty[p, i, j, k] = Ty[p, i, j, k] - updatecoeffsdispersive[listIndex, 2 + (p * 3)] * Ey[i, j, k]
|
||||
|
||||
|
||||
cpdef update_ey_dispersive_1pole_A(int nx, int ny, int nz, int nthreads, floattype_t[:, :] updatecoeffsE, complextype_t[:, :] updatecoeffsdispersive, np.uint32_t[:, :, :, :] ID, complextype_t[:, :, :, :] Ty, floattype_t[:, :, :] Ey, floattype_t[:, :, :] Hx, floattype_t[:, :, :] Hz):
|
||||
"""This function updates the Ey field components when dispersive materials (with 1 pole) are present.
|
||||
|
||||
Args:
|
||||
nx, ny, nz (int): Grid size in cells
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, T, ID, E, H (memoryviews): Access to update coeffients, temporary, ID and field component arrays
|
||||
"""
|
||||
|
||||
cdef int i, j, k, listIndex
|
||||
cdef float phi = 0.0
|
||||
|
||||
for i in prange(1, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(1, nz):
|
||||
listIndex = ID[1, i, j, k]
|
||||
phi = updatecoeffsdispersive[listIndex, 0].real * Ty[0, i, j, k].real
|
||||
Ty[0, i, j, k] = updatecoeffsdispersive[listIndex, 1] * Ty[0, i, j, k] + updatecoeffsdispersive[listIndex, 2] * Ey[i, j, k]
|
||||
Ey[i, j, k] = updatecoeffsE[listIndex, 0] * Ey[i, j, k] + updatecoeffsE[listIndex, 3] * (Hx[i, j, k] - Hx[i, j, k - 1]) - updatecoeffsE[listIndex, 1] * (Hz[i, j, k] - Hz[i - 1, j, k]) - updatecoeffsE[listIndex, 4] * phi
|
||||
|
||||
|
||||
cpdef update_ey_dispersive_1pole_B(int nx, int ny, int nz, int nthreads, complextype_t[:, :] updatecoeffsdispersive, np.uint32_t[:, :, :, :] ID, complextype_t[:, :, :, :] Ty, floattype_t[:, :, :] Ey):
|
||||
"""This function updates the Ey field components when dispersive materials (with 1 pole) are present.
|
||||
|
||||
Args:
|
||||
nx, ny, nz (int): Grid size in cells
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, T, ID, E (memoryviews): Access to update coeffients, temporary, ID and field component arrays
|
||||
"""
|
||||
|
||||
cdef int i, j, k, listIndex
|
||||
|
||||
for i in prange(1, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(1, nz):
|
||||
listIndex = ID[1, i, j, k]
|
||||
Ty[0, i, j, k] = Ty[0, i, j, k] - updatecoeffsdispersive[listIndex, 2] * Ey[i, j, k]
|
||||
|
||||
|
||||
#########################################
|
||||
# Electric field updates - Ez component #
|
||||
#########################################
|
||||
cpdef update_ez(int nx, int ny, int nz, int nthreads, floattype_t[:, :] updatecoeffsE, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Ez, floattype_t[:, :, :] Hx, floattype_t[:, :, :] Hy):
|
||||
"""This function updates the Ez field components.
|
||||
|
||||
Args:
|
||||
nx, ny, nz (int): Grid size in cells
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
"""
|
||||
|
||||
cdef int i, j, k, listIndex
|
||||
|
||||
for i in prange(1, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(1, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[2, i, j, k]
|
||||
Ez[i, j, k] = updatecoeffsE[listIndex, 0] * Ez[i, j, k] + updatecoeffsE[listIndex, 1] * (Hy[i, j, k] - Hy[i - 1, j, k]) - updatecoeffsE[listIndex, 2] * (Hx[i, j, k] - Hx[i, j - 1, k])
|
||||
|
||||
|
||||
cpdef update_ez_dispersive_multipole_A(int nx, int ny, int nz, int nthreads, int maxpoles, floattype_t[:, :] updatecoeffsE, complextype_t[:, :] updatecoeffsdispersive, np.uint32_t[:, :, :, :] ID, complextype_t[:, :, :, :] Tz, floattype_t[:, :, :] Ez, floattype_t[:, :, :] Hx, floattype_t[:, :, :] Hy):
|
||||
"""This function updates the Ez field components when dispersive materials (with multiple poles) are present.
|
||||
|
||||
Args:
|
||||
nx, ny, nz (int): Grid size in cells
|
||||
maxpoles (int): Maximum number of poles
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, T, ID, E, H (memoryviews): Access to update coeffients, temporary, ID and field component arrays
|
||||
"""
|
||||
|
||||
cdef int i, j, k, listIndex, p
|
||||
cdef float phi = 0.0
|
||||
|
||||
for i in prange(1, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(1, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[2, i, j, k]
|
||||
phi = 0.0
|
||||
for p in range(0, maxpoles):
|
||||
phi = phi + updatecoeffsdispersive[listIndex, p * 3].real * Tz[p, i, j, k].real
|
||||
Tz[p, i, j, k] = updatecoeffsdispersive[listIndex, 1 + (p * 3)] * Tz[p, i, j, k] + updatecoeffsdispersive[listIndex, 2 + (p * 3)] * Ez[i, j, k]
|
||||
Ez[i, j, k] = updatecoeffsE[listIndex, 0] * Ez[i, j, k] + updatecoeffsE[listIndex, 1] * (Hy[i, j, k] - Hy[i - 1, j, k]) - updatecoeffsE[listIndex, 2] * (Hx[i, j, k] - Hx[i, j - 1, k]) - updatecoeffsE[listIndex, 4] * phi
|
||||
|
||||
|
||||
cpdef update_ez_dispersive_multipole_B(int nx, int ny, int nz, int nthreads, int maxpoles, complextype_t[:, :] updatecoeffsdispersive, np.uint32_t[:, :, :, :] ID, complextype_t[:, :, :, :] Tz, floattype_t[:, :, :] Ez):
|
||||
"""This function updates the Ez field components when dispersive materials (with multiple poles) are present.
|
||||
|
||||
Args:
|
||||
nx, ny, nz (int): Grid size in cells
|
||||
maxpoles (int): Maximum number of poles
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, T, ID, E (memoryviews): Access to update coeffients, temporary, ID and field component arrays
|
||||
"""
|
||||
|
||||
cdef int i, j, k, listIndex, p
|
||||
|
||||
for i in prange(1, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(1, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[2, i, j, k]
|
||||
for p in range(0, maxpoles):
|
||||
Tz[p, i, j, k] = Tz[p, i, j, k] - updatecoeffsdispersive[listIndex, 2 + (p * 3)] * Ez[i, j, k]
|
||||
|
||||
|
||||
cpdef update_ez_dispersive_1pole_A(int nx, int ny, int nz, int nthreads, floattype_t[:, :] updatecoeffsE, complextype_t[:, :] updatecoeffsdispersive, np.uint32_t[:, :, :, :] ID, complextype_t[:, :, :, :] Tz, floattype_t[:, :, :] Ez, floattype_t[:, :, :] Hx, floattype_t[:, :, :] Hy):
|
||||
"""This function updates the Ez field components when dispersive materials (with 1 pole) are present.
|
||||
|
||||
Args:
|
||||
nx, ny, nz (int): Grid size in cells
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, T, ID, E, H (memoryviews): Access to update coeffients, temporary, ID and field component arrays
|
||||
"""
|
||||
|
||||
cdef int i, j, k, listIndex
|
||||
cdef float phi = 0.0
|
||||
|
||||
for i in prange(1, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(1, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[2, i, j, k]
|
||||
phi = updatecoeffsdispersive[listIndex, 0].real * Tz[0, i, j, k].real
|
||||
Tz[0, i, j, k] = updatecoeffsdispersive[listIndex, 1] * Tz[0, i, j, k] + updatecoeffsdispersive[listIndex, 2] * Ez[i, j, k]
|
||||
Ez[i, j, k] = updatecoeffsE[listIndex, 0] * Ez[i, j, k] + updatecoeffsE[listIndex, 1] * (Hy[i, j, k] - Hy[i - 1, j, k]) - updatecoeffsE[listIndex, 2] * (Hx[i, j, k] - Hx[i, j - 1, k]) - updatecoeffsE[listIndex, 4] * phi
|
||||
|
||||
|
||||
cpdef update_ez_dispersive_1pole_B(int nx, int ny, int nz, int nthreads, complextype_t[:, :] updatecoeffsdispersive, np.uint32_t[:, :, :, :] ID, complextype_t[:, :, :, :] Tz, floattype_t[:, :, :] Ez):
|
||||
"""This function updates the Ez field components when dispersive materials (with 1 pole) are present.
|
||||
|
||||
Args:
|
||||
nx, ny, nz (int): Grid size in cells
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, T, ID, E (memoryviews): Access to update coeffients, temporary, ID and field component arrays
|
||||
"""
|
||||
|
||||
cdef int i, j, k, listIndex
|
||||
|
||||
for i in prange(1, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(1, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[2, i, j, k]
|
||||
Tz[0, i, j, k] = Tz[0, i, j, k] - updatecoeffsdispersive[listIndex, 2] * Ez[i, j, k]
|
||||
|
||||
|
||||
#########################################
|
||||
# Magnetic field updates - Hx component #
|
||||
#########################################
|
||||
cpdef update_hx(int nx, int ny, int nz, int nthreads, floattype_t[:, :] updatecoeffsH, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Hx, floattype_t[:, :, :] Ey, floattype_t[:, :, :] Ez):
|
||||
"""This function updates the Hx field components.
|
||||
|
||||
Args:
|
||||
nx, ny, nz (int): Grid size in cells
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
"""
|
||||
|
||||
cdef int i, j, k, listIndex
|
||||
|
||||
for i in prange(1, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[3, i, j, k]
|
||||
Hx[i, j, k] = updatecoeffsH[listIndex, 0] * Hx[i, j, k] - updatecoeffsH[listIndex, 2] * (Ez[i, j + 1, k] - Ez[i, j, k]) + updatecoeffsH[listIndex, 3] * (Ey[i, j, k + 1] - Ey[i, j, k])
|
||||
|
||||
|
||||
#########################################
|
||||
# Magnetic field updates - Hy component #
|
||||
#########################################
|
||||
cpdef update_hy(int nx, int ny, int nz, int nthreads, floattype_t[:, :] updatecoeffsH, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Hy, floattype_t[:, :, :] Ex, floattype_t[:, :, :] Ez):
|
||||
"""This function updates the Hy field components.
|
||||
|
||||
Args:
|
||||
nx, ny, nz (int): Grid size in cells
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
"""
|
||||
|
||||
cdef int i, j, k, listIndex
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(1, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[4, i, j, k]
|
||||
Hy[i, j, k] = updatecoeffsH[listIndex, 0] * Hy[i, j, k] - updatecoeffsH[listIndex, 3] * (Ex[i, j, k + 1] - Ex[i, j, k]) + updatecoeffsH[listIndex, 1] * (Ez[i + 1, j, k] - Ez[i, j, k])
|
||||
|
||||
|
||||
#########################################
|
||||
# Magnetic field updates - Hz component #
|
||||
#########################################
|
||||
cpdef update_hz(int nx, int ny, int nz, int nthreads, floattype_t[:, :] updatecoeffsH, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Hz, floattype_t[:, :, :] Ex, floattype_t[:, :, :] Ey):
|
||||
"""This function updates the Hz field components.
|
||||
|
||||
Args:
|
||||
nx, ny, nz (int): Grid size in cells
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
"""
|
||||
|
||||
cdef int i, j, k, listIndex
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(1, nz):
|
||||
listIndex = ID[5, i, j, k]
|
||||
Hz[i, j, k] = updatecoeffsH[listIndex, 0] * Hz[i, j, k] - updatecoeffsH[listIndex, 1] * (Ey[i + 1, j, k] - Ey[i, j, k]) + updatecoeffsH[listIndex, 2] * (Ex[i, j + 1, k] - Ex[i, j, k])
|
||||
|
265
gprMax/fractals.py
普通文件
265
gprMax/fractals.py
普通文件
@@ -0,0 +1,265 @@
|
||||
# Copyright (C) 2015: The University of Edinburgh
|
||||
# Authors: Craig Warren and Antonis Giannopoulos
|
||||
#
|
||||
# This file is part of gprMax.
|
||||
#
|
||||
# gprMax is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gprMax is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import numpy as np
|
||||
np.seterr(divide='raise')
|
||||
|
||||
from .constants import floattype, complextype
|
||||
from .utilities import rvalue
|
||||
|
||||
|
||||
class FractalSurface():
|
||||
"""Fractal surfaces."""
|
||||
|
||||
surfaceIDs = ['xminus', 'xplus', 'yminus', 'yplus', 'zminus', 'zplus']
|
||||
|
||||
def __init__(self, xs, xf, ys, yf, zs, zf, dimension):
|
||||
"""
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (float): Extent of the fractal surface (one pair of coordinates must be equal to correctly define a surface).
|
||||
dimension (float): Fractal dimension that controls the fractal distribution.
|
||||
"""
|
||||
|
||||
self.ID = None
|
||||
self.surfaceID = None
|
||||
self.xs = xs
|
||||
self.xf = xf
|
||||
self.ys = ys
|
||||
self.yf = yf
|
||||
self.zs = zs
|
||||
self.zf = zf
|
||||
self.nx = xf - xs
|
||||
self.ny = yf - ys
|
||||
self.nz = zf - zs
|
||||
self.seed = None
|
||||
self.dimension = dimension
|
||||
# Constant related to fractal dimension from: http://dx.doi.org/10.1017/CBO9781139174695
|
||||
self.b = -(2 * self.dimension - 7) / 2
|
||||
self.weighting = (1, 1)
|
||||
self.fractalrange = (0, 0)
|
||||
self.filldepth = 0
|
||||
self.grass = []
|
||||
|
||||
def generate_fractal_surface(self, G):
|
||||
"""Generate a 2D array with a fractal distribution.
|
||||
|
||||
Args:
|
||||
G (class): Grid class instance - holds essential parameters describing the model.
|
||||
"""
|
||||
|
||||
if self.xs == self.xf:
|
||||
surfacedims = (self.ny + 1, self.nz + 1)
|
||||
d = G.dx
|
||||
elif self.ys == self.yf:
|
||||
surfacedims = (self.nx + 1, self.nz + 1)
|
||||
d = G.dy
|
||||
elif self.zs == self.zf:
|
||||
surfacedims = (self.nx + 1, self.ny + 1)
|
||||
d = G.dz
|
||||
|
||||
self.fractalsurface = np.zeros(surfacedims, dtype=complextype)
|
||||
|
||||
# Positional vector at centre of array, scaled by weighting
|
||||
v1 = np.array([self.weighting[0]*(surfacedims[0])/2, self.weighting[1]*(surfacedims[1])/2])
|
||||
|
||||
# 2D array of random numbers to be convolved with the fractal function
|
||||
R = np.random.RandomState(self.seed)
|
||||
A = R.randn(surfacedims[0], surfacedims[1])
|
||||
|
||||
# 2D FFT
|
||||
A = np.fft.fftn(A)
|
||||
|
||||
for i in range(surfacedims[0]):
|
||||
for j in range(surfacedims[1]):
|
||||
# Positional vector for current position
|
||||
v2 = np.array([self.weighting[0]*i, self.weighting[1]*j])
|
||||
rr = np.linalg.norm(v2 - v1)
|
||||
try:
|
||||
self.fractalsurface[i, j] = A[i, j] * 1/(rr**self.b)
|
||||
except FloatingPointError:
|
||||
rr = 0.9
|
||||
self.fractalsurface[i, j] = A[i, j] * 1/(rr**self.b)
|
||||
|
||||
# Shift the zero frequency component to the centre of the spectrum
|
||||
self.fractalsurface = np.fft.ifftshift(self.fractalsurface)
|
||||
# Take the real part (numerical errors can give rise to an imaginary part) of the IFFT
|
||||
self.fractalsurface = np.real(np.fft.ifftn(self.fractalsurface))
|
||||
# Scale the fractal volume according to requested range
|
||||
fractalmin = np.amin(self.fractalsurface)
|
||||
fractalmax = np.amax(self.fractalsurface)
|
||||
fractalrange = fractalmax - fractalmin
|
||||
self.fractalsurface = self.fractalsurface * ((self.fractalrange[1] - self.fractalrange[0])/fractalrange) + self.fractalrange[0] - ((self.fractalrange[1] - self.fractalrange[0])/fractalrange) * fractalmin
|
||||
|
||||
|
||||
class FractalVolume():
|
||||
"""Fractal volumes."""
|
||||
|
||||
def __init__(self, xs, xf, ys, yf, zs, zf, dimension):
|
||||
"""
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (float): Extent of the fractal volume.
|
||||
dimension (float): Fractal dimension that controls the fractal distribution.
|
||||
"""
|
||||
|
||||
self.ID = None
|
||||
self.operatingonID= None
|
||||
self.xs = xs
|
||||
self.xf = xf
|
||||
self.ys = ys
|
||||
self.yf = yf
|
||||
self.zs = zs
|
||||
self.zf = zf
|
||||
self.nx = xf - xs
|
||||
self.ny = yf - ys
|
||||
self.nz = zf - zs
|
||||
self.seed = None
|
||||
self.dimension = dimension
|
||||
# Constant related to fractal dimension from: http://dx.doi.org/10.1017/CBO9781139174695
|
||||
self.b = -(2 * self.dimension - 7) / 2
|
||||
self.weighting = (1, 1, 1)
|
||||
self.nbins = 0
|
||||
self.fractalsurfaces = []
|
||||
|
||||
def generate_fractal_volume(self, G):
|
||||
"""Generate a 3D volume with a fractal distribution.
|
||||
|
||||
Args:
|
||||
G (class): Grid class instance - holds essential parameters describing the model.
|
||||
"""
|
||||
|
||||
self.fractalvolume = np.zeros((self.nx + 1, self.ny + 1, self.nz + 1), dtype=complextype)
|
||||
|
||||
# Positional vector at centre of array, scaled by weighting
|
||||
v1 = np.array([self.weighting[0]*(self.nx + 1)/2, self.weighting[1]*(self.ny + 1)/2, self.weighting[2]*(self.nz + 1)/2])
|
||||
|
||||
# 3D array of random numbers to be convolved with the fractal function
|
||||
R = np.random.RandomState(self.seed)
|
||||
A = R.randn(self.nx + 1, self.ny + 1, self.nz + 1)
|
||||
|
||||
# 3D FFT
|
||||
A = np.fft.fftn(A)
|
||||
|
||||
for i in range(self.nx + 1):
|
||||
for j in range(self.ny + 1):
|
||||
for k in range(self.nz + 1):
|
||||
# Positional vector for current position
|
||||
v2 = np.array([self.weighting[0]*i, self.weighting[1]*j, self.weighting[2]*k])
|
||||
rr = np.linalg.norm(v2 - v1)
|
||||
try:
|
||||
self.fractalvolume[i, j, k] = A[i, j, k] * 1/(rr**self.b)
|
||||
except FloatingPointError:
|
||||
rr = 0.9
|
||||
self.fractalvolume[i, j, k] = A[i, j, k] * 1/(rr**self.b)
|
||||
|
||||
# Shift the zero frequency component to the centre of the spectrum
|
||||
self.fractalvolume = np.fft.ifftshift(self.fractalvolume)
|
||||
# Take the real part (numerical errors can give rise to an imaginary part) of the IFFT
|
||||
self.fractalvolume = np.real(np.fft.ifftn(self.fractalvolume))
|
||||
# Bin fractal values
|
||||
bins = np.linspace(np.amin(self.fractalvolume), np.amax(self.fractalvolume), self.nbins + 1)
|
||||
for j in range(self.ny + 1):
|
||||
for k in range(self.nz + 1):
|
||||
self.fractalvolume[:, j, k] = np.digitize(self.fractalvolume[:, j, k], bins, right=True)
|
||||
|
||||
def generate_volume_mask(self):
|
||||
"""Generate a 3D volume to use as a mask for adding rough surfaces, water and grass/roots. Zero signifies the mask is not set, one signifies the mask is set."""
|
||||
|
||||
self.mask = np.zeros((self.nx + 1, self.ny + 1, self.nz + 1), dtype=np.int8)
|
||||
maskxs = self.originalxs - self.xs
|
||||
maskxf = (self.originalxf - self.originalxs) + maskxs + 1
|
||||
maskys = self.originalys - self.ys
|
||||
maskyf = (self.originalyf - self.originalys) + maskys + 1
|
||||
maskzs = self.originalzs - self.zs
|
||||
maskzf = (self.originalzf - self.originalzs) + maskzs + 1
|
||||
self.mask[maskxs:maskxf, maskys:maskyf, maskzs:maskzf] = 1
|
||||
|
||||
|
||||
class Grass():
|
||||
"""Geometry information for blades of grass."""
|
||||
|
||||
def __init__(self, numblades):
|
||||
"""
|
||||
Args:
|
||||
numblades (int): Number of blades of grass.
|
||||
"""
|
||||
|
||||
self.numblades = numblades
|
||||
self.geometryparams = np.zeros((self.numblades, 6), dtype=floattype)
|
||||
self.seed = None
|
||||
|
||||
# Randomly defined parameters that will be used to calculate geometry
|
||||
self.R1 = np.random.RandomState(self.seed)
|
||||
self.R2 = np.random.RandomState(self.seed)
|
||||
self.R3 = np.random.RandomState(self.seed)
|
||||
self.R4 = np.random.RandomState(self.seed)
|
||||
self.R5 = np.random.RandomState(self.seed)
|
||||
self.R6 = np.random.RandomState(self.seed)
|
||||
|
||||
for i in range(self.numblades):
|
||||
self.geometryparams[i, 0] = 10 + 20 * self.R1.random_sample()
|
||||
self.geometryparams[i, 1] = 10 + 20 * self.R2.random_sample()
|
||||
self.geometryparams[i, 2] = self.R3.choice([-1, 1])
|
||||
self.geometryparams[i, 3] = self.R4.choice([-1, 1])
|
||||
|
||||
def calculate_blade_geometry(self, blade, height):
|
||||
"""Calculates the x and y coordinates for a given height of grass blade.
|
||||
|
||||
Args:
|
||||
blade (int): Numeric ID of grass blade.
|
||||
height (float): Height of grass blade.
|
||||
|
||||
Returns:
|
||||
x, y (float): x and y coordinates of grass blade.
|
||||
"""
|
||||
|
||||
x = self.geometryparams[blade, 2] * (height / self.geometryparams[blade, 0]) * (height / self.geometryparams[blade, 0])
|
||||
y = self.geometryparams[blade, 3] * (height / self.geometryparams[blade, 1]) * (height / self.geometryparams[blade, 1])
|
||||
x = rvalue(x)
|
||||
y = rvalue(y)
|
||||
|
||||
return x, y
|
||||
|
||||
def calculate_root_geometry(self, root, depth):
|
||||
"""Calculates the x and y coordinates for a given depth of grass root.
|
||||
|
||||
Args:
|
||||
root (int): Numeric ID of grass root.
|
||||
depth (float): Depth of grass root.
|
||||
|
||||
Returns:
|
||||
x, y (float): x and y coordinates of grass root.
|
||||
"""
|
||||
|
||||
self.geometryparams[root, 4] += -1 + 2 * self.R5.random_sample()
|
||||
self.geometryparams[root, 5] += -1 + 2 * self.R6.random_sample()
|
||||
x = round(self.geometryparams[root, 4])
|
||||
y = round(self.geometryparams[root, 5])
|
||||
|
||||
return x, y
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
600
gprMax/geometry_primitives.pyx
普通文件
600
gprMax/geometry_primitives.pyx
普通文件
@@ -0,0 +1,600 @@
|
||||
# Copyright (C) 2015: The University of Edinburgh
|
||||
# Authors: Craig Warren and Antonis Giannopoulos
|
||||
#
|
||||
# This file is part of gprMax.
|
||||
#
|
||||
# gprMax is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gprMax is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import numpy as np
|
||||
cimport numpy as np
|
||||
np.seterr(divide='raise')
|
||||
from .utilities import rvalue
|
||||
from .yee_cell_setget_rigid cimport set_rigid_Ex, set_rigid_Ey, set_rigid_Ez, set_rigid_Hx, set_rigid_Hy, set_rigid_Hz, set_rigid_E, unset_rigid_E, set_rigid_H, unset_rigid_H
|
||||
|
||||
|
||||
cpdef bint are_clockwise(float v1x, float v1y, float v2x, float v2y):
|
||||
"""Find if vector 2 is clockwise relative to vector 1.
|
||||
|
||||
Args:
|
||||
v1x, v1y, v2x, v2y (float): Coordinates of vectors.
|
||||
|
||||
Returns:
|
||||
(boolean)
|
||||
"""
|
||||
|
||||
return -v1x*v2y + v1y*v2x > 0
|
||||
|
||||
|
||||
cpdef bint is_within_radius(float vx, float vy, float radius):
|
||||
"""Check if the point is within a given radius of the centre of the circle.
|
||||
|
||||
Args:
|
||||
vx, vy (float): Coordinates of vector.
|
||||
radius (float): Radius.
|
||||
|
||||
Returns:
|
||||
(boolean)
|
||||
"""
|
||||
|
||||
return vx*vx + vy*vy <= radius*radius
|
||||
|
||||
|
||||
cpdef bint is_inside_sector(float px, float py, float ctrx, float ctry, float sectorstartangle, float sectorangle, float radius):
|
||||
"""For a point to be inside a circular sector, it has to meet the following tests:
|
||||
It has to be positioned anti-clockwise from the start "arm" of the sector
|
||||
It has to be positioned clockwise from the end arm of the sector
|
||||
It has to be closer to the center of the circle than the sectors radius.
|
||||
Assumes sector start is always clockwise from sector end,
|
||||
i.e. sector defined in an anti-clockwise direction
|
||||
|
||||
Args:
|
||||
px, py (float): Coordinates of point.
|
||||
ctrx, ctry (float): Coordinates of centre of circle.
|
||||
sectorstartangle (float): Angle (in radians) of start of sector.
|
||||
sectorangle (float): Angle (in radians) that sector makes.
|
||||
radius (float): Radius.
|
||||
|
||||
Returns:
|
||||
(boolean)
|
||||
"""
|
||||
|
||||
cdef float sectorstart1, sectorstart2, sectorend1, sectorend2, relpoint1, relpoint2
|
||||
|
||||
sectorstart1 = radius * np.cos(sectorstartangle)
|
||||
sectorstart2 = radius * np.sin(sectorstartangle)
|
||||
sectorend1 = radius * np.cos(sectorstartangle + sectorangle)
|
||||
sectorend2 = radius * np.sin(sectorstartangle + sectorangle)
|
||||
relpoint1 = px - ctrx
|
||||
relpoint2 = py - ctry
|
||||
|
||||
return not are_clockwise(sectorstart1, sectorstart2, relpoint1, relpoint2) and are_clockwise(sectorend1, sectorend2, relpoint1, relpoint2) and is_within_radius(relpoint1, relpoint2, radius)
|
||||
|
||||
|
||||
cpdef build_edge_x(int i, int j, int k, int numIDx, np.int8_t[:, :, :, :] rigidE, np.int8_t[:, :, :, :] rigidH, np.uint32_t[:, :, :, :] ID):
|
||||
"""Set x-orientated edges in the rigid and ID arrays for a Yee voxel.
|
||||
|
||||
Args:
|
||||
i, j, k (int): Cell coordinates of edge.
|
||||
numIDz (int): Numeric ID of material.
|
||||
rigidE, rigidH, ID (memoryviews): Access to rigid and ID arrays.
|
||||
"""
|
||||
|
||||
set_rigid_Ex(i, j, k, rigidE)
|
||||
ID[0, i, j, k] = numIDx
|
||||
|
||||
|
||||
cpdef build_edge_y(int i, int j, int k, int numIDy, np.int8_t[:, :, :, :] rigidE, np.int8_t[:, :, :, :] rigidH, np.uint32_t[:, :, :, :] ID):
|
||||
"""Set y-orientated edges in the rigid and ID arrays for a Yee voxel.
|
||||
|
||||
Args:
|
||||
i, j, k (int): Cell coordinates of edge.
|
||||
numIDz (int): Numeric ID of material.
|
||||
rigidE, rigidH, ID (memoryviews): Access to rigid and ID arrays.
|
||||
"""
|
||||
|
||||
set_rigid_Ey(i, j, k, rigidE)
|
||||
ID[1, i, j, k] = numIDy
|
||||
|
||||
|
||||
cpdef build_edge_z(int i, int j, int k, int numIDz, np.int8_t[:, :, :, :] rigidE, np.int8_t[:, :, :, :] rigidH, np.uint32_t[:, :, :, :] ID):
|
||||
"""Set z-orientated edges in the rigid and ID arrays for a Yee voxel.
|
||||
|
||||
Args:
|
||||
i, j, k (int): Cell coordinates of edge.
|
||||
numIDz (int): Numeric ID of material.
|
||||
rigidE, rigidH, ID (memoryviews): Access to rigid and ID arrays.
|
||||
"""
|
||||
|
||||
set_rigid_Ez(i, j, k, rigidE)
|
||||
ID[2, i, j, k] = numIDz
|
||||
|
||||
|
||||
cpdef build_face_yz(int i, int j, int k, int numIDy, int numIDz, np.int8_t[:, :, :, :] rigidE, np.int8_t[:, :, :, :] rigidH, np.uint32_t[:, :, :, :] ID):
|
||||
"""Set the edges of the yz-plane face of a Yell cell in the rigid and ID arrays.
|
||||
|
||||
Args:
|
||||
i, j, k (int): Cell coordinates of the face.
|
||||
numIDx, numIDy (int): Numeric ID of material.
|
||||
rigidE, rigidH, ID (memoryviews): Access to rigid and ID arrays.
|
||||
"""
|
||||
|
||||
set_rigid_Ey(i, j, k, rigidE)
|
||||
set_rigid_Ez(i, j, k, rigidE)
|
||||
set_rigid_Ey(i, j, k + 1, rigidE)
|
||||
set_rigid_Ez(i, j + 1, k, rigidE)
|
||||
set_rigid_Hy(i, j, k, rigidH)
|
||||
set_rigid_Hz(i, j, k, rigidH)
|
||||
set_rigid_Hy(i, j, k + 1, rigidH)
|
||||
set_rigid_Hz(i, j + 1, k, rigidH)
|
||||
ID[1, i, j, k] = numIDy
|
||||
ID[2, i, j, k] = numIDz
|
||||
ID[1, i, j, k + 1] = numIDy
|
||||
ID[2, i, j + 1, k] = numIDz
|
||||
ID[4, i, j, k] = numIDy
|
||||
ID[5, i, j, k] = numIDz
|
||||
ID[4, i, j, k + 1] = numIDy
|
||||
ID[5, i, j + 1, k] = numIDz
|
||||
|
||||
|
||||
cpdef build_face_xz(int i, int j, int k, int numIDx, int numIDz, np.int8_t[:, :, :, :] rigidE, np.int8_t[:, :, :, :] rigidH, np.uint32_t[:, :, :, :] ID):
|
||||
"""Set the edges of the xz-plane face of a Yell cell in the rigid and ID arrays.
|
||||
|
||||
Args:
|
||||
i, j, k (int): Cell coordinates of the face.
|
||||
numIDx, numIDy (int): Numeric ID of material.
|
||||
rigidE, rigidH, ID (memoryviews): Access to rigid and ID arrays.
|
||||
"""
|
||||
|
||||
set_rigid_Ex(i, j, k, rigidE)
|
||||
set_rigid_Ez(i, j, k, rigidE)
|
||||
set_rigid_Ex(i, j, k + 1, rigidE)
|
||||
set_rigid_Ez(i + 1, j, k, rigidE)
|
||||
set_rigid_Hx(i, j, k, rigidH)
|
||||
set_rigid_Hz(i, j, k, rigidH)
|
||||
set_rigid_Hx(i, j, k + 1, rigidH)
|
||||
set_rigid_Hz(i + 1, j, k, rigidH)
|
||||
ID[0, i, j, k] = numIDx
|
||||
ID[2, i, j, k] = numIDz
|
||||
ID[0, i, j, k + 1] = numIDx
|
||||
ID[2, i + 1, j, k] = numIDz
|
||||
ID[3, i, j, k] = numIDx
|
||||
ID[5, i, j, k] = numIDz
|
||||
ID[3, i, j, k + 1] = numIDx
|
||||
ID[5, i + 1, j, k] = numIDz
|
||||
|
||||
|
||||
cpdef build_face_xy(int i, int j, int k, int numIDx, int numIDy, np.int8_t[:, :, :, :] rigidE, np.int8_t[:, :, :, :] rigidH, np.uint32_t[:, :, :, :] ID):
|
||||
"""Set the edges of the xy-plane face of a Yell cell in the rigid and ID arrays.
|
||||
|
||||
Args:
|
||||
i, j, k (int): Cell coordinates of the face.
|
||||
numIDx, numIDy (int): Numeric ID of material.
|
||||
rigidE, rigidH, ID (memoryviews): Access to rigid and ID arrays.
|
||||
"""
|
||||
|
||||
set_rigid_Ex(i, j, k, rigidE)
|
||||
set_rigid_Ey(i, j, k, rigidE)
|
||||
set_rigid_Ex(i, j + 1, k, rigidE)
|
||||
set_rigid_Ey(i + 1, j, k, rigidE)
|
||||
set_rigid_Hx(i, j, k, rigidH)
|
||||
set_rigid_Hy(i, j, k, rigidH)
|
||||
set_rigid_Hx(i, j + 1, k, rigidH)
|
||||
set_rigid_Hy(i + 1, j, k, rigidH)
|
||||
ID[0, i, j, k] = numIDx
|
||||
ID[1, i, j, k] = numIDy
|
||||
ID[0, i, j + 1, k] = numIDx
|
||||
ID[1, i + 1, j, k] = numIDy
|
||||
ID[3, i, j, k] = numIDx
|
||||
ID[4, i, j, k] = numIDy
|
||||
ID[3, i, j + 1, k] = numIDx
|
||||
ID[4, i + 1, j, k] = numIDy
|
||||
|
||||
|
||||
cpdef build_voxel(int i, int j, int k, int numID, int numIDx, int numIDy, int numIDz, bint averaging, np.uint32_t[:, :, :] solid, np.int8_t[:, :, :, :] rigidE, np.int8_t[:, :, :, :] rigidH, np.uint32_t[:, :, :, :] ID):
|
||||
"""Set values in the solid, rigid and ID arrays for a Yee voxel.
|
||||
|
||||
Args:
|
||||
i, j, k (int): Cell coordinates of voxel.
|
||||
numID, numIDx, numIDy, numIDz (int): Numeric ID of material.
|
||||
averaging (bint): Whether material property averging will occur for the object.
|
||||
solid, rigidE, rigidH, ID (memoryviews): Access to solid, rigid and ID arrays.
|
||||
"""
|
||||
|
||||
if averaging:
|
||||
solid[i, j, k] = numID
|
||||
unset_rigid_E(i, j, k, rigidE)
|
||||
unset_rigid_H(i, j, k, rigidH)
|
||||
|
||||
else:
|
||||
solid[i, j, k] = numID
|
||||
set_rigid_E(i, j, k, rigidE)
|
||||
set_rigid_H(i, j, k, rigidH)
|
||||
|
||||
ID[0, i, j, k] = numIDx
|
||||
ID[0, i, j + 1, k + 1] = numIDx
|
||||
ID[0, i, j + 1, k] = numIDx
|
||||
ID[0, i, j, k + 1] = numIDx
|
||||
|
||||
ID[1, i, j, k] = numIDy
|
||||
ID[1, i + 1, j, k + 1] = numIDy
|
||||
ID[1, i + 1, j, k] = numIDy
|
||||
ID[1, i, j, k + 1] = numIDy
|
||||
|
||||
ID[2, i, j, k] = numIDz
|
||||
ID[2, i + 1, j + 1, k] = numIDz
|
||||
ID[2, i + 1, j, k] = numIDz
|
||||
ID[2, i, j + 1, k] = numIDz
|
||||
|
||||
ID[3, i, j, k] = numIDx
|
||||
ID[3, i, j + 1, k + 1] = numIDx
|
||||
ID[3, i, j + 1, k] = numIDx
|
||||
ID[3, i, j, k + 1] = numIDx
|
||||
|
||||
ID[4, i, j, k] = numIDy
|
||||
ID[4, i + 1, j, k + 1] = numIDy
|
||||
ID[4, i + 1, j, k] = numIDy
|
||||
ID[4, i, j, k + 1] = numIDy
|
||||
|
||||
ID[5, i, j, k] = numIDz
|
||||
ID[5, i + 1, j + 1, k] = numIDz
|
||||
ID[5, i + 1, j, k] = numIDz
|
||||
ID[5, i, j + 1, k] = numIDz
|
||||
|
||||
|
||||
cpdef build_triangle(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, str normal, int thickness, float dx, float dy, float dz, int numID, int numIDx, int numIDy, int numIDz, bint averaging, np.uint32_t[:, :, :] solid, np.int8_t[:, :, :, :] rigidE, np.int8_t[:, :, :, :] rigidH, np.uint32_t[:, :, :, :] ID):
|
||||
"""Builds #triangle and #triangular_prism commands which sets values in the solid, rigid and ID arrays for a Yee voxel.
|
||||
|
||||
Args:
|
||||
x1, y1, z1, x2, y2, z2, x3, y3, z3 (float): Coordinates of the vertices of the triangular prism.
|
||||
normal (char): Normal direction to the plane of the triangular prism.
|
||||
thickness (int): Thickness of the triangular prism.
|
||||
dx, dy, dz (float): Spatial discretisation.
|
||||
numID, numIDx, numIDy, numIDz (int): Numeric ID of material.
|
||||
averaging (bint): Whether material property averging will occur for the object.
|
||||
solid, rigidE, rigidH, ID (memoryviews): Access to solid, rigid and ID arrays.
|
||||
"""
|
||||
|
||||
cdef int i, j, k, i1, i2, j1, j2, sign, level
|
||||
cdef float area, s, t
|
||||
|
||||
# Calculate a bounding box for the triangle
|
||||
if normal == 'x':
|
||||
area = 0.5 * (-z2 * y3 + z1 * (-y2 + y3) + y1 * (z2 - z3) + y2 * z3)
|
||||
i1 = rvalue(np.amin([y1, y2, y3]) / dy) - 1
|
||||
i2 = rvalue(np.amax([y1, y2, y3]) / dy) + 1
|
||||
j1 = rvalue(np.amin([z1, z2, z3]) / dz) - 1
|
||||
j2 = rvalue(np.amax([z1, z2, z3]) / dz) + 1
|
||||
level = rvalue(x1 / dx)
|
||||
elif normal == 'y':
|
||||
area = 0.5 * (-z2 * x3 + z1 * (-x2 + x3) + x1 * (z2 - z3) + x2 * z3)
|
||||
i1 = rvalue(np.amin([x1, x2, x3]) / dx) - 1
|
||||
i2 = rvalue(np.amax([x1, x2, x3]) / dx) + 1
|
||||
j1 = rvalue(np.amin([z1, z2, z3]) / dz) - 1
|
||||
j2 = rvalue(np.amax([z1, z2, z3]) / dz) + 1
|
||||
level = rvalue(y1 /dy)
|
||||
elif normal == 'z':
|
||||
area = 0.5 * (-y2 * x3 + y1 * (-x2 + x3) + x1 * (y2 - y3) + x2 * y3)
|
||||
i1 = rvalue(np.amin([x1, x2, x3]) / dx) - 1
|
||||
i2 = rvalue(np.amax([x1, x2, x3]) / dx) + 1
|
||||
j1 = rvalue(np.amin([y1, y2, y3]) / dy) - 1
|
||||
j2 = rvalue(np.amax([y1, y2, y3]) / dy) + 1
|
||||
level = rvalue(z1 / dz)
|
||||
|
||||
sign = np.sign(area)
|
||||
|
||||
for i in range(i1, i2):
|
||||
for j in range(j1, j2):
|
||||
|
||||
# Calculate the areas of the 3 triangles defined by the 3 vertices of the main triangle and the point under test
|
||||
if normal == 'x':
|
||||
ir = (i + 0.5) * dy
|
||||
jr = (j + 0.5) * dz
|
||||
s = sign * (z1 * y3 - y1 * z3 + (z3 - z1) * ir + (y1 - y3) * jr);
|
||||
t = sign * (y1 * z2 - z1 * y2 + (z1 - z2) * ir + (y2 - y1) * jr);
|
||||
elif normal == 'y':
|
||||
ir = (i + 0.5) * dx
|
||||
jr = (j + 0.5) * dz
|
||||
s = sign * (z1 * x3 - x1 * z3 + (z3 - z1) * ir + (x1 - x3) * jr);
|
||||
t = sign * (x1 * z2 - z1 * x2 + (z1 - z2) * ir + (x2 - x1) * jr);
|
||||
elif normal == 'z':
|
||||
ir = (i + 0.5) * dx
|
||||
jr = (j + 0.5) * dy
|
||||
s = sign * (y1 * x3 - x1 * y3 + (y3 - y1) * ir + (x1 - x3) * jr);
|
||||
t = sign * (x1 * y2 - y1 * x2 + (y1 - y2) * ir + (x2 - x1) * jr);
|
||||
|
||||
# If these conditions are true then point is inside triangle
|
||||
if s > 0 and t > 0 and (s + t) < 2 * area * sign:
|
||||
if thickness == 0:
|
||||
if normal == 'x':
|
||||
build_face_yz(level, i, j, numIDy, numIDz, rigidE, rigidH, ID)
|
||||
elif normal == 'y':
|
||||
build_face_xz(i, level, j, numIDx, numIDz, rigidE, rigidH, ID)
|
||||
elif normal == 'z':
|
||||
build_face_xy(i, j, level, numIDx, numIDy, rigidE, rigidH, ID)
|
||||
else:
|
||||
for k in range(level, level + thickness):
|
||||
if normal == 'x':
|
||||
build_voxel(k, i, j, numID, numIDx, numIDy, numIDz, averaging, solid, rigidE, rigidH, ID)
|
||||
elif normal == 'y':
|
||||
build_voxel(i, k, j, numID, numIDx, numIDy, numIDz, averaging, solid, rigidE, rigidH, ID)
|
||||
elif normal == 'z':
|
||||
build_voxel(i, j, k, numID, numIDx, numIDy, numIDz, averaging, solid, rigidE, rigidH, ID)
|
||||
|
||||
|
||||
cpdef build_cylindrical_sector(float ctr1, float ctr2, int level, float sectorstartangle, float sectorangle, float radius, str normal, int thickness, float dx, float dy, float dz, int numID, int numIDx, int numIDy, int numIDz, bint averaging, np.uint32_t[:, :, :] solid, np.int8_t[:, :, :, :] rigidE, np.int8_t[:, :, :, :] rigidH, np.uint32_t[:, :, :, :] ID):
|
||||
"""Builds #cylindrical_sector commands which sets values in the solid, rigid and ID arrays for a Yee voxel. It defines a sector of cylinder given by the direction of the axis of the coordinates of the cylinder face centre, depth coordinates, sector start point, sector angle, and sector radius. N.B Assumes sector start is always clockwise from sector end, i.e. sector defined in an anti-clockwise direction.
|
||||
|
||||
Args:
|
||||
ctr1, ctr2 (float): Coordinates of centre of circle.
|
||||
level (int): Third dimensional coordinate.
|
||||
sectorstartangle (float): Angle (in radians) of start of sector.
|
||||
sectorangle (float): Angle (in radians) that sector makes.
|
||||
radius (float): Radius of the cylindrical sector.
|
||||
normal (char): Normal direction to the plane of the cylindrical sector.
|
||||
thickness (int): Thickness of the cylindrical sector.
|
||||
dx, dy, dz (float): Spatial discretisation.
|
||||
numID, numIDx, numIDy, numIDz (int): Numeric ID of material.
|
||||
averaging (bint): Whether material property averging will occur for the object.
|
||||
solid, rigidE, rigidH, ID (memoryviews): Access to solid, rigid and ID arrays.
|
||||
"""
|
||||
|
||||
cdef int x1, x2, y1, y2, z1, z2, x, y, z
|
||||
|
||||
if normal == 'x':
|
||||
# Angles are defined from zero degrees on the positive y-axis going towards positive z-axis
|
||||
y1 = rvalue((ctr1 - radius)/dy)
|
||||
y2 = rvalue((ctr1 + radius)/dy)
|
||||
z1 = rvalue((ctr2 - radius)/dz)
|
||||
z2 = rvalue((ctr2 + radius)/dz)
|
||||
|
||||
for y in range(y1, y2):
|
||||
for z in range(z1, z2):
|
||||
if is_inside_sector(y * dy + 0.5 * dy, z * dz + 0.5 * dz, ctr1, ctr2, sectorstartangle, sectorangle, radius):
|
||||
if thickness == 0:
|
||||
build_face_yz(level, y, z, numIDy, numIDz, rigidE, rigidH, ID)
|
||||
else:
|
||||
for x in range(level, level + thickness):
|
||||
build_voxel(x, y, z, numID, numIDx, numIDy, numIDz, averaging, solid, rigidE, rigidH, ID)
|
||||
|
||||
elif normal == 'y':
|
||||
# Angles are defined from zero degrees on the positive x-axis going towards positive z-axis
|
||||
x1 = rvalue((ctr1 - radius)/dx)
|
||||
x2 = rvalue((ctr1 + radius)/dx)
|
||||
z1 = rvalue((ctr2 - radius)/dz)
|
||||
z2 = rvalue((ctr2 + radius)/dz)
|
||||
|
||||
for x in range(x1, x2):
|
||||
for z in range(z2, z2):
|
||||
if is_inside_sector(x * dx + 0.5 * dx, z * dz + 0.5 * dz, ctr1, ctr2, sectorstartangle, sectorangle, radius):
|
||||
if thickness == 0:
|
||||
build_face_xz(x, level, z, numIDx, numIDz, rigidE, rigidH, ID)
|
||||
else:
|
||||
for y in range(level, level + thickness):
|
||||
build_voxel(x, y, z, numID, numIDx, numIDy, numIDz, averaging, solid, rigidE, rigidH, ID)
|
||||
|
||||
elif normal == 'z':
|
||||
# Angles are defined from zero degrees on the positive x-axis going towards positive y-axis
|
||||
x1 = rvalue((ctr1 - radius)/dx)
|
||||
x2 = rvalue((ctr1 + radius)/dx)
|
||||
y1 = rvalue((ctr2 - radius)/dy)
|
||||
y2 = rvalue((ctr2 + radius)/dy)
|
||||
|
||||
for x in range(x1, x2):
|
||||
for y in range(y1, y2):
|
||||
if is_inside_sector(x * dx + 0.5 * dx, y * dy + 0.5 * dy, ctr1, ctr2, sectorstartangle, sectorangle, radius):
|
||||
if thickness == 0:
|
||||
build_face_xy(x, y, level, numIDx, numIDy, rigidE, rigidH, ID)
|
||||
else:
|
||||
for z in range(level, level + thickness):
|
||||
build_voxel(x, y, z, numID, numIDx, numIDy, numIDz, averaging, solid, rigidE, rigidH, ID)
|
||||
|
||||
|
||||
cpdef build_box(int xs, int xf, int ys, int yf, int zs, int zf, int numID, int numIDx, int numIDy, int numIDz, bint averaging, np.uint32_t[:, :, :] solid, np.int8_t[:, :, :, :] rigidE, np.int8_t[:, :, :, :] rigidH, np.uint32_t[:, :, :, :] ID):
|
||||
"""Builds #box commands which sets values in the solid, rigid and ID arrays.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box.
|
||||
numID, numIDx, numIDy, numIDz (int): Numeric ID of material.
|
||||
averaging (bint): Whether material property averging will occur for the object.
|
||||
solid, rigidE, rigidH, ID (memoryviews): Access to solid, rigid and ID arrays.
|
||||
"""
|
||||
|
||||
cdef int i, j, k
|
||||
|
||||
if averaging:
|
||||
for i in range(xs, xf):
|
||||
for j in range(ys, yf):
|
||||
for k in range(zs, zf):
|
||||
solid[i, j, k] = numID
|
||||
unset_rigid_E(i, j, k, rigidE)
|
||||
unset_rigid_H(i, j, k, rigidH)
|
||||
else:
|
||||
for i in range(xs, xf):
|
||||
for j in range(ys, yf):
|
||||
for k in range(zs, zf):
|
||||
solid[i, j, k] = numID
|
||||
set_rigid_E(i, j, k, rigidE)
|
||||
set_rigid_H(i, j, k, rigidH)
|
||||
|
||||
for i in range(xs, xf):
|
||||
for j in range(ys, yf + 1):
|
||||
for k in range(zs, zf + 1):
|
||||
ID[0, i, j, k] = numIDx
|
||||
|
||||
for i in range(xs, xf + 1):
|
||||
for j in range(ys, yf):
|
||||
for k in range(zs, zf + 1):
|
||||
ID[1, i, j, k] = numIDy
|
||||
|
||||
for i in range(xs, xf + 1):
|
||||
for j in range(ys, yf + 1):
|
||||
for k in range(zs, zf):
|
||||
ID[2, i, j, k] = numIDz
|
||||
|
||||
for i in range(xs, xf + 1):
|
||||
for j in range(ys, yf):
|
||||
for k in range(zs, zf):
|
||||
ID[3, i, j, k] = numIDx
|
||||
|
||||
for i in range(xs, xf):
|
||||
for j in range(ys, yf + 1):
|
||||
for k in range(zs, zf):
|
||||
ID[4, i, j, k] = numIDy
|
||||
|
||||
for i in range(xs, xf):
|
||||
for j in range(ys, yf):
|
||||
for k in range(zs, zf + 1):
|
||||
ID[5, i, j, k] = numIDz
|
||||
|
||||
|
||||
cpdef build_cylinder(float x1, float y1, float z1, float x2, float y2, float z2, float r, float dx, float dy, float dz, int numID, int numIDx, int numIDy, int numIDz, bint averaging, np.uint32_t[:, :, :] solid, np.int8_t[:, :, :, :] rigidE, np.int8_t[:, :, :, :] rigidH, np.uint32_t[:, :, :, :] ID):
|
||||
"""Builds #cylinder commands which sets values in the solid, rigid and ID arrays for a Yee voxel.
|
||||
|
||||
Args:
|
||||
x1, y1, z1, x2, y2, z2 (float): Coordinates of the centres of cylinder faces.
|
||||
r (float): Radius of the cylinder.
|
||||
dx, dy, dz (float): Spatial discretisation.
|
||||
numID, numIDx, numIDy, numIDz (int): Numeric ID of material.
|
||||
averaging (bint): Whether material property averging will occur for the object.
|
||||
solid, rigidE, rigidH, ID (memoryviews): Access to solid, rigid and ID arrays.
|
||||
"""
|
||||
|
||||
cdef int i, j, k, xs, xf, ys, yf, zs, zf
|
||||
cdef float f1f2mag, f2f1mag, f1ptmag, f2ptmag, dot1, dot2, factor1, factor2, theta1, theta2, distance1, distance2
|
||||
cdef bint build
|
||||
cdef np.ndarray f1f2, f2f1, f1pt, f2pt
|
||||
|
||||
# Calculate a bounding box for the cylinder
|
||||
if x1 < x2:
|
||||
xs = rvalue((x1 - r) / dx) - 1
|
||||
xf = rvalue((x2 + r) / dx) + 1
|
||||
else:
|
||||
xs = rvalue((x2 - r) / dx) - 1
|
||||
xf = rvalue((x1 + r) / dx) + 1
|
||||
if y1 < y2:
|
||||
ys = rvalue((y1 - r) / dy) - 1
|
||||
yf = rvalue((y2 + r) / dy) + 1
|
||||
else:
|
||||
ys = rvalue((y2 - r) / dy) - 1
|
||||
yf = rvalue((y1 + r) / dy) + 1
|
||||
if z1 < z2:
|
||||
zs = rvalue((z1 - r) / dz) - 1
|
||||
zf = rvalue((z2 + r) / dz) + 1
|
||||
else:
|
||||
zs = rvalue((z2 - r) / dz) - 1
|
||||
zf = rvalue((z1 + r) / dz) + 1
|
||||
|
||||
# Set bounds to domain if they outside
|
||||
if xs < 0:
|
||||
xs = 0
|
||||
if xf >= solid.shape[0]:
|
||||
xf = solid.shape[0] - 1
|
||||
if ys < 0:
|
||||
ys = 0
|
||||
if yf >= solid.shape[1]:
|
||||
yf = solid.shape[1] - 1
|
||||
if zs < 0:
|
||||
zs = 0
|
||||
if zf >= solid.shape[2]:
|
||||
zf = solid.shape[2] - 1
|
||||
|
||||
# Vectors between centres of cylinder faces
|
||||
f1f2 = np.array([x2 - x1, y2 - y1, z2 - z1], dtype=np.float32)
|
||||
f2f1 = np.array([x1 - x2, y1 - y2, z1 - z2], dtype=np.float32)
|
||||
|
||||
# Magnitudes
|
||||
f1f2mag = np.sqrt((f1f2*f1f2).sum(axis=0))
|
||||
f2f1mag = np.sqrt((f2f1*f2f1).sum(axis=0))
|
||||
|
||||
for i in range(xs, xf):
|
||||
for j in range(ys, yf):
|
||||
for k in range(zs, zf):
|
||||
# Build flag - default false, set to True if point is in cylinder
|
||||
build = 0
|
||||
# Vector from centre of first cylinder face to test point
|
||||
f1pt = np.array([i * dx + 0.5 * dx - x1, j * dy + 0.5 * dy - y1, k * dz + 0.5 * dz - z1], dtype=np.float32)
|
||||
# Vector from centre of second cylinder face to test point
|
||||
f2pt = np.array([i * dx + 0.5 * dx - x2, j * dy + 0.5 * dy - y2, k * dz + 0.5 * dz - z2], dtype=np.float32)
|
||||
# Magnitudes
|
||||
f1ptmag = np.sqrt((f1pt*f1pt).sum(axis=0))
|
||||
f2ptmag = np.sqrt((f2pt*f2pt).sum(axis=0))
|
||||
# Dot products
|
||||
dot1 = np.dot(f1f2, f1pt)
|
||||
dot2 = np.dot(f2f1, f2pt)
|
||||
|
||||
if f1ptmag == 0 or f2ptmag == 0:
|
||||
build = 1
|
||||
else:
|
||||
factor1 = dot1 / (f1f2mag * f1ptmag)
|
||||
factor2 = dot2 / (f2f1mag * f2ptmag)
|
||||
# Catch cases where either factor1 or factor2 are 1
|
||||
try:
|
||||
theta1 = np.arccos(factor1)
|
||||
except FloatingPointError:
|
||||
theta1 = 0
|
||||
try:
|
||||
theta2 = np.arccos(factor2)
|
||||
except FloatingPointError:
|
||||
theta2 = 0
|
||||
distance1 = f1ptmag * np.sin(theta1)
|
||||
distance2 = f2ptmag * np.sin(theta2)
|
||||
if (distance1 <= r or distance2 <= r) and theta1 <= np.pi/2 and theta2 <= np.pi/2:
|
||||
build = 1
|
||||
|
||||
if build:
|
||||
build_voxel(i, j, k, numID, numIDx, numIDy, numIDz, averaging, solid, rigidE, rigidH, ID)
|
||||
|
||||
|
||||
cpdef build_sphere(int xc, int yc, int zc, float r, float dx, float dy, float dz, int numID, int numIDx, int numIDy, int numIDz, bint averaging, np.uint32_t[:, :, :] solid, np.int8_t[:, :, :, :] rigidE, np.int8_t[:, :, :, :] rigidH, np.uint32_t[:, :, :, :] ID):
|
||||
"""Builds #sphere commands which sets values in the solid, rigid and ID arrays for a Yee voxel.
|
||||
|
||||
Args:
|
||||
xc, yc, zc (int): Cell coordinates of the centre of the sphere.
|
||||
r (float): Radius of the sphere.
|
||||
dx, dy, dz (float): Spatial discretisation.
|
||||
numID, numIDx, numIDy, numIDz (int): Numeric ID of material.
|
||||
averaging (bint): Whether material property averging will occur for the object.
|
||||
solid, rigidE, rigidH, ID (memoryviews): Access to solid, rigid and ID arrays.
|
||||
"""
|
||||
|
||||
cdef int i, j, k, xs, xf, ys, yf, zs, zf
|
||||
|
||||
# Calculate a bounding box for sphere
|
||||
xs = rvalue(((xc * dx) - r) / dx) - 1
|
||||
xf = rvalue(((xc * dx) + r) / dx) + 1
|
||||
ys = rvalue(((yc * dy) - r) / dy) - 1
|
||||
yf = rvalue(((yc * dy) + r) / dy) + 1
|
||||
zs = rvalue(((zc * dz) - r) / dz) - 1
|
||||
zf = rvalue(((zc * dz) + r) / dz) + 1
|
||||
|
||||
# Set bounds to domain if they outside
|
||||
if xs < 0:
|
||||
xs = 0
|
||||
if xf >= solid.shape[0]:
|
||||
xf = solid.shape[0] - 1
|
||||
if ys < 0:
|
||||
ys = 0
|
||||
if yf >= solid.shape[1]:
|
||||
yf = solid.shape[1] - 1
|
||||
if zs < 0:
|
||||
zs = 0
|
||||
if zf >= solid.shape[2]:
|
||||
zf = solid.shape[2] - 1
|
||||
|
||||
for i in range(xs, xf):
|
||||
for j in range(ys, yf):
|
||||
for k in range(zs, zf):
|
||||
if np.sqrt((i - xc)**2 * dx**2 + (j - yc)**2 * dy**2 + (k - zc)**2 * dz**2) <= r:
|
||||
build_voxel(i, j, k, numID, numIDx, numIDy, numIDz, averaging, solid, rigidE, rigidH, ID)
|
||||
|
205
gprMax/geometry_views.py
普通文件
205
gprMax/geometry_views.py
普通文件
@@ -0,0 +1,205 @@
|
||||
# Copyright (C) 2015: The University of Edinburgh
|
||||
# Authors: Craig Warren and Antonis Giannopoulos
|
||||
#
|
||||
# This file is part of gprMax.
|
||||
#
|
||||
# gprMax is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gprMax is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import sys
|
||||
import numpy as np
|
||||
from struct import pack
|
||||
|
||||
from .utilities import rvalue
|
||||
|
||||
|
||||
class GeometryView:
|
||||
"""Views of the geometry of the model."""
|
||||
|
||||
if sys.byteorder == 'little':
|
||||
byteorder = 'LittleEndian'
|
||||
else:
|
||||
byteorder = 'BigEndian'
|
||||
|
||||
def __init__(self, xs=None, ys=None, zs=None, xf=None, yf=None, zf=None, dx=None, dy=None, dz=None, filename=None, type=None):
|
||||
"""
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (float): Extent of the volume.
|
||||
dx, dy, dz (float): Spatial discretisation.
|
||||
filename (str): Filename to save to.
|
||||
type (str): Either 'n' for a per cell geometry view, or 'f' for a per cell edge geometry view.
|
||||
"""
|
||||
self.xs = xs
|
||||
self.ys = ys
|
||||
self.zs = zs
|
||||
self.xf = xf
|
||||
self.yf = yf
|
||||
self.zf = zf
|
||||
self.dx = dx
|
||||
self.dy = dy
|
||||
self.dz = dz
|
||||
self.filename = filename
|
||||
self.type = type
|
||||
|
||||
def write_file(self, modelrun, numbermodelruns, G):
|
||||
"""Writes the geometry information to a VTK file. Either ImageData (.vti) for a per cell geometry view, or PolygonalData (.vtp) for a per cell edge geometry view.
|
||||
|
||||
Args:
|
||||
modelrun (int): Current model run number.
|
||||
numbermodelruns (int): Total number of model runs.
|
||||
G (class): Grid class instance - holds essential parameters describing the model.
|
||||
"""
|
||||
|
||||
# Construct filename from user-supplied name and model run number
|
||||
if numbermodelruns == 1:
|
||||
self.filename = G.inputdirectory + self.filename
|
||||
else:
|
||||
self.filename = G.inputdirectory + self.filename + '_' + str(modelrun)
|
||||
|
||||
# No Python 3 support for VTK at time of writing (03/2015)
|
||||
self.vtk_nx = self.xf - self.xs
|
||||
self.vtk_ny = self.yf - self.ys
|
||||
self.vtk_nz = self.zf - self.zs
|
||||
|
||||
if self.type == 'n':
|
||||
self.filename += '.vti'
|
||||
|
||||
# Calculate number of cells according to requested sampling
|
||||
self.vtk_xscells = rvalue(self.xs / self.dx)
|
||||
self.vtk_xfcells = rvalue(self.xf / self.dx)
|
||||
self.vtk_yscells = rvalue(self.ys / self.dy)
|
||||
self.vtk_yfcells = rvalue(self.yf / self.dy)
|
||||
self.vtk_zscells = rvalue(self.zs / self.dz)
|
||||
self.vtk_zfcells = rvalue(self.zf / self.dz)
|
||||
with open(self.filename, 'wb') as f:
|
||||
f.write('<?xml version="1.0"?>\n'.encode('utf-8'))
|
||||
f.write('<VTKFile type="ImageData" version="1.0" byte_order="{}">\n'.format(GeometryView.byteorder).encode('utf-8'))
|
||||
f.write('<ImageData WholeExtent="{} {} {} {} {} {}" Origin="0 0 0" Spacing="{:.3} {:.3} {:.3}">\n'.format(self.vtk_xscells, self.vtk_xfcells, self.vtk_yscells, self.vtk_yfcells, self.vtk_zscells, self.vtk_zfcells, self.dx * G.dx, self.dy * G.dy, self.dz * G.dz).encode('utf-8'))
|
||||
f.write('<Piece Extent="{} {} {} {} {} {}">\n'.format(self.vtk_xscells, self.vtk_xfcells, self.vtk_yscells, self.vtk_yfcells, self.vtk_zscells, self.vtk_zfcells).encode('utf-8'))
|
||||
f.write('<CellData Scalars="Material">\n'.encode('utf-8'))
|
||||
f.write('<DataArray type="UInt32" Name="Material" format="appended" offset="0" />\n'.encode('utf-8'))
|
||||
f.write('</CellData>\n</Piece>\n</ImageData>\n<AppendedData encoding="raw">\n_'.encode('utf-8'))
|
||||
|
||||
# Calculate number of bytes of appended data section
|
||||
datasize = rvalue(np.dtype(np.uint32).itemsize * (self.vtk_nx / self.dx) * (self.vtk_ny / self.dy) * (self.vtk_nz / self.dz))
|
||||
# Write number of bytes of appended data as UInt32
|
||||
f.write(pack('I', datasize))
|
||||
for k in range(self.zs, self.zf, self.dz):
|
||||
for j in range(self.ys, self.yf, self.dy):
|
||||
for i in range(self.xs, self.xf, self.dx):
|
||||
f.write(pack('I', G.solid[i, j, k]))
|
||||
f.write('\n</AppendedData>\n</VTKFile>'.encode('utf-8'))
|
||||
|
||||
# Write gprMax specific information which relates material name to material numeric identifier
|
||||
f.write('\n\n<gprMax>\n'.encode('utf-8'))
|
||||
for material in G.materials:
|
||||
f.write('<Material name="{}">{}</Material>\n'.format(material.ID, material.numID).encode('utf-8'))
|
||||
f.write('</gprMax>\n'.encode('utf-8'))
|
||||
|
||||
elif self.type == 'f':
|
||||
self.filename += '.vtp'
|
||||
|
||||
vtk_numpoints = (self.vtk_nx + 1) * (self.vtk_ny + 1) * (self.vtk_nz + 1)
|
||||
vtk_numpoint_components = 3
|
||||
vtk_numlines = 2 * self.vtk_nx * self.vtk_ny + 2 * self.vtk_ny * self.vtk_nz + 2 * self.vtk_nx * self.vtk_nz + 3 * self.vtk_nx * self.vtk_ny * self.vtk_nz + self.vtk_nx + self.vtk_ny + self.vtk_nz
|
||||
vtk_numline_components = 2;
|
||||
vtk_connectivity_offset = (vtk_numpoints * vtk_numpoint_components * np.dtype(np.float32).itemsize) + np.dtype(np.uint32).itemsize
|
||||
vtk_offsets_offset = vtk_connectivity_offset + (vtk_numlines * vtk_numline_components * np.dtype(np.uint32).itemsize) + np.dtype(np.uint32).itemsize
|
||||
vtk_id_offset = vtk_offsets_offset + (vtk_numlines * np.dtype(np.uint32).itemsize) + np.dtype(np.uint32).itemsize
|
||||
vtk_offsets_size = vtk_numlines
|
||||
|
||||
with open(self.filename, 'wb') as f:
|
||||
f.write('<?xml version="1.0"?>\n'.encode('utf-8'))
|
||||
f.write('<VTKFile type="PolyData" version="1.0" byte_order="{}">\n'.format(GeometryView.byteorder).encode('utf-8'))
|
||||
f.write('<PolyData>\n<Piece NumberOfPoints="{}" NumberOfVerts="0" NumberOfLines="{}" NumberOfStrips="0" NumberOfPolys="0">\n'.format(vtk_numpoints, vtk_numlines).encode('utf-8'))
|
||||
f.write('<Points>\n<DataArray type="Float32" NumberOfComponents="3" format="appended" offset="0" />\n</Points>\n'.encode('utf-8'))
|
||||
f.write('<Lines>\n<DataArray type="UInt32" Name="connectivity" format="appended" offset="{}" />\n'.format(vtk_connectivity_offset).encode('utf-8'))
|
||||
f.write('<DataArray type="UInt32" Name="offsets" format="appended" offset="{}" />\n</Lines>\n'.format(vtk_offsets_offset).encode('utf-8'))
|
||||
f.write('<CellData Scalars="Material">\n<DataArray type="UInt32" Name="Material" format="appended" offset="{}" />\n</CellData>\n'.format(vtk_id_offset).encode('utf-8'))
|
||||
f.write('</Piece>\n</PolyData>\n<AppendedData encoding="raw">\n_'.encode('utf-8'))
|
||||
|
||||
# Write points
|
||||
datasize = np.dtype(np.float32).itemsize * vtk_numpoints * vtk_numpoint_components
|
||||
f.write(pack('I', datasize))
|
||||
for i in range(self.xs, self.xf + 1):
|
||||
for j in range(self.ys, self.yf + 1):
|
||||
for k in range(self.zs, self.zf + 1):
|
||||
f.write(pack('fff', i * G.dx, j * G.dy, k * G.dz))
|
||||
|
||||
# Write cell type (line) connectivity for x components
|
||||
datasize = np.dtype(np.uint32).itemsize * vtk_numlines * vtk_numline_components
|
||||
f.write(pack('I', datasize))
|
||||
vtk_x2 = (self.vtk_ny + 1) * (self.vtk_nz + 1)
|
||||
for vtk_x1 in range(self.vtk_nx * (self.vtk_ny + 1) * (self.vtk_nz + 1)):
|
||||
f.write(pack('II', vtk_x1, vtk_x2))
|
||||
# print('x {} {}'.format(vtk_x1, vtk_x2))
|
||||
vtk_x2 += 1
|
||||
|
||||
# Write cell type (line) connectivity for y components
|
||||
vtk_ycnt1 = 1
|
||||
vtk_ycnt2 = 0
|
||||
for vtk_y1 in range((self.vtk_nx + 1) * (self.vtk_ny + 1) * (self.vtk_nz + 1)):
|
||||
if vtk_y1 >= (vtk_ycnt1 * (self.vtk_ny + 1) * (self.vtk_nz + 1)) - (self.vtk_nz + 1) and vtk_y1 < vtk_ycnt1 * (self.vtk_ny + 1) * (self.vtk_nz + 1):
|
||||
vtk_ycnt2 += 1
|
||||
else:
|
||||
vtk_y2 = vtk_y1 + self.vtk_nz + 1
|
||||
f.write(pack('II', vtk_y1, vtk_y2))
|
||||
# print('y {} {}'.format(vtk_y1, vtk_y2))
|
||||
if vtk_ycnt2 == self.vtk_nz + 1:
|
||||
vtk_ycnt1 += 1
|
||||
vtk_ycnt2 = 0
|
||||
|
||||
# Write cell type (line) connectivity for z components
|
||||
vtk_zcnt = self.vtk_nz
|
||||
for vtk_z1 in range((self.vtk_nx + 1) * (self.vtk_ny + 1) * self.vtk_nz + (self.vtk_nx + 1) * (self.vtk_ny + 1)):
|
||||
if vtk_z1 != vtk_zcnt:
|
||||
vtk_z2 = vtk_z1 + 1
|
||||
f.write(pack('II', vtk_z1, vtk_z2))
|
||||
# print('z {} {}'.format(vtk_z1, vtk_z2))
|
||||
else:
|
||||
vtk_zcnt += self.vtk_nz + 1
|
||||
|
||||
# Write cell type (line) offsets
|
||||
vtk_cell_pts = 2
|
||||
datasize = np.dtype(np.uint32).itemsize * vtk_offsets_size
|
||||
f.write(pack('I', datasize))
|
||||
for vtk_offsets in range(vtk_cell_pts, (vtk_numline_components * vtk_numlines) + vtk_cell_pts, vtk_cell_pts):
|
||||
f.write(pack('I', vtk_offsets))
|
||||
|
||||
# Write Ex, Ey, Ez values from ID array
|
||||
datasize = np.dtype(np.uint32).itemsize * vtk_numlines
|
||||
f.write(pack('I', datasize))
|
||||
for i in range(self.xs, self.xf):
|
||||
for j in range(self.ys, self.yf + 1):
|
||||
for k in range(self.zs, self.zf + 1):
|
||||
f.write(pack('I', G.ID[0, i, j, k]))
|
||||
|
||||
for i in range(self.xs, self.xf + 1):
|
||||
for j in range(self.ys, self.yf):
|
||||
for k in range(self.zs, self.zf + 1):
|
||||
f.write(pack('I', G.ID[1, i, j, k]))
|
||||
|
||||
for i in range(self.xs, self.xf + 1):
|
||||
for j in range(self.ys, self.yf + 1):
|
||||
for k in range(self.zs, self.zf):
|
||||
f.write(pack('I', G.ID[2, i, j, k]))
|
||||
|
||||
f.write('\n</AppendedData>\n</VTKFile>'.encode('utf-8'))
|
||||
|
||||
# Write gprMax specific information which relates material name to material numeric identifier
|
||||
f.write('\n\n<gprMax>\n'.encode('utf-8'))
|
||||
for material in G.materials:
|
||||
f.write('<Material name="{}">{}</Material>\n'.format(material.ID, material.numID).encode('utf-8'))
|
||||
f.write('</gprMax>\n'.encode('utf-8'))
|
||||
|
||||
|
396
gprMax/gprMax.py
普通文件
396
gprMax/gprMax.py
普通文件
@@ -0,0 +1,396 @@
|
||||
# Copyright (C) 2015: The University of Edinburgh
|
||||
# Authors: Craig Warren and Antonis Giannopoulos
|
||||
#
|
||||
# This file is part of gprMax.
|
||||
#
|
||||
# gprMax is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gprMax is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""gprMax.gprMax: provides entry point main()."""
|
||||
|
||||
# Set the version number here
|
||||
__version__ = '3.0.0b1'
|
||||
versionname = ' (Bowmore)'
|
||||
|
||||
import sys, os, datetime, itertools, argparse
|
||||
if sys.platform != 'win32':
|
||||
import resource
|
||||
from time import perf_counter
|
||||
from copy import deepcopy
|
||||
from enum import Enum
|
||||
|
||||
import numpy as np
|
||||
|
||||
from .constants import e0
|
||||
from .exceptions import CmdInputError
|
||||
from .fields_output import prepare_output_file, write_output
|
||||
from .fields_update import *
|
||||
from .grid import FDTDGrid
|
||||
from .input_cmds_geometry import process_geometrycmds
|
||||
from .input_cmds_file import python_code_blocks, write_python_processed, check_cmd_names
|
||||
from .input_cmds_multiuse import process_multicmds
|
||||
from .input_cmds_singleuse import process_singlecmds
|
||||
from .materials import Material
|
||||
from .pml_call_updates import update_pml_electric, update_pml_magnetic
|
||||
from .pml import build_pml, calculate_initial_pml_params
|
||||
from .utilities import update_progress, logo, human_size
|
||||
from .yee_cell_build import build_ex_component, build_ey_component, build_ez_component, build_hx_component, build_hy_component, build_hz_component
|
||||
|
||||
|
||||
def main():
|
||||
"""This is the main function for gprMax."""
|
||||
|
||||
# Print gprMax logo, version, and licencing/copyright information
|
||||
logo(__version__ + versionname)
|
||||
|
||||
# Parse command line arguments
|
||||
parser = argparse.ArgumentParser(prog='gprMax', description='Electromagnetic modelling software based on the Finite-Difference Time-Domain (FDTD) method')
|
||||
parser.add_argument('inputfile', help='path to and name of inputfile')
|
||||
parser.add_argument('--geometry-only', action='store_true', default=False, help='only build model and produce geometry files')
|
||||
parser.add_argument('-n', default=1, type=int, help='number of times to run the input file')
|
||||
parser.add_argument('-mpi', action='store_true', default=False, help='switch on MPI')
|
||||
parser.add_argument('--commands-python', action='store_true', default=False, help='write an input file after any Python code blocks in the original input file have been processed')
|
||||
args = parser.parse_args()
|
||||
numbermodelruns = args.n
|
||||
inputdirectory = os.path.dirname(os.path.abspath(args.inputfile)) + os.sep
|
||||
inputfile = inputdirectory + os.path.basename(args.inputfile)
|
||||
|
||||
print('Model input file: {}\n'.format(inputfile))
|
||||
|
||||
# Mixed mode MPI/OpenMP - task farm for model runs with MPI; each model parallelised with OpenMP
|
||||
if args.mpi:
|
||||
from mpi4py import MPI
|
||||
|
||||
# Define MPI message tags
|
||||
tags = Enum('tags', {'READY': 0, 'DONE': 1, 'EXIT': 2, 'START': 3})
|
||||
|
||||
# Initializations and preliminaries
|
||||
comm = MPI.COMM_WORLD # get MPI communicator object
|
||||
size = comm.size # total number of processes
|
||||
rank = comm.rank # rank of this process
|
||||
status = MPI.Status() # get MPI status object
|
||||
name = MPI.Get_processor_name() # get name of processor/host
|
||||
|
||||
if rank == 0:
|
||||
# Master process
|
||||
modelrun = 1
|
||||
numworkers = size - 1
|
||||
closedworkers = 0
|
||||
print('Master: PID {} on {} using {} workers.'.format(os.getpid(), name, numworkers))
|
||||
while closedworkers < numworkers:
|
||||
data = comm.recv(source=MPI.ANY_SOURCE, tag=MPI.ANY_TAG, status=status)
|
||||
source = status.Get_source()
|
||||
tag = status.Get_tag()
|
||||
if tag == tags.READY.value:
|
||||
# Worker is ready, so send it a task
|
||||
if modelrun < numbermodelruns + 1:
|
||||
comm.send(modelrun, dest=source, tag=tags.START.value)
|
||||
print('Master: sending model {} to worker {}.'.format(modelrun, source))
|
||||
modelrun += 1
|
||||
else:
|
||||
comm.send(None, dest=source, tag=tags.EXIT.value)
|
||||
elif tag == tags.DONE.value:
|
||||
print('Worker {}: completed.'.format(source))
|
||||
elif tag == tags.EXIT.value:
|
||||
print('Worker {}: exited.'.format(source))
|
||||
closedworkers += 1
|
||||
else:
|
||||
# Worker process
|
||||
|
||||
print('Worker {}: PID {} on {} requesting {} OpenMP threads.'.format(rank, os.getpid(), name, os.environ.get('OMP_NUM_THREADS')))
|
||||
while True:
|
||||
comm.send(None, dest=0, tag=tags.READY.value)
|
||||
# Receive a model number to run from the master
|
||||
modelrun = comm.recv(source=0, tag=MPI.ANY_TAG, status=status)
|
||||
tag = status.Get_tag()
|
||||
|
||||
if tag == tags.START.value:
|
||||
# Run a model
|
||||
run_model(args, modelrun, numbermodelruns, inputfile, inputdirectory)
|
||||
comm.send(None, dest=0, tag=tags.DONE.value)
|
||||
elif tag == tags.EXIT.value:
|
||||
break
|
||||
|
||||
comm.send(None, dest=0, tag=tags.EXIT.value)
|
||||
|
||||
# Standard behaviour - models run serially; each model parallelised with OpenMP
|
||||
else:
|
||||
tsimstart = perf_counter()
|
||||
for modelrun in range(1, numbermodelruns + 1):
|
||||
run_model(args, modelrun, numbermodelruns, inputfile, inputdirectory)
|
||||
tsimend = perf_counter()
|
||||
print('\nTotal simulation time [HH:MM:SS]: {}'.format(datetime.timedelta(seconds=int(tsimend - tsimstart))))
|
||||
|
||||
print('\nSimulation completed.\n{}\n'.format(65*'*'))
|
||||
|
||||
|
||||
def run_model(args, modelrun, numbermodelruns, inputfile, inputdirectory):
|
||||
"""Runs a model - processes the input file; builds the Yee cells; calculates update coefficients; runs main FDTD loop.
|
||||
|
||||
Args:
|
||||
args (dict): Namespace with command line arguments
|
||||
modelrun (int): Current model run number.
|
||||
numbermodelruns (int): Total number of model runs.
|
||||
inputfile (str): Name of the input file to open.
|
||||
inputdirectory (str): Path to the directory containing the inputfile.
|
||||
"""
|
||||
|
||||
# Process any user input Python commands
|
||||
processedlines = python_code_blocks(inputfile, modelrun, numbermodelruns, inputdirectory)
|
||||
|
||||
# Write a file containing the input commands after Python blocks have been processed
|
||||
if args.commands_python:
|
||||
write_python_processed(inputfile, modelrun, numbermodelruns, processedlines)
|
||||
|
||||
# Check validity of command names & that essential commands are present
|
||||
singlecmds, multicmds, geometry = check_cmd_names(processedlines)
|
||||
|
||||
# Initialise an instance of the FDTDGrid class
|
||||
G = FDTDGrid()
|
||||
G.inputdirectory = inputdirectory
|
||||
|
||||
# Process parameters for commands that can only occur once in the model
|
||||
process_singlecmds(singlecmds, multicmds, G)
|
||||
|
||||
# Process parameters for commands that can occur multiple times in the model
|
||||
process_multicmds(multicmds, G)
|
||||
|
||||
# Initialise an array for volumetric material IDs (solid), boolean arrays for specifying materials not to be averaged (rigid),
|
||||
# an array for cell edge IDs (ID), and arrays for the field components.
|
||||
G.initialise_std_arrays()
|
||||
|
||||
# Process the geometry commands in the order they were given
|
||||
tinputprocstart = perf_counter()
|
||||
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_pml(G)
|
||||
calculate_initial_pml_params(G)
|
||||
|
||||
# Build the model, i.e. set the material properties (ID) for every edge of every Yee cell
|
||||
tbuildstart = perf_counter()
|
||||
build_ex_component(G.solid, G.rigidE, G.ID, G)
|
||||
build_ey_component(G.solid, G.rigidE, G.ID, G)
|
||||
build_ez_component(G.solid, G.rigidE, G.ID, G)
|
||||
build_hx_component(G.solid, G.rigidH, G.ID, G)
|
||||
build_hy_component(G.solid, G.rigidH, G.ID, G)
|
||||
build_hz_component(G.solid, G.rigidH, G.ID, G)
|
||||
tbuildend = perf_counter()
|
||||
print('\nModel built in [HH:MM:SS]: {}'.format(datetime.timedelta(seconds=int(tbuildend - tbuildstart))))
|
||||
|
||||
# Process any voltage sources that have resistance to create a new material at the source location
|
||||
# that adds the voltage source conductivity to the underlying parameters
|
||||
if G.voltagesources:
|
||||
for source in G.voltagesources:
|
||||
if source.resistance != 0:
|
||||
if source.polarisation == 'x':
|
||||
requirednumID = G.ID[0, source.positionx, source.positiony, source.positionz]
|
||||
material = next(x for x in G.materials if x.numID == requirednumID)
|
||||
newmaterial = deepcopy(material)
|
||||
newmaterial.ID = material.ID + '|VoltageSource_' + str(source.resistance)
|
||||
newmaterial.numID = len(G.materials)
|
||||
newmaterial.se += G.dx / (source.resistance * G.dy * G.dz)
|
||||
newmaterial.average = False
|
||||
G.ID[0, source.positionx, source.positiony, source.positionz] = newmaterial.numID
|
||||
elif source.polarisation == 'y':
|
||||
requirednumID = G.ID[1, source.positionx, source.positiony, source.positionz]
|
||||
material = next(x for x in G.materials if x.numID == requirednumID)
|
||||
newmaterial = deepcopy(material)
|
||||
newmaterial.ID = material.ID + '|VoltageSource_' + str(source.resistance)
|
||||
newmaterial.numID = len(G.materials)
|
||||
newmaterial.se += G.dy / (source.resistance * G.dx * G.dz)
|
||||
newmaterial.average = False
|
||||
G.ID[1, source.positionx, source.positiony, source.positionz] = newmaterial.numID
|
||||
elif source.polarisation == 'z':
|
||||
requirednumID = G.ID[2, source.positionx, source.positiony, source.positionz]
|
||||
material = next(x for x in G.materials if x.numID == requirednumID)
|
||||
newmaterial = deepcopy(material)
|
||||
newmaterial.ID = material.ID + '|VoltageSource_' + str(source.resistance)
|
||||
newmaterial.numID = len(G.materials)
|
||||
newmaterial.se += G.dz / (source.resistance * G.dx * G.dy)
|
||||
newmaterial.average = False
|
||||
G.ID[2, source.positionx, source.positiony, source.positionz] = newmaterial.numID
|
||||
G.materials.append(newmaterial)
|
||||
|
||||
# Initialise arrays for storing temporary values if there are any dispersive materials
|
||||
if Material.maxpoles != 0:
|
||||
G.initialise_dispersive_arrays(len(G.materials))
|
||||
|
||||
# Initialise arrays of update coefficients to pass to update functions
|
||||
G.initialise_std_updatecoeff_arrays(len(G.materials))
|
||||
|
||||
# Calculate update coefficients, store in arrays, and list materials in model
|
||||
if G.messages:
|
||||
print('\nMaterials:\n')
|
||||
print('ID\tName\t\tProperties')
|
||||
print('{}'.format('-'*50))
|
||||
for x, material in enumerate(G.materials):
|
||||
material.calculate_update_coeffsE(G)
|
||||
material.calculate_update_coeffsH(G)
|
||||
|
||||
G.updatecoeffsE[x, :] = material.CA, material.CBx, material.CBy, material.CBz, material.srce
|
||||
G.updatecoeffsH[x, :] = material.DA, material.DBx, material.DBy, material.DBz, material.srcm
|
||||
|
||||
if Material.maxpoles != 0:
|
||||
z = 0
|
||||
for y in range(Material.maxpoles):
|
||||
G.updatecoeffsdispersive[x, z:z+3] = e0 * material.eqt2[y], material.eqt[y], material.zt[y]
|
||||
z += 3
|
||||
|
||||
if G.messages:
|
||||
if material.deltaer and material.tau:
|
||||
tmp = 'delta_epsr={}, tau={} secs; '.format(','.join('%4.2f' % deltaer for deltaer in material.deltaer), ','.join('%4.3e' % 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={:4.2f}, sig={:.3e} S/m; mur={:4.2f}, sig*={:.3e} S/m; '.format(material.numID, material.ID, material.er, material.se, material.mr, material.sm) + tmp + dielectricsmoothing)
|
||||
|
||||
# Write files for any geometry views
|
||||
if G.geometryviews:
|
||||
tgeostart = perf_counter()
|
||||
for geometryview in G.geometryviews:
|
||||
geometryview.write_file(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 only geometry
|
||||
if not args.geometry_only:
|
||||
|
||||
# Prepare any snapshot files
|
||||
if G.snapshots:
|
||||
for snapshot in G.snapshots:
|
||||
snapshot.prepare_file(modelrun, numbermodelruns, G)
|
||||
|
||||
# Prepare output file
|
||||
inputfileparts = inputfile.split('.')
|
||||
if numbermodelruns == 1:
|
||||
outputfile = inputfileparts[0] + '.out'
|
||||
else:
|
||||
outputfile = inputfileparts[0] + str(modelrun) + '.out'
|
||||
sys.stdout.write('\nOutput to file: {}\n'.format(outputfile))
|
||||
sys.stdout.flush()
|
||||
f = prepare_output_file(outputfile, G)
|
||||
|
||||
# Adjust position of sources and receivers if required
|
||||
if G.txstepx > 0 or G.txstepy > 0 or G.txstepz > 0:
|
||||
for source in itertools.chain(G.hertziandipoles, G.magneticdipoles, G.voltagesources):
|
||||
source.positionx += (modelrun - 1) * G.txstepx
|
||||
source.positiony += (modelrun - 1) * G.txstepy
|
||||
source.positionz += (modelrun - 1) * G.txstepz
|
||||
if G.rxstepx > 0 or G.rxstepy > 0 or G.rxstepz > 0:
|
||||
for receiver in G.rxs:
|
||||
receiver.positionx += (modelrun - 1) * G.rxstepx
|
||||
receiver.positiony += (modelrun - 1) * G.rxstepy
|
||||
receiver.positionz += (modelrun - 1) * G.rxstepz
|
||||
|
||||
##################################
|
||||
# Main FDTD calculation loop #
|
||||
##################################
|
||||
tsolvestart = perf_counter()
|
||||
# Absolute time
|
||||
abstime = 0
|
||||
|
||||
for timestep in range(G.iterations):
|
||||
if timestep == 0:
|
||||
tstepstart = perf_counter()
|
||||
|
||||
# Write field outputs to file
|
||||
write_output(f, timestep, G.Ex, G.Ey, G.Ez, G.Hx, G.Hy, G.Hz, G)
|
||||
|
||||
# Write any snapshots to file
|
||||
if G.snapshots:
|
||||
for snapshot in G.snapshots:
|
||||
if snapshot.time == timestep + 1:
|
||||
snapshot.write_snapshot(G.Ex, G.Ey, G.Ez, G.Hx, G.Hy, G.Hz, G)
|
||||
|
||||
# Update electric field components
|
||||
# If there are any dispersive materials do 1st part of dispersive update. It is split into two parts as it requires present and updated electric field values.
|
||||
if Material.maxpoles == 1:
|
||||
update_ex_dispersive_1pole_A(G.nx, G.ny, G.nz, G.nthreads, G.updatecoeffsE, G.updatecoeffsdispersive, G.ID, G.Tx, G.Ex, G.Hy, G.Hz)
|
||||
update_ey_dispersive_1pole_A(G.nx, G.ny, G.nz, G.nthreads, G.updatecoeffsE, G.updatecoeffsdispersive, G.ID, G.Ty, G.Ey, G.Hx, G.Hz)
|
||||
update_ez_dispersive_1pole_A(G.nx, G.ny, G.nz, G.nthreads, G.updatecoeffsE, G.updatecoeffsdispersive, G.ID, G.Tz, G.Ez, G.Hx, G.Hy)
|
||||
elif Material.maxpoles > 1:
|
||||
update_ex_dispersive_multipole_A(G.nx, G.ny, G.nz, G.nthreads, Material.maxpoles, G.updatecoeffsE, G.updatecoeffsdispersive, G.ID, G.Tx, G.Ex, G.Hy, G.Hz)
|
||||
update_ey_dispersive_multipole_A(G.nx, G.ny, G.nz, G.nthreads, Material.maxpoles, G.updatecoeffsE, G.updatecoeffsdispersive, G.ID, G.Ty, G.Ey, G.Hx, G.Hz)
|
||||
update_ez_dispersive_multipole_A(G.nx, G.ny, G.nz, G.nthreads, Material.maxpoles, G.updatecoeffsE, G.updatecoeffsdispersive, G.ID, G.Tz, G.Ez, G.Hx, G.Hy)
|
||||
# Otherwise all materials are non-dispersive so do standard update
|
||||
else:
|
||||
update_ex(G.nx, G.ny, G.nz, G.nthreads, G.updatecoeffsE, G.ID, G.Ex, G.Hy, G.Hz)
|
||||
update_ey(G.nx, G.ny, G.nz, G.nthreads, G.updatecoeffsE, G.ID, G.Ey, G.Hx, G.Hz)
|
||||
update_ez(G.nx, G.ny, G.nz, G.nthreads, G.updatecoeffsE, G.ID, G.Ez, G.Hx, G.Hy)
|
||||
|
||||
# Update electric field components with the PML correction
|
||||
update_pml_electric(G)
|
||||
|
||||
# Update electric field components with electric sources
|
||||
if G.voltagesources:
|
||||
for v in G.voltagesources:
|
||||
v.update_fields(abstime, timestep, G.updatecoeffsE, G.ID, G.Ex, G.Ey, G.Ez, G)
|
||||
if G.hertziandipoles: # Update any Hertzian dipole sources last
|
||||
for h in G.hertziandipoles:
|
||||
h.update_fields(abstime, timestep, G.updatecoeffsE, G.ID, G.Ex, G.Ey, G.Ez, G)
|
||||
|
||||
# If there are any dispersive materials do 2nd part of dispersive update. It is split into two parts as it requires present and updated electric field values. Therefore it can only be completely updated after the electric field has been updated by the PML and source updates.
|
||||
if Material.maxpoles == 1:
|
||||
update_ex_dispersive_1pole_B(G.nx, G.ny, G.nz, G.nthreads, G.updatecoeffsdispersive, G.ID, G.Tx, G.Ex)
|
||||
update_ey_dispersive_1pole_B(G.nx, G.ny, G.nz, G.nthreads, G.updatecoeffsdispersive, G.ID, G.Ty, G.Ey)
|
||||
update_ez_dispersive_1pole_B(G.nx, G.ny, G.nz, G.nthreads, G.updatecoeffsdispersive, G.ID, G.Tz, G.Ez)
|
||||
elif Material.maxpoles > 1:
|
||||
update_ex_dispersive_multipole_B(G.nx, G.ny, G.nz, G.nthreads, Material.maxpoles, G.updatecoeffsdispersive, G.ID, G.Tx, G.Ex)
|
||||
update_ey_dispersive_multipole_B(G.nx, G.ny, G.nz, G.nthreads, Material.maxpoles, G.updatecoeffsdispersive, G.ID, G.Ty, G.Ey)
|
||||
update_ez_dispersive_multipole_B(G.nx, G.ny, G.nz, G.nthreads, Material.maxpoles, G.updatecoeffsdispersive, G.ID, G.Tz, G.Ez)
|
||||
|
||||
# Increment absolute time value
|
||||
abstime += 0.5 * G.dt
|
||||
|
||||
# Update magnetic field components
|
||||
update_hx(G.nx, G.ny, G.nz, G.nthreads, G.updatecoeffsH, G.ID, G.Hx, G.Ey, G.Ez)
|
||||
update_hy(G.nx, G.ny, G.nz, G.nthreads, G.updatecoeffsH, G.ID, G.Hy, G.Ex, G.Ez)
|
||||
update_hz(G.nx, G.ny, G.nz, G.nthreads, G.updatecoeffsH, G.ID, G.Hz, G.Ex, G.Ey)
|
||||
|
||||
# Update magnetic field components with the PML correction
|
||||
update_pml_magnetic(G)
|
||||
|
||||
# Update magnetic field components with magnetic sources
|
||||
if G.magneticdipoles:
|
||||
for m in G.magneticdipoles:
|
||||
m.update_fields(abstime, timestep, G.updatecoeffsH, G.ID, G.Hx, G.Hy, G.Hz, G)
|
||||
|
||||
# Increment absolute time value
|
||||
abstime += 0.5 * G.dt
|
||||
|
||||
# Calculate time for two iterations, used to estimate overall runtime
|
||||
if timestep == 1:
|
||||
tstepend = perf_counter()
|
||||
runtime = datetime.timedelta(seconds=int((tstepend - tstepstart) / 2 * G.iterations))
|
||||
sys.stdout.write('Estimated runtime [HH:MM:SS]: {}\n'.format(runtime))
|
||||
sys.stdout.write('Solving for model run {} of {}...\n'.format(modelrun, numbermodelruns))
|
||||
sys.stdout.flush()
|
||||
elif timestep > 1:
|
||||
update_progress((timestep + 1) / G.iterations)
|
||||
|
||||
# Close output file
|
||||
f.close()
|
||||
tsolveend = perf_counter()
|
||||
print('\n\nSolving took [HH:MM:SS]:'.format(datetime.timedelta(seconds=int(tsolveend - tsolvestart))))
|
||||
if sys.platform != 'win32':
|
||||
print('Peak memory (approx) required: {}'.format(human_size(resource.getrusage(resource.RUSAGE_SELF).ru_maxrss, False)))
|
||||
|
||||
|
||||
|
||||
|
102
gprMax/grid.py
普通文件
102
gprMax/grid.py
普通文件
@@ -0,0 +1,102 @@
|
||||
# Copyright (C) 2015: The University of Edinburgh
|
||||
# Authors: Craig Warren and Antonis Giannopoulos
|
||||
#
|
||||
# This file is part of gprMax.
|
||||
#
|
||||
# gprMax is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gprMax is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import numpy as np
|
||||
|
||||
from .constants import floattype, complextype
|
||||
from .materials import Material
|
||||
|
||||
|
||||
class FDTDGrid():
|
||||
"""Holds attributes associated with the entire grid. A convenient way for accessing regularly used parameters."""
|
||||
|
||||
def __init__(self):
|
||||
self.inputdirectory = ''
|
||||
self.title = ''
|
||||
self.messages = True
|
||||
self.nx = 0
|
||||
self.ny = 0
|
||||
self.nz = 0
|
||||
self.dx = 0
|
||||
self.dy = 0
|
||||
self.dz = 0
|
||||
self.dt = 0
|
||||
self.iterations = 0
|
||||
self.timewindow = 0
|
||||
self.nthreads = 0
|
||||
self.cfs = []
|
||||
self.pmlthickness = (10, 10, 10, 10, 10, 10)
|
||||
self.pmls = []
|
||||
self.materials = []
|
||||
self.mixingmodels = []
|
||||
self.averagevolumeobjects = True
|
||||
self.fractalvolumes = []
|
||||
self.geometryviews = []
|
||||
self.waveforms = []
|
||||
self.voltagesources = []
|
||||
self.hertziandipoles = []
|
||||
self.magneticdipoles = []
|
||||
self.txs = [] # Only used for converting old output files to HDF5 format
|
||||
self.txstepx = 0
|
||||
self.txstepy = 0
|
||||
self.txstepz = 0
|
||||
self.rxstepx = 0
|
||||
self.rxstepy = 0
|
||||
self.rxstepz = 0
|
||||
self.rxs = []
|
||||
self.snapshots = []
|
||||
|
||||
def initialise_std_arrays(self):
|
||||
"""Initialise an array for volumetric material IDs (solid); boolean arrays for specifying whether materials can have dielectric smoothing (rigid);
|
||||
an array for cell edge IDs (ID); and arrays for the electric and magnetic field components. Solid and ID arrays are initialised to free_space (one); rigid arrays
|
||||
to allow dielectric smoothing (zero).
|
||||
"""
|
||||
self.solid = np.ones((self.nx + 1, self.ny + 1, self.nz + 1), dtype=np.uint32)
|
||||
self.rigidE = np.zeros((12, self.nx + 1, self.ny + 1, self.nz + 1), dtype=np.int8)
|
||||
self.rigidH = np.zeros((6, self.nx + 1, self.ny + 1, self.nz + 1), dtype=np.int8)
|
||||
self.ID = np.ones((6, self.nx + 1, self.ny + 1, self.nz + 1), dtype=np.uint32)
|
||||
self.Ex = np.zeros((self.nx, self.ny + 1, self.nz + 1), dtype=floattype)
|
||||
self.Ey = np.zeros((self.nx + 1, self.ny, self.nz + 1), dtype=floattype)
|
||||
self.Ez = np.zeros((self.nx + 1, self.ny + 1, self.nz), dtype=floattype)
|
||||
self.Hx = np.zeros((self.nx + 1, self.ny, self.nz), dtype=floattype)
|
||||
self.Hy = np.zeros((self.nx, self.ny + 1, self.nz), dtype=floattype)
|
||||
self.Hz = np.zeros((self.nx, self.ny, self.nz + 1), dtype=floattype)
|
||||
|
||||
def initialise_std_updatecoeff_arrays(self, nummaterials):
|
||||
"""Initialise arrays for storing update coefficients.
|
||||
|
||||
Args:
|
||||
nummaterials (int): Number of materials present in the model.
|
||||
"""
|
||||
self.updatecoeffsE = np.zeros((nummaterials, 5), dtype=floattype)
|
||||
self.updatecoeffsH = np.zeros((nummaterials, 5), dtype=floattype)
|
||||
|
||||
def initialise_dispersive_arrays(self, nummaterials):
|
||||
"""Initialise arrays for storing coefficients when there are dispersive materials present.
|
||||
|
||||
Args:
|
||||
nummaterials (int): Number of materials present in the model.
|
||||
"""
|
||||
self.Tx = np.zeros((Material.maxpoles, self.nx, self.ny + 1, self.nz + 1), dtype=complextype)
|
||||
self.Ty = np.zeros((Material.maxpoles, self.nx + 1, self.ny, self.nz + 1), dtype=complextype)
|
||||
self.Tz = np.zeros((Material.maxpoles, self.nx + 1, self.ny + 1, self.nz), dtype=complextype)
|
||||
self.updatecoeffsdispersive = np.zeros((nummaterials, 3 * Material.maxpoles), dtype=complextype)
|
||||
|
||||
|
||||
|
||||
|
174
gprMax/input_cmds_file.py
普通文件
174
gprMax/input_cmds_file.py
普通文件
@@ -0,0 +1,174 @@
|
||||
# Copyright (C) 2015: The University of Edinburgh
|
||||
# Authors: Craig Warren and Antonis Giannopoulos
|
||||
#
|
||||
# This file is part of gprMax.
|
||||
#
|
||||
# gprMax is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gprMax is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import sys, os
|
||||
|
||||
from .constants import c, e0, m0, z0
|
||||
from .exceptions import CmdInputError
|
||||
from .utilities import ListStream
|
||||
|
||||
|
||||
def python_code_blocks(inputfile, modelrun, numbermodelruns, inputdirectory):
|
||||
"""Looks for and processes any Python code found in the input file. It will ignore any lines that are comments, i.e. begin with a double hash (##), and any blank lines. It will also ignore any lines that do not begin with a hash (#) after it has processed Python commands.
|
||||
|
||||
Args:
|
||||
inputfile (str): Name of the input file to open.
|
||||
modelrun (int): Current model run number.
|
||||
numbermodelruns (int): Total number of model runs.
|
||||
inputdirectory (str): Directory containing input file.
|
||||
|
||||
Returns:
|
||||
processedlines (list): Input commands after Python processing.
|
||||
"""
|
||||
|
||||
with open(inputfile, 'r') as f:
|
||||
# Strip out any newline characters and comments that must begin with double hashes
|
||||
inputlines = [line.rstrip() for line in f if(not line.startswith('##') and line.rstrip('\n'))]
|
||||
|
||||
# List to hold final processed commands
|
||||
processedlines = []
|
||||
|
||||
# Separate namespace for users Python code blocks to use; pre-populated some standard constants and the
|
||||
# current model run number and total number of model runs
|
||||
usernamespace = {'c': c, 'e0': e0, 'm0': m0, 'z0': z0, 'current_model_run': modelrun, 'number_model_runs': numbermodelruns, 'inputdirectory': inputdirectory}
|
||||
print('Constants/variables available for Python scripting: {}\n'.format(usernamespace))
|
||||
|
||||
x = 0
|
||||
while(x < len(inputlines)):
|
||||
if(inputlines[x].startswith('#python:')):
|
||||
# String to hold Python code to be executed
|
||||
pythoncode = ''
|
||||
x += 1
|
||||
while not inputlines[x].startswith('#end_python:'):
|
||||
# Add all code in current code block to string
|
||||
pythoncode += inputlines[x] + '\n'
|
||||
x += 1
|
||||
if x == len(inputlines):
|
||||
raise CmdInputError('Cannot find the end of the Python code block, i.e. missing #end_python: command.')
|
||||
# Compile code for faster execution
|
||||
pythoncompiledcode = compile(pythoncode, '<string>', 'exec')
|
||||
# Redirect stdio to a ListStream
|
||||
sys.stdout = codeout = ListStream()
|
||||
# Execute code block & make available only usernamespace
|
||||
exec(pythoncompiledcode, usernamespace)
|
||||
|
||||
# Now strip out any lines that don't begin with a hash command
|
||||
codeproc = [line + ('\n') for line in codeout.data if(line.startswith('#'))]
|
||||
|
||||
# Add processed Python code to list
|
||||
processedlines.extend(codeproc)
|
||||
x += 1
|
||||
|
||||
elif(inputlines[x].startswith('#')):
|
||||
# Add gprMax command to list
|
||||
inputlines[x] += ('\n')
|
||||
processedlines.append(inputlines[x])
|
||||
x += 1
|
||||
|
||||
else:
|
||||
x += 1
|
||||
|
||||
sys.stdout = sys.__stdout__ # Reset stdio
|
||||
|
||||
return processedlines
|
||||
|
||||
|
||||
def write_python_processed(inputfile, modelrun, numbermodelruns, processedlines):
|
||||
"""Writes input commands to file after Python processing.
|
||||
|
||||
Args:
|
||||
inputfile (str): Name of the input file to open.
|
||||
modelrun (int): Current model run number.
|
||||
numbermodelruns (int): Total number of model runs.
|
||||
processedlines (list): Input commands after Python processing.
|
||||
"""
|
||||
|
||||
if numbermodelruns == 1:
|
||||
processedfile = os.path.splitext(inputfile)[0] + '_proc.in'
|
||||
else:
|
||||
processedfile = os.path.splitext(inputfile)[0] + str(modelrun) + '_proc.in'
|
||||
|
||||
with open(processedfile, 'w') as f:
|
||||
for item in processedlines:
|
||||
f.write('{}'.format(item))
|
||||
|
||||
print('Written input commands after Python processing to file: {}\n'.format(processedfile))
|
||||
|
||||
|
||||
def check_cmd_names(processedlines):
|
||||
"""Checks the validity of commands, i.e. are they gprMax commands, and that all essential commands are present.
|
||||
|
||||
Args:
|
||||
processedlines (list): Input commands after Python processing.
|
||||
|
||||
Returns:
|
||||
singlecmds (dict): Commands that can only occur once in the model.
|
||||
multiplecmds (dict): Commands that can have multiple instances in the model.
|
||||
geometry (list): Geometry commands in the model.
|
||||
"""
|
||||
|
||||
# Dictionaries of available commands
|
||||
# Essential commands neccessary to run a gprMax model
|
||||
essentialcmds = ['#domain', '#dx_dy_dz', '#time_window']
|
||||
|
||||
# Commands that there should only be one instance of in a model
|
||||
singlecmds = dict.fromkeys(['#domain', '#dx_dy_dz', '#time_window', '#title', '#messages', '#num_threads', '#time_step_stability_factor', '#time_step_limit_type', '#pml_cells', '#excitation_file', '#src_steps', '#rx_steps'], 'None')
|
||||
|
||||
# Commands that there can be multiple instances of in a model - these will be lists within the dictionary
|
||||
multiplecmds = {key: [] for key in ['#geometry_view', '#material', '#soil_peplinski', '#add_dispersion_debye', '#add_dispersion_lorenz', '#add_dispersion_drude', '#waveform', '#voltage_source', '#hertzian_dipole', '#magnetic_dipole', '#rx', '#rx_box', '#snapshot', '#pml_cfs']}
|
||||
|
||||
# Geometry object building commands that there can be multiple instances of in a model - these will be lists within the dictionary
|
||||
geometrycmds = ['#edge', '#plate', '#triangle', '#box', '#sphere', '#cylinder', '#cylindrical_sector', '#fractal_box', '#add_surface_roughness', '#add_surface_water', '#add_grass']
|
||||
# List to store all geometry object commands in order from input file
|
||||
geometry = []
|
||||
|
||||
# Check if command names are valid, if essential commands are present, and add command parameters to appropriate dictionary values or lists
|
||||
countessentialcmds = 0
|
||||
lindex = 0
|
||||
while(lindex < len(processedlines)):
|
||||
cmd = processedlines[lindex].split(':')
|
||||
cmdname = cmd[0].lower()
|
||||
|
||||
# Check if command name is valid
|
||||
if cmdname not in essentialcmds and cmdname not in singlecmds and cmdname not in multiplecmds and cmdname not in geometrycmds:
|
||||
raise CmdInputError('Your input file contains the invalid command: ' + cmdname)
|
||||
|
||||
# Count essential commands
|
||||
if cmdname in essentialcmds:
|
||||
countessentialcmds += 1
|
||||
|
||||
# Assign command parameters as values to dictionary keys
|
||||
if cmdname in singlecmds:
|
||||
if singlecmds[cmdname] == 'None':
|
||||
singlecmds[cmdname] = cmd[1].strip(' \t\n')
|
||||
else:
|
||||
raise CmdInputError('You can only have one ' + cmdname + ' commmand in your model')
|
||||
|
||||
elif cmdname in multiplecmds:
|
||||
multiplecmds[cmdname].append(cmd[1].strip(' \t\n'))
|
||||
|
||||
elif cmdname in geometrycmds:
|
||||
geometry.append(processedlines[lindex].strip(' \t\n'))
|
||||
|
||||
lindex += 1
|
||||
|
||||
if (countessentialcmds < len(essentialcmds)):
|
||||
raise CmdInputError('Your input file is missing essential gprMax commands required to run a model. Essential commands are: ' + ', '.join(essentialcmds))
|
||||
|
||||
return singlecmds, multiplecmds, geometry
|
||||
|
1438
gprMax/input_cmds_geometry.py
普通文件
1438
gprMax/input_cmds_geometry.py
普通文件
文件差异内容过多而无法显示
加载差异
620
gprMax/input_cmds_multiuse.py
普通文件
620
gprMax/input_cmds_multiuse.py
普通文件
@@ -0,0 +1,620 @@
|
||||
# Copyright (C) 2015: The University of Edinburgh
|
||||
# Authors: Craig Warren and Antonis Giannopoulos
|
||||
#
|
||||
# This file is part of gprMax.
|
||||
#
|
||||
# gprMax is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gprMax is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from .exceptions import CmdInputError
|
||||
from .geometry_views import GeometryView
|
||||
from .materials import Material, PeplinskiSoil
|
||||
from .pml import CFS
|
||||
from .receivers import Rx
|
||||
from .snapshots import Snapshot
|
||||
from .sources import VoltageSource, HertzianDipole, MagneticDipole
|
||||
from .utilities import rvalue
|
||||
from .waveforms import Waveform
|
||||
|
||||
|
||||
def process_multicmds(multicmds, G):
|
||||
"""Checks the validity of command parameters and creates instances of classes of parameters.
|
||||
|
||||
Args:
|
||||
multicmds (dict): Commands that can have multiple instances in the model.
|
||||
G (class): Grid class instance - holds essential parameters describing the model.
|
||||
"""
|
||||
|
||||
# Waveform definitions
|
||||
cmdname = '#waveform'
|
||||
if multicmds[cmdname] != 'None':
|
||||
for cmdinstance in multicmds[cmdname]:
|
||||
tmp = cmdinstance.split()
|
||||
if len(tmp) != 4:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires exactly four parameters')
|
||||
if tmp[0].lower() not in Waveform.waveformtypes:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' must have one of the following types {}'.format(','.join(Waveform.waveformtypes)))
|
||||
if float(tmp[2]) <= 0:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires an excitation frequency value of greater than zero')
|
||||
if any(x.ID == tmp[3] for x in G.waveforms):
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' with ID {} already exists'.format(tmp[2]))
|
||||
|
||||
w = Waveform()
|
||||
w.ID = tmp[3]
|
||||
w.type = tmp[0].lower()
|
||||
w.amp = float(tmp[1])
|
||||
w.freq = float(tmp[2])
|
||||
|
||||
if G.messages:
|
||||
print('Waveform {} of type {} with amplitude {}, frequency {:.3e} Hz created.'.format(w.ID, w.type, w.amp, w.freq))
|
||||
|
||||
G.waveforms.append(w)
|
||||
|
||||
|
||||
# Voltage source
|
||||
cmdname = '#voltage_source'
|
||||
if multicmds[cmdname] != 'None':
|
||||
for cmdinstance in multicmds[cmdname]:
|
||||
tmp = cmdinstance.split()
|
||||
if len(tmp) < 6:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires at least six parameters')
|
||||
|
||||
# Check polarity & position parameters
|
||||
if tmp[0].lower() not in ('x', 'y', 'z'):
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' polarisation must be x, y, or z')
|
||||
positionx = rvalue(float(tmp[1])/G.dx)
|
||||
positiony = rvalue(float(tmp[2])/G.dy)
|
||||
positionz = rvalue(float(tmp[3])/G.dz)
|
||||
resistance = float(tmp[4])
|
||||
if positionx < 0 or positionx > G.nx:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' x-coordinate is not within the model domain')
|
||||
if positiony < 0 or positiony > G.ny:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' y-coordinate is not within the model domain')
|
||||
if positionz < 0 or positionz > G.nz:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' z-coordinate is not within the model domain')
|
||||
if resistance < 0:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires a source resistance of zero or greater')
|
||||
|
||||
# Check if there is a waveformID in the waveforms list
|
||||
if not any(x.ID == tmp[5] for x in G.waveforms):
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' there is no waveform with the identifier {}'.format(tmp[5]))
|
||||
|
||||
v = VoltageSource()
|
||||
v.polarisation= tmp[0]
|
||||
v.positionx = positionx
|
||||
v.positiony = positiony
|
||||
v.positionz = positionz
|
||||
v.resistance = resistance
|
||||
|
||||
if len(tmp) > 6:
|
||||
# Check source start & source remove time parameters
|
||||
start = float(tmp[6])
|
||||
stop = float(tmp[7])
|
||||
if start < 0:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' delay of the initiation of the source should not be less than zero')
|
||||
if stop < 0:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' time to remove the source should not be less than zero')
|
||||
if stop - start <= 0:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' duration of the source should not be zero or less')
|
||||
v.start = start
|
||||
if stop > G.timewindow:
|
||||
v.stop = G.timewindow
|
||||
v.waveformID = tmp[8]
|
||||
tmp = ' start time {:.3e} secs, finish time {:.3e} secs '.format(v.start, v.stop)
|
||||
else:
|
||||
v.start = 0
|
||||
v.stop = G.timewindow
|
||||
v.waveformID = tmp[5]
|
||||
tmp = ' '
|
||||
|
||||
if G.messages:
|
||||
print('Voltage source with polarity {} at {:.3f}m, {:.3f}m, {:.3f}m, resistance {:.1f} Ohms,'.format(v.polarisation, v.positionx * G.dx, v.positiony * G.dy, v.positionz * G.dz, v.resistance) + tmp + 'using waveform {} created.'.format(v.waveformID))
|
||||
|
||||
G.voltagesources.append(v)
|
||||
|
||||
|
||||
# Hertzian dipole
|
||||
cmdname = '#hertzian_dipole'
|
||||
if multicmds[cmdname] != 'None':
|
||||
for cmdinstance in multicmds[cmdname]:
|
||||
tmp = cmdinstance.split()
|
||||
if len(tmp) != 5:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires at least five parameters')
|
||||
|
||||
# Check polarity & position parameters
|
||||
if tmp[0].lower() not in ('x', 'y', 'z'):
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' polarisation must be x, y, or z')
|
||||
positionx = rvalue(float(tmp[1])/G.dx)
|
||||
positiony = rvalue(float(tmp[2])/G.dy)
|
||||
positionz = rvalue(float(tmp[3])/G.dz)
|
||||
if positionx < 0 or positionx > G.nx:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' x-coordinate is not within the model domain')
|
||||
if positiony < 0 or positiony > G.ny:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' y-coordinate is not within the model domain')
|
||||
if positionz < 0 or positionz > G.nz:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' z-coordinate is not within the model domain')
|
||||
|
||||
# Check if there is a waveformID in the waveforms list
|
||||
if not any(x.ID == tmp[4] for x in G.waveforms):
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' there is no waveform with the identifier {}'.format(tmp[4]))
|
||||
|
||||
h = HertzianDipole()
|
||||
h.polarisation = tmp[0]
|
||||
h.positionx = positionx
|
||||
h.positiony = positiony
|
||||
h.positionz = positionz
|
||||
|
||||
if len(tmp) > 6:
|
||||
# Check source start & source remove time parameters
|
||||
start = float(tmp[6])
|
||||
stop = float(tmp[7])
|
||||
if start < 0:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' delay of the initiation of the source should not be less than zero')
|
||||
if stop < 0:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' time to remove the source should not be less than zero')
|
||||
if stop - start <= 0:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' duration of the source should not be zero or less')
|
||||
h.start = start
|
||||
if stop > G.timewindow:
|
||||
h.stop = G.timewindow
|
||||
h.waveformID = tmp[7]
|
||||
tmp = ' start time {:.3e} secs, finish time {:.3e} secs '.format(h.start, h.stop)
|
||||
else:
|
||||
h.start = 0
|
||||
h.stop = G.timewindow
|
||||
h.waveformID = tmp[4]
|
||||
tmp = ' '
|
||||
|
||||
if G.messages:
|
||||
print('Hertzian dipole with polarity {} at {:.3f}m, {:.3f}m, {:.3f}m,'.format(h.polarisation, h.positionx * G.dx, h.positiony * G.dy, h.positionz * G.dz) + tmp + 'using waveform {} created.'.format(h.waveformID))
|
||||
|
||||
G.hertziandipoles.append(h)
|
||||
|
||||
|
||||
# Magnetic dipole
|
||||
cmdname = '#magnetic_dipole'
|
||||
if multicmds[cmdname] != 'None':
|
||||
for cmdinstance in multicmds[cmdname]:
|
||||
tmp = cmdinstance.split()
|
||||
if len(tmp) != 5:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires at least five parameters')
|
||||
|
||||
# Check polarity & position parameters
|
||||
if tmp[0].lower() not in ('x', 'y', 'z'):
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' polarisation must be x, y, or z')
|
||||
positionx = rvalue(float(tmp[1])/G.dx)
|
||||
positiony = rvalue(float(tmp[2])/G.dy)
|
||||
positionz = rvalue(float(tmp[3])/G.dz)
|
||||
if positionx < 0 or positionx > G.nx:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' x-coordinate is not within the model domain')
|
||||
if positiony < 0 or positiony > G.ny:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' y-coordinate is not within the model domain')
|
||||
if positionz < 0 or positionz > G.nz:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' z-coordinate is not within the model domain')
|
||||
|
||||
# Check if there is a waveformID in the waveforms list
|
||||
if not any(x.ID == tmp[4] for x in G.waveforms):
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' there is no waveform with the identifier {}'.format(tmp[4]))
|
||||
|
||||
m = MagneticDipole()
|
||||
m.polarisation = tmp[0]
|
||||
m.positionx = positionx
|
||||
m.positiony = positiony
|
||||
m.positionz = positionz
|
||||
|
||||
if len(tmp) > 6:
|
||||
# Check source start & source remove time parameters
|
||||
start = float(tmp[6])
|
||||
stop = float(tmp[7])
|
||||
if start < 0:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' delay of the initiation of the source should not be less than zero')
|
||||
if stop < 0:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' time to remove the source should not be less than zero')
|
||||
if stop - start <= 0:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' duration of the source should not be zero or less')
|
||||
m.start = start
|
||||
if stop > G.timewindow:
|
||||
m.stop = G.timewindow
|
||||
m.waveformID = tmp[7]
|
||||
tmp = ' start time {:.3e} secs, finish time {:.3e} secs '.format(m.start, m.stop)
|
||||
else:
|
||||
m.start = 0
|
||||
m.stop = G.timewindow
|
||||
m.waveformID = tmp[4]
|
||||
tmp = ' '
|
||||
|
||||
if G.messages:
|
||||
print('Magnetic dipole with polarity {} at {:.3f}m, {:.3f}m, {:.3f}m,'.format(m.polarisation, m.positionx * G.dx, m.positiony * G.dy, m.positionz * G.dz) + tmp + 'using waveform {} created.'.format(m.waveformID))
|
||||
|
||||
G.magneticdipoles.append(m)
|
||||
|
||||
|
||||
# Receiver
|
||||
cmdname = '#rx'
|
||||
if multicmds[cmdname] != 'None':
|
||||
for cmdinstance in multicmds[cmdname]:
|
||||
tmp = cmdinstance.split()
|
||||
if len(tmp) != 3:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires exactly three parameters')
|
||||
|
||||
# Check position parameters
|
||||
positionx = rvalue(float(tmp[0])/G.dx)
|
||||
positiony = rvalue(float(tmp[1])/G.dy)
|
||||
positionz = rvalue(float(tmp[2])/G.dz)
|
||||
if positionx < 0 or positionx > G.nx:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' x-coordinate is not within the model domain')
|
||||
if positiony < 0 or positiony > G.ny:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' y-coordinate is not within the model domain')
|
||||
if positionz < 0 or positionz > G.nz:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' z-coordinate is not within the model domain')
|
||||
|
||||
r = Rx(positionx=positionx, positiony=positiony, positionz=positionz)
|
||||
|
||||
if G.messages:
|
||||
print('Receiver at {:.3f}m, {:.3f}m, {:.3f}m created.'.format(r.positionx * G.dx, r.positiony * G.dy, r.positionz * G.dz))
|
||||
|
||||
G.rxs.append(r)
|
||||
|
||||
|
||||
# Receiver box
|
||||
cmdname = '#rx_box'
|
||||
if multicmds[cmdname] != 'None':
|
||||
for cmdinstance in multicmds[cmdname]:
|
||||
tmp = cmdinstance.split()
|
||||
if len(tmp) != 9:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires exactly nine parameters')
|
||||
|
||||
xs = rvalue(float(tmp[0])/G.dx)
|
||||
xf = rvalue(float(tmp[3])/G.dx)
|
||||
ys = rvalue(float(tmp[1])/G.dy)
|
||||
yf = rvalue(float(tmp[4])/G.dy)
|
||||
zs = rvalue(float(tmp[2])/G.dz)
|
||||
zf = rvalue(float(tmp[5])/G.dz)
|
||||
dx = rvalue(float(tmp[6])/G.dx)
|
||||
dy = rvalue(float(tmp[7])/G.dy)
|
||||
dz = rvalue(float(tmp[8])/G.dz)
|
||||
|
||||
if xs < 0 or xs > G.nx:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the lower x-coordinate {} is not within the model domain'.format(xs))
|
||||
if xf < 0 or xf > G.nx:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the upper x-coordinate {} is not within the model domain'.format(xf))
|
||||
if ys < 0 or ys > G.ny:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the lower y-coordinate {} is not within the model domain'.format(ys))
|
||||
if yf < 0 or yf > G.ny:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the upper y-coordinate {} is not within the model domain'.format(yf))
|
||||
if zs < 0 or zs > G.nz:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the lower z-coordinate {} is not within the model domain'.format(zs))
|
||||
if zf < 0 or zf > G.nz:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the upper z-coordinate {} is not within the model domain'.format(zf))
|
||||
if xs >= xf or ys >= yf or zs >= zf:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the lower coordinates should be less than the upper coordinates')
|
||||
if dx < 0 or dy < 0 or dz < 0:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the step size should not be less than zero')
|
||||
if dx < G.dx or dy < G.dy or dz < G.dz:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the step size should not be less than the spatial discretisation')
|
||||
|
||||
for x in range(xs, xf, dx):
|
||||
for y in range(ys, yf, dy):
|
||||
for z in range(zs, zf, dz):
|
||||
r = Rx(positionx=x, positiony=y, positionz=z)
|
||||
G.rxs.append(r)
|
||||
|
||||
if G.messages:
|
||||
print('Receiver box {:.3f}m, {:.3f}m, {:.3f}m, to {:.3f}m, {:.3f}m, {:.3f}m with steps {:.3f}m, {:.3f}m, {:.3f} created.'.format(xs * G.dx, ys * G.dy, zs * G.dz, xf * G.dx, yf * G.dy, zf * G.dz, dx * G.dx, dy * G.dy, dz * G.dz))
|
||||
|
||||
|
||||
# Snapshot
|
||||
cmdname = '#snapshot'
|
||||
if multicmds[cmdname] != 'None':
|
||||
for cmdinstance in multicmds[cmdname]:
|
||||
tmp = cmdinstance.split()
|
||||
if len(tmp) != 11:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires exactly eleven parameters')
|
||||
|
||||
xs = rvalue(float(tmp[0])/G.dx)
|
||||
xf = rvalue(float(tmp[3])/G.dx)
|
||||
ys = rvalue(float(tmp[1])/G.dy)
|
||||
yf = rvalue(float(tmp[4])/G.dy)
|
||||
zs = rvalue(float(tmp[2])/G.dz)
|
||||
zf = rvalue(float(tmp[5])/G.dz)
|
||||
dx = rvalue(float(tmp[6])/G.dx)
|
||||
dy = rvalue(float(tmp[7])/G.dy)
|
||||
dz = rvalue(float(tmp[8])/G.dz)
|
||||
|
||||
# If real floating point value given
|
||||
if '.' in tmp[9] or 'e' in tmp[9]:
|
||||
if float(tmp[9]) > 0:
|
||||
time = rvalue((float(tmp[9]) / G.dt)) + 1
|
||||
else:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' time value must be greater than zero')
|
||||
# If number of iterations given
|
||||
else:
|
||||
time = int(tmp[9])
|
||||
|
||||
if dx < 0 or dy < 0 or dz < 0:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the step size should not be less than zero')
|
||||
if dx < G.dx or dy < G.dy or dz < G.dz:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the step size should not be less than the spatial discretisation')
|
||||
if time <= 0 or time > G.iterations:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' time value is not valid')
|
||||
|
||||
s = Snapshot(xs, ys, zs, xf, yf, zf, dx, dy, dz, time, tmp[10])
|
||||
|
||||
if G.messages:
|
||||
print('Snapshot from {:.3f}m, {:.3f}m, {:.3f}m, to {:.3f}m, {:.3f}m, {:.3f}m, discretisation {:.3f}m, {:.3f}m, {:.3f}m, at {:.3e} secs with filename {} created.'.format(xs * G.dx, ys * G.dy, zs * G.dz, xf * G.dx, yf * G.dy, zf * G.dz, dx * G.dx, dx * G.dy, dx * G.dz, s.time * G.dt, s.filename))
|
||||
|
||||
G.snapshots.append(s)
|
||||
|
||||
|
||||
# Materials
|
||||
# Create built-in materials
|
||||
m = Material(0, 'pec', G)
|
||||
m.average = False
|
||||
G.materials.append(m)
|
||||
|
||||
m = Material(1, 'free_space', G)
|
||||
m.average = True
|
||||
G.materials.append(m)
|
||||
|
||||
cmdname = '#material'
|
||||
if multicmds[cmdname] != 'None':
|
||||
for cmdinstance in multicmds[cmdname]:
|
||||
tmp = cmdinstance.split()
|
||||
if len(tmp) != 5:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires exactly five parameters')
|
||||
if float(tmp[0]) < 0:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires a positive value for static (DC) permittivity')
|
||||
if float(tmp[1]) < 0:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires a positive value for conductivity')
|
||||
if float(tmp[2]) < 0:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires a positive value for permeability')
|
||||
if float(tmp[3]) < 0:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires a positive value for magnetic conductivity')
|
||||
if any(x.ID == tmp[4] for x in G.materials):
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' with ID {} already exists'.format(tmp[4]))
|
||||
|
||||
# Create a new instance of the Material class material (start index after pec & free_space)
|
||||
m = Material(len(G.materials), tmp[4], G)
|
||||
m.er = float(tmp[0])
|
||||
m.se = float(tmp[1])
|
||||
m.mr = float(tmp[2])
|
||||
m.sm = float(tmp[3])
|
||||
|
||||
if G.messages:
|
||||
print('Material {} with epsr={:4.2f}, sig={:.3e} S/m; mur={:4.2f}, sig*={:.3e} S/m created.'.format(m.ID, m.er, m.se, m.mr, m.sm))
|
||||
|
||||
# Append the new material object to the materials list
|
||||
G.materials.append(m)
|
||||
|
||||
|
||||
cmdname = '#add_dispersion_debye'
|
||||
if multicmds[cmdname] != 'None':
|
||||
for cmdinstance in multicmds[cmdname]:
|
||||
tmp = cmdinstance.split()
|
||||
|
||||
if len(tmp) < 4:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires at least four parameters')
|
||||
if int(tmp[0]) < 0:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires a positive value for number of poles')
|
||||
poles = int(tmp[0])
|
||||
materialsrequested = tmp[(2 * poles) + 1:len(tmp)]
|
||||
|
||||
# Look up requested materials in existing list of material instances
|
||||
materials = [y for x in materialsrequested for y in G.materials if y.ID == x]
|
||||
|
||||
if len(materials) != len(materialsrequested):
|
||||
notfound = [x for x in materialsrequested if x not in materials]
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' material(s) {} do not exist'.format(notfound))
|
||||
|
||||
for material in materials:
|
||||
material.type = 'debye'
|
||||
material.poles = poles
|
||||
material.average = False
|
||||
for pole in range(1, 2 * poles, 2):
|
||||
if float(tmp[pole]) > 0 and float(tmp[pole + 1]) > G.dt:
|
||||
material.deltaer.append(float(tmp[pole]))
|
||||
material.tau.append(float(tmp[pole + 1]))
|
||||
else:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires positive values for the permittivity difference and relaxation times, and relaxation times that are greater than the time step for the model.')
|
||||
if material.poles > Material.maxpoles:
|
||||
Material.maxpoles = material.poles
|
||||
|
||||
if G.messages:
|
||||
print('Debye-type disperion added to {} with delta_epsr={}, and tau={} secs created.'.format(material.ID, ','.join('%4.2f' % deltaer for deltaer in material.deltaer), ','.join('%4.3e' % tau for tau in material.tau)))
|
||||
|
||||
cmdname = '#add_dispersion_lorenz'
|
||||
if multicmds[cmdname] != 'None':
|
||||
for cmdinstance in multicmds[cmdname]:
|
||||
tmp = cmdinstance.split()
|
||||
|
||||
if len(tmp) < 5:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires at least five parameters')
|
||||
if int(tmp[0]) < 0:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires a positive value for number of poles')
|
||||
poles = int(tmp[0])
|
||||
materialsrequested = tmp[(3 * poles) + 1:len(tmp)]
|
||||
|
||||
# Look up requested materials in existing list of material instances
|
||||
materials = [y for x in materialsrequested for y in G.materials if y.ID == x]
|
||||
|
||||
if len(materials) != len(materialsrequested):
|
||||
notfound = [x for x in materialsrequested if x not in materials]
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' material(s) {} do not exist'.format(notfound))
|
||||
|
||||
for material in materials:
|
||||
material.type = 'lorenz'
|
||||
material.poles = poles
|
||||
material.average = False
|
||||
for pole in range(1, 3 * poles, 3):
|
||||
if float(tmp[pole]) > 0 and float(tmp[pole + 1]) > G.dt and float(tmp[pole + 2]) > G.dt:
|
||||
material.deltaer.append(float(tmp[pole]))
|
||||
material.tau.append(float(tmp[pole + 1]))
|
||||
material.alpha.append(float(tmp[pole + 2]))
|
||||
else:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires positive values for the permittivity difference and relaxation times, and relaxation times that are greater than the time step for the model.')
|
||||
if material.poles > Material.maxpoles:
|
||||
Material.maxpoles = material.poles
|
||||
|
||||
if G.messages:
|
||||
print('Lorenz-type disperion added to {} with delta_epsr={}, tau={} secs, and alpha={} created.'.format(material.ID, ','.join('%4.2f' % deltaer for deltaer in material.deltaer), ','.join('%4.3e' % tau for tau in material.tau), ','.join('%4.3e' % alpha for alpha in material.alpha)))
|
||||
|
||||
|
||||
cmdname = '#add_dispersion_drude'
|
||||
if multicmds[cmdname] != 'None':
|
||||
for cmdinstance in multicmds[cmdname]:
|
||||
tmp = cmdinstance.split()
|
||||
|
||||
if len(tmp) < 5:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires at least five parameters')
|
||||
if int(tmp[0]) < 0:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires a positive value for number of poles')
|
||||
poles = int(tmp[0])
|
||||
materialsrequested = tmp[(3 * poles) + 1:len(tmp)]
|
||||
|
||||
# Look up requested materials in existing list of material instances
|
||||
materials = [y for x in materialsrequested for y in G.materials if y.ID == x]
|
||||
|
||||
if len(materials) != len(materialsrequested):
|
||||
notfound = [x for x in materialsrequested if x not in materials]
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' material(s) {} do not exist'.format(notfound))
|
||||
|
||||
for material in materials:
|
||||
material.type = 'drude'
|
||||
material.poles = poles
|
||||
material.average = False
|
||||
for pole in range(1, 3 * poles, 3):
|
||||
if float(tmp[pole]) > 0 and float(tmp[pole + 1]) > G.dt and float(tmp[pole + 2]) > G.dt:
|
||||
material.deltaer.append(float(tmp[pole]))
|
||||
material.tau.append(float(tmp[pole + 1]))
|
||||
material.alpha.append(float(tmp[pole + 2]))
|
||||
else:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires positive values for the permittivity difference and relaxation times, and relaxation times that are greater than the time step for the model.')
|
||||
if material.poles > Material.maxpoles:
|
||||
Material.maxpoles = material.poles
|
||||
|
||||
if G.messages:
|
||||
print('Drude-type disperion added to {} with delta_epsr={}, tau1={} secs, and tau2={} secs created.'.format(material.ID, ','.join('%4.2f' % deltaer for deltaer in material.deltaer), ','.join('%4.3e' % tau for tau in material.tau), ','.join('%4.3e' % alpha for alpha in material.alpha)))
|
||||
|
||||
|
||||
cmdname = '#soil_peplinski'
|
||||
if multicmds[cmdname] != 'None':
|
||||
for cmdinstance in multicmds[cmdname]:
|
||||
tmp = cmdinstance.split()
|
||||
if len(tmp) != 7:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires at exactly seven parameters')
|
||||
if float(tmp[0]) < 0:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires a positive value for the sand fraction')
|
||||
if float(tmp[1]) < 0:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires a positive value for the clay fraction')
|
||||
if float(tmp[2]) < 0:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires a positive value for the bulk density')
|
||||
if float(tmp[3]) < 0:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires a positive value for the sand particle density')
|
||||
if float(tmp[4]) < 0:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires a positive value for the lower limit of the water volumetric fraction')
|
||||
if float(tmp[5]) < 0:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires a positive value for the upper limit of the water volumetric fraction')
|
||||
if any(x.ID == tmp[6] for x in G.mixingmodels):
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' with ID {} already exists'.format(tmp[6]))
|
||||
|
||||
# Create a new instance of the Material class material (start index after pec & free_space)
|
||||
s = PeplinskiSoil(tmp[6], float(tmp[0]), float(tmp[1]), float(tmp[2]), float(tmp[3]), (float(tmp[4]), float(tmp[5])))
|
||||
|
||||
if G.messages:
|
||||
print('Mixing model (Peplinski) used to create {} with sand fraction {:.3f}, clay fraction {:.3f}, bulk density {:.3f} g/cm3, sand particle density {:.3f} g/cm3, and water volumetric fraction {} to {} created.'.format(s.ID, s.S, s.C, s.rb, s.rs, s.mu[0], s.mu[1]))
|
||||
|
||||
# Append the new material object to the materials list
|
||||
G.mixingmodels.append(s)
|
||||
|
||||
|
||||
# Geometry views (creates VTK-based geometry files)
|
||||
cmdname = '#geometry_view'
|
||||
if multicmds[cmdname] != 'None':
|
||||
for cmdinstance in multicmds[cmdname]:
|
||||
tmp = cmdinstance.split()
|
||||
if len(tmp) != 11:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires exactly eleven parameters')
|
||||
|
||||
xs = rvalue(float(tmp[0])/G.dx)
|
||||
xf = rvalue(float(tmp[3])/G.dx)
|
||||
ys = rvalue(float(tmp[1])/G.dy)
|
||||
yf = rvalue(float(tmp[4])/G.dy)
|
||||
zs = rvalue(float(tmp[2])/G.dz)
|
||||
zf = rvalue(float(tmp[5])/G.dz)
|
||||
dx = rvalue(float(tmp[6])/G.dx)
|
||||
dy = rvalue(float(tmp[7])/G.dy)
|
||||
dz = rvalue(float(tmp[8])/G.dz)
|
||||
|
||||
if xs < 0 or xs > G.nx:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the lower x-coordinate {} is not within the model domain'.format(xs * G.dx))
|
||||
if xf < 0 or xf > G.nx:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the upper x-coordinate {} is not within the model domain'.format(xf * G.dx))
|
||||
if ys < 0 or ys > G.ny:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the lower y-coordinate {} is not within the model domain'.format(ys * G.dy))
|
||||
if yf < 0 or yf > G.ny:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the upper y-coordinate {} is not within the model domain'.format(yf * G.dy))
|
||||
if zs < 0 or zs > G.nz:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the lower z-coordinate {} is not within the model domain'.format(zs * G.dz))
|
||||
if zf < 0 or zf > G.nz:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the upper z-coordinate {} is not within the model domain'.format(zf * G.dz))
|
||||
if xs >= xf or ys >= yf or zs >= zf:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the lower coordinates should be less than the upper coordinates')
|
||||
if dx < 0 or dy < 0 or dz < 0:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the step size should not be less than zero')
|
||||
if dx < G.dx or dy < G.dy or dz < G.dz:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the step size should not be less than the spatial discretisation')
|
||||
if tmp[10].lower() != 'n' and tmp[10].lower() != 'f':
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires type to be either n (normal) or f (fine)')
|
||||
|
||||
g = GeometryView(xs, ys, zs, xf, yf, zf, dx, dy, dz, tmp[9], tmp[10].lower())
|
||||
|
||||
if G.messages:
|
||||
print('Geometry view from {:.3f}m, {:.3f}m, {:.3f}m, to {:.3f}m, {:.3f}m, {:.3f}m, discretisation {:.3f}m, {:.3f}m, {:.3f}m, filename {} created.'.format(xs * G.dx, ys * G.dy, zs * G.dz, xf * G.dx, yf * G.dy, zf * G.dz, dx * G.dx, dy * G.dy, dz * G.dz, g.filename))
|
||||
|
||||
# Append the new GeometryView object to the geometry views list
|
||||
G.geometryviews.append(g)
|
||||
|
||||
|
||||
# Complex frequency shifted (CFS) PML parameter
|
||||
cmdname = '#pml_cfs'
|
||||
if multicmds[cmdname] != 'None':
|
||||
if len(multicmds[cmdname]) > 2:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' can only be used up to two times, for up to a 2nd order PML')
|
||||
for cmdinstance in multicmds[cmdname]:
|
||||
tmp = cmdinstance.split()
|
||||
if len(tmp) != 9:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires exactly nine parameters')
|
||||
if tmp[0] not in CFS.scalingtypes or tmp[3] not in CFS.scalingtypes or tmp[6] not in CFS.scalingtypes:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' must have scaling type {}'.format(','.join(CFS.scalingtypes)))
|
||||
if float(tmp[1]) < 0 or float(tmp[2]) < 0 or float(tmp[4]) < 0 or float(tmp[5]) < 0 or float(tmp[7]) < 0:
|
||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' minimum and maximum scaling values must be greater than zero')
|
||||
|
||||
cfs = CFS()
|
||||
cfs.alphascaling = tmp[0]
|
||||
cfs.alphamin = float(tmp[1])
|
||||
cfs.alphamax = float(tmp[2])
|
||||
cfs.kappascaling = tmp[3]
|
||||
cfs.kappamin = float(tmp[4])
|
||||
cfs.kappamax = float(tmp[5])
|
||||
cfs.sigmascaling = tmp[6]
|
||||
cfs.sigmamin = float(tmp[7])
|
||||
if tmp[8] == 'None':
|
||||
cfs.sigmamax = None
|
||||
else:
|
||||
cfs.sigmamax = float(tmp[8])
|
||||
|
||||
if G.messages:
|
||||
print('CFS parameters: alpha scaling {}, alpha_min {:.2f}, alpha_max {:.2f}, kappa scaling {}, kappa_min {:.2f}, kappa_max {:.2f}, sigma scaling {}, sigma_min {:.2f}, sigma_max {} created.'.format(cfs.alphascaling, cfs.alphamin, cfs.alphamax, cfs.kappascaling, cfs.kappamin, cfs.kappamax, cfs.sigmascaling, cfs.sigmamin, cfs.sigmamax))
|
||||
|
||||
G.cfs.append(cfs)
|
||||
|
258
gprMax/input_cmds_singleuse.py
普通文件
258
gprMax/input_cmds_singleuse.py
普通文件
@@ -0,0 +1,258 @@
|
||||
# Copyright (C) 2015: The University of Edinburgh
|
||||
# Authors: Craig Warren and Antonis Giannopoulos
|
||||
#
|
||||
# This file is part of gprMax.
|
||||
#
|
||||
# gprMax is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gprMax is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os, sys
|
||||
import numpy as np
|
||||
from psutil import virtual_memory
|
||||
|
||||
from .constants import c, floattype
|
||||
from .exceptions import CmdInputError
|
||||
from .pml import PML, CFS
|
||||
from .utilities import rvalue, human_size
|
||||
from .waveforms import Waveform
|
||||
|
||||
|
||||
def process_singlecmds(singlecmds, multicmds, G):
|
||||
"""Checks the validity of command parameters and creates instances of classes of parameters.
|
||||
|
||||
Args:
|
||||
singlecmds (dict): Commands that can only occur once in the model.
|
||||
multicmds (dict): Commands that can have multiple instances in the model (required to pass to process_materials_file function).
|
||||
G (class): Grid class instance - holds essential parameters describing the model.
|
||||
"""
|
||||
|
||||
# Check validity of command parameters in order needed
|
||||
# messages
|
||||
cmd = '#messages'
|
||||
if singlecmds[cmd] != 'None':
|
||||
tmp = singlecmds[cmd].split()
|
||||
if len(tmp) != 1:
|
||||
raise CmdInputError(cmd + ' requires exactly one parameter')
|
||||
if singlecmds[cmd].lower() == 'y':
|
||||
G.messages = True
|
||||
elif singlecmds[cmd].lower() == 'n':
|
||||
G.messages = False
|
||||
else:
|
||||
raise CmdInputError(cmd + ' requires input values of either y or n')
|
||||
|
||||
|
||||
# Title
|
||||
cmd = '#title'
|
||||
if singlecmds[cmd] != 'None':
|
||||
G.title = singlecmds[cmd]
|
||||
if G.messages:
|
||||
print('Model title: {}'.format(G.title))
|
||||
|
||||
|
||||
# Number of processors to run on (OpenMP)
|
||||
cmd = '#num_threads'
|
||||
ompthreads = os.environ.get('OMP_NUM_THREADS')
|
||||
if singlecmds[cmd] != 'None':
|
||||
tmp = tuple(int(x) for x in singlecmds[cmd].split())
|
||||
if len(tmp) != 1:
|
||||
raise CmdInputError(cmd + ' requires exactly one parameter to specify the number of OpenMP threads to use')
|
||||
if tmp[0] < 1:
|
||||
raise CmdInputError(cmd + ' requires the value to be an integer not less than one')
|
||||
G.nthreads = tmp[0]
|
||||
elif ompthreads:
|
||||
G.nthreads = int(ompthreads)
|
||||
else:
|
||||
# Set number of threads to number of physical CPU cores, i.e. avoid hyperthreading with OpenMP for now
|
||||
if sys.platform == 'darwin':
|
||||
G.nthreads = int(os.popen('sysctl hw.physicalcpu').readlines()[0].split(':')[1].strip())
|
||||
elif sys.platform == 'win32':
|
||||
# Consider using wmi tools to check hyperthreading on Windows
|
||||
G.nthreads = os.cpu_count()
|
||||
elif 'linux' in sys.platform:
|
||||
lscpu = os.popen('lscpu').readlines()
|
||||
cpusockets = [item for item in lscpu if item.startswith('Socket(s)')]
|
||||
cpusockets = int(cpusockets[0].split(':')[1].strip())
|
||||
corespersocket = [item for item in lscpu if item.startswith('Core(s) per socket')]
|
||||
corespersocket = int(corespersocket[0].split(':')[1].strip())
|
||||
G.nthreads = cpusockets * corespersocket
|
||||
else:
|
||||
G.nthreads = os.cpu_count()
|
||||
if G.messages:
|
||||
print('Number of threads: {}'.format(G.nthreads))
|
||||
|
||||
|
||||
# Spatial discretisation
|
||||
cmd = '#dx_dy_dz'
|
||||
tmp = [float(x) for x in singlecmds[cmd].split()]
|
||||
if len(tmp) != 3:
|
||||
raise CmdInputError(cmd + ' requires exactly three parameters')
|
||||
if tmp[0] <= 0:
|
||||
raise CmdInputError(cmd + ' requires the x-direction spatial step to be greater than zero')
|
||||
if tmp[1] <= 0:
|
||||
raise CmdInputError(cmd + ' requires the y-direction spatial step to be greater than zero')
|
||||
if tmp[2] <= 0:
|
||||
raise CmdInputError(cmd + ' requires the z-direction spatial step to be greater than zero')
|
||||
G.dx = tmp[0]
|
||||
G.dy = tmp[1]
|
||||
G.dz = tmp[2]
|
||||
if G.messages:
|
||||
print('Spatial discretisation: {:.3f} x {:.3f} x {:.3f} m'.format(G.dx, G.dy, G.dz))
|
||||
|
||||
|
||||
# Domain
|
||||
cmd = '#domain'
|
||||
tmp = [float(x) for x in singlecmds[cmd].split()]
|
||||
nx = rvalue(tmp[0]/G.dx)
|
||||
ny = rvalue(tmp[1]/G.dy)
|
||||
nz = rvalue(tmp[2]/G.dz)
|
||||
if len(tmp) != 3:
|
||||
raise CmdInputError(cmd + ' requires exactly three parameters')
|
||||
G.nx = nx
|
||||
G.ny = ny
|
||||
G.nz = nz
|
||||
if G.messages:
|
||||
print('Model domain: {:.3f} x {:.3f} x {:.3f} m ({:d} x {:d} x {:d} = {:d} Mcells)'.format(tmp[0], tmp[1], tmp[2], G.nx, G.ny, G.nz, int((G.nx * G.ny * G.nz)/1e6)))
|
||||
mem = (((G.nx + 1) * (G.ny + 1) * (G.nz + 1) * 13 * np.dtype(floattype).itemsize + (G.nx + 1) * (G.ny + 1) * (G.nz + 1) * 18) * 1.1) + 30e6
|
||||
print('Memory (approx) required/available: {} / {}'.format(human_size(mem), human_size(virtual_memory().total)))
|
||||
|
||||
|
||||
# Time step CFL limit - use either 2D or 3D (default)
|
||||
cmd = '#time_step_limit_type'
|
||||
if singlecmds[cmd] != 'None':
|
||||
tmp = singlecmds[cmd].split()
|
||||
if len(tmp) != 1:
|
||||
raise CmdInputError(cmd + ' requires exactly one parameter')
|
||||
if singlecmds[cmd].lower() == '2d':
|
||||
if G.nx == 1:
|
||||
G.dt = 1 / (c * np.sqrt((1 / G.dy) * (1 / G.dy) + (1 / G.dz) * (1 / G.dz)))
|
||||
elif G.ny == 1:
|
||||
G.dt = 1 / (c * np.sqrt((1 / G.dx) * (1 / G.dx) + (1 / G.dz) * (1 / G.dz)))
|
||||
elif G.nz == 1:
|
||||
G.dt = 1 / (c * np.sqrt((1 / G.dx) * (1 / G.dx) + (1 / G.dy) * (1 / G.dy)))
|
||||
else:
|
||||
raise CmdInputError(cmd + ' 2D CFL limit can only be used when one dimension of the domain is one cell')
|
||||
elif singlecmds[cmd].lower() == '3d':
|
||||
G.dt = 1 / (c * np.sqrt((1 / G.dx) * (1 / G.dx) + (1 / G.dy) * (1 / G.dy) + (1 / G.dz) * (1 / G.dz)))
|
||||
else:
|
||||
raise CmdInputError(cmd + ' requires input values of either 2D or 3D')
|
||||
else:
|
||||
G.dt = 1 / (c * np.sqrt((1 / G.dx) * (1 / G.dx) + (1 / G.dy) * (1 / G.dy) + (1 / G.dz) * (1 / G.dz)))
|
||||
if G.messages:
|
||||
print('Time step: {:.3e} secs'.format(G.dt))
|
||||
|
||||
|
||||
# Time step stability factor
|
||||
cmd = '#time_step_stability_factor'
|
||||
if singlecmds[cmd] != 'None':
|
||||
tmp = tuple(float(x) for x in singlecmds[cmd].split())
|
||||
if len(tmp) != 1:
|
||||
raise CmdInputError(cmd + ' requires exactly one parameter')
|
||||
if tmp[0] <= 0 or tmp[0] > 1:
|
||||
raise CmdInputError(cmd + ' requires the value of the time step stability factor to be between zero and one')
|
||||
G.dt = G.dt * tmp[0]
|
||||
if G.messages:
|
||||
print('Time step (modified): {:.3e} secs'.format(G.dt))
|
||||
|
||||
|
||||
# Time window
|
||||
cmd = '#time_window'
|
||||
tmp = singlecmds[cmd].split()
|
||||
if len(tmp) != 1:
|
||||
raise CmdInputError(cmd + ' requires exactly one parameter to specify the time window. Either in seconds or number of iterations.')
|
||||
tmp = tmp[0].lower()
|
||||
# If real floating point value given
|
||||
if '.' in tmp or 'e' in tmp:
|
||||
if float(tmp) > 0:
|
||||
G.timewindow = float(tmp)
|
||||
G.iterations = rvalue((float(tmp) / G.dt)) + 1
|
||||
else:
|
||||
raise CmdInputError(cmd + ' must have a value greater than zero')
|
||||
# If number of iterations given
|
||||
else:
|
||||
G.timewindow = (int(tmp) - 1) * G.dt
|
||||
G.iterations = int(tmp)
|
||||
if G.messages:
|
||||
print('Time window: {:.3e} secs ({} iterations)'.format(G.timewindow, G.iterations))
|
||||
|
||||
|
||||
# PML
|
||||
cmd = '#pml_cells'
|
||||
if singlecmds[cmd] != 'None':
|
||||
tmp = singlecmds[cmd].split()
|
||||
if len(tmp) != 1 and len(tmp) != 6:
|
||||
raise CmdInputError(cmd + ' requires either one or six parameters')
|
||||
if len(tmp) == 1:
|
||||
G.pmlthickness = (int(tmp[0]), int(tmp[0]), int(tmp[0]), int(tmp[0]), int(tmp[0]), int(tmp[0]))
|
||||
else:
|
||||
G.pmlthickness = (int(tmp[0]), int(tmp[1]), int(tmp[2]), int(tmp[3]), int(tmp[4]), int(tmp[5]))
|
||||
if 2*G.pmlthickness[0] >= G.nx or 2*G.pmlthickness[1] >= G.ny or 2*G.pmlthickness[2] >= G.nz or 2*G.pmlthickness[3] >= G.nx or 2*G.pmlthickness[4] >= G.ny or 2*G.pmlthickness[5] >= G.nz:
|
||||
raise CmdInputError(cmd + ' has too many cells for the domain size')
|
||||
|
||||
|
||||
# src_steps
|
||||
cmd = '#src_steps'
|
||||
if singlecmds[cmd] != 'None':
|
||||
tmp = singlecmds[cmd].split()
|
||||
if len(tmp) != 3:
|
||||
raise CmdInputError(cmd + ' requires exactly three parameters')
|
||||
G.txstepx = rvalue(float(tmp[0])/G.dx)
|
||||
G.txstepy = rvalue(float(tmp[1])/G.dy)
|
||||
G.txstepz = rvalue(float(tmp[2])/G.dz)
|
||||
if G.messages:
|
||||
print('All sources will step {:.3f}m, {:.3f}m, {:.3f}m for each model run.'.format(G.txstepx * G.dx, G.txstepy * G.dy, G.txstepz * G.dz))
|
||||
|
||||
|
||||
# rx_steps
|
||||
cmd = '#rx_steps'
|
||||
if singlecmds[cmd] != 'None':
|
||||
tmp = singlecmds[cmd].split()
|
||||
if len(tmp) != 3:
|
||||
raise CmdInputError(cmd + ' requires exactly three parameters')
|
||||
G.rxstepx = rvalue(float(tmp[0])/G.dx)
|
||||
G.rxstepy = rvalue(float(tmp[1])/G.dy)
|
||||
G.rxstepz = rvalue(float(tmp[2])/G.dz)
|
||||
if G.messages:
|
||||
print('All receivers will step {:.3f}m, {:.3f}m, {:.3f}m for each model run.'.format(G.rxstepx * G.dx, G.rxstepy * G.dy, G.rxstepz * G.dz))
|
||||
|
||||
|
||||
# Excitation file for user-defined source waveforms
|
||||
cmd = '#excitation_file'
|
||||
if singlecmds[cmd] != 'None':
|
||||
tmp = singlecmds[cmd].split()
|
||||
if len(tmp) != 1:
|
||||
raise CmdInputError(cmd + ' requires exactly one parameter')
|
||||
excitationfile = tmp[0]
|
||||
|
||||
# Open file and get waveform names
|
||||
with open(excitationfile, 'r') as f:
|
||||
waveformIDs = f.readline().split()
|
||||
|
||||
# Read all waveform values into an array
|
||||
waveformvalues = np.loadtxt(excitationfile, skiprows=1, dtype=floattype)
|
||||
|
||||
for waveform in range(len(waveformIDs)):
|
||||
if any(x.ID == waveformIDs[waveform] for x in G.waveforms):
|
||||
raise CmdInputError('Waveform with ID {} already exists'.format(waveformIDs[waveform]))
|
||||
w = Waveform()
|
||||
w.ID = waveformIDs[waveform]
|
||||
w.type = 'user'
|
||||
w.uservalues = waveformvalues[:,waveform]
|
||||
|
||||
if G.messages:
|
||||
print('User waveform {} created.'.format(w.ID))
|
||||
|
||||
G.waveforms.append(w)
|
||||
|
||||
|
||||
|
||||
|
233
gprMax/materials.py
普通文件
233
gprMax/materials.py
普通文件
@@ -0,0 +1,233 @@
|
||||
# Copyright (C) 2015: The University of Edinburgh
|
||||
# Authors: Craig Warren and Antonis Giannopoulos
|
||||
#
|
||||
# This file is part of gprMax.
|
||||
#
|
||||
# gprMax is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gprMax is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import numpy as np
|
||||
|
||||
from .constants import e0, m0, floattype, complextype
|
||||
|
||||
|
||||
class Material():
|
||||
"""Materials, their properties and update coefficients."""
|
||||
|
||||
# Maximum number of dispersive material poles in a model
|
||||
maxpoles = 0
|
||||
|
||||
# Types of material
|
||||
types = ['standard', 'debye', 'lorenz', 'drude']
|
||||
|
||||
# Properties of water from: http://dx.doi.org/10.1109/TGRS.2006.873208
|
||||
waterer = 80.1
|
||||
watereri = 4.9
|
||||
waterdeltaer = waterer - watereri
|
||||
watertau = 9.231e-12
|
||||
|
||||
# Properties of grass from: http://dx.doi.org/10.1007/BF00902994
|
||||
grasser = 18.5087
|
||||
grasseri = 12.7174
|
||||
grassdeltaer = grasser - grasseri
|
||||
grasstau = 1.0793e-11
|
||||
|
||||
def __init__(self, numID, ID, G):
|
||||
"""
|
||||
Args:
|
||||
numID (int): Numeric identifier of the material.
|
||||
ID (str): Name of the material.
|
||||
G (class): Grid class instance - holds essential parameters describing the model.
|
||||
"""
|
||||
self.numID = numID
|
||||
self.ID = ID
|
||||
self.type = 'standard'
|
||||
# Default material averaging
|
||||
self.average = True
|
||||
|
||||
# Default material constitutive parameters (free_space)
|
||||
self.er = 1.0
|
||||
self.se = 0.0
|
||||
self.mr = 1.0
|
||||
self.sm = 0.0
|
||||
|
||||
# Parameters for dispersive materials
|
||||
self.poles = 0
|
||||
self.deltaer = []
|
||||
self.tau = []
|
||||
self.alpha = []
|
||||
|
||||
def calculate_update_coeffsH(self, G):
|
||||
"""Calculates the magnetic update coefficients of the material.
|
||||
|
||||
Args:
|
||||
G (class): Grid class instance - holds essential parameters describing the model.
|
||||
"""
|
||||
HA = (m0*self.mr / G.dt) + 0.5*self.sm
|
||||
HB = (m0*self.mr / G.dt) - 0.5*self.sm
|
||||
self.DA = HB / HA
|
||||
self.DBx = (1 / G.dx) * 1 / HA
|
||||
self.DBy = (1 / G.dy) * 1 / HA
|
||||
self.DBz = (1 / G.dz) * 1 / HA
|
||||
self.srcm = 1 / HA
|
||||
|
||||
# Calculate electric update coefficients
|
||||
def calculate_update_coeffsE(self, G):
|
||||
"""Calculates the electric update coefficients of the material.
|
||||
|
||||
Args:
|
||||
G (class): Grid class instance - holds essential parameters describing the model.
|
||||
"""
|
||||
|
||||
# The implementation of the dispersive material modelling comes from the derivation in: http://dx.doi.org/10.1109/TAP.2014.2308549
|
||||
if self.maxpoles > 0:
|
||||
self.w = np.zeros(self.maxpoles, dtype=complextype)
|
||||
self.q = np.zeros(self.maxpoles, dtype=complextype)
|
||||
self.zt = np.zeros(self.maxpoles, dtype=complextype)
|
||||
self.zt2 = np.zeros(self.maxpoles, dtype=complextype)
|
||||
self.eqt = np.zeros(self.maxpoles, dtype=complextype)
|
||||
self.eqt2 = np.zeros(self.maxpoles, dtype=complextype)
|
||||
|
||||
for x in range(self.poles):
|
||||
if self.type == 'debye':
|
||||
self.w[x] = self.deltaer[x] / self.tau[x]
|
||||
self.q[x] = -1 / self.tau[x]
|
||||
elif self.type == 'lorenz':
|
||||
wp2 = (2 * np.pi * (1 / self.tau[x])) * (2 * np.pi * (1 / self.tau[x]))
|
||||
self.w[x] = -(wp2 * self.deltaer[x]) * j / np.sqrt(wp2 - (self.alpha[x] * self.alpha[x]))
|
||||
self.q[x] = -self.alpha[x] + np.sqrt(wp2 - (self.alpha[x] * self.alpha[x])) * j
|
||||
elif self.type == 'drude':
|
||||
wp2 = (2 * np.pi * (1 / self.tau[x])) * (2 * np.pi * (1 / self.tau[x]))
|
||||
self.se += wp2 / self.alpha[x]
|
||||
self.w[x] = - (wp2 / self.alpha[x])
|
||||
self.q[x] = - self.alpha[x]
|
||||
|
||||
self.eqt[x] = np.exp(self.q[x] * G.dt)
|
||||
self.eqt2[x] = np.exp(self.q[x] * (G.dt / 2))
|
||||
self.zt[x] = (self.w[x] / self.q[x]) * (1 - self.eqt[x]) / G.dt
|
||||
self.zt2[x] = (self.w[x] / self.q[x]) * (1 - self.eqt2[x])
|
||||
|
||||
EA = (e0*self.er / G.dt) + 0.5*self.se - (e0 / G.dt) * np.sum(self.zt2.real)
|
||||
EB = (e0*self.er / G.dt) - 0.5*self.se - (e0 / G.dt) * np.sum(self.zt2.real)
|
||||
|
||||
else:
|
||||
EA = (e0*self.er / G.dt) + 0.5*self.se
|
||||
EB = (e0*self.er / G.dt) - 0.5*self.se
|
||||
|
||||
if self.ID == 'pec':
|
||||
self.CA = 0
|
||||
self.CBx = 0
|
||||
self.CBy = 0
|
||||
self.CBz = 0
|
||||
self.srce = 0
|
||||
else:
|
||||
self.CA = EB / EA
|
||||
self.CBx = (1 / G.dx) * 1 / EA
|
||||
self.CBy = (1 / G.dy) * 1 / EA
|
||||
self.CBz = (1 / G.dz) * 1 / EA
|
||||
self.srce = 1 / EA
|
||||
|
||||
|
||||
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 (str): Name of the soil.
|
||||
sandfraction (float): Sand fraction of the soil.
|
||||
clayfraction (float): Clay fraction of the soil.
|
||||
bulkdensity (float): Bulk density of the soil (g/cm3).
|
||||
sandpartdensity (float): Density of the sand particles in the soil (g/cm3).
|
||||
watervolfraction (float): 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
|
||||
|
||||
def calculate_debye_properties(self, nbins, G):
|
||||
"""Calculates the real and imaginery part of a Debye model for the soil as well as a conductivity. It uses a semi-empirical model (http://dx.doi.org/10.1109/36.387598).
|
||||
|
||||
Args:
|
||||
nbins (int): Number of bins to use to create the different materials.
|
||||
G (class): Grid class instance - holds essential parameters describing the model.
|
||||
"""
|
||||
|
||||
# Debye model properties of water
|
||||
f = 1.3e9
|
||||
w = 2 * np.pi * f
|
||||
erealw = Material.watereri + ((Material.waterdeltaer) / (1 + (w * Material.watertau)**2))
|
||||
eimagw = w * Material.watertau * ((Material.waterdeltaer) / (1 + (w * Material.watertau)**2))
|
||||
|
||||
a = 0.65 # Experimentally derived constant
|
||||
es = (1.01 + 0.44 * self.rs)**2 - 0.062
|
||||
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
|
||||
sigf1 = 0.0467 + 0.2204 * self.rb - 0.411 * self.S + 0.6614 * self.C
|
||||
# For frequencies in the range 1.4GHz to 18GHz
|
||||
sigf2 = -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
|
||||
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
|
||||
|
||||
# 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
|
||||
er1 = (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
|
||||
er2 = 1.15 * er1 - 0.68
|
||||
|
||||
# Imaginary part for frequencies in the range 0.3GHz to 1.3GHz
|
||||
eri = er2 - (muiter[0]**(b2/a) * Material.waterdeltaer)
|
||||
|
||||
# Effective conductivity
|
||||
sig = muiter[0]**(b2/a) * ((sigf1 * (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
|
||||
else:
|
||||
self.startmaterialnum = len(G.materials)
|
||||
if not material:
|
||||
m = Material(len(G.materials), requiredID, G)
|
||||
m.average = False
|
||||
m.er = eri
|
||||
m.se = sig
|
||||
m.deltaer.append(er2 - m.er)
|
||||
m.tau.append(Material.watertau)
|
||||
G.materials.append(m)
|
||||
|
||||
muiter.iternext()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
343
gprMax/pml.py
普通文件
343
gprMax/pml.py
普通文件
@@ -0,0 +1,343 @@
|
||||
# Copyright (C) 2015: The University of Edinburgh
|
||||
# Authors: Craig Warren and Antonis Giannopoulos
|
||||
#
|
||||
# This file is part of gprMax.
|
||||
#
|
||||
# gprMax is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gprMax is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import numpy as np
|
||||
|
||||
from .constants import e0, z0, floattype
|
||||
|
||||
|
||||
class CFS():
|
||||
"""PML CFS parameters."""
|
||||
|
||||
# Allowable scaling types
|
||||
scalingtypes = {'constant': 0, 'linear': 1, 'inverselinear': -1, 'quadratic': 2, 'cubic': 3, 'quartic': 4}
|
||||
|
||||
def __init__(self, alphascaling='constant', alphamin=0, alphamax=0, kappascaling='constant', kappamin=1, kappamax=1, sigmascaling='quartic', sigmamin=0, sigmamax=None):
|
||||
"""
|
||||
Args:
|
||||
alphascaling (str): Type of scaling used for alpha parameter. Can be: 'constant', 'linear', 'inverselinear', 'quadratic', 'cubic', 'quartic'.
|
||||
alphamin (float): Minimum value for alpha parameter.
|
||||
alphamax (float): Maximum value for alpha parameter.
|
||||
kappascaling (str): Type of scaling used for kappa parameter. Can be: 'constant', 'linear', 'inverselinear', 'quadratic', 'cubic', 'quartic'.
|
||||
kappamin (float): Minimum value for kappa parameter.
|
||||
kappamax (float): Maximum value for kappa 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.alphamax = alphamax
|
||||
self.kappascaling = kappascaling
|
||||
self.kappamin = kappamin
|
||||
self.kappamax = kappamax
|
||||
self.sigmascaling = sigmascaling
|
||||
self.sigmamin = sigmamin
|
||||
self.sigmamax = sigmamax
|
||||
|
||||
def calculate_sigmamax(self, direction, er, mr, G):
|
||||
"""Calculates an optimum value for sigma max based on underlying material properties.
|
||||
|
||||
Args:
|
||||
direction (str): Direction of PML slab
|
||||
er (float): Average permittivity of underlying material.
|
||||
mr (float): Average permeability of underlying material.
|
||||
G (class): Grid class instance - holds essential parameters describing the model.
|
||||
"""
|
||||
# Get general direction from first letter of PML direction
|
||||
if direction[0] == 'x':
|
||||
d = G.dx
|
||||
elif direction[0] == 'y':
|
||||
d = G.dy
|
||||
elif direction[0] == 'z':
|
||||
d = G.dz
|
||||
# Calculation of the maximum value of sigma from http://dx.doi.org/10.1109/8.546249
|
||||
m = CFS.scalingtypes[self.sigmascaling]
|
||||
self.sigmamax = (0.8 * (m + 1)) / (z0 * d * np.sqrt(er * mr))
|
||||
|
||||
def scaling_polynomial(self, min, max, 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.
|
||||
|
||||
Args:
|
||||
min (float): Minimum value for scaling.
|
||||
max (float): Maximum value for scaling.
|
||||
order (int): Order of polynomial for scaling.
|
||||
Evalues (float): numpy array holding scaling value for electric PML update.
|
||||
Hvalues (float): numpy array holding scaling value for magnetic PML update.
|
||||
|
||||
Returns:
|
||||
Evalues (float): numpy array holding scaling value for electric PML update.
|
||||
Hvalues (float): numpy array holding scaling value for magnetic PML update.
|
||||
"""
|
||||
tmp = max * ((np.linspace(0, (len(Evalues) - 1) + 0.5, num=2*len(Evalues))) / (len(Evalues) - 1)) ** order
|
||||
Evalues = tmp[0:-1:2]
|
||||
Hvalues = tmp[1::2]
|
||||
return Evalues, Hvalues
|
||||
|
||||
def calculate_values(self, min, max, scaling, Evalues, Hvalues):
|
||||
"""Calculates values for electric and magnetic PML updates based on scaling type and minimum and maximum values.
|
||||
|
||||
Args:
|
||||
min (float): Minimum value for scaling.
|
||||
max (float): Maximum value for scaling.
|
||||
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:
|
||||
Evalues (float): numpy array holding scaling value for electric PML update.
|
||||
Hvalues (float): numpy array holding scaling 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 = Evalues[::-1]
|
||||
Hvalues = Hvalues[::-1]
|
||||
# print('Evalues: scaling {}, {}'.format(scaling, Evalues))
|
||||
# print('Hvalues: scaling {}, {}'.format(scaling, Hvalues))
|
||||
return Evalues, Hvalues
|
||||
|
||||
|
||||
class PML():
|
||||
"""PML - the implementation comes from the derivation in: http://dx.doi.org/10.1109/TAP.2011.2180344"""
|
||||
|
||||
def __init__(self, direction=None, xs=0, ys=0, zs=0, xf=0, yf=0, zf=0, cfs=[]):
|
||||
"""
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (float): Extent of the PML volume.
|
||||
cfs (list): CFS class instances associated with the PML.
|
||||
"""
|
||||
self.direction = direction
|
||||
self.xs = xs
|
||||
self.xf = xf
|
||||
self.ys = ys
|
||||
self.yf = yf
|
||||
self.zs = zs
|
||||
self.zf = zf
|
||||
self.nx = xf - xs
|
||||
self.ny = yf - ys
|
||||
self.nz = zf - zs
|
||||
self.CFS = cfs
|
||||
if not self.CFS:
|
||||
self.CFS = [CFS()]
|
||||
|
||||
# Subscript notation, e.g. 'EPhiyxz' means the electric field Phi vector, of which the
|
||||
# component being corrected is y, the stretching direction is x, and field derivative
|
||||
# is z direction.
|
||||
if self.direction == 'xminus' or self.direction == 'xplus':
|
||||
self.thickness = self.nx
|
||||
self.EPhiyxz = np.zeros((len(self.CFS), self.nx + 1, self.ny, self.nz + 1), dtype=floattype)
|
||||
self.EPhizxy = np.zeros((len(self.CFS), self.nx + 1, self.ny + 1, self.nz), dtype=floattype)
|
||||
self.HPhiyxz = np.zeros((len(self.CFS), self.nx, self.ny + 1, self.nz), dtype=floattype)
|
||||
self.HPhizxy = np.zeros((len(self.CFS), self.nx, self.ny, self.nz + 1), dtype=floattype)
|
||||
elif self.direction == 'yminus' or self.direction == 'yplus':
|
||||
self.thickness = self.ny
|
||||
self.EPhixyz = np.zeros((len(self.CFS), self.nx, self.ny + 1, self.nz + 1), dtype=floattype)
|
||||
self.EPhizyx = np.zeros((len(self.CFS), self.nx + 1, self.ny + 1, self.nz), dtype=floattype)
|
||||
self.HPhixyz = np.zeros((len(self.CFS), self.nx + 1, self.ny, self.nz), dtype=floattype)
|
||||
self.HPhizyx = np.zeros((len(self.CFS), self.nx, self.ny, self.nz + 1), dtype=floattype)
|
||||
elif self.direction == 'zminus' or self.direction == 'zplus':
|
||||
self.thickness = self.nz
|
||||
self.EPhixzy = np.zeros((len(self.CFS), self.nx, self.ny + 1, self.nz + 1), dtype=floattype)
|
||||
self.EPhiyzx = np.zeros((len(self.CFS), self.nx + 1, self.ny, self.nz + 1), dtype=floattype)
|
||||
self.HPhixzy = np.zeros((len(self.CFS), self.nx + 1, self.ny, self.nz), dtype=floattype)
|
||||
self.HPhiyzx = np.zeros((len(self.CFS), self.nx, self.ny + 1, self.nz), dtype=floattype)
|
||||
|
||||
self.ERA = np.zeros((len(self.CFS), self.thickness + 1), dtype=floattype)
|
||||
self.ERB = np.zeros((len(self.CFS), self.thickness + 1), dtype=floattype)
|
||||
self.ERE = np.zeros((len(self.CFS), self.thickness + 1), dtype=floattype)
|
||||
self.ERF = np.zeros((len(self.CFS), self.thickness + 1), dtype=floattype)
|
||||
self.HRA = np.zeros((len(self.CFS), self.thickness + 1), dtype=floattype)
|
||||
self.HRB = np.zeros((len(self.CFS), self.thickness + 1), dtype=floattype)
|
||||
self.HRE = np.zeros((len(self.CFS), self.thickness + 1), dtype=floattype)
|
||||
self.HRF = np.zeros((len(self.CFS), self.thickness + 1), dtype=floattype)
|
||||
|
||||
def calculate_update_coeffs(self, er, mr, G):
|
||||
"""Calculates electric and magnetic update coefficients for the PML.
|
||||
|
||||
Args:
|
||||
er (float): Average permittivity of underlying material
|
||||
mr (float): Average permeability of underlying material
|
||||
G (class): Grid class instance - holds essential parameters describing the model.
|
||||
"""
|
||||
|
||||
for x, cfs in enumerate(self.CFS):
|
||||
Ealpha = np.zeros(self.thickness + 1, dtype=floattype)
|
||||
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)
|
||||
Ealpha, Halpha = cfs.calculate_values(cfs.alphamin, cfs.alphamax, cfs.alphascaling, Ealpha, Halpha)
|
||||
Ekappa, Hkappa = cfs.calculate_values(cfs.kappamin, cfs.kappamax, cfs.kappascaling, Ekappa, Hkappa)
|
||||
Esigma, Hsigma = cfs.calculate_values(cfs.sigmamin, cfs.sigmamax, cfs.sigmascaling, Esigma, Hsigma)
|
||||
|
||||
# print('Ealpha {}'.format(Ealpha))
|
||||
# print('Halpha {}'.format(Halpha))
|
||||
# print('Ekappa {}'.format(Ekappa))
|
||||
# print('Hkappa {}'.format(Hkappa))
|
||||
# print('Esigma {}'.format(Esigma))
|
||||
# print('Hsigma {}'.format(Hsigma))
|
||||
|
||||
# Electric PML update coefficients
|
||||
tmp = (2*e0*Ekappa) + G.dt * (Ealpha * Ekappa + Esigma)
|
||||
self.ERA[x, :] = (2*e0 + G.dt*Ealpha) / tmp
|
||||
self.ERB[x, :] = (2*e0*Ekappa) / tmp
|
||||
self.ERE[x, :] = ((2*e0*Ekappa) - G.dt * (Ealpha * Ekappa + Esigma)) / tmp
|
||||
self.ERF[x, :] = (2*Esigma*G.dt) / (Ekappa * tmp)
|
||||
|
||||
# Magnetic PML update coefficients
|
||||
tmp = (2*e0*Hkappa) + G.dt * (Halpha * Hkappa + Hsigma)
|
||||
self.HRA[x, :] = (2*e0 + G.dt*Halpha) / tmp
|
||||
self.HRB[x, :] = (2*e0*Hkappa) / tmp
|
||||
self.HRE[x, :] = ((2*e0*Hkappa) - G.dt * (Halpha * Hkappa + Hsigma)) / tmp
|
||||
self.HRF[x, :] = (2*Hsigma*G.dt) / (Hkappa * tmp)
|
||||
|
||||
# print('ERA {}'.format(self.ERA))
|
||||
# print('ERB {}'.format(self.ERB))
|
||||
# print('ERE {}'.format(self.ERE))
|
||||
# print('ERF {}'.format(self.ERF))
|
||||
# print('HRA {}'.format(self.HRA))
|
||||
# print('HRB {}'.format(self.HRB))
|
||||
# print('HRE {}'.format(self.HRE))
|
||||
# print('HRF {}'.format(self.HRF))
|
||||
|
||||
|
||||
def build_pml(G):
|
||||
"""This function builds instances of the PML."""
|
||||
|
||||
if G.messages:
|
||||
print('')
|
||||
# Create the PML slabs
|
||||
if G.pmlthickness[0] > 0:
|
||||
pml = PML(direction='xminus', xf=G.pmlthickness[0], yf=G.ny, zf=G.nz, cfs=G.cfs)
|
||||
if G.messages and G.pmlthickness.count(G.pmlthickness[0]) != len(G.pmlthickness):
|
||||
print('PML {} slab with {} cells created.'.format(pml.direction, pml.thickness))
|
||||
G.pmls.append(pml)
|
||||
if G.pmlthickness[1] > 0:
|
||||
pml = PML(direction='yminus', xf=G.nx, yf=G.pmlthickness[1], zf=G.nz, cfs=G.cfs)
|
||||
if G.messages and G.pmlthickness.count(G.pmlthickness[0]) != len(G.pmlthickness):
|
||||
print('PML {} slab with {} cells created.'.format(pml.direction, pml.thickness))
|
||||
G.pmls.append(pml)
|
||||
if G.pmlthickness[2] > 0:
|
||||
pml = PML(direction='zminus', xf=G.nx, yf=G.ny, zf=G.pmlthickness[2], cfs=G.cfs)
|
||||
if G.messages and G.pmlthickness.count(G.pmlthickness[0]) != len(G.pmlthickness):
|
||||
print('PML {} slab with {} cells created.'.format(pml.direction, pml.thickness))
|
||||
G.pmls.append(pml)
|
||||
if G.pmlthickness[3] > 0:
|
||||
pml = PML(direction='xplus', xs=G.nx-G.pmlthickness[3], xf=G.nx, yf=G.ny, zf=G.nz, cfs=G.cfs)
|
||||
if G.messages and G.pmlthickness.count(G.pmlthickness[0]) != len(G.pmlthickness):
|
||||
print('PML {} slab with {} cells created.'.format(pml.direction, pml.thickness))
|
||||
G.pmls.append(pml)
|
||||
if G.pmlthickness[4] > 0:
|
||||
pml = PML(direction='yplus', xf=G.nx, ys=G.ny-G.pmlthickness[4], yf=G.ny, zf=G.nz, cfs=G.cfs)
|
||||
if G.messages and G.pmlthickness.count(G.pmlthickness[0]) != len(G.pmlthickness):
|
||||
print('PML {} slab with {} cells created.'.format(pml.direction, pml.thickness))
|
||||
G.pmls.append(pml)
|
||||
if G.pmlthickness[5] > 0:
|
||||
pml = PML(direction='zplus', xf=G.nx, yf=G.ny, zs=G.nz-G.pmlthickness[5], zf=G.nz, cfs=G.cfs)
|
||||
if G.messages and G.pmlthickness.count(G.pmlthickness[0]) != len(G.pmlthickness):
|
||||
print('PML {} slab with {} cells created.'.format(pml.direction, pml.thickness))
|
||||
G.pmls.append(pml)
|
||||
if G.messages and G.pmlthickness.count(G.pmlthickness[0]) == len(G.pmlthickness):
|
||||
if G.pmlthickness[0] == 0:
|
||||
print('PML is switched off')
|
||||
else:
|
||||
print('PML: {} cells'.format(pml.thickness))
|
||||
|
||||
|
||||
def calculate_initial_pml_params(G):
|
||||
""" This function calculates the initial parameters and coefficients for PML including setting scaling
|
||||
(based on underlying material er and mr from solid array).
|
||||
"""
|
||||
|
||||
for pml in G.pmls:
|
||||
sumer = 0
|
||||
summr = 0
|
||||
if pml.direction == 'xminus':
|
||||
for j in range(G.ny):
|
||||
for k in range(G.nz):
|
||||
numID = G.solid[0, j, k]
|
||||
material = next(x for x in G.materials if x.numID == numID)
|
||||
sumer += material.er
|
||||
summr += material.mr
|
||||
averageer = sumer / (G.ny * G.nz)
|
||||
averagemr = summr / (G.ny * G.nz)
|
||||
elif pml.direction == 'xplus':
|
||||
for j in range(G.ny):
|
||||
for k in range(G.nz):
|
||||
numID = G.solid[G.nx - pml.thickness, j, k]
|
||||
material = next(x for x in G.materials if x.numID == numID)
|
||||
sumer += material.er
|
||||
summr += material.mr
|
||||
averageer = sumer / (G.ny * G.nz)
|
||||
averagemr = summr / (G.ny * G.nz)
|
||||
elif pml.direction == 'yminus':
|
||||
for i in range(G.nx):
|
||||
for k in range(G.nz):
|
||||
numID = G.solid[i, 0, k]
|
||||
material = next(x for x in G.materials if x.numID == numID)
|
||||
sumer += material.er
|
||||
summr += material.mr
|
||||
averageer = sumer / (G.nx * G.nz)
|
||||
averagemr = summr / (G.nx * G.nz)
|
||||
elif pml.direction == 'yplus':
|
||||
for i in range(G.nx):
|
||||
for k in range(G.nz):
|
||||
numID = G.solid[i, G.ny - pml.thickness, k]
|
||||
material = next(x for x in G.materials if x.numID == numID)
|
||||
sumer += material.er
|
||||
summr += material.mr
|
||||
averageer = sumer / (G.nx * G.nz)
|
||||
averagemr = summr / (G.nx * G.nz)
|
||||
elif pml.direction == 'zminus':
|
||||
for i in range(G.nx):
|
||||
for j in range(G.ny):
|
||||
numID = G.solid[i, j, 0]
|
||||
material = next(x for x in G.materials if x.numID == numID)
|
||||
sumer += material.er
|
||||
summr += material.mr
|
||||
averageer = sumer / (G.nx * G.ny)
|
||||
averagemr = summr / (G.nx * G.ny)
|
||||
elif pml.direction == 'zplus':
|
||||
for i in range(G.nx):
|
||||
for j in range(G.ny):
|
||||
numID = G.solid[i, j, G.nz - pml.thickness]
|
||||
material = next(x for x in G.materials if x.numID == numID)
|
||||
sumer += material.er
|
||||
summr += material.mr
|
||||
averageer = sumer / (G.nx * G.ny)
|
||||
averagemr = summr / (G.nx * G.ny)
|
||||
pml.calculate_update_coeffs(averageer, averagemr, G)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
665
gprMax/pml_1order_update.pyx
普通文件
665
gprMax/pml_1order_update.pyx
普通文件
@@ -0,0 +1,665 @@
|
||||
# Copyright (C) 2015: The University of Edinburgh
|
||||
# Authors: Craig Warren and Antonis Giannopoulos
|
||||
#
|
||||
# This file is part of gprMax.
|
||||
#
|
||||
# gprMax is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gprMax is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import numpy as np
|
||||
cimport numpy as np
|
||||
from cython.parallel import prange
|
||||
from .constants cimport floattype_t, complextype_t
|
||||
|
||||
|
||||
#############################################
|
||||
# Electric field PML updates - Ex component #
|
||||
#############################################
|
||||
cpdef update_pml_1order_ex_yplus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsE, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Ex, floattype_t[:, :, :] Hz, floattype_t[:, :, :, :] EPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dy):
|
||||
"""This function updates the Ex field components in the y stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dHz
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[0, i + xs, j + ys, k + zs]
|
||||
dHz = (Hz[i + xs, j + ys, k + zs] - Hz[i + xs, j - 1 + ys, k + zs]) / dy
|
||||
Ex[i + xs, j + ys, k + zs] = Ex[i + xs, j + ys, k + zs] + updatecoeffsE[listIndex, 4] * ((RA[0, j] - 1) * dHz + RB[0, j] * EPhi[0, i, j, k])
|
||||
EPhi[0, i, j, k] = RE[0, j] * EPhi[0, i, j, k] - RF[0, j] * dHz
|
||||
|
||||
|
||||
cpdef update_pml_1order_ex_yminus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsE, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Ex, floattype_t[:, :, :] Hz, floattype_t[:, :, :, :] EPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dy):
|
||||
"""This function updates the Ex field components in the y stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dHz
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[0, i + xs, yf - j, k + zs]
|
||||
dHz = (Hz[i + xs, yf - j, k + zs] - Hz[i + xs, yf - j - 1, k + zs]) / dy
|
||||
Ex[i + xs, yf - j, k + zs] = Ex[i + xs, yf - j, k + zs] + updatecoeffsE[listIndex, 4] * ((RA[0, j] - 1) * dHz + RB[0, j] * EPhi[0, i, j, k])
|
||||
EPhi[0, i, j, k] = RE[0, j] * EPhi[0, i, j, k] - RF[0, j] * dHz
|
||||
|
||||
|
||||
cpdef update_pml_1order_ex_zplus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsE, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Ex, floattype_t[:, :, :] Hy, floattype_t[:, :, :, :] EPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dz):
|
||||
"""This function updates the Ex field components in the z stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dHy
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[0, i + xs, j + ys, k + zs]
|
||||
dHy = (Hy[i + xs, j + ys, k + zs] - Hy[i + xs, j + ys, k - 1 + zs]) / dz
|
||||
Ex[i + xs, j + ys, k + zs] = Ex[i + xs, j + ys, k + zs] - updatecoeffsE[listIndex, 4] * ((RA[0, k] - 1) * dHy + RB[0, k] * EPhi[0, i, j, k])
|
||||
EPhi[0, i, j, k] = RE[0, k] * EPhi[0, i, j, k] - RF[0, k] * dHy
|
||||
|
||||
|
||||
cpdef update_pml_1order_ex_zminus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsE, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Ex, floattype_t[:, :, :] Hy, floattype_t[:, :, :, :] EPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dz):
|
||||
"""This function updates the Ex field components in the z stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dHy
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[0, i + xs, j + ys, zf - k]
|
||||
dHy = (Hy[i + xs, j + ys, zf - k] - Hy[i + xs, j + ys, zf - k - 1]) / dz
|
||||
Ex[i + xs, j + ys, zf - k] = Ex[i + xs, j + ys, zf - k] - updatecoeffsE[listIndex, 4] * ((RA[0, k] - 1) * dHy + RB[0, k] * EPhi[0, i, j, k])
|
||||
EPhi[0, i, j, k] = RE[0, k] * EPhi[0, i, j, k] - RF[0, k] * dHy
|
||||
|
||||
|
||||
#############################################
|
||||
# Electric field PML updates - Ey component #
|
||||
#############################################
|
||||
cpdef update_pml_1order_ey_xplus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsE, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Ey, floattype_t[:, :, :] Hz, floattype_t[:, :, :, :] EPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dx):
|
||||
"""This function updates the Ey field components in the x stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dHz
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[1, i + xs, j + ys, k + zs]
|
||||
dHz = (Hz[i + xs, j + ys, k + zs] - Hz[i - 1 + xs, j + ys, k + zs]) / dx
|
||||
Ey[i + xs, j + ys, k + zs] = Ey[i + xs, j + ys, k + zs] - updatecoeffsE[listIndex, 4] * ((RA[0, i] - 1) * dHz + RB[0, i] * EPhi[0, i, j, k])
|
||||
EPhi[0, i, j, k] = RE[0, i] * EPhi[0, i, j, k] - RF[0, i] * dHz
|
||||
|
||||
|
||||
cpdef update_pml_1order_ey_xminus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsE, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Ey, floattype_t[:, :, :] Hz, floattype_t[:, :, :, :] EPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dx):
|
||||
"""This function updates the Ey field components in the x stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dHz
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[1, xf - i, j + ys, k + zs]
|
||||
dHz = (Hz[xf - i, j + ys, k + zs] - Hz[xf - i - 1, j + ys, k + zs]) / dx
|
||||
Ey[xf - i, j + ys, k + zs] = Ey[xf - i, j + ys, k + zs] - updatecoeffsE[listIndex, 4] * ((RA[0, i] - 1) * dHz + RB[0, i] * EPhi[0, i, j, k])
|
||||
EPhi[0, i, j, k] = RE[0, i] * EPhi[0, i, j, k] - RF[0, i] * dHz
|
||||
|
||||
|
||||
cpdef update_pml_1order_ey_zplus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsE, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Ey, floattype_t[:, :, :] Hx, floattype_t[:, :, :, :] EPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dz):
|
||||
"""This function updates the Ey field components in the z stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dHx
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[1, i + xs, j + ys, k + zs]
|
||||
dHx = (Hx[i + xs, j + ys, k + zs] - Hx[i + xs, j + ys, k - 1 + zs]) / dz
|
||||
Ey[i + xs, j + ys, k + zs] = Ey[i + xs, j + ys, k + zs] + updatecoeffsE[listIndex, 4] * ((RA[0, k] - 1) * dHx + RB[0, k] * EPhi[0, i, j, k])
|
||||
EPhi[0, i, j, k] = RE[0, k] * EPhi[0, i, j, k] - RF[0, k] * dHx
|
||||
|
||||
|
||||
cpdef update_pml_1order_ey_zminus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsE, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Ey, floattype_t[:, :, :] Hx, floattype_t[:, :, :, :] EPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dz):
|
||||
"""This function updates the Ey field components in the z stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dHx
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[1, i + xs, j + ys, zf - k]
|
||||
dHx = (Hx[i + xs, j + ys, zf - k] - Hx[i + xs, j + ys, zf - k - 1]) / dz
|
||||
Ey[i + xs, j + ys, zf - k] = Ey[i + xs, j + ys, zf - k] + updatecoeffsE[listIndex, 4] * ((RA[0, k] - 1) * dHx + RB[0, k] * EPhi[0, i, j, k])
|
||||
EPhi[0, i, j, k] = RE[0, k] * EPhi[0, i, j, k] - RF[0, k] * dHx
|
||||
|
||||
|
||||
#############################################
|
||||
# Electric field PML updates - Ez component #
|
||||
#############################################
|
||||
cpdef update_pml_1order_ez_xplus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsE, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Ez, floattype_t[:, :, :] Hy, floattype_t[:, :, :, :] EPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dx):
|
||||
"""This function updates the Ey field components in the z stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dHy
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[2, i + xs, j + ys, k + zs]
|
||||
dHy = (Hy[i + xs, j + ys, k + zs] - Hy[i - 1 + xs, j + ys, k + zs]) / dx
|
||||
Ez[i + xs, j + ys, k + zs] = Ez[i + xs, j + ys, k + zs] + updatecoeffsE[listIndex, 4] * ((RA[0, i] - 1) * dHy + RB[0, i] * EPhi[0, i, j, k])
|
||||
EPhi[0, i, j, k] = RE[0, i] * EPhi[0, i, j, k] - RF[0, i] * dHy
|
||||
|
||||
|
||||
cpdef update_pml_1order_ez_xminus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsE, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Ez, floattype_t[:, :, :] Hy, floattype_t[:, :, :, :] EPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dx):
|
||||
"""This function updates the Ez field components in the x stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dHy
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[2, xf - i, j + ys, k + zs]
|
||||
dHy = (Hy[xf - i, j + ys, k + zs] - Hy[xf - i - 1, j + ys, k + zs]) / dx
|
||||
Ez[xf - i, j + ys, k + zs] = Ez[xf - i, j + ys, k + zs] + updatecoeffsE[listIndex, 4] * ((RA[0, i] - 1) * dHy + RB[0, i] * EPhi[0, i, j, k])
|
||||
EPhi[0, i, j, k] = RE[0, i] * EPhi[0, i, j, k] - RF[0, i] * dHy
|
||||
|
||||
|
||||
cpdef update_pml_1order_ez_yplus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsE, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Ez, floattype_t[:, :, :] Hx, floattype_t[:, :, :, :] EPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dy):
|
||||
"""This function updates the Ez field components in the y stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dHx
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[2, i + xs, j + ys, k + zs]
|
||||
dHx = (Hx[i + xs, j + ys, k + zs] - Hx[i + xs, j - 1 + ys, k + zs]) / dy
|
||||
Ez[i + xs, j + ys, k + zs] = Ez[i + xs, j + ys, k + zs] - updatecoeffsE[listIndex, 4] * ((RA[0, j] - 1) * dHx + RB[0, j] * EPhi[0, i, j, k])
|
||||
EPhi[0, i, j, k] = RE[0, j] * EPhi[0, i, j, k] - RF[0, j] * dHx
|
||||
|
||||
|
||||
cpdef update_pml_1order_ez_yminus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsE, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Ez, floattype_t[:, :, :] Hx, floattype_t[:, :, :, :] EPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dy):
|
||||
"""This function updates the Ez field components in the y stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dHx
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[2, i + xs, yf - j, k + zs]
|
||||
dHx = (Hx[i + xs, yf - j, k + zs] - Hx[i + xs, yf - j - 1, k + zs]) / dy
|
||||
Ez[i + xs, yf - j, k + zs] = Ez[i + xs, yf - j, k + zs] - updatecoeffsE[listIndex, 4] * ((RA[0, j] - 1) * dHx + RB[0, j] * EPhi[0, i, j, k])
|
||||
EPhi[0, i, j, k] = RE[0, j] * EPhi[0, i, j, k] - RF[0, j] * dHx
|
||||
|
||||
|
||||
#############################################
|
||||
# Magnetic field PML updates - Hx component #
|
||||
#############################################
|
||||
cpdef update_pml_1order_hx_yplus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsH, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Hx, floattype_t[:, :, :] Ez, floattype_t[:, :, :, :] HPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dy):
|
||||
"""This function updates the Hx field components in the y stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dEz
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[3, i + xs, j + ys, k + zs]
|
||||
dEz = (Ez[i + xs, j + 1 + ys, k + zs] - Ez[i + xs, j + ys, k + zs]) / dy
|
||||
Hx[i + xs, j + ys, k + zs] = Hx[i + xs, j + ys, k + zs] - updatecoeffsH[listIndex, 4] * ((RA[0, j] - 1) * dEz + RB[0, j] * HPhi[0, i, j, k])
|
||||
HPhi[0, i, j, k] = RE[0, j] * HPhi[0, i, j, k] - RF[0, j] * dEz
|
||||
|
||||
|
||||
cpdef update_pml_1order_hx_yminus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsH, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Hx, floattype_t[:, :, :] Ez, floattype_t[:, :, :, :] HPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dy):
|
||||
"""This function updates the Hx field components in the y stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dEz
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[3, i + xs, yf - (j + 1), k + zs]
|
||||
dEz = (Ez[i + xs, yf - j, k + zs] - Ez[i + xs, yf - (j + 1), k + zs]) / dy
|
||||
Hx[i + xs, yf - (j + 1), k + zs] = Hx[i + xs, yf - (j + 1), k + zs] - updatecoeffsH[listIndex, 4] * ((RA[0, j] - 1) * dEz + RB[0, j] * HPhi[0, i, j, k])
|
||||
HPhi[0, i, j, k] = RE[0, j] * HPhi[0, i, j, k] - RF[0, j] * dEz
|
||||
|
||||
|
||||
cpdef update_pml_1order_hx_zplus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsH, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Hx, floattype_t[:, :, :] Ey, floattype_t[:, :, :, :] HPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dz):
|
||||
"""This function updates the Hx field components in the z stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dEy
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[3, i + xs, j + ys, k + zs]
|
||||
dEy = (Ey[i + xs, j + ys, k + 1 + zs] - Ey[i + xs, j + ys, k + zs]) / dz
|
||||
Hx[i + xs, j + ys, k + zs] = Hx[i + xs, j + ys, k + zs] + updatecoeffsH[listIndex, 4] * ((RA[0, k] - 1) * dEy + RB[0, k] * HPhi[0, i, j, k])
|
||||
HPhi[0, i, j, k] = RE[0, k] * HPhi[0, i, j, k] - RF[0, k] * dEy
|
||||
|
||||
|
||||
cpdef update_pml_1order_hx_zminus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsH, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Hx, floattype_t[:, :, :] Ey, floattype_t[:, :, :, :] HPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dz):
|
||||
"""This function updates the Hx field components in the z stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dEy
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[3, i + xs, j + ys, zf - (k + 1)]
|
||||
dEy = (Ey[i + xs, j + ys, zf - k] - Ey[i + xs, j + ys, zf - (k + 1)]) / dz
|
||||
Hx[i + xs, j + ys, zf - (k + 1)] = Hx[i + xs, j + ys, zf - (k + 1)] + updatecoeffsH[listIndex, 4] * ((RA[0, k] - 1) * dEy + RB[0, k] * HPhi[0, i, j, k])
|
||||
HPhi[0, i, j, k] = RE[0, k] * HPhi[0, i, j, k] - RF[0, k] * dEy
|
||||
|
||||
|
||||
#############################################
|
||||
# Magnetic field PML updates - Hy component #
|
||||
#############################################
|
||||
cpdef update_pml_1order_hy_xplus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsH, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Hy, floattype_t[:, :, :] Ez, floattype_t[:, :, :, :] HPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dx):
|
||||
"""This function updates the Hy field components in the x stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dEz
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[4, i + xs, j + ys, k + zs]
|
||||
dEz = (Ez[i + 1 + xs, j + ys, k + zs] - Ez[i + xs, j + ys, k + zs]) / dx
|
||||
Hy[i + xs, j + ys, k + zs] = Hy[i + xs, j + ys, k + zs] + updatecoeffsH[listIndex, 4] * ((RA[0, i] - 1) * dEz + RB[0, i] * HPhi[0, i, j, k])
|
||||
HPhi[0, i, j, k] = RE[0, i] * HPhi[0, i, j, k] - RF[0, i] * dEz
|
||||
|
||||
|
||||
cpdef update_pml_1order_hy_xminus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsH, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Hy, floattype_t[:, :, :] Ez, floattype_t[:, :, :, :] HPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dx):
|
||||
"""This function updates the Hy field components in the x stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dEz
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[4, xf - (i + 1), j + ys, k + zs]
|
||||
dEz = (Ez[xf - i, j + ys, k + zs] - Ez[xf - (i + 1), j + ys, k + zs]) / dx
|
||||
Hy[xf - (i + 1), j + ys, k + zs] = Hy[xf - (i + 1), j + ys, k + zs] + updatecoeffsH[listIndex, 4] * ((RA[0, i] - 1) * dEz + RB[0, i] * HPhi[0, i, j, k])
|
||||
HPhi[0, i, j, k] = RE[0, i] * HPhi[0, i, j, k] - RF[0, i] * dEz
|
||||
|
||||
|
||||
cpdef update_pml_1order_hy_zplus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsH, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Hy, floattype_t[:, :, :] Ex, floattype_t[:, :, :, :] HPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dz):
|
||||
"""This function updates the Hy field components in the z stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dEx
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[4, i + xs, j + ys, k + zs]
|
||||
dEx = (Ex[i + xs, j + ys, k + 1 + zs] - Ex[i + xs, j + ys, k + zs]) / dz
|
||||
Hy[i + xs, j + ys, k + zs] = Hy[i + xs, j + ys, k + zs] - updatecoeffsH[listIndex, 4] * ((RA[0, k] - 1) * dEx + RB[0, k] * HPhi[0, i, j, k])
|
||||
HPhi[0, i, j, k] = RE[0, k] * HPhi[0, i, j, k] - RF[0, k] * dEx
|
||||
|
||||
|
||||
cpdef update_pml_1order_hy_zminus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsH, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Hy, floattype_t[:, :, :] Ex, floattype_t[:, :, :, :] HPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dz):
|
||||
"""This function updates the Hy field components in the z stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dEx
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[4, i + xs, j + ys, zf - (k + 1)]
|
||||
dEx = (Ex[i + xs, j + ys, zf - k] - Ex[i + xs, j + ys, zf - (k + 1)]) / dz
|
||||
Hy[i + xs, j + ys, zf - (k + 1)] = Hy[i + xs, j + ys, zf - (k + 1)] - updatecoeffsH[listIndex, 4] * ((RA[0, k] - 1) * dEx + RB[0, k] * HPhi[0, i, j, k])
|
||||
HPhi[0, i, j, k] = RE[0, k] * HPhi[0, i, j, k] - RF[0, k] * dEx
|
||||
|
||||
|
||||
#############################################
|
||||
# Magnetic field PML updates - Hz component #
|
||||
#############################################
|
||||
cpdef update_pml_1order_hz_xplus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsH, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Hz, floattype_t[:, :, :] Ey, floattype_t[:, :, :, :] HPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dx):
|
||||
"""This function updates the Hz field components in the x stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dEy
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[5, i + xs, j + ys, k + zs]
|
||||
dEy = (Ey[i + 1 + xs, j + ys, k + zs] - Ey[i + xs, j + ys, k + zs]) / dx
|
||||
Hz[i + xs, j + ys, k + zs] = Hz[i + xs, j + ys, k + zs] - updatecoeffsH[listIndex, 4] * ((RA[0, i] - 1) * dEy + RB[0, i] * HPhi[0, i, j, k])
|
||||
HPhi[0, i, j, k] = RE[0, i] * HPhi[0, i, j, k] - RF[0, i] * dEy
|
||||
|
||||
|
||||
cpdef update_pml_1order_hz_xminus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsH, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Hz, floattype_t[:, :, :] Ey, floattype_t[:, :, :, :] HPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dx):
|
||||
"""This function updates the Hz field components in the x stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dEy
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[5, xf - (i + 1), j + ys, k + zs]
|
||||
dEy = (Ey[xf - i, j + ys, k + zs] - Ey[xf - (i + 1), j + ys, k + zs]) / dx
|
||||
Hz[xf - (i + 1), j + ys, k + zs] = Hz[xf - (i + 1), j + ys, k + zs] - updatecoeffsH[listIndex, 4] * ((RA[0, i] - 1) * dEy + RB[0, i] * HPhi[0, i, j, k])
|
||||
HPhi[0, i, j, k] = RE[0, i] * HPhi[0, i, j, k] - RF[0, i] * dEy
|
||||
|
||||
|
||||
cpdef update_pml_1order_hz_yplus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsH, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Hz, floattype_t[:, :, :] Ex, floattype_t[:, :, :, :] HPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dy):
|
||||
"""This function updates the Hz field components in the y stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dEx
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[5, i + xs, j + ys, k + zs]
|
||||
dEx = (Ex[i + xs, j + 1 + ys, k + zs] - Ex[i + xs, j + ys, k + zs]) / dy
|
||||
Hz[i + xs, j + ys, k + zs] = Hz[i + xs, j + ys, k + zs] + updatecoeffsH[listIndex, 4] * ((RA[0, j] - 1) * dEx + RB[0, j] * HPhi[0, i, j, k])
|
||||
HPhi[0, i, j, k] = RE[0, j] * HPhi[0, i, j, k] - RF[0, j] * dEx
|
||||
|
||||
|
||||
cpdef update_pml_1order_hz_yminus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsH, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Hz, floattype_t[:, :, :] Ex, floattype_t[:, :, :, :] HPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dy):
|
||||
"""This function updates the Hz field components in the y stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dEx
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[5, i + xs, yf - (j + 1), k + zs]
|
||||
dEx = (Ex[i + xs, yf - j, k + zs] - Ex[i + xs, yf - (j + 1), k + zs]) / dy
|
||||
Hz[i + xs, yf - (j + 1), k + zs] = Hz[i + xs, yf - (j + 1), k + zs] + updatecoeffsH[listIndex, 4] * ((RA[0, j] - 1) * dEx + RB[0, j] * HPhi[0, i, j, k])
|
||||
HPhi[0, i, j, k] = RE[0, j] * HPhi[0, i, j, k] - RF[0, j] * dEx
|
||||
|
689
gprMax/pml_2order_update.pyx
普通文件
689
gprMax/pml_2order_update.pyx
普通文件
@@ -0,0 +1,689 @@
|
||||
# Copyright (C) 2015: The University of Edinburgh
|
||||
# Authors: Craig Warren and Antonis Giannopoulos
|
||||
#
|
||||
# This file is part of gprMax.
|
||||
#
|
||||
# gprMax is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gprMax is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import numpy as np
|
||||
cimport numpy as np
|
||||
from cython.parallel import prange
|
||||
from .constants cimport floattype_t, complextype_t
|
||||
|
||||
|
||||
#############################################
|
||||
# Electric field PML updates - Ex component #
|
||||
#############################################
|
||||
cpdef update_pml_2order_ex_yplus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsE, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Ex, floattype_t[:, :, :] Hz, floattype_t[:, :, :, :] EPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dy):
|
||||
"""This function updates the Ex field components in the y stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dHz
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[0, i + xs, j + ys, k + zs]
|
||||
dHz = (Hz[i + xs, j + ys, k + zs] - Hz[i + xs, j - 1 + ys, k + zs]) / dy
|
||||
Ex[i + xs, j + ys, k + zs] = Ex[i + xs, j + ys, k + zs] + updatecoeffsE[listIndex, 4] * ((RA[0, j] * RA[1, j] - 1) * dHz + RA[1, j] * RB[0, j] * EPhi[0, i, j, k] + RB[1, j] * EPhi[1, i, j, k])
|
||||
EPhi[1, i, j, k] = RE[1, j] * EPhi[1, i, j, k] - RF[1, j] * (RA[0, j] * dHz + RB[0, j] * EPhi[0, i, j, k])
|
||||
EPhi[0, i, j, k] = RE[0, j] * EPhi[0, i, j, k] - RF[0, j] * dHz
|
||||
|
||||
|
||||
cpdef update_pml_2order_ex_yminus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsE, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Ex, floattype_t[:, :, :] Hz, floattype_t[:, :, :, :] EPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dy):
|
||||
"""This function updates the Ex field components in the y stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dHz
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[0, i + xs, yf - j, k + zs]
|
||||
dHz = (Hz[i + xs, yf - j, k + zs] - Hz[i + xs, yf - j - 1, k + zs]) / dy
|
||||
Ex[i + xs, yf - j, k + zs] = Ex[i + xs, yf - j, k + zs] + updatecoeffsE[listIndex, 4] * ((RA[0, j] * RA[1, j] - 1) * dHz + RA[1, j] * RB[0, j] * EPhi[0, i, j, k] + RB[1, j] * EPhi[1, i, j, k])
|
||||
EPhi[1, i, j, k] = RE[1, j] * EPhi[1, i, j, k] - RF[1, j] * (RA[0, j] * dHz + RB[0, j] * EPhi[0, i, j, k])
|
||||
EPhi[0, i, j, k] = RE[0, j] * EPhi[0, i, j, k] - RF[0, j] * dHz
|
||||
|
||||
|
||||
cpdef update_pml_2order_ex_zplus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsE, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Ex, floattype_t[:, :, :] Hy, floattype_t[:, :, :, :] EPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dz):
|
||||
"""This function updates the Ex field components in the z stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dHy
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[0, i + xs, j + ys, k + zs]
|
||||
dHy = (Hy[i + xs, j + ys, k + zs] - Hy[i + xs, j + ys, k - 1 + zs]) / dz
|
||||
Ex[i + xs, j + ys, k + zs] = Ex[i + xs, j + ys, k + zs] - updatecoeffsE[listIndex, 4] * ((RA[0, k] * RA[1, k] - 1) * dHy + RA[1, k] * RB[0, k] * EPhi[0, i, j, k] + RB[1, k] * EPhi[1, i, j, k])
|
||||
EPhi[1, i, j, k] = RE[1, k] * EPhi[1, i, j, k] - RF[1, k] * (RA[0, k] * dHy + RB[0, k] * EPhi[0, i, j, k])
|
||||
EPhi[0, i, j, k] = RE[0, k] * EPhi[0, i, j, k] - RF[0, k] * dHy
|
||||
|
||||
|
||||
cpdef update_pml_2order_ex_zminus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsE, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Ex, floattype_t[:, :, :] Hy, floattype_t[:, :, :, :] EPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dz):
|
||||
"""This function updates the Ex field components in the z stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dHy
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[0, i + xs, j + ys, zf - k]
|
||||
dHy = (Hy[i + xs, j + ys, zf - k] - Hy[i + xs, j + ys, zf - k - 1]) / dz
|
||||
Ex[i + xs, j + ys, zf - k] = Ex[i + xs, j + ys, zf - k] - updatecoeffsE[listIndex, 4] * ((RA[0, k] * RA[1, k] - 1) * dHy + RA[1, k] * RB[0, k] * EPhi[0, i, j, k] + RB[1, k] * EPhi[1, i, j, k])
|
||||
EPhi[1, i, j, k] = RE[1, k] * EPhi[1, i, j, k] - RF[1, k] * (RA[0, k] * dHy + RB[0, k] * EPhi[0, i, j, k])
|
||||
EPhi[0, i, j, k] = RE[0, k] * EPhi[0, i, j, k] - RF[0, k] * dHy
|
||||
|
||||
|
||||
#############################################
|
||||
# Electric field PML updates - Ey component #
|
||||
#############################################
|
||||
cpdef update_pml_2order_ey_xplus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsE, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Ey, floattype_t[:, :, :] Hz, floattype_t[:, :, :, :] EPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dx):
|
||||
"""This function updates the Ey field components in the x stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dHz
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[1, i + xs, j + ys, k + zs]
|
||||
dHz = (Hz[i + xs, j + ys, k + zs] - Hz[i - 1 + xs, j + ys, k + zs]) / dx
|
||||
Ey[i + xs, j + ys, k + zs] = Ey[i + xs, j + ys, k + zs] - updatecoeffsE[listIndex, 4] * ((RA[0, i] * RA[1, i] - 1) * dHz + RA[1, i] * RB[0, i] * EPhi[0, i, j, k] + RB[1, i] * EPhi[1, i, j, k])
|
||||
EPhi[1, i, j, k] = RE[1, i] * EPhi[1, i, j, k] - RF[1, i] * (RA[0, i] * dHz + RB[0, i] * EPhi[0, i, j, k])
|
||||
EPhi[0, i, j, k] = RE[0, i] * EPhi[0, i, j, k] - RF[0, i] * dHz
|
||||
|
||||
|
||||
cpdef update_pml_2order_ey_xminus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsE, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Ey, floattype_t[:, :, :] Hz, floattype_t[:, :, :, :] EPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dx):
|
||||
"""This function updates the Ey field components in the x stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dHz
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[1, xf - i, j + ys, k + zs]
|
||||
dHz = (Hz[xf - i, j + ys, k + zs] - Hz[xf - i - 1, j + ys, k + zs]) / dx
|
||||
Ey[xf - i, j + ys, k + zs] = Ey[xf - i, j + ys, k + zs] - updatecoeffsE[listIndex, 4] * ((RA[0, i] * RA[1, i] - 1) * dHz + RA[1, i] * RB[0, i] * EPhi[0, i, j, k] + RB[1, i] * EPhi[1, i, j, k])
|
||||
EPhi[1, i, j, k] = RE[1, i] * EPhi[1, i, j, k] - RF[1, i] * (RA[0, i] * dHz + RB[0, i] * EPhi[0, i, j, k])
|
||||
EPhi[0, i, j, k] = RE[0, i] * EPhi[0, i, j, k] - RF[0, i] * dHz
|
||||
|
||||
|
||||
cpdef update_pml_2order_ey_zplus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsE, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Ey, floattype_t[:, :, :] Hx, floattype_t[:, :, :, :] EPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dz):
|
||||
"""This function updates the Ey field components in the z stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dHx
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[1, i + xs, j + ys, k + zs]
|
||||
dHx = (Hx[i + xs, j + ys, k + zs] - Hx[i + xs, j + ys, k - 1 + zs]) / dz
|
||||
Ey[i + xs, j + ys, k + zs] = Ey[i + xs, j + ys, k + zs] + updatecoeffsE[listIndex, 4] * ((RA[0, k] * RA[1, k] - 1) * dHx + RA[1, k] * RB[0, k] * EPhi[0, i, j, k] + RB[1, k] * EPhi[1, i, j, k])
|
||||
EPhi[1, i, j, k] = RE[1, k] * EPhi[1, i, j, k] - RF[1, k] * (RA[0, k] * dHx + RB[0, k] * EPhi[0, i, j, k])
|
||||
EPhi[0, i, j, k] = RE[0, k] * EPhi[0, i, j, k] - RF[0, k] * dHx
|
||||
|
||||
|
||||
cpdef update_pml_2order_ey_zminus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsE, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Ey, floattype_t[:, :, :] Hx, floattype_t[:, :, :, :] EPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dz):
|
||||
"""This function updates the Ey field components in the z stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dHx
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[1, i + xs, j + ys, zf - k]
|
||||
dHx = (Hx[i + xs, j + ys, zf - k] - Hx[i + xs, j + ys, zf - k - 1]) / dz
|
||||
Ey[i + xs, j + ys, zf - k] = Ey[i + xs, j + ys, zf - k] + updatecoeffsE[listIndex, 4] * ((RA[0, k] * RA[1, k] - 1) * dHx + RA[1, k] * RB[0, k] * EPhi[0, i, j, k] + RB[1, k] * EPhi[1, i, j, k])
|
||||
EPhi[1, i, j, k] = RE[1, k] * EPhi[1, i, j, k] - RF[1, k] * (RA[0, k] * dHx + RB[0, k] * EPhi[0, i, j, k])
|
||||
EPhi[0, i, j, k] = RE[0, k] * EPhi[0, i, j, k] - RF[0, k] * dHx
|
||||
|
||||
|
||||
#############################################
|
||||
# Electric field PML updates - Ez component #
|
||||
#############################################
|
||||
cpdef update_pml_2order_ez_xplus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsE, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Ez, floattype_t[:, :, :] Hy, floattype_t[:, :, :, :] EPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dx):
|
||||
"""This function updates the Ey field components in the z stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dHy
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[2, i + xs, j + ys, k + zs]
|
||||
dHy = (Hy[i + xs, j + ys, k + zs] - Hy[i - 1 + xs, j + ys, k + zs]) / dx
|
||||
Ez[i + xs, j + ys, k + zs] = Ez[i + xs, j + ys, k + zs] + updatecoeffsE[listIndex, 4] * ((RA[0, i] * RA[1, i] - 1) * dHy + RA[1, i] * RB[0, i] * EPhi[0, i, j, k] + RB[1, i] * EPhi[1, i, j, k])
|
||||
EPhi[1, i, j, k] = RE[1, i] * EPhi[1, i, j, k] - RF[1, i] * (RA[0, i] * dHy + RB[0, i] * EPhi[0, i, j, k])
|
||||
EPhi[0, i, j, k] = RE[0, i] * EPhi[0, i, j, k] - RF[0, i] * dHy
|
||||
|
||||
|
||||
cpdef update_pml_2order_ez_xminus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsE, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Ez, floattype_t[:, :, :] Hy, floattype_t[:, :, :, :] EPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dx):
|
||||
"""This function updates the Ez field components in the x stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dHy
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[2, xf - i, j + ys, k + zs]
|
||||
dHy = (Hy[xf - i, j + ys, k + zs] - Hy[xf - i - 1, j + ys, k + zs]) / dx
|
||||
Ez[xf - i, j + ys, k + zs] = Ez[xf - i, j + ys, k + zs] + updatecoeffsE[listIndex, 4] * ((RA[0, i] * RA[1, i] - 1) * dHy + RA[1, i] * RB[0, i] * EPhi[0, i, j, k] + RB[1, i] * EPhi[1, i, j, k])
|
||||
EPhi[1, i, j, k] = RE[1, i] * EPhi[1, i, j, k] - RF[1, i] * (RA[0, i] * dHy + RB[0, i] * EPhi[0, i, j, k])
|
||||
EPhi[0, i, j, k] = RE[0, i] * EPhi[0, i, j, k] - RF[0, i] * dHy
|
||||
|
||||
|
||||
cpdef update_pml_2order_ez_yplus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsE, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Ez, floattype_t[:, :, :] Hx, floattype_t[:, :, :, :] EPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dy):
|
||||
"""This function updates the Ez field components in the y stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dHx
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[2, i + xs, j + ys, k + zs]
|
||||
dHx = (Hx[i + xs, j + ys, k + zs] - Hx[i + xs, j - 1 + ys, k + zs]) / dy
|
||||
Ez[i + xs, j + ys, k + zs] = Ez[i + xs, j + ys, k + zs] - updatecoeffsE[listIndex, 4] * ((RA[0, j] * RA[1, j] - 1) * dHx + RA[1, j] * RB[0, j] * EPhi[0, i, j, k] + RB[1, j] * EPhi[1, i, j, k])
|
||||
EPhi[1, i, j, k] = RE[1, j] * EPhi[1, i, j, k] - RF[1, j] * (RA[0, j] * dHx + RB[0, j] * EPhi[0, i, j, k])
|
||||
EPhi[0, i, j, k] = RE[0, j] * EPhi[0, i, j, k] - RF[0, j] * dHx
|
||||
|
||||
|
||||
cpdef update_pml_2order_ez_yminus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsE, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Ez, floattype_t[:, :, :] Hx, floattype_t[:, :, :, :] EPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dy):
|
||||
"""This function updates the Ez field components in the y stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dHx
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[2, i + xs, yf - j, k + zs]
|
||||
dHx = (Hx[i + xs, yf - j, k + zs] - Hx[i + xs, yf - j - 1, k + zs]) / dy
|
||||
Ez[i + xs, yf - j, k + zs] = Ez[i + xs, yf - j, k + zs] - updatecoeffsE[listIndex, 4] * ((RA[0, j] * RA[1, j] - 1) * dHx + RA[1, j] * RB[0, j] * EPhi[0, i, j, k] + RB[1, j] * EPhi[1, i, j, k])
|
||||
EPhi[1, i, j, k] = RE[1, j] * EPhi[1, i, j, k] - RF[1, j] * (RA[0, j] * dHx + RB[0, j] * EPhi[0, i, j, k])
|
||||
EPhi[0, i, j, k] = RE[0, j] * EPhi[0, i, j, k] - RF[0, j] * dHx
|
||||
|
||||
|
||||
#############################################
|
||||
# Magnetic field PML updates - Hx component #
|
||||
#############################################
|
||||
cpdef update_pml_2order_hx_yplus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsH, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Hx, floattype_t[:, :, :] Ez, floattype_t[:, :, :, :] HPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dy):
|
||||
"""This function updates the Hx field components in the y stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dEz
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[3, i + xs, j + ys, k + zs]
|
||||
dEz = (Ez[i + xs, j + 1 + ys, k + zs] - Ez[i + xs, j + ys, k + zs]) / dy
|
||||
Hx[i + xs, j + ys, k + zs] = Hx[i + xs, j + ys, k + zs] - updatecoeffsH[listIndex, 4] * ((RA[0, j] * RA[1, j] - 1) * dEz + RA[1, j] * RB[0, j] * HPhi[0, i, j, k] + RB[1, j] * HPhi[1, i, j, k])
|
||||
HPhi[1, i, j, k] = RE[1, j] * HPhi[1, i, j, k] - RF[1, j] * (RA[0, j] * dEz + RB[0, j] * HPhi[0, i, j, k])
|
||||
HPhi[0, i, j, k] = RE[0, j] * HPhi[0, i, j, k] - RF[0, j] * dEz
|
||||
|
||||
|
||||
cpdef update_pml_2order_hx_yminus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsH, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Hx, floattype_t[:, :, :] Ez, floattype_t[:, :, :, :] HPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dy):
|
||||
"""This function updates the Hx field components in the y stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dEz
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[3, i + xs, yf - (j + 1), k + zs]
|
||||
dEz = (Ez[i + xs, yf - j, k + zs] - Ez[i + xs, yf - (j + 1), k + zs]) / dy
|
||||
Hx[i + xs, yf - (j + 1), k + zs] = Hx[i + xs, yf - (j + 1), k + zs] - updatecoeffsH[listIndex, 4] * ((RA[0, j] * RA[1, j] - 1) * dEz + RA[1, j] * RB[0, j] * HPhi[0, i, j, k] + RB[1, j] * HPhi[1, i, j, k])
|
||||
HPhi[1, i, j, k] = RE[1, j] * HPhi[1, i, j, k] - RF[1, j] * (RA[0, j] * dEz + RB[0, j] * HPhi[0, i, j, k])
|
||||
HPhi[0, i, j, k] = RE[0, j] * HPhi[0, i, j, k] - RF[0, j] * dEz
|
||||
|
||||
|
||||
cpdef update_pml_2order_hx_zplus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsH, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Hx, floattype_t[:, :, :] Ey, floattype_t[:, :, :, :] HPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dz):
|
||||
"""This function updates the Hx field components in the z stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dEy
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[3, i + xs, j + ys, k + zs]
|
||||
dEy = (Ey[i + xs, j + ys, k + 1 + zs] - Ey[i + xs, j + ys, k + zs]) / dz
|
||||
Hx[i + xs, j + ys, k + zs] = Hx[i + xs, j + ys, k + zs] + updatecoeffsH[listIndex, 4] * ((RA[0, k] * RA[1, k] - 1) * dEy + RA[1, k] * RB[0, k] * HPhi[0, i, j, k] + RB[1, k] * HPhi[1, i, j, k])
|
||||
HPhi[1, i, j, k] = RE[1, k] * HPhi[1, i, j, k] - RF[1, k] * (RA[0, k] * dEy + RB[0, k] * HPhi[0, i, j, k])
|
||||
HPhi[0, i, j, k] = RE[0, k] * HPhi[0, i, j, k] - RF[0, k] * dEy
|
||||
|
||||
|
||||
cpdef update_pml_2order_hx_zminus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsH, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Hx, floattype_t[:, :, :] Ey, floattype_t[:, :, :, :] HPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dz):
|
||||
"""This function updates the Hx field components in the z stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dEy
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[3, i + xs, j + ys, zf - (k + 1)]
|
||||
dEy = (Ey[i + xs, j + ys, zf - k] - Ey[i + xs, j + ys, zf - (k + 1)]) / dz
|
||||
Hx[i + xs, j + ys, zf - (k + 1)] = Hx[i + xs, j + ys, zf - (k + 1)] + updatecoeffsH[listIndex, 4] * ((RA[0, k] * RA[1, k] - 1) * dEy + RA[1, k] * RB[0, k] * HPhi[0, i, j, k] + RB[1, k] * HPhi[1, i, j, k])
|
||||
HPhi[1, i, j, k] = RE[1, k] * HPhi[1, i, j, k] - RF[1, k] * (RA[0, k] * dEy + RB[0, k] * HPhi[0, i, j, k])
|
||||
HPhi[0, i, j, k] = RE[0, k] * HPhi[0, i, j, k] - RF[0, k] * dEy
|
||||
|
||||
|
||||
#############################################
|
||||
# Magnetic field PML updates - Hy component #
|
||||
#############################################
|
||||
cpdef update_pml_2order_hy_xplus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsH, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Hy, floattype_t[:, :, :] Ez, floattype_t[:, :, :, :] HPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dx):
|
||||
"""This function updates the Hy field components in the x stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dEz
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[4, i + xs, j + ys, k + zs]
|
||||
dEz = (Ez[i + 1 + xs, j + ys, k + zs] - Ez[i + xs, j + ys, k + zs]) / dx
|
||||
Hy[i + xs, j + ys, k + zs] = Hy[i + xs, j + ys, k + zs] + updatecoeffsH[listIndex, 4] * ((RA[0, i] * RA[1, i] - 1) * dEz + RA[1, i] * RB[0, i] * HPhi[0, i, j, k] + RB[1, i] * HPhi[1, i, j, k])
|
||||
HPhi[1, i, j, k] = RE[1, i] * HPhi[1, i, j, k] - RF[1, i] * (RA[0, i] * dEz + RB[0, i] * HPhi[0, i, j, k])
|
||||
HPhi[0, i, j, k] = RE[0, i] * HPhi[0, i, j, k] - RF[0, i] * dEz
|
||||
|
||||
|
||||
cpdef update_pml_2order_hy_xminus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsH, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Hy, floattype_t[:, :, :] Ez, floattype_t[:, :, :, :] HPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dx):
|
||||
"""This function updates the Hy field components in the x stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dEz
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[4, xf - (i + 1), j + ys, k + zs]
|
||||
dEz = (Ez[xf - i, j + ys, k + zs] - Ez[xf - (i + 1), j + ys, k + zs]) / dx
|
||||
Hy[xf - (i + 1), j + ys, k + zs] = Hy[xf - (i + 1), j + ys, k + zs] + updatecoeffsH[listIndex, 4] * ((RA[0, i] * RA[1, i] - 1) * dEz + RA[1, i] * RB[0, i] * HPhi[0, i, j, k] + RB[1, i] * HPhi[1, i, j, k])
|
||||
HPhi[1, i, j, k] = RE[1, i] * HPhi[1, i, j, k] - RF[1, i] * (RA[0, i] * dEz + RB[0, i] * HPhi[0, i, j, k])
|
||||
HPhi[0, i, j, k] = RE[0, i] * HPhi[0, i, j, k] - RF[0, i] * dEz
|
||||
|
||||
|
||||
cpdef update_pml_2order_hy_zplus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsH, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Hy, floattype_t[:, :, :] Ex, floattype_t[:, :, :, :] HPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dz):
|
||||
"""This function updates the Hy field components in the z stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dEx
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[4, i + xs, j + ys, k + zs]
|
||||
dEx = (Ex[i + xs, j + ys, k + 1 + zs] - Ex[i + xs, j + ys, k + zs]) / dz
|
||||
Hy[i + xs, j + ys, k + zs] = Hy[i + xs, j + ys, k + zs] - updatecoeffsH[listIndex, 4] * ((RA[0, k] * RA[1, k] - 1) * dEx + RA[1, k] * RB[0, k] * HPhi[0, i, j, k] + RB[1, k] * HPhi[1, i, j, k])
|
||||
HPhi[1, i, j, k] = RE[1, k] * HPhi[1, i, j, k] - RF[1, k] * (RA[0, k] * dEx + RB[0, k] * HPhi[0, i, j, k])
|
||||
HPhi[0, i, j, k] = RE[0, k] * HPhi[0, i, j, k] - RF[0, k] * dEx
|
||||
|
||||
|
||||
cpdef update_pml_2order_hy_zminus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsH, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Hy, floattype_t[:, :, :] Ex, floattype_t[:, :, :, :] HPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dz):
|
||||
"""This function updates the Hy field components in the z stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dEx
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[4, i + xs, j + ys, zf - (k + 1)]
|
||||
dEx = (Ex[i + xs, j + ys, zf - k] - Ex[i + xs, j + ys, zf - (k + 1)]) / dz
|
||||
Hy[i + xs, j + ys, zf - (k + 1)] = Hy[i + xs, j + ys, zf - (k + 1)] - updatecoeffsH[listIndex, 4] * ((RA[0, k] * RA[1, k] - 1) * dEx + RA[1, k] * RB[0, k] * HPhi[0, i, j, k] + RB[1, k] * HPhi[1, i, j, k])
|
||||
HPhi[1, i, j, k] = RE[1, k] * HPhi[1, i, j, k] - RF[1, k] * (RA[0, k] * dEx + RB[0, k] * HPhi[0, i, j, k])
|
||||
HPhi[0, i, j, k] = RE[0, k] * HPhi[0, i, j, k] - RF[0, k] * dEx
|
||||
|
||||
|
||||
#############################################
|
||||
# Magnetic field PML updates - Hz component #
|
||||
#############################################
|
||||
cpdef update_pml_2order_hz_xplus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsH, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Hz, floattype_t[:, :, :] Ey, floattype_t[:, :, :, :] HPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dx):
|
||||
"""This function updates the Hz field components in the x stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dEy
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[5, i + xs, j + ys, k + zs]
|
||||
dEy = (Ey[i + 1 + xs, j + ys, k + zs] - Ey[i + xs, j + ys, k + zs]) / dx
|
||||
Hz[i + xs, j + ys, k + zs] = Hz[i + xs, j + ys, k + zs] - updatecoeffsH[listIndex, 4] * ((RA[0, i] * RA[1, i] - 1) * dEy + RA[1, i] * RB[0, i] * HPhi[0, i, j, k] + RB[1, i] * HPhi[1, i, j, k])
|
||||
HPhi[1, i, j, k] = RE[1, i] * HPhi[1, i, j, k] - RF[1, i] * (RA[0, i] * dEy + RB[0, i] * HPhi[0, i, j, k])
|
||||
HPhi[0, i, j, k] = RE[0, i] * HPhi[0, i, j, k] - RF[0, i] * dEy
|
||||
|
||||
|
||||
cpdef update_pml_2order_hz_xminus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsH, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Hz, floattype_t[:, :, :] Ey, floattype_t[:, :, :, :] HPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dx):
|
||||
"""This function updates the Hz field components in the x stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dEy
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[5, xf - (i + 1), j + ys, k + zs]
|
||||
dEy = (Ey[xf - i, j + ys, k + zs] - Ey[xf - (i + 1), j + ys, k + zs]) / dx
|
||||
Hz[xf - (i + 1), j + ys, k + zs] = Hz[xf - (i + 1), j + ys, k + zs] - updatecoeffsH[listIndex, 4] * ((RA[0, i] * RA[1, i] - 1) * dEy + RA[1, i] * RB[0, i] * HPhi[0, i, j, k] + RB[1, i] * HPhi[1, i, j, k])
|
||||
HPhi[1, i, j, k] = RE[1, i] * HPhi[1, i, j, k] - RF[1, i] * (RA[0, i] * dEy + RB[0, i] * HPhi[0, i, j, k])
|
||||
HPhi[0, i, j, k] = RE[0, i] * HPhi[0, i, j, k] - RF[0, i] * dEy
|
||||
|
||||
|
||||
cpdef update_pml_2order_hz_yplus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsH, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Hz, floattype_t[:, :, :] Ex, floattype_t[:, :, :, :] HPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dy):
|
||||
"""This function updates the Hz field components in the y stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dEx
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[5, i + xs, j + ys, k + zs]
|
||||
dEx = (Ex[i + xs, j + 1 + ys, k + zs] - Ex[i + xs, j + ys, k + zs]) / dy
|
||||
Hz[i + xs, j + ys, k + zs] = Hz[i + xs, j + ys, k + zs] + updatecoeffsH[listIndex, 4] * ((RA[0, j] * RA[1, j] - 1) * dEx + RA[1, j] * RB[0, j] * HPhi[0, i, j, k] + RB[1, j] * HPhi[1, i, j, k])
|
||||
HPhi[1, i, j, k] = RE[1, j] * HPhi[1, i, j, k] - RF[1, j] * (RA[0, j] * dEx + RB[0, j] * HPhi[0, i, j, k])
|
||||
HPhi[0, i, j, k] = RE[0, j] * HPhi[0, i, j, k] - RF[0, j] * dEx
|
||||
|
||||
|
||||
cpdef update_pml_2order_hz_yminus(int xs, int xf, int ys, int yf, int zs, int zf, int nthreads, floattype_t[:, :] updatecoeffsH, np.uint32_t[:, :, :, :] ID, floattype_t[:, :, :] Hz, floattype_t[:, :, :] Ex, floattype_t[:, :, :, :] HPhi, floattype_t[:, :] RA, floattype_t[:, :] RB, floattype_t[:, :] RE, floattype_t[:, :] RF, float dy):
|
||||
"""This function updates the Hz field components in the y stretching direction.
|
||||
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (int): Cell coordinates of entire box
|
||||
nthreads (int): Number of threads to use
|
||||
updatecoeffs, ID, E, H (memoryviews): Access to update coeffients, ID and field component arrays
|
||||
EPhi, HPhi, RA, RB, RE, RF (memoryviews): Access to PML coefficient arrays
|
||||
dx, dy, dz (float): Spatial discretisation
|
||||
"""
|
||||
|
||||
cdef int i, j, k, nx, ny, nz, listIndex
|
||||
cdef float dEx
|
||||
nx = xf - xs
|
||||
ny = yf - ys
|
||||
nz = zf - zs
|
||||
|
||||
for i in prange(0, nx, nogil=True, schedule='static', chunksize=1, num_threads=nthreads):
|
||||
for j in range(0, ny):
|
||||
for k in range(0, nz):
|
||||
listIndex = ID[5, i + xs, yf - (j + 1), k + zs]
|
||||
dEx = (Ex[i + xs, yf - j, k + zs] - Ex[i + xs, yf - (j + 1), k + zs]) / dy
|
||||
Hz[i + xs, yf - (j + 1), k + zs] = Hz[i + xs, yf - (j + 1), k + zs] + updatecoeffsH[listIndex, 4] * ((RA[0, j] * RA[1, j] - 1) * dEx + RA[1, j] * RB[0, j] * HPhi[0, i, j, k] + RB[1, j] * HPhi[1, i, j, k])
|
||||
HPhi[1, i, j, k] = RE[1, j] * HPhi[1, i, j, k] - RF[1, j] * (RA[0, j] * dEx + RB[0, j] * HPhi[0, i, j, k])
|
||||
HPhi[0, i, j, k] = RE[0, j] * HPhi[0, i, j, k] - RF[0, j] * dEx
|
||||
|
118
gprMax/pml_call_updates.py
普通文件
118
gprMax/pml_call_updates.py
普通文件
@@ -0,0 +1,118 @@
|
||||
# Copyright (C) 2015: The University of Edinburgh
|
||||
# Authors: Craig Warren and Antonis Giannopoulos
|
||||
#
|
||||
# This file is part of gprMax.
|
||||
#
|
||||
# gprMax is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gprMax is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from .pml_1order_update import *
|
||||
from .pml_2order_update import *
|
||||
|
||||
|
||||
def update_pml_electric(G):
|
||||
"""This functions updates electric field components with the PML correction."""
|
||||
|
||||
for pml in G.pmls:
|
||||
if pml.direction == 'xminus':
|
||||
if len(pml.CFS) == 1:
|
||||
update_pml_1order_ey_xminus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsE, G.ID, G.Ey, G.Hz, pml.EPhiyxz, pml.ERA, pml.ERB, pml.ERE, pml.ERF, G.dx)
|
||||
update_pml_1order_ez_xminus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsE, G.ID, G.Ez, G.Hy, pml.EPhizxy, pml.ERA, pml.ERB, pml.ERE, pml.ERF, G.dx)
|
||||
elif len(pml.CFS) == 2:
|
||||
update_pml_2order_ey_xminus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsE, G.ID, G.Ey, G.Hz, pml.EPhiyxz, pml.ERA, pml.ERB, pml.ERE, pml.ERF, G.dx)
|
||||
update_pml_2order_ez_xminus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsE, G.ID, G.Ez, G.Hy, pml.EPhizxy, pml.ERA, pml.ERB, pml.ERE, pml.ERF, G.dx)
|
||||
elif pml.direction == 'xplus':
|
||||
if len(pml.CFS) == 1:
|
||||
update_pml_1order_ey_xplus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsE, G.ID, G.Ey, G.Hz, pml.EPhiyxz, pml.ERA, pml.ERB, pml.ERE, pml.ERF, G.dx)
|
||||
update_pml_1order_ez_xplus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsE, G.ID, G.Ez, G.Hy, pml.EPhizxy, pml.ERA, pml.ERB, pml.ERE, pml.ERF, G.dx)
|
||||
elif len(pml.CFS) == 2:
|
||||
update_pml_2order_ey_xplus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsE, G.ID, G.Ey, G.Hz, pml.EPhiyxz, pml.ERA, pml.ERB, pml.ERE, pml.ERF, G.dx)
|
||||
update_pml_2order_ez_xplus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsE, G.ID, G.Ez, G.Hy, pml.EPhizxy, pml.ERA, pml.ERB, pml.ERE, pml.ERF, G.dx)
|
||||
elif pml.direction == 'yminus':
|
||||
if len(pml.CFS) == 1:
|
||||
update_pml_1order_ex_yminus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsE, G.ID, G.Ex, G.Hz, pml.EPhixyz, pml.ERA, pml.ERB, pml.ERE, pml.ERF, G.dy)
|
||||
update_pml_1order_ez_yminus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsE, G.ID, G.Ez, G.Hx, pml.EPhizyx, pml.ERA, pml.ERB, pml.ERE, pml.ERF, G.dy)
|
||||
elif len(pml.CFS) == 2:
|
||||
update_pml_2order_ex_yminus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsE, G.ID, G.Ex, G.Hz, pml.EPhixyz, pml.ERA, pml.ERB, pml.ERE, pml.ERF, G.dy)
|
||||
update_pml_2order_ez_yminus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsE, G.ID, G.Ez, G.Hx, pml.EPhizyx, pml.ERA, pml.ERB, pml.ERE, pml.ERF, G.dy)
|
||||
elif pml.direction == 'yplus':
|
||||
if len(pml.CFS) == 1:
|
||||
update_pml_1order_ex_yplus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsE, G.ID, G.Ex, G.Hz, pml.EPhixyz, pml.ERA, pml.ERB, pml.ERE, pml.ERF, G.dy)
|
||||
update_pml_1order_ez_yplus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsE, G.ID, G.Ez, G.Hx, pml.EPhizyx, pml.ERA, pml.ERB, pml.ERE, pml.ERF, G.dy)
|
||||
elif len(pml.CFS) == 2:
|
||||
update_pml_2order_ex_yplus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsE, G.ID, G.Ex, G.Hz, pml.EPhixyz, pml.ERA, pml.ERB, pml.ERE, pml.ERF, G.dy)
|
||||
update_pml_2order_ez_yplus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsE, G.ID, G.Ez, G.Hx, pml.EPhizyx, pml.ERA, pml.ERB, pml.ERE, pml.ERF, G.dy)
|
||||
elif pml.direction == 'zminus':
|
||||
if len(pml.CFS) == 1:
|
||||
update_pml_1order_ex_zminus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsE, G.ID, G.Ex, G.Hy, pml.EPhixzy, pml.ERA, pml.ERB, pml.ERE, pml.ERF, G.dz)
|
||||
update_pml_1order_ey_zminus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsE, G.ID, G.Ey, G.Hx, pml.EPhiyzx, pml.ERA, pml.ERB, pml.ERE, pml.ERF, G.dz)
|
||||
elif len(pml.CFS) == 2:
|
||||
update_pml_2order_ex_zminus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsE, G.ID, G.Ex, G.Hy, pml.EPhixzy, pml.ERA, pml.ERB, pml.ERE, pml.ERF, G.dz)
|
||||
update_pml_2order_ey_zminus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsE, G.ID, G.Ey, G.Hx, pml.EPhiyzx, pml.ERA, pml.ERB, pml.ERE, pml.ERF, G.dz)
|
||||
elif pml.direction == 'zplus':
|
||||
if len(pml.CFS) == 1:
|
||||
update_pml_1order_ex_zplus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsE, G.ID, G.Ex, G.Hy, pml.EPhixzy, pml.ERA, pml.ERB, pml.ERE, pml.ERF, G.dz)
|
||||
update_pml_1order_ey_zplus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsE, G.ID, G.Ey, G.Hx, pml.EPhiyzx, pml.ERA, pml.ERB, pml.ERE, pml.ERF, G.dz)
|
||||
elif len(pml.CFS) == 2:
|
||||
update_pml_2order_ex_zplus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsE, G.ID, G.Ex, G.Hy, pml.EPhixzy, pml.ERA, pml.ERB, pml.ERE, pml.ERF, G.dz)
|
||||
update_pml_2order_ey_zplus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsE, G.ID, G.Ey, G.Hx, pml.EPhiyzx, pml.ERA, pml.ERB, pml.ERE, pml.ERF, G.dz)
|
||||
|
||||
|
||||
def update_pml_magnetic(G):
|
||||
"""This functions updates magnetic field components with the PML correction."""
|
||||
|
||||
for pml in G.pmls:
|
||||
if pml.direction == 'xminus':
|
||||
if len(pml.CFS) == 1:
|
||||
update_pml_1order_hy_xminus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsH, G.ID, G.Hy, G.Ez, pml.HPhiyxz, pml.HRA, pml.HRB, pml.HRE, pml.HRF, G.dx)
|
||||
update_pml_1order_hz_xminus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsH, G.ID, G.Hz, G.Ey, pml.HPhizxy, pml.HRA, pml.HRB, pml.HRE, pml.HRF, G.dx)
|
||||
elif len(pml.CFS) == 2:
|
||||
update_pml_2order_hy_xminus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsH, G.ID, G.Hy, G.Ez, pml.HPhiyxz, pml.HRA, pml.HRB, pml.HRE, pml.HRF, G.dx)
|
||||
update_pml_2order_hz_xminus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsH, G.ID, G.Hz, G.Ey, pml.HPhizxy, pml.HRA, pml.HRB, pml.HRE, pml.HRF, G.dx)
|
||||
elif pml.direction == 'xplus':
|
||||
if len(pml.CFS) == 1:
|
||||
update_pml_1order_hy_xplus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsH, G.ID, G.Hy, G.Ez, pml.HPhiyxz, pml.HRA, pml.HRB, pml.HRE, pml.HRF, G.dx)
|
||||
update_pml_1order_hz_xplus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsH, G.ID, G.Hz, G.Ey, pml.HPhizxy, pml.HRA, pml.HRB, pml.HRE, pml.HRF, G.dx)
|
||||
elif len(pml.CFS) == 2:
|
||||
update_pml_2order_hy_xplus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsH, G.ID, G.Hy, G.Ez, pml.HPhiyxz, pml.HRA, pml.HRB, pml.HRE, pml.HRF, G.dx)
|
||||
update_pml_2order_hz_xplus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsH, G.ID, G.Hz, G.Ey, pml.HPhizxy, pml.HRA, pml.HRB, pml.HRE, pml.HRF, G.dx)
|
||||
elif pml.direction == 'yminus':
|
||||
if len(pml.CFS) == 1:
|
||||
update_pml_1order_hx_yminus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsH, G.ID, G.Hx, G.Ez, pml.HPhixyz, pml.HRA, pml.HRB, pml.HRE, pml.HRF, G.dy)
|
||||
update_pml_1order_hz_yminus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsH, G.ID, G.Hz, G.Ex, pml.HPhizyx, pml.HRA, pml.HRB, pml.HRE, pml.HRF, G.dy)
|
||||
elif len(pml.CFS) == 2:
|
||||
update_pml_2order_hx_yminus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsH, G.ID, G.Hx, G.Ez, pml.HPhixyz, pml.HRA, pml.HRB, pml.HRE, pml.HRF, G.dy)
|
||||
update_pml_2order_hz_yminus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsH, G.ID, G.Hz, G.Ex, pml.HPhizyx, pml.HRA, pml.HRB, pml.HRE, pml.HRF, G.dy)
|
||||
elif pml.direction == 'yplus':
|
||||
if len(pml.CFS) == 1:
|
||||
update_pml_1order_hx_yplus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsH, G.ID, G.Hx, G.Ez, pml.HPhixyz, pml.HRA, pml.HRB, pml.HRE, pml.HRF, G.dy)
|
||||
update_pml_1order_hz_yplus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsH, G.ID, G.Hz, G.Ex, pml.HPhizyx, pml.HRA, pml.HRB, pml.HRE, pml.HRF, G.dy)
|
||||
elif len(pml.CFS) == 2:
|
||||
update_pml_2order_hx_yplus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsH, G.ID, G.Hx, G.Ez, pml.HPhixyz, pml.HRA, pml.HRB, pml.HRE, pml.HRF, G.dy)
|
||||
update_pml_2order_hz_yplus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsH, G.ID, G.Hz, G.Ex, pml.HPhizyx, pml.HRA, pml.HRB, pml.HRE, pml.HRF, G.dy)
|
||||
elif pml.direction == 'zminus':
|
||||
if len(pml.CFS) == 1:
|
||||
update_pml_1order_hx_zminus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsH, G.ID, G.Hx, G.Ey, pml.HPhixzy, pml.HRA, pml.HRB, pml.HRE, pml.HRF, G.dz)
|
||||
update_pml_1order_hy_zminus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsH, G.ID, G.Hy, G.Ex, pml.HPhiyzx, pml.HRA, pml.HRB, pml.HRE, pml.HRF, G.dz)
|
||||
elif len(pml.CFS) == 2:
|
||||
update_pml_2order_hx_zminus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsH, G.ID, G.Hx, G.Ey, pml.HPhixzy, pml.HRA, pml.HRB, pml.HRE, pml.HRF, G.dz)
|
||||
update_pml_2order_hy_zminus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsH, G.ID, G.Hy, G.Ex, pml.HPhiyzx, pml.HRA, pml.HRB, pml.HRE, pml.HRF, G.dz)
|
||||
elif pml.direction == 'zplus':
|
||||
if len(pml.CFS) == 1:
|
||||
update_pml_1order_hx_zplus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsH, G.ID, G.Hx, G.Ey, pml.HPhixzy, pml.HRA, pml.HRB, pml.HRE, pml.HRF, G.dz)
|
||||
update_pml_1order_hy_zplus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsH, G.ID, G.Hy, G.Ex, pml.HPhiyzx, pml.HRA, pml.HRB, pml.HRE, pml.HRF, G.dz)
|
||||
elif len(pml.CFS) == 2:
|
||||
update_pml_2order_hx_zplus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsH, G.ID, G.Hx, G.Ey, pml.HPhixzy, pml.HRA, pml.HRB, pml.HRE, pml.HRF, G.dz)
|
||||
update_pml_2order_hy_zplus(pml.xs, pml.xf, pml.ys, pml.yf, pml.zs, pml.zf, G.nthreads, G.updatecoeffsH, G.ID, G.Hy, G.Ex, pml.HPhiyzx, pml.HRA, pml.HRB, pml.HRE, pml.HRF, G.dz)
|
||||
|
||||
|
31
gprMax/receivers.py
普通文件
31
gprMax/receivers.py
普通文件
@@ -0,0 +1,31 @@
|
||||
# Copyright (C) 2015: The University of Edinburgh
|
||||
# Authors: Craig Warren and Antonis Giannopoulos
|
||||
#
|
||||
# This file is part of gprMax.
|
||||
#
|
||||
# gprMax is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gprMax is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
class Rx:
|
||||
"""Receiever output points."""
|
||||
|
||||
def __init__(self, positionx=None, positiony=None, positionz=None):
|
||||
"""
|
||||
Args:
|
||||
positionx (float): x-coordinate of location in model.
|
||||
positiony (float): y-coordinate of location in model.
|
||||
positionz (float): z-coordinate of location in model.
|
||||
"""
|
||||
self.positionx = positionx
|
||||
self.positiony = positiony
|
||||
self.positionz = positionz
|
144
gprMax/snapshots.py
普通文件
144
gprMax/snapshots.py
普通文件
@@ -0,0 +1,144 @@
|
||||
# Copyright (C) 2015: The University of Edinburgh
|
||||
# Authors: Craig Warren and Antonis Giannopoulos
|
||||
#
|
||||
# This file is part of gprMax.
|
||||
#
|
||||
# gprMax is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gprMax is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import sys
|
||||
import numpy as np
|
||||
from struct import pack
|
||||
|
||||
from .constants import floattype
|
||||
from .utilities import rvalue
|
||||
|
||||
|
||||
class Snapshot:
|
||||
"""Snapshots of the electric and magnetic field values."""
|
||||
|
||||
# Set string for byte order
|
||||
if sys.byteorder == 'little':
|
||||
byteorder = 'LittleEndian'
|
||||
else:
|
||||
byteorder = 'BigEndian'
|
||||
|
||||
# Set format text and string depending on float type
|
||||
if np.dtype(floattype).name == 'float32':
|
||||
floatname = 'Float32'
|
||||
floatstring = 'f'
|
||||
elif np.dtype(floattype).name == 'float64':
|
||||
floatname = 'Float64'
|
||||
floatstring = 'd'
|
||||
|
||||
def __init__(self, xs=None, ys=None, zs=None, xf=None, yf=None, zf=None, dx=None, dy=None, dz=None, time=None, filename=None):
|
||||
"""
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf (float): Extent of the volume.
|
||||
dx, dy, dz (float): Spatial discretisation.
|
||||
time (int): Iteration number to take the snapshot on.
|
||||
filename (str): Filename to save to.
|
||||
"""
|
||||
self.xs = xs
|
||||
self.ys = ys
|
||||
self.zs = zs
|
||||
self.xf = xf
|
||||
self.yf = yf
|
||||
self.zf = zf
|
||||
self.dx = dx
|
||||
self.dy = dy
|
||||
self.dz = dz
|
||||
self.time = time
|
||||
self.filename = filename
|
||||
|
||||
def prepare_file(self, modelrun, numbermodelruns, G):
|
||||
"""Prepares a VTK ImageData (.vti) file for a snapshot.
|
||||
|
||||
Args:
|
||||
modelrun (int): Current model run number.
|
||||
numbermodelruns (int): Total number of model runs.
|
||||
G (class): Grid class instance - holds essential parameters describing the model.
|
||||
"""
|
||||
|
||||
# No Python 3 support for VTK at time of writing (03/2015)
|
||||
self.vtk_nx = self.xf - self.xs
|
||||
self.vtk_ny = self.yf - self.ys
|
||||
self.vtk_nz = self.zf - self.zs
|
||||
|
||||
# Construct filename from user-supplied name and model run number
|
||||
if numbermodelruns == 1:
|
||||
self.filename = G.inputdirectory + self.filename + '.vti'
|
||||
else:
|
||||
self.filename = G.inputdirectory + self.filename + '_' + str(modelrun) + '.vti'
|
||||
|
||||
# Calculate number of cells according to requested sampling
|
||||
self.vtk_xscells = rvalue(self.xs / self.dx)
|
||||
self.vtk_xfcells = rvalue(self.xf / self.dx)
|
||||
self.vtk_yscells = rvalue(self.ys / self.dy)
|
||||
self.vtk_yfcells = rvalue(self.yf / self.dz)
|
||||
self.vtk_zscells = rvalue(self.zs / self.dz)
|
||||
self.vtk_zfcells = rvalue(self.zf / self.dz)
|
||||
vtk_hfield_offset = 3 * np.dtype(floattype).itemsize * (self.vtk_xfcells - self.vtk_xscells) * (self.vtk_yfcells - self.vtk_yscells) * (self.vtk_zfcells - self.vtk_zscells) + np.dtype(np.uint32).itemsize
|
||||
# vtk_current_offset = 2 * vtk_hfield_offset
|
||||
|
||||
self.filehandle = open(self.filename, 'wb')
|
||||
self.filehandle.write('<?xml version="1.0"?>\n'.encode('utf-8'))
|
||||
self.filehandle.write('<VTKFile type="ImageData" version="1.0" byte_order="{}">\n'.format(Snapshot.byteorder).encode('utf-8'))
|
||||
self.filehandle.write('<ImageData WholeExtent="{} {} {} {} {} {}" Origin="0 0 0" Spacing="{:.3} {:.3} {:.3}">\n'.format(self.vtk_xscells, self.vtk_xfcells, self.vtk_yscells, self.vtk_yfcells, self.vtk_zscells, self.vtk_zfcells, self.dx * G.dx, self.dy * G.dy, self.dz * G.dz).encode('utf-8'))
|
||||
self.filehandle.write('<Piece Extent="{} {} {} {} {} {}">\n'.format(self.vtk_xscells, self.vtk_xfcells, self.vtk_yscells, self.vtk_yfcells, self.vtk_zscells, self.vtk_zfcells).encode('utf-8'))
|
||||
self.filehandle.write('<CellData Vectors="E-field H-field">\n'.encode('utf-8'))
|
||||
# self.filehandle.write('<CellData Vectors="E-field H-field Current">\n'.encode('utf-8'))
|
||||
self.filehandle.write('<DataArray type="{}" Name="E-field" NumberOfComponents="3" format="appended" offset="0" />\n'.format(Snapshot.floatname).encode('utf-8'))
|
||||
self.filehandle.write('<DataArray type="{}" Name="H-field" NumberOfComponents="3" format="appended" offset="{}" />\n'.format(Snapshot.floatname, vtk_hfield_offset).encode('utf-8'))
|
||||
# self.filehandle.write('<DataArray type="{}" Name="Current" NumberOfComponents="3" format="appended" offset="{}" />\n'.format(Snapshot.floatname, vtk_current_offset).encode('utf-8'))
|
||||
self.filehandle.write('</CellData>\n</Piece>\n</ImageData>\n<AppendedData encoding="raw">\n_'.encode('utf-8'))
|
||||
|
||||
def write_snapshot(self, Ex, Ey, Ez, Hx, Hy, Hz, G):
|
||||
"""Writes electric and magnetic field values to VTK ImageData (.vti) file.
|
||||
|
||||
Args:
|
||||
Ex, Ey, Ez, Hx, Hy, Hz (memory view): Electric and magnetic field values.
|
||||
G (class): Grid class instance - holds essential parameters describing the model.
|
||||
"""
|
||||
|
||||
datasize = 3 * np.dtype(floattype).itemsize * (self.vtk_xfcells - self.vtk_xscells) * (self.vtk_yfcells - self.vtk_yscells) * (self.vtk_zfcells - self.vtk_zscells)
|
||||
# Write number of bytes of appended data as UInt32
|
||||
self.filehandle.write(pack('I', datasize))
|
||||
for k in range(self.zs, self.zf, self.dz):
|
||||
for j in range(self.ys, self.yf, self.dy):
|
||||
for i in range(self.xs, self.xf, self.dx):
|
||||
# The electric field component value at a point comes from average of the 4 electric field component values in that cell
|
||||
self.filehandle.write(pack(Snapshot.floatstring, (Ex[i, j, k] + Ex[i, j + 1, k] + Ex[i, j, k + 1] + Ex[i, j + 1, k + 1]) / 4))
|
||||
self.filehandle.write(pack(Snapshot.floatstring, (Ey[i, j, k] + Ey[i + 1, j, k] + Ey[i, j, k + 1] + Ey[i + 1, j, k + 1]) / 4))
|
||||
self.filehandle.write(pack(Snapshot.floatstring, (Ez[i, j, k] + Ez[i + 1, j, k] + Ez[i, j + 1, k] + Ez[i + 1, j + 1, k]) / 4))
|
||||
|
||||
self.filehandle.write(pack('I', datasize))
|
||||
for k in range(self.zs, self.zf, self.dz):
|
||||
for j in range(self.ys, self.yf, self.dy):
|
||||
for i in range(self.xs, self.xf, self.dx):
|
||||
# The magnetic field component value at a point comes from average of 2 magnetic field component values in that cell and the following cell
|
||||
self.filehandle.write(pack(Snapshot.floatstring, (Hx[i, j, k] + Hx[i + 1, j, k]) / 2))
|
||||
self.filehandle.write(pack(Snapshot.floatstring, (Hy[i, j, k] + Hy[i, j + 1, k]) / 2))
|
||||
self.filehandle.write(pack(Snapshot.floatstring, (Hz[i, j, k] + Hz[i, j, k + 1]) / 2))
|
||||
|
||||
# self.filehandle.write(pack('I', datasize))
|
||||
# for k in range(self.zs, self.zf, self.dz):
|
||||
# for j in range(self.ys, self.yf, self.dy):
|
||||
# for i in range(self.xs, self.xf, self.dx):
|
||||
# self.filehandle.write(pack(Snapshot.floatstring, Ix[i, j, k]))
|
||||
# self.filehandle.write(pack(Snapshot.floatstring, Iy[i, j, k]))
|
||||
# self.filehandle.write(pack(Snapshot.floatstring, Iz[i, j, k]))
|
||||
|
||||
self.filehandle.write('\n</AppendedData>\n</VTKFile>'.encode('utf-8'))
|
||||
self.filehandle.close()
|
||||
|
158
gprMax/sources.py
普通文件
158
gprMax/sources.py
普通文件
@@ -0,0 +1,158 @@
|
||||
# Copyright (C) 2015: The University of Edinburgh
|
||||
# Authors: Craig Warren and Antonis Giannopoulos
|
||||
#
|
||||
# This file is part of gprMax.
|
||||
#
|
||||
# gprMax is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gprMax is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import numpy as np
|
||||
|
||||
from .utilities import rvalue
|
||||
|
||||
|
||||
class VoltageSource:
|
||||
"""Voltage sources."""
|
||||
|
||||
def __init__(self):
|
||||
self.polarisation = None
|
||||
self.positionx = None
|
||||
self.positiony = None
|
||||
self.positionz = None
|
||||
self.start = None
|
||||
self.stop = None
|
||||
self.resistance = None
|
||||
self.waveformID = None
|
||||
|
||||
def update_fields(self, abstime, timestep, updatecoeffsE, ID, Ex, Ey, Ez, G):
|
||||
"""Updates electric field values for a voltage source.
|
||||
|
||||
Args:
|
||||
abstime (float): Absolute time.
|
||||
timestep (int): Iteration number.
|
||||
updatecoeffsE (memory view): numpy array of electric field update coefficients.
|
||||
ID (memory view): numpy array of numeric IDs corresponding to materials in the model.
|
||||
Ex, Ey, Ez (memory view): numpy array of electric field values.
|
||||
G (class): Grid class instance - holds essential parameters describing the model.
|
||||
"""
|
||||
|
||||
if abstime >= self.start and abstime <= self.stop:
|
||||
# Set the time of the waveform evaluation to account for any delay in the start
|
||||
time = abstime - self.start
|
||||
i = self.positionx
|
||||
j = self.positiony
|
||||
k = self.positionz
|
||||
waveform = next(x for x in G.waveforms if x.ID == self.waveformID)
|
||||
|
||||
if self.polarisation is 'x':
|
||||
if self.resistance != 0:
|
||||
Ex[i, j, k] -= updatecoeffsE[ID[0, i, j, k], 4] * waveform.amp * waveform.calculate_value(time, G.dt) * (1 / (self.resistance * G.dy * G.dz))
|
||||
else:
|
||||
Ex[i, j, k] = -1 * waveform.amp * waveform.calculate_value(time, G.dt) / G.dx
|
||||
|
||||
elif self.polarisation is 'y':
|
||||
if self.resistance != 0:
|
||||
Ey[i, j, k] -= updatecoeffsE[ID[1, i, j, k], 4] * waveform.amp * waveform.calculate_value(time, G.dt) * (1 / (self.resistance * G.dx * G.dz))
|
||||
else:
|
||||
Ey[i, j, k] = -1 * waveform.amp * waveform.calculate_value(time, G.dt) / G.dy
|
||||
|
||||
elif self.polarisation is 'z':
|
||||
if self.resistance != 0:
|
||||
Ez[i, j, k] -= updatecoeffsE[ID[2, i, j, k], 4] * waveform.amp * waveform.calculate_value(time, G.dt) * (1 / (self.resistance * G.dx * G.dy))
|
||||
else:
|
||||
Ez[i, j, k] = -1 * waveform.amp * waveform.calculate_value(time, G.dt) / G.dz
|
||||
|
||||
|
||||
class HertzianDipole:
|
||||
"""Hertzian dipoles, i.e. normal additive source (current density)."""
|
||||
|
||||
def __init__(self):
|
||||
self.polarisation = None
|
||||
self.positionx = None
|
||||
self.positiony = None
|
||||
self.positionz = None
|
||||
self.start = None
|
||||
self.stop = None
|
||||
self.waveformID = None
|
||||
|
||||
def update_fields(self, abstime, timestep, updatecoeffsE, ID, Ex, Ey, Ez, G):
|
||||
"""Updates electric field values for a Hertzian dipole.
|
||||
|
||||
Args:
|
||||
abstime (float): Absolute time.
|
||||
timestep (int): Iteration number.
|
||||
updatecoeffsE (memory view): numpy array of electric field update coefficients.
|
||||
ID (memory view): numpy array of numeric IDs corresponding to materials in the model.
|
||||
Ex, Ey, Ez (memory view): numpy array of electric field values.
|
||||
G (class): Grid class instance - holds essential parameters describing the model.
|
||||
"""
|
||||
|
||||
if abstime >= self.start and abstime <= self.stop:
|
||||
# Set the time of the waveform evaluation to account for any delay in the start
|
||||
time = abstime - self.start
|
||||
i = self.positionx
|
||||
j = self.positiony
|
||||
k = self.positionz
|
||||
waveform = next(x for x in G.waveforms if x.ID == self.waveformID)
|
||||
|
||||
if self.polarisation is 'x':
|
||||
Ex[i, j, k] -= updatecoeffsE[ID[0, i, j, k], 4] * waveform.amp * waveform.calculate_value(time, G.dt) * (1 / (G.dy * G.dz))
|
||||
|
||||
elif self.polarisation is 'y':
|
||||
Ey[i, j, k] -= updatecoeffsE[ID[1, i, j, k], 4] * waveform.amp * waveform.calculate_value(time, G.dt) * (1 / (G.dx * G.dz))
|
||||
|
||||
elif self.polarisation is 'z':
|
||||
Ez[i, j, k] -= updatecoeffsE[ID[2, i, j, k], 4] * waveform.amp * waveform.calculate_value(time, G.dt) * (1 / (G.dx * G.dy))
|
||||
|
||||
|
||||
class MagneticDipole:
|
||||
"""Magnetic dipoles, i.e. current on a small loop."""
|
||||
|
||||
def __init__(self):
|
||||
self.polarisation = None
|
||||
self.positionx = None
|
||||
self.positiony = None
|
||||
self.positionz = None
|
||||
self.start = None
|
||||
self.stop = None
|
||||
self.waveformID = None
|
||||
|
||||
def update_fields(self, abstime, timestep, updatecoeffsH, ID, Hx, Hy, Hz, G):
|
||||
"""Updates electric field values for a magnetic dipole.
|
||||
|
||||
Args:
|
||||
abstime (float): Absolute time.
|
||||
timestep (int): Iteration number.
|
||||
updatecoeffsH (memory view): numpy array of magnetic field update coefficients.
|
||||
ID (memory view): numpy array of numeric IDs corresponding to materials in the model.
|
||||
Hx, Hy, Hz (memory view): numpy array of magnetic field values.
|
||||
G (class): Grid class instance - holds essential parameters describing the model.
|
||||
"""
|
||||
|
||||
if abstime >= self.start and abstime <= self.stop:
|
||||
# Set the time of the waveform evaluation to account for any delay in the start
|
||||
time = abstime - self.start
|
||||
i = self.positionx
|
||||
j = self.positiony
|
||||
k = self.positionz
|
||||
waveform = next(x for x in G.waveforms if x.ID == self.waveformID)
|
||||
|
||||
if self.polarisation is 'x':
|
||||
Hx[i, j, k] -= waveform.amp * waveform.calculate_value(time, G.dt) * (G.dt / (G.dx * G.dy * G.dz))
|
||||
|
||||
elif self.polarisation is 'y':
|
||||
Hy[i, j, k] -= waveform.amp * waveform.calculate_value(time, G.dt) * (G.dt / (G.dx * G.dy * G.dz))
|
||||
|
||||
elif self.polarisation is 'z':
|
||||
Hz[i, j, k] -= waveform.amp * waveform.calculate_value(time, G.dt) * (G.dt / (G.dx * G.dy * G.dz))
|
||||
|
119
gprMax/utilities.py
普通文件
119
gprMax/utilities.py
普通文件
@@ -0,0 +1,119 @@
|
||||
# Copyright (C) 2015: The University of Edinburgh
|
||||
# Authors: Craig Warren and Antonis Giannopoulos
|
||||
#
|
||||
# This file is part of gprMax.
|
||||
#
|
||||
# gprMax is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gprMax is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import sys
|
||||
import decimal as d
|
||||
from pyfiglet import Figlet
|
||||
|
||||
|
||||
class ListStream:
|
||||
"""A list can be streamed into. Required when temporarily redirecting stdio to capture output from users Python code blocks."""
|
||||
|
||||
def __init__(self):
|
||||
self.data = []
|
||||
|
||||
def write(self, s):
|
||||
self.data.append(s)
|
||||
|
||||
|
||||
def logo(version):
|
||||
"""Print gprMax logo, version, and licencing/copyright information.
|
||||
|
||||
Args:
|
||||
version (str): Version number.
|
||||
"""
|
||||
|
||||
licenseinfo = """
|
||||
Copyright (C) 2015: The University of Edinburgh
|
||||
Authors: Craig Warren and Antonis Giannopoulos
|
||||
|
||||
gprMax is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
gprMax is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with gprMax. If not, see <http://www.gnu.org/licenses/>."""
|
||||
width = 65
|
||||
url = 'www.gprmax.com'
|
||||
print('\n{} {} {}'.format('*'*round((width - len(url))/2), url, '*'*round((width - len(url))/2)))
|
||||
gprMaxlogo = Figlet(font='standard', width=width, justify='center')
|
||||
print('{}'.format(gprMaxlogo.renderText('gprMax')))
|
||||
print('{} v{} {}'.format('*'*round((width - len(version))/2), (version), '*'*round((width - len(version))/2)))
|
||||
print(licenseinfo)
|
||||
print('\n{}\n'.format('*'*(width+3)))
|
||||
|
||||
|
||||
def update_progress(progress):
|
||||
"""Displays or updates a console progress bar.
|
||||
|
||||
Args:
|
||||
progress (float): Number between zero and one to signify progress.
|
||||
"""
|
||||
|
||||
# Modify this to change the length of the progress bar
|
||||
barLength = 50
|
||||
block = rvalue(barLength * progress)
|
||||
text = '\r|{}| {:2.1f}%'.format( '#' * block + '-' * (barLength - block), progress * 100)
|
||||
sys.stdout.write(text)
|
||||
sys.stdout.flush()
|
||||
|
||||
|
||||
def rvalue(value):
|
||||
"""Rounds half values downward.
|
||||
|
||||
Args:
|
||||
value (float): Number to round.
|
||||
|
||||
Returns:
|
||||
Rounded value (float).
|
||||
"""
|
||||
|
||||
return int(d.Decimal(value).quantize(d.Decimal('1'),rounding=d.ROUND_HALF_DOWN))
|
||||
|
||||
|
||||
def human_size(size, a_kilobyte_is_1024_bytes=True):
|
||||
"""Convert a file size to human-readable form.
|
||||
|
||||
Args:
|
||||
size (int): file size in bytes
|
||||
a_kilobyte_is_1024_bytes (boolean) - true for multiples of 1024, false for multiples of 1000
|
||||
|
||||
Returns:
|
||||
Human-readable (string).
|
||||
"""
|
||||
|
||||
suffixes = {1000: ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'], 1024: ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']}
|
||||
|
||||
if size < 0:
|
||||
raise ValueError('Number must be non-negative.')
|
||||
|
||||
multiple = 1024 if a_kilobyte_is_1024_bytes else 1000
|
||||
for suffix in suffixes[multiple]:
|
||||
size /= multiple
|
||||
if size < multiple:
|
||||
return '{0:.1f} {1}'.format(size, suffix)
|
||||
|
||||
raise ValueError('Number is too large.')
|
||||
|
||||
|
102
gprMax/waveforms.py
普通文件
102
gprMax/waveforms.py
普通文件
@@ -0,0 +1,102 @@
|
||||
# Copyright (C) 2015: The University of Edinburgh
|
||||
# Authors: Craig Warren and Antonis Giannopoulos
|
||||
#
|
||||
# This file is part of gprMax.
|
||||
#
|
||||
# gprMax is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gprMax is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import numpy as np
|
||||
|
||||
from .utilities import rvalue
|
||||
|
||||
|
||||
class Waveform:
|
||||
"""Definitions of waveform shapes that can be used with sources."""
|
||||
|
||||
waveformtypes = ['gaussian', 'gaussiandot', 'gaussiandotdot', 'ricker', 'sine', 'contsine', 'impulse', 'user']
|
||||
|
||||
def __init__(self):
|
||||
self.ID = None
|
||||
self.type = None
|
||||
self.amp = 1
|
||||
self.freq = 0
|
||||
self.uservalues = None
|
||||
|
||||
def calculate_value(self, time, dt):
|
||||
"""Calculates value of the waveform at a specific time.
|
||||
|
||||
Args:
|
||||
time (float): Absolute time.
|
||||
dt (float): Absolute time discretisation.
|
||||
|
||||
Returns:
|
||||
waveform (float): Calculated value for waveform.
|
||||
"""
|
||||
|
||||
chi = 1 / self.freq
|
||||
zeta = 2 * np.pi * np.pi * self.freq * self.freq
|
||||
delay = time - chi
|
||||
|
||||
if self.type == 'gaussian':
|
||||
waveform = np.exp(-zeta * delay * delay)
|
||||
|
||||
elif self.type == 'gaussiandot':
|
||||
waveform = -2 * zeta * delay * np.exp(-zeta * delay * delay)
|
||||
|
||||
elif self.type == 'gaussiandotnorm':
|
||||
normalise = np.sqrt(np.exp(1) / (2 * zeta))
|
||||
waveform = -2 * zeta * delay * np.exp(-zeta * delay * delay) * normalise
|
||||
|
||||
elif self.type == 'gaussiandotdot':
|
||||
waveform = 2 * zeta * (2 * zeta * delay * delay - 1) * np.exp(-zeta * delay * delay)
|
||||
|
||||
elif self.type == 'gaussiandotdotnorm':
|
||||
normalise = 1 / (2 * zeta)
|
||||
waveform = 2 * zeta * (2 * zeta * delay * delay - 1) * np.exp(-zeta * delay * delay) * normalise
|
||||
|
||||
elif self.type == 'gaussiandotdotdot':
|
||||
waveform = zeta * zeta * (3 * delay - 2 * zeta * delay * delay * delay) * np.exp(-zeta * delay * delay)
|
||||
|
||||
elif self.type == 'ricker':
|
||||
normalise = 1 / (2 * zeta)
|
||||
waveform = - (2 * zeta * (2 * zeta * delay * delay - 1) * np.exp(-zeta * delay * delay)) * normalise
|
||||
|
||||
elif self.type == 'sine':
|
||||
waveform = np.sin(2 * np.pi * self.freq * time)
|
||||
if time * self.freq > 1:
|
||||
waveform = 0
|
||||
|
||||
elif self.type == 'contsine':
|
||||
rampamp = 0.25
|
||||
ramp = rampamp * time * self.freq
|
||||
if ramp > 1:
|
||||
ramp = 1
|
||||
waveform = ramp * np.sin(2 * np.pi * self.freq * time)
|
||||
|
||||
elif self.type == 'impulse':
|
||||
# time < G.dt condition required to do impulsive magnetic dipole
|
||||
if time == 0 or time < dt:
|
||||
waveform = 1
|
||||
elif time >= dt:
|
||||
waveform = 0
|
||||
|
||||
elif self.type == 'user':
|
||||
index = rvalue(time / dt)
|
||||
# Check to see if there are still user specified values and if not use zero
|
||||
if index > len(self.uservalues) - 1:
|
||||
waveform = 0
|
||||
else:
|
||||
waveform = self.uservalues[index]
|
||||
|
||||
return waveform
|
332
gprMax/yee_cell_build.pyx
普通文件
332
gprMax/yee_cell_build.pyx
普通文件
@@ -0,0 +1,332 @@
|
||||
# Copyright (C) 2015: The University of Edinburgh
|
||||
# Authors: Craig Warren and Antonis Giannopoulos
|
||||
#
|
||||
# This file is part of gprMax.
|
||||
#
|
||||
# gprMax is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gprMax is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import numpy as np
|
||||
cimport numpy as np
|
||||
from .materials import Material
|
||||
from .yee_cell_setget_rigid cimport get_rigid_Ex, get_rigid_Ey, get_rigid_Ez, get_rigid_Hx, get_rigid_Hy, get_rigid_Hz
|
||||
|
||||
|
||||
cpdef build_ex_component(np.uint32_t[:, :, :] solid, np.int8_t[:, :, :, :] rigidE, np.uint32_t[:, :, :, :] ID, G):
|
||||
"""This function builds the Ex components in the ID array.
|
||||
|
||||
Args:
|
||||
solid, rigid, ID (memoryviews): Access to solid, rigid and ID arrays
|
||||
"""
|
||||
|
||||
cdef int i, j, k, numID1, numID2, numID3, numID4
|
||||
|
||||
for i in range(0, G.nx):
|
||||
for j in range(1, G.ny):
|
||||
for k in range(1, G.nz):
|
||||
|
||||
# If rigid is True do not average
|
||||
if get_rigid_Ex(i, j, k, rigidE):
|
||||
pass
|
||||
else:
|
||||
numID1 = solid[i, j, k]
|
||||
numID2 = solid[i, j - 1, k]
|
||||
numID3 = solid[i, j - 1, k - 1]
|
||||
numID4 = solid[i, j, k - 1]
|
||||
|
||||
# If all values are the same no need to average
|
||||
if numID1 == numID2 and numID1 == numID3 and numID1 == numID4:
|
||||
ID[0, i, j, k] = numID1
|
||||
else:
|
||||
# Averaging is required
|
||||
# Make an ID composed of the names of the four materials that will be averaged
|
||||
requiredID = G.materials[numID1].ID + '|' + G.materials[numID2].ID + '|' + G.materials[numID3].ID + '|' + G.materials[numID4].ID
|
||||
# Check if this material already exists
|
||||
tmp = requiredID.split('|')
|
||||
material = [x for x in G.materials if
|
||||
x.ID.count(tmp[0]) == requiredID.count(tmp[0]) and
|
||||
x.ID.count(tmp[1]) == requiredID.count(tmp[1]) and
|
||||
x.ID.count(tmp[2]) == requiredID.count(tmp[2]) and
|
||||
x.ID.count(tmp[3]) == requiredID.count(tmp[3])]
|
||||
|
||||
if material:
|
||||
ID[0, i, j, k] = material[0].numID
|
||||
else:
|
||||
# Create new material
|
||||
newNumID = len(G.materials)
|
||||
m = Material(newNumID, requiredID, G)
|
||||
# Create averaged constituents for material
|
||||
m.er = np.mean((G.materials[numID1].er, G.materials[numID2].er, G.materials[numID3].er, G.materials[numID4].er), axis=0)
|
||||
m.se = np.mean((G.materials[numID1].se, G.materials[numID2].se, G.materials[numID3].se, G.materials[numID4].se), axis=0)
|
||||
m.mr = np.mean((G.materials[numID1].mr, G.materials[numID2].mr, G.materials[numID3].mr, G.materials[numID4].mr), axis=0)
|
||||
m.sm = np.mean((G.materials[numID1].sm, G.materials[numID2].sm, G.materials[numID3].sm, G.materials[numID4].sm), axis=0)
|
||||
|
||||
# Append the new material object to the materials list
|
||||
G.materials.append(m)
|
||||
ID[0, i, j, k] = newNumID
|
||||
|
||||
cpdef build_ey_component(np.uint32_t[:, :, :] solid, np.int8_t[:, :, :, :] rigidE, np.uint32_t[:, :, :, :] ID, G):
|
||||
"""This function builds the Ey components in the ID array.
|
||||
|
||||
Args:
|
||||
solid, rigid, ID (memoryviews): Access to solid, rigid and ID arrays
|
||||
"""
|
||||
|
||||
cdef int i, j, k, numID1, numID2, numID3, numID4
|
||||
|
||||
for i in range(1, G.nx):
|
||||
for j in range(0, G.ny):
|
||||
for k in range(1, G.nz):
|
||||
|
||||
# If rigid is True do not average
|
||||
if get_rigid_Ey(i, j, k, rigidE):
|
||||
pass
|
||||
else:
|
||||
numID1 = solid[i, j, k]
|
||||
numID2 = solid[i - 1, j, k]
|
||||
numID3 = solid[i - 1, j, k - 1]
|
||||
numID4 = solid[i, j, k - 1]
|
||||
|
||||
# If all values are the same no need to average
|
||||
if numID1 == numID2 and numID1 == numID3 and numID1 == numID4:
|
||||
ID[1, i, j, k] = numID1
|
||||
else:
|
||||
# Averaging is required
|
||||
# Make an ID composed of the names of the four materials that will be averaged
|
||||
requiredID = G.materials[numID1].ID + '|' + G.materials[numID2].ID + '|' + G.materials[numID3].ID + '|' + G.materials[numID4].ID
|
||||
# Check if this material already exists
|
||||
tmp = requiredID.split('|')
|
||||
material = [x for x in G.materials if
|
||||
x.ID.count(tmp[0]) == requiredID.count(tmp[0]) and
|
||||
x.ID.count(tmp[1]) == requiredID.count(tmp[1]) and
|
||||
x.ID.count(tmp[2]) == requiredID.count(tmp[2]) and
|
||||
x.ID.count(tmp[3]) == requiredID.count(tmp[3])]
|
||||
|
||||
if material:
|
||||
ID[1, i, j, k] = material[0].numID
|
||||
else:
|
||||
# Create new material
|
||||
newNumID = len(G.materials)
|
||||
m = Material(newNumID, requiredID, G)
|
||||
# Create averaged constituents for material
|
||||
m.er = np.mean((G.materials[numID1].er, G.materials[numID2].er, G.materials[numID3].er, G.materials[numID4].er), axis=0)
|
||||
m.se = np.mean((G.materials[numID1].se, G.materials[numID2].se, G.materials[numID3].se, G.materials[numID4].se), axis=0)
|
||||
m.mr = np.mean((G.materials[numID1].mr, G.materials[numID2].mr, G.materials[numID3].mr, G.materials[numID4].mr), axis=0)
|
||||
m.sm = np.mean((G.materials[numID1].sm, G.materials[numID2].sm, G.materials[numID3].sm, G.materials[numID4].sm), axis=0)
|
||||
|
||||
# Append the new material object to the materials list
|
||||
G.materials.append(m)
|
||||
ID[1, i, j, k] = newNumID
|
||||
|
||||
cpdef build_ez_component(np.uint32_t[:, :, :] solid, np.int8_t[:, :, :, :] rigidE, np.uint32_t[:, :, :, :] ID, G):
|
||||
"""This function builds the Ez components in the ID array.
|
||||
|
||||
Args:
|
||||
solid, rigid, ID (memoryviews): Access to solid, rigid and ID arrays
|
||||
"""
|
||||
|
||||
cdef int i, j, k, numID1, numID2, numID3, numID4
|
||||
|
||||
for i in range(1, G.nx):
|
||||
for j in range(1, G.ny):
|
||||
for k in range(0, G.nz):
|
||||
|
||||
# If rigid is True do not average
|
||||
if get_rigid_Ez(i, j, k, rigidE):
|
||||
pass
|
||||
else:
|
||||
numID1 = solid[i, j, k]
|
||||
numID2 = solid[i - 1, j, k]
|
||||
numID3 = solid[i - 1, j - 1, k]
|
||||
numID4 = solid[i, j - 1, k]
|
||||
|
||||
# If all values are the same no need to average
|
||||
if numID1 == numID2 and numID1 == numID3 and numID1 == numID4:
|
||||
ID[2, i, j, k] = numID1
|
||||
else:
|
||||
# Averaging is required
|
||||
# Make an ID composed of the names of the four materials that will be averaged
|
||||
requiredID = G.materials[numID1].ID + '|' + G.materials[numID2].ID + '|' + G.materials[numID3].ID + '|' + G.materials[numID4].ID
|
||||
# Check if this material already exists
|
||||
tmp = requiredID.split('|')
|
||||
material = [x for x in G.materials if
|
||||
x.ID.count(tmp[0]) == requiredID.count(tmp[0]) and
|
||||
x.ID.count(tmp[1]) == requiredID.count(tmp[1]) and
|
||||
x.ID.count(tmp[2]) == requiredID.count(tmp[2]) and
|
||||
x.ID.count(tmp[3]) == requiredID.count(tmp[3])]
|
||||
|
||||
if material:
|
||||
ID[2, i, j, k] = material[0].numID
|
||||
else:
|
||||
# Create new material
|
||||
newNumID = len(G.materials)
|
||||
m = Material(newNumID, requiredID, G)
|
||||
# Create averaged constituents for material
|
||||
m.er = np.mean((G.materials[numID1].er, G.materials[numID2].er, G.materials[numID3].er, G.materials[numID4].er), axis=0)
|
||||
m.se = np.mean((G.materials[numID1].se, G.materials[numID2].se, G.materials[numID3].se, G.materials[numID4].se), axis=0)
|
||||
m.mr = np.mean((G.materials[numID1].mr, G.materials[numID2].mr, G.materials[numID3].mr, G.materials[numID4].mr), axis=0)
|
||||
m.sm = np.mean((G.materials[numID1].sm, G.materials[numID2].sm, G.materials[numID3].sm, G.materials[numID4].sm), axis=0)
|
||||
|
||||
# Append the new material object to the materials list
|
||||
G.materials.append(m)
|
||||
ID[2, i, j, k] = newNumID
|
||||
|
||||
cpdef build_hx_component(np.uint32_t[:, :, :] solid, np.int8_t[:, :, :, :] rigidH, np.uint32_t[:, :, :, :] ID, G):
|
||||
"""This function builds the Hx components in the ID array.
|
||||
|
||||
Args:
|
||||
solid, rigid, ID (memoryviews): Access to solid, rigid and ID arrays
|
||||
"""
|
||||
|
||||
cdef int i, j, k, numID1, numID2
|
||||
|
||||
for i in range(1, G.nx):
|
||||
for j in range(0, G.ny):
|
||||
for k in range(0, G.nz):
|
||||
|
||||
# If rigid is True do not average
|
||||
if get_rigid_Hx(i, j, k, rigidH):
|
||||
pass
|
||||
else:
|
||||
numID1 = solid[i, j, k]
|
||||
numID2 = solid[i - 1, j, k]
|
||||
|
||||
# If all values are the same no need to average
|
||||
if numID1 == numID2:
|
||||
ID[3, i, j, k] = numID1
|
||||
else:
|
||||
# Averaging is required
|
||||
# Make an ID composed of the names of the four materials that will be averaged
|
||||
requiredID = G.materials[numID1].ID + '|' + G.materials[numID2].ID
|
||||
# Check if this material already exists
|
||||
tmp = requiredID.split('|')
|
||||
material = [x for x in G.materials if
|
||||
(x.ID.count(tmp[0]) == requiredID.count(tmp[0]) and
|
||||
x.ID.count(tmp[1]) == requiredID.count(tmp[1])) or
|
||||
(x.ID.count(tmp[0]) % 2 == 0 and x.ID.count(tmp[1]) % 2 == 0)]
|
||||
|
||||
if material:
|
||||
ID[3, i, j, k] = material[0].numID
|
||||
else:
|
||||
# Create new material
|
||||
newNumID = len(G.materials)
|
||||
m = Material(newNumID, requiredID, G)
|
||||
# Create averaged constituents for material
|
||||
m.er = np.mean((G.materials[numID1].er, G.materials[numID2].er), axis=0)
|
||||
m.se = np.mean((G.materials[numID1].se, G.materials[numID2].se), axis=0)
|
||||
m.mr = np.mean((G.materials[numID1].mr, G.materials[numID2].mr), axis=0)
|
||||
m.sm = np.mean((G.materials[numID1].sm, G.materials[numID2].sm), axis=0)
|
||||
|
||||
# Append the new material object to the materials list
|
||||
G.materials.append(m)
|
||||
ID[3, i, j, k] = newNumID
|
||||
|
||||
cpdef build_hy_component(np.uint32_t[:, :, :] solid, np.int8_t[:, :, :, :] rigidH, np.uint32_t[:, :, :, :] ID, G):
|
||||
"""This function builds the Hy components in the ID array.
|
||||
|
||||
Args:
|
||||
solid, rigid, ID (memoryviews): Access to solid, rigid and ID arrays
|
||||
"""
|
||||
|
||||
cdef int i, j, k, numID1, numID2
|
||||
|
||||
for i in range(0, G.nx):
|
||||
for j in range(1, G.ny):
|
||||
for k in range(0, G.nz):
|
||||
|
||||
# If rigid is True do not average
|
||||
if get_rigid_Hy(i, j, k, rigidH):
|
||||
pass
|
||||
else:
|
||||
numID1 = solid[i, j, k]
|
||||
numID2 = solid[i, j - 1, k]
|
||||
|
||||
# If all values are the same no need to average
|
||||
if numID1 == numID2:
|
||||
ID[4, i, j, k] = numID1
|
||||
else:
|
||||
# Averaging is required
|
||||
# Make an ID composed of the names of the four materials that will be averaged
|
||||
requiredID = G.materials[numID1].ID + '|' + G.materials[numID2].ID
|
||||
# Check if this material already exists
|
||||
tmp = requiredID.split('|')
|
||||
material = [x for x in G.materials if
|
||||
(x.ID.count(tmp[0]) == requiredID.count(tmp[0]) and
|
||||
x.ID.count(tmp[1]) == requiredID.count(tmp[1])) or
|
||||
(x.ID.count(tmp[0]) % 2 == 0 and x.ID.count(tmp[1]) % 2 == 0)]
|
||||
|
||||
if material:
|
||||
ID[4, i, j, k] = material[0].numID
|
||||
else:
|
||||
# Create new material
|
||||
newNumID = len(G.materials)
|
||||
m = Material(newNumID, requiredID, G)
|
||||
# Create averaged constituents for material
|
||||
m.er = np.mean((G.materials[numID1].er, G.materials[numID2].er), axis=0)
|
||||
m.se = np.mean((G.materials[numID1].se, G.materials[numID2].se), axis=0)
|
||||
m.mr = np.mean((G.materials[numID1].mr, G.materials[numID2].mr), axis=0)
|
||||
m.sm = np.mean((G.materials[numID1].sm, G.materials[numID2].sm), axis=0)
|
||||
|
||||
# Append the new material object to the materials list
|
||||
G.materials.append(m)
|
||||
ID[4, i, j, k] = newNumID
|
||||
|
||||
cpdef build_hz_component(np.uint32_t[:, :, :] solid, np.int8_t[:, :, :, :] rigidH, np.uint32_t[:, :, :, :] ID, G):
|
||||
"""This function builds the Hz components in the ID array.
|
||||
|
||||
Args:
|
||||
solid, rigid, ID (memoryviews): Access to solid, rigid and ID arrays
|
||||
"""
|
||||
|
||||
cdef int i, j, k, numID1, numID2
|
||||
|
||||
for i in range(0, G.nx):
|
||||
for j in range(0, G.ny):
|
||||
for k in range(1, G.nz):
|
||||
|
||||
# If rigid is True do not average
|
||||
if get_rigid_Hz(i, j, k, rigidH):
|
||||
pass
|
||||
else:
|
||||
numID1 = solid[i, j, k]
|
||||
numID2 = solid[i, j, k - 1]
|
||||
|
||||
# If all values are the same no need to average
|
||||
if numID1 == numID2:
|
||||
ID[5, i, j, k] = numID1
|
||||
else:
|
||||
# Averaging is required
|
||||
# Make an ID composed of the names of the four materials that will be averaged
|
||||
requiredID = G.materials[numID1].ID + '|' + G.materials[numID2].ID
|
||||
# Check if this material already exists
|
||||
tmp = requiredID.split('|')
|
||||
material = [x for x in G.materials if
|
||||
(x.ID.count(tmp[0]) == requiredID.count(tmp[0]) and
|
||||
x.ID.count(tmp[1]) == requiredID.count(tmp[1])) or
|
||||
(x.ID.count(tmp[0]) % 2 == 0 and x.ID.count(tmp[1]) % 2 == 0)]
|
||||
|
||||
if material:
|
||||
ID[5, i, j, k] = material[0].numID
|
||||
else:
|
||||
# Create new material
|
||||
newNumID = len(G.materials)
|
||||
m = Material(newNumID, requiredID, G)
|
||||
# Create averaged constituents for material
|
||||
m.er = np.mean((G.materials[numID1].er, G.materials[numID2].er), axis=0)
|
||||
m.se = np.mean((G.materials[numID1].se, G.materials[numID2].se), axis=0)
|
||||
m.mr = np.mean((G.materials[numID1].mr, G.materials[numID2].mr), axis=0)
|
||||
m.sm = np.mean((G.materials[numID1].sm, G.materials[numID2].sm), axis=0)
|
||||
|
||||
# Append the new material object to the materials list
|
||||
G.materials.append(m)
|
||||
ID[5, i, j, k] = newNumID
|
44
gprMax/yee_cell_setget_rigid.pxd
普通文件
44
gprMax/yee_cell_setget_rigid.pxd
普通文件
@@ -0,0 +1,44 @@
|
||||
# Copyright (C) 2015: The University of Edinburgh
|
||||
# Authors: Craig Warren and Antonis Giannopoulos
|
||||
#
|
||||
# This file is part of gprMax.
|
||||
#
|
||||
# gprMax is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gprMax is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import numpy as np
|
||||
cimport numpy as np
|
||||
|
||||
# Get and set functions for the rigid electric component array. The rigid array is 4D with the 1st dimension holding
|
||||
# the 12 electric edge components of a cell - Ex1, Ex2, Ex3, Ex4, Ey1, Ey2, Ey3, Ey4, Ez1, Ez2, Ez3, Ez4
|
||||
cdef bint get_rigid_Ex(int i, int j, int k, np.int8_t[:, :, :, :] rigidE)
|
||||
cdef bint get_rigid_Ey(int i, int j, int k, np.int8_t[:, :, :, :] rigidE)
|
||||
cdef bint get_rigid_Ez(int i, int j, int k, np.int8_t[:, :, :, :] rigidE)
|
||||
cdef void set_rigid_Ex(int i, int j, int k, np.int8_t[:, :, :, :] rigidE)
|
||||
cdef void set_rigid_Ey(int i, int j, int k, np.int8_t[:, :, :, :] rigidE)
|
||||
cdef void set_rigid_Ez(int i, int j, int k, np.int8_t[:, :, :, :] rigidE)
|
||||
cdef void set_rigid_E(int i, int j, int k, np.int8_t[:, :, :, :] rigidE)
|
||||
cdef void unset_rigid_E(int i, int j, int k, np.int8_t[:, :, :, :] rigidE)
|
||||
|
||||
# Get and set functions for the rigid magnetic component array. The rigid array is 4D with the 1st dimension holding
|
||||
# the 6 magnetic edge components - Hx1, Hx2, Hy1, Hy2, Hz1, Hz2
|
||||
cdef bint get_rigid_Hx(int i, int j, int k, np.int8_t[:, :, :, :] rigidH)
|
||||
cdef bint get_rigid_Hy(int i, int j, int k, np.int8_t[:, :, :, :] rigidH)
|
||||
cdef bint get_rigid_Hz(int i, int j, int k, np.int8_t[:, :, :, :] rigidH)
|
||||
cdef void set_rigid_Hx(int i, int j, int k, np.int8_t[:, :, :, :] rigidH)
|
||||
cdef void set_rigid_Hy(int i, int j, int k, np.int8_t[:, :, :, :] rigidH)
|
||||
cdef void set_rigid_Hz(int i, int j, int k, np.int8_t[:, :, :, :] rigidH)
|
||||
cdef void set_rigid_H(int i, int j, int k, np.int8_t[:, :, :, :] rigidH)
|
||||
cdef void unset_rigid_H(int i, int j, int k, np.int8_t[:, :, :, :] rigidH)
|
||||
|
||||
|
157
gprMax/yee_cell_setget_rigid.pyx
普通文件
157
gprMax/yee_cell_setget_rigid.pyx
普通文件
@@ -0,0 +1,157 @@
|
||||
# Copyright (C) 2015: The University of Edinburgh
|
||||
# Authors: Craig Warren and Antonis Giannopoulos
|
||||
#
|
||||
# This file is part of gprMax.
|
||||
#
|
||||
# gprMax is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gprMax is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import numpy as np
|
||||
cimport numpy as np
|
||||
|
||||
# Get and set functions for the rigid electric component array. The rigid array is 4D with the 1st dimension holding
|
||||
# the 12 electric edge components of a cell - Ex1, Ex2, Ex3, Ex4, Ey1, Ey2, Ey3, Ey4, Ez1, Ez2, Ez3, Ez4
|
||||
cdef bint get_rigid_Ex(int i, int j, int k, np.int8_t[:, :, :, :] rigidE):
|
||||
cdef bint result
|
||||
result = False
|
||||
if rigidE[0, i, j, k]:
|
||||
result = True
|
||||
if j != 0:
|
||||
if rigidE[1, i, j - 1, k]:
|
||||
result = True
|
||||
if k != 0:
|
||||
if rigidE[3, i, j, k - 1]:
|
||||
result = True
|
||||
if j != 0 and k != 0:
|
||||
if rigidE[2, i, j - 1, k - 1]:
|
||||
result = True
|
||||
return result
|
||||
|
||||
cdef bint get_rigid_Ey(int i, int j, int k, np.int8_t[:, :, :, :] rigidE):
|
||||
cdef bint result
|
||||
result = False
|
||||
if rigidE[4, i, j, k]:
|
||||
result = True
|
||||
if i != 0:
|
||||
if rigidE[7, i - 1, j, k]:
|
||||
result = True
|
||||
if k != 0:
|
||||
if rigidE[5, i, j, k - 1]:
|
||||
result = True
|
||||
if i != 0 and k != 0:
|
||||
if rigidE[6, i - 1, j, k - 1]:
|
||||
result = True
|
||||
return result
|
||||
|
||||
cdef bint get_rigid_Ez(int i, int j, int k, np.int8_t[:, :, :, :] rigidE):
|
||||
cdef bint result
|
||||
result = False
|
||||
if rigidE[8, i, j, k]:
|
||||
result = True
|
||||
if i != 0:
|
||||
if rigidE[9, i - 1, j, k]:
|
||||
result = True
|
||||
if j != 0:
|
||||
if rigidE[11, i, j - 1, k]:
|
||||
result = True
|
||||
if i != 0 and j != 0:
|
||||
if rigidE[10, i - 1, j - 1, k]:
|
||||
result = True
|
||||
return result
|
||||
|
||||
cdef void set_rigid_Ex(int i, int j, int k, np.int8_t[:, :, :, :] rigidE):
|
||||
rigidE[0, i, j, k] = True
|
||||
if j != 0:
|
||||
rigidE[1, i, j - 1, k] = True
|
||||
if k != 0:
|
||||
rigidE[3, i, j, k - 1] = True
|
||||
if j != 0 and k != 0:
|
||||
rigidE[2, i, j - 1, k - 1] = True
|
||||
|
||||
cdef void set_rigid_Ey(int i, int j, int k, np.int8_t[:, :, :, :] rigidE):
|
||||
rigidE[4, i, j, k] = True
|
||||
if i != 0:
|
||||
rigidE[7, i - 1, j, k] = True
|
||||
if k != 0:
|
||||
rigidE[5, i, j, k - 1] = True
|
||||
if i != 0 and k != 0:
|
||||
rigidE[6, i - 1, j, k - 1] = True
|
||||
|
||||
cdef void set_rigid_Ez(int i, int j, int k, np.int8_t[:, :, :, :] rigidE):
|
||||
rigidE[8, i, j, k] = True
|
||||
if i != 0:
|
||||
rigidE[9, i - 1, j, k] = True
|
||||
if j != 0:
|
||||
rigidE[11, i, j - 1, k] = True
|
||||
if i != 0 and j != 0:
|
||||
rigidE[10, i - 1, j - 1, k] = True
|
||||
|
||||
cdef void set_rigid_E(int i, int j, int k, np.int8_t[:, :, :, :] rigidE):
|
||||
rigidE[:, i, j, k] = True
|
||||
|
||||
cdef void unset_rigid_E(int i, int j, int k, np.int8_t[:, :, :, :] rigidE):
|
||||
rigidE[:, i, j, k] = False
|
||||
|
||||
# Get and set functions for the rigid magnetic component array. The rigid array is 4D with the 1st dimension holding
|
||||
# the 6 magnetic edge components - Hx1, Hx2, Hy1, Hy2, Hz1, Hz2
|
||||
cdef bint get_rigid_Hx(int i, int j, int k, np.int8_t[:, :, :, :] rigidH):
|
||||
cdef bint result
|
||||
result = False
|
||||
if rigidH[0, i, j, k]:
|
||||
result = True
|
||||
if i != 0:
|
||||
if rigidH[1, i - 1, j, k]:
|
||||
result = True
|
||||
return result
|
||||
|
||||
cdef bint get_rigid_Hy(int i, int j, int k, np.int8_t[:, :, :, :] rigidH):
|
||||
cdef bint result
|
||||
result = False
|
||||
if rigidH[2, i, j, k]:
|
||||
result = True
|
||||
if j != 0:
|
||||
if rigidH[3, i, j - 1, k]:
|
||||
result = True
|
||||
return result
|
||||
|
||||
cdef bint get_rigid_Hz(int i, int j, int k, np.int8_t[:, :, :, :] rigidH):
|
||||
cdef bint result
|
||||
result = False
|
||||
if rigidH[4, i, j, k]:
|
||||
result = True
|
||||
if k != 0:
|
||||
if rigidH[5, i, j, k - 1]:
|
||||
result = True
|
||||
return result
|
||||
|
||||
cdef void set_rigid_Hx(int i, int j, int k, np.int8_t[:, :, :, :] rigidH):
|
||||
rigidH[0, i, j, k] = True
|
||||
if i != 0:
|
||||
rigidH[1, i - 1, j, k] = True
|
||||
|
||||
cdef void set_rigid_Hy(int i, int j, int k, np.int8_t[:, :, :, :] rigidH):
|
||||
rigidH[2, i, j, k] = True
|
||||
if j != 0:
|
||||
rigidH[3, i, j - 1, k] = True
|
||||
|
||||
cdef void set_rigid_Hz(int i, int j, int k, np.int8_t[:, :, :, :] rigidH):
|
||||
rigidH[4, i, j, k] = True
|
||||
if k != 0:
|
||||
rigidH[5, i, j, k - 1] = True
|
||||
|
||||
cdef void set_rigid_H(int i, int j, int k, np.int8_t[:, :, :, :] rigidH):
|
||||
rigidH[:, i, j, k] = True
|
||||
|
||||
cdef void unset_rigid_H(int i, int j, int k, np.int8_t[:, :, :, :] rigidH):
|
||||
rigidH[:, i, j, k] = False
|
||||
|
在新工单中引用
屏蔽一个用户