你已经派生过 gprMax
镜像自地址
https://gitee.com/sunhf/gprMax.git
已同步 2025-08-04 11:36:52 +08:00
5
.gitattributes
vendored
5
.gitattributes
vendored
@@ -1,6 +1 @@
|
||||
tools/Jupyter_notebooks/* linguist-vendored
|
||||
reframe_tests/regression_checks/TestGeometryView_5176823e/partial_volume.vtkhdf filter=lfs diff=lfs merge=lfs -text
|
||||
reframe_tests/regression_checks/TestGeometryView_5176823e/full_volume.vtkhdf filter=lfs diff=lfs merge=lfs -text
|
||||
reframe_tests/regression_checks/TestGeometryView_77980202/full_volume.vtkhdf filter=lfs diff=lfs merge=lfs -text
|
||||
reframe_tests/regression_checks/TestGeometryObject_a6a096cb/full_volume.h5 filter=lfs diff=lfs merge=lfs -text
|
||||
reframe_tests/regression_checks/TestGeometryObject_a6a096cb/partial_volume.h5 filter=lfs diff=lfs merge=lfs -text
|
||||
|
@@ -6,6 +6,9 @@
|
||||
|
||||
.. image:: images_shared/gprMax_logo_small.png
|
||||
:target: http://www.gprmax.com
|
||||
:alt: gprMax
|
||||
|
||||
.. include_in_docs_after_this_label
|
||||
|
||||
***************
|
||||
Getting Started
|
||||
@@ -208,6 +211,6 @@ Periodically you should update conda and the required Python packages. With the
|
||||
|
||||
|
||||
Thanks To Our Contributors ✨🔗
|
||||
==========================
|
||||
===============================
|
||||
.. image:: https://contrib.rocks/image?repo=gprMax/gprMax
|
||||
:target: https://github.com/gprMax/gprMax/graphs/contributors
|
||||
|
@@ -5,7 +5,7 @@
|
||||
SPHINXOPTS = -aE
|
||||
SPHINXBUILD = sphinx-build
|
||||
PAPER =
|
||||
BUILDDIR = ./
|
||||
BUILDDIR = ./build
|
||||
|
||||
# User-friendly check for sphinx-build
|
||||
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
|
||||
|
@@ -6,9 +6,13 @@
|
||||
# -- Project information -----------------------------------------------------
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
|
||||
sys.path.insert(0, os.path.abspath("../.."))
|
||||
|
||||
project = "gprMax"
|
||||
copyright = f'2015-{time.strftime("%Y")}, The University of Edinburgh, United Kingdom. Authors: Craig Warren, Antonis Giannopoulos, and John Hartley'
|
||||
author = "Craig Warren, Antonis Giannopoulos, and John Hartley"
|
||||
|
@@ -1 +1,6 @@
|
||||
.. figure:: ../../images_shared/gprMax_logo_small.png
|
||||
:target: http://www.gprmax.com
|
||||
:alt: gprMax
|
||||
|
||||
.. include:: ../../README.rst
|
||||
:start-after: .. include_in_docs_after_this_label
|
||||
|
@@ -69,11 +69,12 @@ The essential functions are:
|
||||
|
||||
Running model(s)
|
||||
----------------
|
||||
.. autofunction:: gprMax.gprMax.run
|
||||
.. autofunction:: gprMax.run
|
||||
|
||||
Creating a model scene
|
||||
----------------------
|
||||
.. autoclass:: gprMax.scene.Scene
|
||||
.. autoclass:: gprMax.Scene
|
||||
:members: add
|
||||
|
||||
Domain
|
||||
------
|
||||
@@ -193,11 +194,11 @@ Add Surface Water
|
||||
|
||||
Geometry View
|
||||
-------------
|
||||
.. autoclass:: gprMax.user_objects.cmds_multiuse.GeometryView
|
||||
.. autoclass:: gprMax.user_objects.cmds_output.GeometryView
|
||||
|
||||
Geometry Objects Write
|
||||
----------------------
|
||||
.. autoclass:: gprMax.user_objects.cmds_multiuse.GeometryObjectsWrite
|
||||
.. autoclass:: gprMax.user_objects.cmds_output.GeometryObjectsWrite
|
||||
|
||||
Source and output functions
|
||||
===========================
|
||||
@@ -248,11 +249,11 @@ Receiver Steps
|
||||
|
||||
Snapshot
|
||||
--------
|
||||
.. autoclass:: gprMax.user_objects.cmds_multiuse.Snapshot
|
||||
.. autoclass:: gprMax.user_objects.cmds_output.Snapshot
|
||||
|
||||
Subgrid
|
||||
-------
|
||||
.. autoclass:: gprMax.subgrids.user_objects.SubGridHSG
|
||||
.. autoclass:: gprMax.SubGridHSG
|
||||
|
||||
|
||||
.. _pml-tuning:
|
||||
@@ -262,7 +263,15 @@ PML functions
|
||||
|
||||
The default behaviour for the absorbing boundary conditions (ABC) is first order Complex Frequency Shifted (CFS) Perfectly Matched Layers (PML), with thicknesses of 10 cells on each of the six sides of the model domain. The PML can be customised using the following commands:
|
||||
|
||||
PML properties
|
||||
PML Formulation
|
||||
---------------
|
||||
.. autoclass:: gprMax.user_objects.cmds_singleuse.PMLFormulation
|
||||
|
||||
PML Thickness
|
||||
-------------
|
||||
.. autoclass:: gprMax.user_objects.cmds_singleuse.PMLThickness
|
||||
|
||||
PML Properties
|
||||
--------------
|
||||
.. autoclass:: gprMax.user_objects.cmds_singleuse.PMLProps
|
||||
|
||||
|
@@ -359,6 +359,8 @@ For example for a soil with sand fraction 0.5, clay fraction 0.5, bulk density :
|
||||
|
||||
Further information on the Peplinski soil model and our implementation can be found in 'Giannakis, I. (2016). Realistic numerical modelling of Ground Penetrating Radar for landmine detection. The University of Edinburgh, United Kingdom. (http://hdl.handle.net/1842/20449)'
|
||||
|
||||
.. _object-construction-commands:
|
||||
|
||||
Object construction commands
|
||||
============================
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
# Copyright (C) 2015-2025: The University of Edinburgh, United Kingdom
|
||||
# Authors: Craig Warren, Antonis Giannopoulos, John Hartley,
|
||||
# Authors: Craig Warren, Antonis Giannopoulos, John Hartley,
|
||||
# and Nathan Mannall
|
||||
#
|
||||
# This file is part of gprMax.
|
||||
@@ -187,7 +187,11 @@ class MPIContext(Context):
|
||||
|
||||
def run(self) -> Dict:
|
||||
try:
|
||||
return super().run()
|
||||
result = super().run()
|
||||
logger.debug("Waiting for all ranks to finish.")
|
||||
self.comm.Barrier()
|
||||
logger.debug("Completed.")
|
||||
return result
|
||||
except:
|
||||
logger.exception(f"Rank {self.rank} encountered an error. Aborting...")
|
||||
self.comm.Abort()
|
||||
|
@@ -27,6 +27,10 @@ from gprMax.config cimport float_or_double_complex
|
||||
cpdef void generate_fractal2D(
|
||||
int nx,
|
||||
int ny,
|
||||
int ox,
|
||||
int oy,
|
||||
int gx,
|
||||
int gy,
|
||||
int nthreads,
|
||||
float D,
|
||||
np.float64_t[:] weighting,
|
||||
@@ -51,12 +55,16 @@ cpdef void generate_fractal2D(
|
||||
|
||||
cdef Py_ssize_t i, j
|
||||
cdef double v2x, v2y, rr, B
|
||||
cdef int sx, sy
|
||||
|
||||
sx = gx // 2
|
||||
sy = gy // 2
|
||||
|
||||
for i in prange(nx, nogil=True, schedule='static', num_threads=nthreads):
|
||||
for j in range(ny):
|
||||
# Positional vector for current position
|
||||
v2x = weighting[0] * i
|
||||
v2y = weighting[1] * j
|
||||
v2x = weighting[0] * ((i + ox + sx) % gx)
|
||||
v2y = weighting[1] * ((j + oy + sy) % gy)
|
||||
|
||||
# Calulate norm of v2 - v1
|
||||
rr = ((v2x - v1[0])**2 + (v2y - v1[1])**2)**(1/2)
|
||||
@@ -71,6 +79,12 @@ cpdef void generate_fractal3D(
|
||||
int nx,
|
||||
int ny,
|
||||
int nz,
|
||||
int ox,
|
||||
int oy,
|
||||
int oz,
|
||||
int gx,
|
||||
int gy,
|
||||
int gz,
|
||||
int nthreads,
|
||||
float D,
|
||||
np.float64_t[:] weighting,
|
||||
@@ -95,14 +109,19 @@ cpdef void generate_fractal3D(
|
||||
|
||||
cdef Py_ssize_t i, j, k
|
||||
cdef double v2x, v2y, v2z, rr, B
|
||||
cdef int sx, sy, sz
|
||||
|
||||
sx = gx // 2
|
||||
sy = gy // 2
|
||||
sz = gz // 2
|
||||
|
||||
for i in prange(nx, nogil=True, schedule='static', num_threads=nthreads):
|
||||
for j in range(ny):
|
||||
for k in range(nz):
|
||||
# Positional vector for current position
|
||||
v2x = weighting[0] * i
|
||||
v2y = weighting[1] * j
|
||||
v2z = weighting[2] * k
|
||||
v2x = weighting[0] * ((i + ox + sx) % gx)
|
||||
v2y = weighting[1] * ((j + oy + sy) % gy)
|
||||
v2z = weighting[2] * ((k + oz + sz) % gz)
|
||||
|
||||
# Calulate norm of v2 - v1
|
||||
rr = ((v2x - v1[0])**2 + (v2y - v1[1])**2 + (v2z - v1[2])**2)**(1/2)
|
||||
|
@@ -1,341 +0,0 @@
|
||||
# Copyright (C) 2015-2025: The University of Edinburgh, United Kingdom
|
||||
# Authors: Craig Warren, Antonis Giannopoulos, John Hartley,
|
||||
# and Nathan Mannall
|
||||
#
|
||||
# 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 scipy import fftpack
|
||||
|
||||
import gprMax.config as config
|
||||
|
||||
from .cython.fractals_generate import generate_fractal2D, generate_fractal3D
|
||||
from .utilities.utilities import round_value
|
||||
|
||||
np.seterr(divide="raise")
|
||||
|
||||
|
||||
class FractalSurface:
|
||||
"""Fractal surfaces."""
|
||||
|
||||
surfaceIDs = ["xminus", "xplus", "yminus", "yplus", "zminus", "zplus"]
|
||||
|
||||
def __init__(self, xs, xf, ys, yf, zs, zf, dimension, seed):
|
||||
"""
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf: floats for the extent of the fractal surface
|
||||
(one pair of coordinates must be equal
|
||||
to correctly define a surface).
|
||||
dimension: float for the fractal dimension that controls the fractal
|
||||
distribution.
|
||||
seed: int for seed value for random number generator.
|
||||
"""
|
||||
|
||||
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.dtype = np.dtype(np.complex128)
|
||||
self.seed = seed
|
||||
self.dimension = (
|
||||
dimension # Fractal dimension from: http://dx.doi.org/10.1017/CBO9781139174695
|
||||
)
|
||||
self.weighting = np.array([1, 1], dtype=np.float64)
|
||||
self.fractalrange = (0, 0)
|
||||
self.filldepth = 0
|
||||
self.grass = []
|
||||
|
||||
def get_surface_dims(self):
|
||||
"""Gets the dimensions of the fractal surface based on surface plane."""
|
||||
|
||||
if self.xs == self.xf:
|
||||
surfacedims = (self.ny, self.nz)
|
||||
elif self.ys == self.yf:
|
||||
surfacedims = (self.nx, self.nz)
|
||||
elif self.zs == self.zf:
|
||||
surfacedims = (self.nx, self.ny)
|
||||
|
||||
return surfacedims
|
||||
|
||||
def generate_fractal_surface(self):
|
||||
"""Generate a 2D array with a fractal distribution."""
|
||||
|
||||
surfacedims = self.get_surface_dims()
|
||||
|
||||
self.fractalsurface = np.zeros(surfacedims, dtype=self.dtype)
|
||||
|
||||
# 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
|
||||
rng = np.random.default_rng(seed=self.seed)
|
||||
A = rng.standard_normal(size=(surfacedims[0], surfacedims[1]))
|
||||
|
||||
# 2D FFT
|
||||
A = fftpack.fftn(A)
|
||||
# Shift the zero frequency component to the centre of the array
|
||||
A = fftpack.fftshift(A)
|
||||
|
||||
# Generate fractal
|
||||
generate_fractal2D(
|
||||
surfacedims[0],
|
||||
surfacedims[1],
|
||||
config.get_model_config().ompthreads,
|
||||
self.dimension,
|
||||
self.weighting,
|
||||
v1,
|
||||
A,
|
||||
self.fractalsurface,
|
||||
)
|
||||
# Shift the zero frequency component to start of the array
|
||||
self.fractalsurface = fftpack.ifftshift(self.fractalsurface)
|
||||
# Set DC component of FFT to zero
|
||||
self.fractalsurface[0, 0] = 0
|
||||
# Take the real part (numerical errors can give rise to an imaginary part)
|
||||
# of the IFFT, and convert type to floattype. N.B calculation of fractals
|
||||
# must always be carried out at double precision, i.e. float64, complex128
|
||||
self.fractalsurface = np.real(fftpack.ifftn(self.fractalsurface)).astype(
|
||||
config.sim_config.dtypes["float_or_double"], copy=False
|
||||
)
|
||||
# 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, seed):
|
||||
"""
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf: floats for the extent of the fractal volume.
|
||||
dimension: float for the fractal dimension that controls the fractal
|
||||
distribution.
|
||||
seed: int for seed value for random number generator.
|
||||
"""
|
||||
|
||||
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.originalxs = xs
|
||||
self.originalxf = xf
|
||||
self.originalys = ys
|
||||
self.originalyf = yf
|
||||
self.originalzs = zs
|
||||
self.originalzf = zf
|
||||
self.averaging = False
|
||||
self.dtype = np.dtype(np.complex128)
|
||||
self.seed = seed
|
||||
self.dimension = (
|
||||
dimension # Fractal dimension from: http://dx.doi.org/10.1017/CBO9781139174695
|
||||
)
|
||||
self.weighting = np.array([1, 1, 1], dtype=np.float64)
|
||||
self.nbins = 0
|
||||
self.fractalsurfaces = []
|
||||
|
||||
def generate_fractal_volume(self):
|
||||
"""Generate a 3D volume with a fractal distribution."""
|
||||
|
||||
# Scale filter according to size of fractal volume
|
||||
if self.nx == 1:
|
||||
filterscaling = np.amin(np.array([self.ny, self.nz])) / np.array([self.ny, self.nz])
|
||||
filterscaling = np.insert(filterscaling, 0, 1)
|
||||
elif self.ny == 1:
|
||||
filterscaling = np.amin(np.array([self.nx, self.nz])) / np.array([self.nx, self.nz])
|
||||
filterscaling = np.insert(filterscaling, 1, 1)
|
||||
elif self.nz == 1:
|
||||
filterscaling = np.amin(np.array([self.nx, self.ny])) / np.array([self.nx, self.ny])
|
||||
filterscaling = np.insert(filterscaling, 2, 1)
|
||||
else:
|
||||
filterscaling = np.amin(np.array([self.nx, self.ny, self.nz])) / np.array(
|
||||
[self.nx, self.ny, self.nz]
|
||||
)
|
||||
|
||||
# Adjust weighting to account for filter scaling
|
||||
self.weighting = np.multiply(self.weighting, filterscaling)
|
||||
|
||||
self.fractalvolume = np.zeros((self.nx, self.ny, self.nz), dtype=self.dtype)
|
||||
|
||||
# Positional vector at centre of array, scaled by weighting
|
||||
v1 = np.array(
|
||||
[
|
||||
self.weighting[0] * self.nx / 2,
|
||||
self.weighting[1] * self.ny / 2,
|
||||
self.weighting[2] * self.nz / 2,
|
||||
]
|
||||
)
|
||||
|
||||
# 3D array of random numbers to be convolved with the fractal function
|
||||
rng = np.random.default_rng(seed=self.seed)
|
||||
A = rng.standard_normal(size=(self.nx, self.ny, self.nz))
|
||||
|
||||
# 3D FFT
|
||||
A = fftpack.fftn(A)
|
||||
# Shift the zero frequency component to the centre of the array
|
||||
A = fftpack.fftshift(A)
|
||||
|
||||
# Generate fractal
|
||||
generate_fractal3D(
|
||||
self.nx,
|
||||
self.ny,
|
||||
self.nz,
|
||||
config.get_model_config().ompthreads,
|
||||
self.dimension,
|
||||
self.weighting,
|
||||
v1,
|
||||
A,
|
||||
self.fractalvolume,
|
||||
)
|
||||
|
||||
# Shift the zero frequency component to the start of the array
|
||||
self.fractalvolume = fftpack.ifftshift(self.fractalvolume)
|
||||
# Set DC component of FFT to zero
|
||||
self.fractalvolume[0, 0, 0] = 0
|
||||
# Take the real part (numerical errors can give rise to an imaginary part)
|
||||
# of the IFFT, and convert type to floattype. N.B calculation of fractals
|
||||
# must always be carried out at double precision, i.e. float64, complex128
|
||||
self.fractalvolume = np.real(fftpack.ifftn(self.fractalvolume)).astype(
|
||||
config.sim_config.dtypes["float_or_double"], copy=False
|
||||
)
|
||||
|
||||
# Bin fractal values
|
||||
bins = np.linspace(np.amin(self.fractalvolume), np.amax(self.fractalvolume), self.nbins)
|
||||
for j in range(self.ny):
|
||||
for k in range(self.nz):
|
||||
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, self.ny, self.nz), dtype=np.int8)
|
||||
maskxs = self.originalxs - self.xs
|
||||
maskxf = (self.originalxf - self.originalxs) + maskxs
|
||||
maskys = self.originalys - self.ys
|
||||
maskyf = (self.originalyf - self.originalys) + maskys
|
||||
maskzs = self.originalzs - self.zs
|
||||
maskzf = (self.originalzf - self.originalzs) + maskzs
|
||||
self.mask[maskxs:maskxf, maskys:maskyf, maskzs:maskzf] = 1
|
||||
|
||||
|
||||
class Grass:
|
||||
"""Geometry information for blades of grass."""
|
||||
|
||||
def __init__(self, numblades, seed):
|
||||
"""
|
||||
Args:
|
||||
numblades: int for the number of blades of grass.
|
||||
seed: int for seed value for random number generator.
|
||||
"""
|
||||
|
||||
self.numblades = numblades
|
||||
self.geometryparams = np.zeros(
|
||||
(self.numblades, 6), dtype=config.sim_config.dtypes["float_or_double"]
|
||||
)
|
||||
self.seed = seed
|
||||
self.set_geometry_parameters()
|
||||
|
||||
def set_geometry_parameters(self):
|
||||
"""Sets randomly defined parameters that will be used to calculate
|
||||
blade and root geometries.
|
||||
"""
|
||||
|
||||
self.R1 = np.random.default_rng(seed=self.seed)
|
||||
self.R2 = np.random.default_rng(seed=self.seed)
|
||||
self.R3 = np.random.default_rng(seed=self.seed)
|
||||
self.R4 = np.random.default_rng(seed=self.seed)
|
||||
self.R5 = np.random.default_rng(seed=self.seed)
|
||||
self.R6 = np.random.default_rng(seed=self.seed)
|
||||
|
||||
for i in range(self.numblades):
|
||||
self.geometryparams[i, 0] = 10 + 20 * self.R1.random()
|
||||
self.geometryparams[i, 1] = 10 + 20 * self.R2.random()
|
||||
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 for the numeric ID of grass blade.
|
||||
height: float for the height of grass blade.
|
||||
|
||||
Returns:
|
||||
x, y: floats for the 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 = round_value(x)
|
||||
y = round_value(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 for the umeric ID of grass root.
|
||||
depth: float for the depth of grass root.
|
||||
|
||||
Returns:
|
||||
x, y: floats for the x and y coordinates of grass root.
|
||||
"""
|
||||
|
||||
self.geometryparams[root, 4] += -1 + 2 * self.R5.random()
|
||||
self.geometryparams[root, 5] += -1 + 2 * self.R6.random()
|
||||
x = round(self.geometryparams[root, 4])
|
||||
y = round(self.geometryparams[root, 5])
|
||||
|
||||
return x, y
|
460
gprMax/fractals/fractal_surface.py
普通文件
460
gprMax/fractals/fractal_surface.py
普通文件
@@ -0,0 +1,460 @@
|
||||
# Copyright (C) 2015-2025: The University of Edinburgh, United Kingdom
|
||||
# Authors: Craig Warren, Antonis Giannopoulos, John Hartley,
|
||||
# and Nathan Mannall
|
||||
#
|
||||
# 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 logging
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
import numpy as np
|
||||
import numpy.typing as npt
|
||||
from mpi4py import MPI
|
||||
from mpi4py_fft import PFFT, DistArray, newDistArray
|
||||
from mpi4py_fft.pencil import Subcomm
|
||||
from scipy import fftpack
|
||||
|
||||
from gprMax import config
|
||||
from gprMax.cython.fractals_generate import generate_fractal2D
|
||||
from gprMax.fractals.grass import Grass
|
||||
from gprMax.fractals.mpi_utilities import calculate_starts_and_subshape, create_mpi_type
|
||||
from gprMax.utilities.mpi import Dim, Dir, get_relative_neighbour
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
np.seterr(divide="raise")
|
||||
|
||||
|
||||
class FractalSurface:
|
||||
"""Fractal surfaces."""
|
||||
|
||||
surfaceIDs = ["xminus", "xplus", "yminus", "yplus", "zminus", "zplus"]
|
||||
|
||||
def __init__(self, xs, xf, ys, yf, zs, zf, dimension, seed):
|
||||
"""
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf: floats for the extent of the fractal surface
|
||||
(one pair of coordinates must be equal
|
||||
to correctly define a surface).
|
||||
dimension: float for the fractal dimension that controls the fractal
|
||||
distribution.
|
||||
seed: int for seed value for random number generator.
|
||||
"""
|
||||
|
||||
self.ID = None
|
||||
self.surfaceID = None
|
||||
self.start = np.array([xs, ys, zs], dtype=np.int32)
|
||||
self.stop = np.array([xf, yf, zf], dtype=np.int32)
|
||||
self.dtype = np.dtype(np.complex128)
|
||||
self.seed = seed
|
||||
self.dimension = (
|
||||
dimension # Fractal dimension from: http://dx.doi.org/10.1017/CBO9781139174695
|
||||
)
|
||||
self.weighting = np.array([1, 1], dtype=np.float64)
|
||||
self.fractalrange: Tuple[int, int] = (0, 0)
|
||||
self.filldepth = 0
|
||||
self.grass: List[Grass] = []
|
||||
|
||||
@property
|
||||
def xs(self) -> int:
|
||||
return self.start[0]
|
||||
|
||||
@xs.setter
|
||||
def xs(self, value: int):
|
||||
self.start[0] = value
|
||||
|
||||
@property
|
||||
def ys(self) -> int:
|
||||
return self.start[1]
|
||||
|
||||
@ys.setter
|
||||
def ys(self, value: int):
|
||||
self.start[1] = value
|
||||
|
||||
@property
|
||||
def zs(self) -> int:
|
||||
return self.start[2]
|
||||
|
||||
@zs.setter
|
||||
def zs(self, value: int):
|
||||
self.start[2] = value
|
||||
|
||||
@property
|
||||
def xf(self) -> int:
|
||||
return self.stop[0]
|
||||
|
||||
@xf.setter
|
||||
def xf(self, value: int):
|
||||
self.stop[0] = value
|
||||
|
||||
@property
|
||||
def yf(self) -> int:
|
||||
return self.stop[1]
|
||||
|
||||
@yf.setter
|
||||
def yf(self, value: int):
|
||||
self.stop[1] = value
|
||||
|
||||
@property
|
||||
def zf(self) -> int:
|
||||
return self.stop[2]
|
||||
|
||||
@zf.setter
|
||||
def zf(self, value: int):
|
||||
self.stop[2] = value
|
||||
|
||||
@property
|
||||
def size(self) -> npt.NDArray[np.int32]:
|
||||
return self.stop - self.start
|
||||
|
||||
@property
|
||||
def nx(self) -> int:
|
||||
return self.xf - self.xs
|
||||
|
||||
@property
|
||||
def ny(self) -> int:
|
||||
return self.yf - self.ys
|
||||
|
||||
@property
|
||||
def nz(self) -> int:
|
||||
return self.zf - self.zs
|
||||
|
||||
def get_surface_dims(self):
|
||||
"""Gets the dimensions of the fractal surface based on surface plane."""
|
||||
|
||||
if self.xs == self.xf:
|
||||
surfacedims = (self.ny, self.nz)
|
||||
elif self.ys == self.yf:
|
||||
surfacedims = (self.nx, self.nz)
|
||||
elif self.zs == self.zf:
|
||||
surfacedims = (self.nx, self.ny)
|
||||
|
||||
return surfacedims
|
||||
|
||||
def generate_fractal_surface(self) -> bool:
|
||||
"""Generate a 2D array with a fractal distribution."""
|
||||
|
||||
surfacedims = self.get_surface_dims()
|
||||
|
||||
self.fractalsurface = np.zeros(surfacedims, dtype=self.dtype)
|
||||
|
||||
# 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
|
||||
rng = np.random.default_rng(seed=self.seed)
|
||||
A = rng.standard_normal(size=(surfacedims[0], surfacedims[1]))
|
||||
|
||||
# 2D FFT
|
||||
A = fftpack.fftn(A)
|
||||
|
||||
# Generate fractal
|
||||
generate_fractal2D(
|
||||
surfacedims[0],
|
||||
surfacedims[1],
|
||||
0,
|
||||
0,
|
||||
surfacedims[0],
|
||||
surfacedims[1],
|
||||
config.get_model_config().ompthreads,
|
||||
self.dimension,
|
||||
self.weighting,
|
||||
v1,
|
||||
A,
|
||||
self.fractalsurface,
|
||||
)
|
||||
|
||||
# Set DC component of FFT to zero
|
||||
self.fractalsurface[0, 0] = 0
|
||||
# Take the real part (numerical errors can give rise to an imaginary part)
|
||||
# of the IFFT, and convert type to floattype. N.B calculation of fractals
|
||||
# must always be carried out at double precision, i.e. float64, complex128
|
||||
self.fractalsurface = np.real(fftpack.ifftn(self.fractalsurface)).astype(
|
||||
config.sim_config.dtypes["float_or_double"], copy=False
|
||||
)
|
||||
# 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
|
||||
)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
class MPIFractalSurface(FractalSurface):
|
||||
def __init__(
|
||||
self,
|
||||
xs: int,
|
||||
xf: int,
|
||||
ys: int,
|
||||
yf: int,
|
||||
zs: int,
|
||||
zf: int,
|
||||
dimension: float,
|
||||
seed: Optional[int],
|
||||
comm: MPI.Cartcomm,
|
||||
upper_bound: npt.NDArray[np.int32],
|
||||
):
|
||||
super().__init__(xs, xf, ys, yf, zs, zf, dimension, seed)
|
||||
self.comm = comm
|
||||
self.upper_bound = upper_bound
|
||||
|
||||
def generate_fractal_surface(self) -> bool:
|
||||
"""Generate a 2D array with a fractal distribution."""
|
||||
|
||||
if self.xs == self.xf:
|
||||
color = self.xs
|
||||
static_dimension = Dim.X
|
||||
dims = [Dim.Y, Dim.Z]
|
||||
elif self.ys == self.yf:
|
||||
color = self.ys
|
||||
static_dimension = Dim.Y
|
||||
dims = [Dim.X, Dim.Z]
|
||||
elif self.zs == self.zf:
|
||||
color = self.zs
|
||||
static_dimension = Dim.Z
|
||||
dims = [Dim.X, Dim.Y]
|
||||
|
||||
# Exit early if this rank does not contain the Fractal Surface
|
||||
if (
|
||||
any(self.stop[dims] <= 0)
|
||||
or any(self.start[dims] >= self.upper_bound[dims])
|
||||
or self.fractalrange[1] <= 0
|
||||
or self.fractalrange[0] >= self.upper_bound[static_dimension]
|
||||
):
|
||||
self.comm.Split(MPI.UNDEFINED)
|
||||
# Update start and stop to local bounds
|
||||
self.start = np.maximum(self.start, 0)
|
||||
self.start = np.minimum(self.start, self.upper_bound)
|
||||
self.stop = np.maximum(self.stop, 0)
|
||||
self.stop = np.minimum(self.stop, self.upper_bound)
|
||||
return False
|
||||
else:
|
||||
# Create new cartsesian communicator for the Fractal Surface
|
||||
comm = self.comm.Split(color=color)
|
||||
assert isinstance(comm, MPI.Intracomm)
|
||||
min_coord = np.array(self.comm.coords, dtype=np.int32)[dims]
|
||||
max_coord = min_coord + 1
|
||||
comm.Allreduce(MPI.IN_PLACE, min_coord, MPI.MIN)
|
||||
comm.Allreduce(MPI.IN_PLACE, max_coord, MPI.MAX)
|
||||
cart_dims = (max_coord - min_coord).tolist()
|
||||
self.comm = comm.Create_cart(cart_dims)
|
||||
|
||||
# Check domain decomosition is valid for the Fractal Volume
|
||||
if all([dim > 1 for dim in self.comm.dims]):
|
||||
raise ValueError(
|
||||
"Fractal surface must be positioned such that its MPI decomposition is 1 in at"
|
||||
f" least 1 dimension. Current decompostion is: {self.comm.dims}"
|
||||
)
|
||||
|
||||
# Check domain decomosition is valid for the Fractal Volume
|
||||
if len(self.grass) > 0 and self.comm.size > 1:
|
||||
raise ValueError(
|
||||
"Grass cannot currently be split across multiple MPI rank. Either change the MPI "
|
||||
" decomposition such that the grass object is contained within a single MPI rank,"
|
||||
" or divide the grass object into multiple sections. Current decompostion is:"
|
||||
f" {self.comm.dims}"
|
||||
)
|
||||
|
||||
surfacedims = self.get_surface_dims()
|
||||
|
||||
# Positional vector at centre of array, scaled by weighting
|
||||
v1 = self.weighting * surfacedims / 2
|
||||
|
||||
subcomm = Subcomm(self.comm)
|
||||
|
||||
A = DistArray(self.size[dims], subcomm, dtype=self.dtype)
|
||||
|
||||
fft = PFFT(
|
||||
None,
|
||||
axes=tuple(np.argsort(self.comm.dims)[::-1]),
|
||||
darray=A,
|
||||
collapse=False,
|
||||
backend="fftw",
|
||||
)
|
||||
|
||||
# Decomposition of A may be different to the MPIGrid
|
||||
A_shape = np.array(A.shape)
|
||||
A_substart = np.array(A.substart)
|
||||
|
||||
# 3D array of random numbers to be convolved with the fractal function
|
||||
rng = np.random.default_rng(seed=self.seed)
|
||||
|
||||
for index in np.ndindex(*A.global_shape):
|
||||
index = np.array(index)
|
||||
if any(index < A_substart) or any(index >= A_substart + A_shape):
|
||||
rng.standard_normal()
|
||||
else:
|
||||
index -= A_substart
|
||||
A[index[0], index[1]] = rng.standard_normal()
|
||||
|
||||
A_hat = newDistArray(fft)
|
||||
assert isinstance(A_hat, DistArray)
|
||||
|
||||
# 2D FFT
|
||||
fft.forward(A, A_hat, normalize=False)
|
||||
|
||||
# Generate fractal
|
||||
generate_fractal2D(
|
||||
A_hat.shape[0],
|
||||
A_hat.shape[1],
|
||||
A_hat.substart[0],
|
||||
A_hat.substart[1],
|
||||
A_hat.global_shape[0],
|
||||
A_hat.global_shape[1],
|
||||
config.get_model_config().ompthreads,
|
||||
self.dimension,
|
||||
self.weighting,
|
||||
v1,
|
||||
A_hat,
|
||||
A_hat,
|
||||
)
|
||||
|
||||
# Set DC component of FFT to zero
|
||||
if all(A_substart == 0):
|
||||
A_hat[0, 0] = 0
|
||||
|
||||
# Inverse 2D FFT transform
|
||||
fft.backward(A_hat, A, normalize=True)
|
||||
|
||||
# Take the real part (numerical errors can give rise to an imaginary part)
|
||||
# of the IFFT, and convert type to floattype. N.B calculation of fractals
|
||||
# must always be carried out at double precision, i.e. float64, complex128
|
||||
A = np.real(A).astype(config.sim_config.dtypes["float_or_double"], copy=False)
|
||||
|
||||
# Allreduce to get min and max values in the fractal surface
|
||||
min_value = np.array(np.amin(A), dtype=config.sim_config.dtypes["float_or_double"])
|
||||
max_value = np.array(np.amax(A), dtype=config.sim_config.dtypes["float_or_double"])
|
||||
self.comm.Allreduce(MPI.IN_PLACE, min_value, MPI.MIN)
|
||||
self.comm.Allreduce(MPI.IN_PLACE, max_value, MPI.MAX)
|
||||
|
||||
# Scale the fractal volume according to requested range
|
||||
fractalrange = max_value - min_value
|
||||
A = (
|
||||
A * ((self.fractalrange[1] - self.fractalrange[0]) / fractalrange)
|
||||
+ self.fractalrange[0]
|
||||
- ((self.fractalrange[1] - self.fractalrange[0]) / fractalrange) * min_value
|
||||
)
|
||||
|
||||
# Distribute A (DistArray) to match the MPIGrid decomposition
|
||||
local_shape = (np.minimum(self.stop, self.upper_bound) - np.maximum(self.start, 0))[dims]
|
||||
self.fractalsurface = np.zeros(
|
||||
local_shape,
|
||||
dtype=config.sim_config.dtypes["float_or_double"],
|
||||
)
|
||||
|
||||
# Negative means send to negative neighbour
|
||||
# Positive means receive from negative neighbour
|
||||
negative_offset = np.where(self.start[dims] >= 0, A_substart, self.start[dims] + A_substart)
|
||||
|
||||
# Negative means send to positive neighbour
|
||||
# Positive means receive from positive neighbour
|
||||
positive_offset = np.minimum(self.stop, self.upper_bound)[dims] - (
|
||||
self.start[dims] + A_substart + A_shape
|
||||
)
|
||||
|
||||
dirs = np.full(2, Dir.NONE)
|
||||
|
||||
starts, subshape = calculate_starts_and_subshape(
|
||||
A_shape, -negative_offset, -positive_offset, dirs, sending=True
|
||||
)
|
||||
ends = starts + subshape
|
||||
A_local = A[starts[0] : ends[0], starts[1] : ends[1]]
|
||||
|
||||
starts, subshape = calculate_starts_and_subshape(
|
||||
local_shape, negative_offset, positive_offset, dirs
|
||||
)
|
||||
ends = starts + subshape
|
||||
self.fractalsurface[starts[0] : ends[0], starts[1] : ends[1]] = A_local
|
||||
|
||||
requests: List[MPI.Request] = []
|
||||
|
||||
# Need to check neighbours in each direction (2D plane)
|
||||
sections = [
|
||||
(Dir.NEG, Dir.NONE),
|
||||
(Dir.POS, Dir.NONE),
|
||||
(Dir.NONE, Dir.NEG),
|
||||
(Dir.NONE, Dir.POS),
|
||||
(Dir.NEG, Dir.NEG),
|
||||
(Dir.NEG, Dir.POS),
|
||||
(Dir.POS, Dir.NEG),
|
||||
(Dir.POS, Dir.POS),
|
||||
]
|
||||
|
||||
for section in sections:
|
||||
dirs[0] = section[0]
|
||||
dirs[1] = section[1]
|
||||
rank = get_relative_neighbour(self.comm, dirs)
|
||||
|
||||
# Skip if no neighbour
|
||||
if rank == -1:
|
||||
continue
|
||||
|
||||
# Check if any data to send
|
||||
if all(
|
||||
np.select(
|
||||
[dirs == Dir.NEG, dirs == Dir.POS],
|
||||
[negative_offset <= 0, positive_offset <= 0],
|
||||
dirs == Dir.NONE,
|
||||
)
|
||||
):
|
||||
mpi_type = create_mpi_type(
|
||||
A_shape, -negative_offset, -positive_offset, dirs, sending=True
|
||||
)
|
||||
|
||||
logger.debug(
|
||||
f"Sending fractal surface to rank {rank}, MPI type={mpi_type.decode()}"
|
||||
)
|
||||
self.comm.Isend([A, mpi_type], rank)
|
||||
|
||||
# Check if any data to receive
|
||||
if all(
|
||||
np.select(
|
||||
[dirs == Dir.NEG, dirs == Dir.POS],
|
||||
[negative_offset > 0, positive_offset > 0],
|
||||
dirs == Dir.NONE,
|
||||
)
|
||||
):
|
||||
mpi_type = create_mpi_type(local_shape, negative_offset, positive_offset, dirs)
|
||||
|
||||
logger.debug(
|
||||
f"Receiving fractal surface from rank {rank}, MPI type={mpi_type.decode()}"
|
||||
)
|
||||
request = self.comm.Irecv([self.fractalsurface, mpi_type], rank)
|
||||
requests.append(request)
|
||||
|
||||
if len(requests) > 0:
|
||||
requests[0].Waitall(requests)
|
||||
|
||||
# Update start and stop to local bounds
|
||||
self.start = np.maximum(self.start, 0)
|
||||
self.start = np.minimum(self.start, self.upper_bound)
|
||||
self.stop = np.maximum(self.stop, 0)
|
||||
self.stop = np.minimum(self.stop, self.upper_bound)
|
||||
|
||||
logger.debug(
|
||||
f"Generated fractal surface: start={self.start}, stop={self.stop}, size={self.size}, fractalrange={self.fractalrange}"
|
||||
)
|
||||
|
||||
return True
|
525
gprMax/fractals/fractal_volume.py
普通文件
525
gprMax/fractals/fractal_volume.py
普通文件
@@ -0,0 +1,525 @@
|
||||
# Copyright (C) 2015-2025: The University of Edinburgh, United Kingdom
|
||||
# Authors: Craig Warren, Antonis Giannopoulos, John Hartley,
|
||||
# and Nathan Mannall
|
||||
#
|
||||
# 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 logging
|
||||
from typing import List, Optional, Tuple, Union
|
||||
|
||||
import numpy as np
|
||||
import numpy.typing as npt
|
||||
from mpi4py import MPI
|
||||
from mpi4py_fft import PFFT, DistArray, newDistArray
|
||||
from mpi4py_fft.pencil import Subcomm
|
||||
from scipy import fftpack
|
||||
|
||||
from gprMax import config
|
||||
from gprMax.cython.fractals_generate import generate_fractal3D
|
||||
from gprMax.fractals.fractal_surface import FractalSurface
|
||||
from gprMax.fractals.mpi_utilities import calculate_starts_and_subshape, create_mpi_type
|
||||
from gprMax.materials import ListMaterial, PeplinskiSoil, RangeMaterial
|
||||
from gprMax.utilities.mpi import Dim, Dir, get_relative_neighbour
|
||||
from gprMax.utilities.utilities import round_value
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
np.seterr(divide="raise")
|
||||
|
||||
|
||||
class FractalVolume:
|
||||
"""Fractal volumes."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
xs: int,
|
||||
xf: int,
|
||||
ys: int,
|
||||
yf: int,
|
||||
zs: int,
|
||||
zf: int,
|
||||
dimension: float,
|
||||
seed: Optional[int],
|
||||
):
|
||||
"""
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf: floats for the extent of the fractal volume.
|
||||
dimension: float for the fractal dimension that controls the fractal
|
||||
distribution.
|
||||
seed: int for seed value for random number generator.
|
||||
"""
|
||||
|
||||
self.ID = None
|
||||
self.operatingonID = None
|
||||
self.start = np.array([xs, ys, zs], dtype=np.int32)
|
||||
self.stop = np.array([xf, yf, zf], dtype=np.int32)
|
||||
self.original_start = self.start.copy()
|
||||
self.original_stop = self.stop.copy()
|
||||
self.averaging = False
|
||||
self.dtype = np.dtype(np.complex128)
|
||||
self.seed = seed
|
||||
self.dimension = (
|
||||
dimension # Fractal dimension from: http://dx.doi.org/10.1017/CBO9781139174695
|
||||
)
|
||||
self.weighting = np.array([1, 1, 1], dtype=np.float64)
|
||||
self.nbins = 0
|
||||
self.mixingmodel: Optional[Union[PeplinskiSoil, RangeMaterial, ListMaterial]] = None
|
||||
self.fractalsurfaces: List[FractalSurface] = []
|
||||
|
||||
@property
|
||||
def xs(self) -> int:
|
||||
return self.start[0]
|
||||
|
||||
@xs.setter
|
||||
def xs(self, value: int):
|
||||
self.start[0] = value
|
||||
|
||||
@property
|
||||
def ys(self) -> int:
|
||||
return self.start[1]
|
||||
|
||||
@ys.setter
|
||||
def ys(self, value: int):
|
||||
self.start[1] = value
|
||||
|
||||
@property
|
||||
def zs(self) -> int:
|
||||
return self.start[2]
|
||||
|
||||
@zs.setter
|
||||
def zs(self, value: int):
|
||||
self.start[2] = value
|
||||
|
||||
@property
|
||||
def xf(self) -> int:
|
||||
return self.stop[0]
|
||||
|
||||
@xf.setter
|
||||
def xf(self, value: int):
|
||||
self.stop[0] = value
|
||||
|
||||
@property
|
||||
def yf(self) -> int:
|
||||
return self.stop[1]
|
||||
|
||||
@yf.setter
|
||||
def yf(self, value: int):
|
||||
self.stop[1] = value
|
||||
|
||||
@property
|
||||
def zf(self) -> int:
|
||||
return self.stop[2]
|
||||
|
||||
@zf.setter
|
||||
def zf(self, value: int):
|
||||
self.stop[2] = value
|
||||
|
||||
@property
|
||||
def size(self) -> npt.NDArray[np.int32]:
|
||||
return self.stop - self.start
|
||||
|
||||
@property
|
||||
def nx(self) -> int:
|
||||
return self.xf - self.xs
|
||||
|
||||
@property
|
||||
def ny(self) -> int:
|
||||
return self.yf - self.ys
|
||||
|
||||
@property
|
||||
def nz(self) -> int:
|
||||
return self.zf - self.zs
|
||||
|
||||
@property
|
||||
def originalxs(self) -> int:
|
||||
return self.original_start[0]
|
||||
|
||||
@originalxs.setter
|
||||
def originalxs(self, value: int):
|
||||
self.original_start[0] = value
|
||||
|
||||
@property
|
||||
def originalys(self) -> int:
|
||||
return self.original_start[1]
|
||||
|
||||
@originalys.setter
|
||||
def originalys(self, value: int):
|
||||
self.original_start[1] = value
|
||||
|
||||
@property
|
||||
def originalzs(self) -> int:
|
||||
return self.original_start[2]
|
||||
|
||||
@originalzs.setter
|
||||
def originalzs(self, value: int):
|
||||
self.original_start[2] = value
|
||||
|
||||
@property
|
||||
def originalxf(self) -> int:
|
||||
return self.original_stop[0]
|
||||
|
||||
@originalxf.setter
|
||||
def originalxf(self, value: int):
|
||||
self.original_stop[0] = value
|
||||
|
||||
@property
|
||||
def originalyf(self) -> int:
|
||||
return self.original_stop[1]
|
||||
|
||||
@originalyf.setter
|
||||
def originalyf(self, value: int):
|
||||
self.original_stop[1] = value
|
||||
|
||||
@property
|
||||
def originalzf(self) -> int:
|
||||
return self.original_stop[2]
|
||||
|
||||
@originalzf.setter
|
||||
def originalzf(self, value: int):
|
||||
self.original_stop[2] = value
|
||||
|
||||
def generate_fractal_volume(self) -> bool:
|
||||
"""Generate a 3D volume with a fractal distribution."""
|
||||
|
||||
# Scale filter according to size of fractal volume
|
||||
if self.nx == 1:
|
||||
filterscaling = np.amin(np.array([self.ny, self.nz])) / np.array([self.ny, self.nz])
|
||||
filterscaling = np.insert(filterscaling, 0, 1)
|
||||
elif self.ny == 1:
|
||||
filterscaling = np.amin(np.array([self.nx, self.nz])) / np.array([self.nx, self.nz])
|
||||
filterscaling = np.insert(filterscaling, 1, 1)
|
||||
elif self.nz == 1:
|
||||
filterscaling = np.amin(np.array([self.nx, self.ny])) / np.array([self.nx, self.ny])
|
||||
filterscaling = np.insert(filterscaling, 2, 1)
|
||||
else:
|
||||
filterscaling = np.amin(np.array([self.nx, self.ny, self.nz])) / np.array(
|
||||
[self.nx, self.ny, self.nz]
|
||||
)
|
||||
|
||||
# Adjust weighting to account for filter scaling
|
||||
self.weighting = np.multiply(self.weighting, filterscaling)
|
||||
|
||||
self.fractalvolume = np.zeros((self.nx, self.ny, self.nz), dtype=self.dtype)
|
||||
|
||||
# Positional vector at centre of array, scaled by weighting
|
||||
v1 = np.array(
|
||||
[
|
||||
self.weighting[0] * self.nx / 2,
|
||||
self.weighting[1] * self.ny / 2,
|
||||
self.weighting[2] * self.nz / 2,
|
||||
]
|
||||
)
|
||||
|
||||
# 3D array of random numbers to be convolved with the fractal function
|
||||
rng = np.random.default_rng(seed=self.seed)
|
||||
A = rng.standard_normal(size=(self.nx, self.ny, self.nz))
|
||||
|
||||
# 3D FFT
|
||||
A = fftpack.fftn(A)
|
||||
|
||||
# Generate fractal
|
||||
generate_fractal3D(
|
||||
self.nx,
|
||||
self.ny,
|
||||
self.nz,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
self.nx,
|
||||
self.ny,
|
||||
self.nz,
|
||||
config.get_model_config().ompthreads,
|
||||
self.dimension,
|
||||
self.weighting,
|
||||
v1,
|
||||
A,
|
||||
self.fractalvolume,
|
||||
)
|
||||
|
||||
# Set DC component of FFT to zero
|
||||
self.fractalvolume[0, 0, 0] = 0
|
||||
# Take the real part (numerical errors can give rise to an imaginary part)
|
||||
# of the IFFT, and convert type to floattype. N.B calculation of fractals
|
||||
# must always be carried out at double precision, i.e. float64, complex128
|
||||
self.fractalvolume = np.real(fftpack.ifftn(self.fractalvolume)).astype(
|
||||
config.sim_config.dtypes["float_or_double"], copy=False
|
||||
)
|
||||
|
||||
# Bin fractal values
|
||||
bins = np.linspace(np.amin(self.fractalvolume), np.amax(self.fractalvolume), self.nbins)
|
||||
for j in range(self.ny):
|
||||
for k in range(self.nz):
|
||||
self.fractalvolume[:, j, k] = np.digitize(
|
||||
self.fractalvolume[:, j, k], bins, right=True
|
||||
)
|
||||
|
||||
return 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, self.ny, self.nz), dtype=np.int8)
|
||||
maskxs = self.originalxs - self.xs
|
||||
maskxf = (self.originalxf - self.originalxs) + maskxs
|
||||
maskys = self.originalys - self.ys
|
||||
maskyf = (self.originalyf - self.originalys) + maskys
|
||||
maskzs = self.originalzs - self.zs
|
||||
maskzf = (self.originalzf - self.originalzs) + maskzs
|
||||
self.mask[maskxs:maskxf, maskys:maskyf, maskzs:maskzf] = 1
|
||||
|
||||
|
||||
class MPIFractalVolume(FractalVolume):
|
||||
def __init__(
|
||||
self,
|
||||
xs: int,
|
||||
xf: int,
|
||||
ys: int,
|
||||
yf: int,
|
||||
zs: int,
|
||||
zf: int,
|
||||
dimension: float,
|
||||
seed: Optional[int],
|
||||
comm: MPI.Cartcomm,
|
||||
upper_bound: npt.NDArray[np.int32],
|
||||
):
|
||||
super().__init__(xs, xf, ys, yf, zs, zf, dimension, seed)
|
||||
self.comm = comm
|
||||
self.upper_bound = upper_bound
|
||||
|
||||
# Limit the original start and stop to within the local bounds
|
||||
self.original_start = np.maximum(self.original_start, 0)
|
||||
self.original_stop = np.minimum(self.original_stop, self.upper_bound)
|
||||
|
||||
# Ensure original_stop is not less than original_start
|
||||
self.original_stop = np.where(
|
||||
self.original_stop < self.original_start, self.original_start, self.original_stop
|
||||
)
|
||||
|
||||
def generate_fractal_volume(self) -> bool:
|
||||
"""Generate a 3D volume with a fractal distribution."""
|
||||
|
||||
# Exit early if this rank does not contain the Fractal Volume
|
||||
# The size of a fractal volume can increase if a Fractal Surface
|
||||
# is attached. Hence the check needs to happen here once that
|
||||
# has happened.
|
||||
if any(self.stop <= 0) or any(self.start >= self.upper_bound):
|
||||
self.comm.Split(MPI.UNDEFINED)
|
||||
return False
|
||||
else:
|
||||
# Create new cartsesian communicator for the Fractal Volume
|
||||
comm = self.comm.Split()
|
||||
assert isinstance(comm, MPI.Intracomm)
|
||||
min_coord = np.array(self.comm.coords, dtype=np.int32)
|
||||
max_coord = min_coord + 1
|
||||
comm.Allreduce(MPI.IN_PLACE, min_coord, MPI.MIN)
|
||||
comm.Allreduce(MPI.IN_PLACE, max_coord, MPI.MAX)
|
||||
self.comm = comm.Create_cart((max_coord - min_coord).tolist())
|
||||
|
||||
# Check domain decomosition is valid for the Fractal Volume
|
||||
if all([dim > 1 for dim in self.comm.dims]):
|
||||
raise ValueError(
|
||||
"Fractal volume must be positioned such that its MPI decomposition is 1 in at least"
|
||||
f" 1 dimension. Current decompostion is: {self.comm.dims}"
|
||||
)
|
||||
|
||||
# Scale filter according to size of fractal volume
|
||||
sorted_size = np.sort(self.size)
|
||||
min_size = sorted_size[1] if sorted_size[0] == 1 else sorted_size[0]
|
||||
filterscaling = np.where(self.size == 1, 1, min_size / self.size)
|
||||
|
||||
# Adjust weighting to account for filter scaling
|
||||
self.weighting = np.multiply(self.weighting, filterscaling)
|
||||
|
||||
# Positional vector at centre of array, scaled by weighting
|
||||
v1 = self.weighting * self.size / 2
|
||||
|
||||
subcomm = Subcomm(self.comm)
|
||||
A = DistArray(self.size, subcomm, dtype=self.dtype)
|
||||
fft = PFFT(
|
||||
None,
|
||||
axes=tuple(np.argsort(self.comm.dims)[::-1]),
|
||||
darray=A,
|
||||
collapse=False,
|
||||
backend="fftw",
|
||||
)
|
||||
|
||||
# Decomposition of A may be different to the MPIGrid
|
||||
A_shape = np.array(A.shape)
|
||||
A_substart = np.array(A.substart)
|
||||
static_dimension = Dim(A.alignment)
|
||||
|
||||
# 3D array of random numbers to be convolved with the fractal function
|
||||
rng = np.random.default_rng(seed=self.seed)
|
||||
|
||||
for index in np.ndindex(*A.global_shape):
|
||||
index = np.array(index)
|
||||
if any(index < A_substart) or any(index >= A_substart + A_shape):
|
||||
rng.standard_normal()
|
||||
else:
|
||||
index -= A_substart
|
||||
A[index[0], index[1], index[2]] = rng.standard_normal()
|
||||
|
||||
A_hat = newDistArray(fft)
|
||||
assert isinstance(A_hat, DistArray)
|
||||
|
||||
# 3D FFT
|
||||
fft.forward(A, A_hat, normalize=False)
|
||||
|
||||
# Generate fractal
|
||||
generate_fractal3D(
|
||||
A_hat.shape[0],
|
||||
A_hat.shape[1],
|
||||
A_hat.shape[2],
|
||||
A_hat.substart[0],
|
||||
A_hat.substart[1],
|
||||
A_hat.substart[2],
|
||||
A_hat.global_shape[0],
|
||||
A_hat.global_shape[1],
|
||||
A_hat.global_shape[2],
|
||||
config.get_model_config().ompthreads,
|
||||
self.dimension,
|
||||
self.weighting,
|
||||
v1,
|
||||
A_hat,
|
||||
A_hat,
|
||||
)
|
||||
|
||||
# Set DC component of FFT to zero
|
||||
if all(A_substart == 0):
|
||||
A_hat[0, 0, 0] = 0
|
||||
|
||||
# Inverse 3D FFT transform
|
||||
fft.backward(A_hat, A, normalize=True)
|
||||
|
||||
# Take the real part (numerical errors can give rise to an imaginary part)
|
||||
# of the IFFT, and convert type to floattype. N.B calculation of fractals
|
||||
# must always be carried out at double precision, i.e. float64, complex128
|
||||
A = np.real(A).astype(config.sim_config.dtypes["float_or_double"], copy=False)
|
||||
|
||||
# Allreduce to get min and max values in the fractal volume
|
||||
min_value = np.array(np.amin(A), dtype=config.sim_config.dtypes["float_or_double"])
|
||||
max_value = np.array(np.amax(A), dtype=config.sim_config.dtypes["float_or_double"])
|
||||
self.comm.Allreduce(MPI.IN_PLACE, min_value, MPI.MIN)
|
||||
self.comm.Allreduce(MPI.IN_PLACE, max_value, MPI.MAX)
|
||||
|
||||
# Bin fractal values
|
||||
bins = np.linspace(min_value, max_value, self.nbins)
|
||||
for j in range(A_shape[1]):
|
||||
for k in range(A_shape[2]):
|
||||
A[:, j, k] = np.digitize(A[:, j, k], bins, right=True)
|
||||
|
||||
# Distribute A (DistArray) to match the MPIGrid decomposition
|
||||
local_shape = np.minimum(self.stop, self.upper_bound) - np.maximum(self.start, 0)
|
||||
self.fractalvolume = np.zeros(
|
||||
local_shape,
|
||||
dtype=config.sim_config.dtypes["float_or_double"],
|
||||
)
|
||||
|
||||
# Negative means send to negative neighbour
|
||||
# Positive means receive from negative neighbour
|
||||
negative_offset = np.where(self.start >= 0, A_substart, self.start + A_substart)
|
||||
|
||||
# Negative means send to positive neighbour
|
||||
# Positive means receive from positive neighbour
|
||||
positive_offset = np.minimum(self.stop, self.upper_bound) - (
|
||||
self.start + A_substart + A_shape
|
||||
)
|
||||
|
||||
dirs = np.full(3, Dir.NONE)
|
||||
|
||||
starts, subshape = calculate_starts_and_subshape(
|
||||
A_shape, -negative_offset, -positive_offset, dirs, sending=True
|
||||
)
|
||||
ends = starts + subshape
|
||||
A_local = A[starts[0] : ends[0], starts[1] : ends[1], starts[2] : ends[2]]
|
||||
|
||||
starts, subshape = calculate_starts_and_subshape(
|
||||
local_shape, negative_offset, positive_offset, dirs
|
||||
)
|
||||
ends = starts + subshape
|
||||
self.fractalvolume[starts[0] : ends[0], starts[1] : ends[1], starts[2] : ends[2]] = A_local
|
||||
|
||||
requests: List[MPI.Request] = []
|
||||
|
||||
# Need to check neighbours in each direction (2D plane)
|
||||
sections = [
|
||||
(Dir.NEG, Dir.NONE),
|
||||
(Dir.POS, Dir.NONE),
|
||||
(Dir.NONE, Dir.NEG),
|
||||
(Dir.NONE, Dir.POS),
|
||||
(Dir.NEG, Dir.NEG),
|
||||
(Dir.NEG, Dir.POS),
|
||||
(Dir.POS, Dir.NEG),
|
||||
(Dir.POS, Dir.POS),
|
||||
]
|
||||
|
||||
# Dimensions of the 2D plane
|
||||
dims = [dim for dim in Dim if dim != static_dimension]
|
||||
|
||||
for section in sections:
|
||||
dirs[dims[0]] = section[0]
|
||||
dirs[dims[1]] = section[1]
|
||||
rank = get_relative_neighbour(self.comm, dirs)
|
||||
|
||||
# Skip if no neighbour
|
||||
if rank == -1:
|
||||
continue
|
||||
|
||||
# Check if any data to send
|
||||
if all(
|
||||
np.select(
|
||||
[dirs == Dir.NEG, dirs == Dir.POS],
|
||||
[negative_offset <= 0, positive_offset <= 0],
|
||||
dirs == Dir.NONE,
|
||||
)
|
||||
):
|
||||
mpi_type = create_mpi_type(
|
||||
A_shape, -negative_offset, -positive_offset, dirs, sending=True
|
||||
)
|
||||
|
||||
logger.debug(f"Sending fractal volume to rank {rank}, MPI type={mpi_type.decode()}")
|
||||
self.comm.Isend([A, mpi_type], rank)
|
||||
|
||||
# Check if any data to receive
|
||||
if all(
|
||||
np.select(
|
||||
[dirs == Dir.NEG, dirs == Dir.POS],
|
||||
[negative_offset > 0, positive_offset > 0],
|
||||
dirs == Dir.NONE,
|
||||
)
|
||||
):
|
||||
mpi_type = create_mpi_type(local_shape, negative_offset, positive_offset, dirs)
|
||||
|
||||
logger.debug(
|
||||
f"Receiving fractal volume from rank {rank}, MPI type={mpi_type.decode()}"
|
||||
)
|
||||
request = self.comm.Irecv([self.fractalvolume, mpi_type], rank)
|
||||
requests.append(request)
|
||||
|
||||
if len(requests) > 0:
|
||||
requests[0].Waitall(requests)
|
||||
|
||||
# Update start and stop to local bounds
|
||||
self.start = np.maximum(self.start, 0)
|
||||
self.stop = np.minimum(self.stop, self.upper_bound)
|
||||
|
||||
logger.debug(
|
||||
f"Generated fractal volume: start={self.start}, stop={self.stop}, size={self.size}"
|
||||
)
|
||||
|
||||
return True
|
105
gprMax/fractals/grass.py
普通文件
105
gprMax/fractals/grass.py
普通文件
@@ -0,0 +1,105 @@
|
||||
# Copyright (C) 2015-2025: The University of Edinburgh, United Kingdom
|
||||
# Authors: Craig Warren, Antonis Giannopoulos, John Hartley,
|
||||
# and Nathan Mannall
|
||||
#
|
||||
# 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 gprMax import config
|
||||
from gprMax.utilities.utilities import round_value
|
||||
|
||||
np.seterr(divide="raise")
|
||||
|
||||
|
||||
class Grass:
|
||||
"""Geometry information for blades of grass."""
|
||||
|
||||
def __init__(self, numblades, seed):
|
||||
"""
|
||||
Args:
|
||||
numblades: int for the number of blades of grass.
|
||||
seed: int for seed value for random number generator.
|
||||
"""
|
||||
|
||||
self.numblades = numblades
|
||||
self.geometryparams = np.zeros(
|
||||
(self.numblades, 6), dtype=config.sim_config.dtypes["float_or_double"]
|
||||
)
|
||||
self.seed = seed
|
||||
self.set_geometry_parameters()
|
||||
|
||||
def set_geometry_parameters(self):
|
||||
"""Sets randomly defined parameters that will be used to calculate
|
||||
blade and root geometries.
|
||||
"""
|
||||
|
||||
self.R1 = np.random.default_rng(seed=self.seed)
|
||||
self.R2 = np.random.default_rng(seed=self.seed)
|
||||
self.R3 = np.random.default_rng(seed=self.seed)
|
||||
self.R4 = np.random.default_rng(seed=self.seed)
|
||||
self.R5 = np.random.default_rng(seed=self.seed)
|
||||
self.R6 = np.random.default_rng(seed=self.seed)
|
||||
|
||||
for i in range(self.numblades):
|
||||
self.geometryparams[i, 0] = 10 + 20 * self.R1.random()
|
||||
self.geometryparams[i, 1] = 10 + 20 * self.R2.random()
|
||||
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 for the numeric ID of grass blade.
|
||||
height: float for the height of grass blade.
|
||||
|
||||
Returns:
|
||||
x, y: floats for the 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 = round_value(x)
|
||||
y = round_value(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 for the umeric ID of grass root.
|
||||
depth: float for the depth of grass root.
|
||||
|
||||
Returns:
|
||||
x, y: floats for the x and y coordinates of grass root.
|
||||
"""
|
||||
|
||||
self.geometryparams[root, 4] += -1 + 2 * self.R5.random()
|
||||
self.geometryparams[root, 5] += -1 + 2 * self.R6.random()
|
||||
x = round(self.geometryparams[root, 4])
|
||||
y = round(self.geometryparams[root, 5])
|
||||
|
||||
return x, y
|
75
gprMax/fractals/mpi_utilities.py
普通文件
75
gprMax/fractals/mpi_utilities.py
普通文件
@@ -0,0 +1,75 @@
|
||||
# Copyright (C) 2015-2025: The University of Edinburgh, United Kingdom
|
||||
# Authors: Craig Warren, Antonis Giannopoulos, John Hartley,
|
||||
# and Nathan Mannall
|
||||
#
|
||||
# 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 typing import Tuple
|
||||
|
||||
import numpy as np
|
||||
import numpy.typing as npt
|
||||
from mpi4py import MPI
|
||||
|
||||
from gprMax.utilities.mpi import Dir
|
||||
|
||||
|
||||
def calculate_starts_and_subshape(
|
||||
shape: npt.NDArray[np.int32],
|
||||
negative_offset: npt.NDArray[np.int32],
|
||||
positive_offset: npt.NDArray[np.int32],
|
||||
dirs: npt.NDArray[np.int32],
|
||||
sending: bool = False,
|
||||
) -> Tuple[npt.NDArray[np.int32], npt.NDArray[np.int32]]:
|
||||
negative_offset = np.where(
|
||||
dirs == Dir.NONE,
|
||||
np.maximum(negative_offset, 0),
|
||||
np.abs(negative_offset),
|
||||
)
|
||||
|
||||
positive_offset = np.where(
|
||||
dirs == Dir.NONE,
|
||||
np.maximum(positive_offset, 0),
|
||||
np.abs(positive_offset),
|
||||
)
|
||||
|
||||
starts = np.select(
|
||||
[dirs == Dir.NEG, dirs == Dir.POS],
|
||||
[0, shape - positive_offset - sending],
|
||||
default=negative_offset,
|
||||
)
|
||||
|
||||
subshape = np.select(
|
||||
[dirs == Dir.NEG, dirs == Dir.POS],
|
||||
[negative_offset + sending, positive_offset + sending],
|
||||
default=shape - negative_offset - positive_offset,
|
||||
)
|
||||
|
||||
return starts, subshape
|
||||
|
||||
|
||||
def create_mpi_type(
|
||||
shape: npt.NDArray[np.int32],
|
||||
negative_offset: npt.NDArray[np.int32],
|
||||
positive_offset: npt.NDArray[np.int32],
|
||||
dirs: npt.NDArray[np.int32],
|
||||
sending: bool = False,
|
||||
) -> MPI.Datatype:
|
||||
starts, subshape = calculate_starts_and_subshape(
|
||||
shape, negative_offset, positive_offset, dirs, sending
|
||||
)
|
||||
mpi_type = MPI.FLOAT.Create_subarray(shape.tolist(), subshape.tolist(), starts.tolist())
|
||||
mpi_type.Commit()
|
||||
return mpi_type
|
@@ -1,658 +0,0 @@
|
||||
# Copyright (C) 2015-2025: The University of Edinburgh, United Kingdom
|
||||
# Authors: Craig Warren, Antonis Giannopoulos, John Hartley,
|
||||
# and Nathan Mannall
|
||||
#
|
||||
# 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 logging
|
||||
import sys
|
||||
from abc import ABC, abstractmethod
|
||||
from io import TextIOWrapper
|
||||
from itertools import chain
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Sequence, Tuple, Union
|
||||
|
||||
import h5py
|
||||
import numpy as np
|
||||
import numpy.typing as npt
|
||||
from tqdm import tqdm
|
||||
|
||||
import gprMax.config as config
|
||||
from gprMax.grid.fdtd_grid import FDTDGrid
|
||||
from gprMax.grid.mpi_grid import MPIGrid
|
||||
from gprMax.materials import Material
|
||||
from gprMax.receivers import Rx
|
||||
from gprMax.sources import Source
|
||||
from gprMax.vtkhdf_filehandlers.vtk_image_data import VtkImageData
|
||||
from gprMax.vtkhdf_filehandlers.vtk_unstructured_grid import VtkUnstructuredGrid
|
||||
from gprMax.vtkhdf_filehandlers.vtkhdf import VtkCellType, VtkHdfFile
|
||||
|
||||
from ._version import __version__
|
||||
from .cython.geometry_outputs import get_line_properties
|
||||
from .subgrids.grid import SubGridBaseGrid
|
||||
from .utilities.utilities import get_terminal_width
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def save_geometry_views(gvs: "List[GeometryView]"):
|
||||
"""Creates and saves geometryviews.
|
||||
|
||||
Args:
|
||||
gvs: list of all GeometryViews.
|
||||
"""
|
||||
|
||||
logger.info("")
|
||||
for i, gv in enumerate(gvs):
|
||||
gv.set_filename()
|
||||
gv.prep_vtk()
|
||||
pbar = tqdm(
|
||||
total=gv.nbytes,
|
||||
unit="byte",
|
||||
unit_scale=True,
|
||||
desc=f"Writing geometry view file {i + 1}/{len(gvs)}, {gv.filename.name}",
|
||||
ncols=get_terminal_width() - 1,
|
||||
file=sys.stdout,
|
||||
disable=not config.sim_config.general["progressbars"],
|
||||
)
|
||||
gv.write_vtk()
|
||||
pbar.update(gv.nbytes)
|
||||
pbar.close()
|
||||
|
||||
logger.info("")
|
||||
|
||||
|
||||
class GeometryView(ABC):
|
||||
"""Base class for Geometry Views."""
|
||||
|
||||
FILE_EXTENSION = ".vtkhdf"
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
xs: int,
|
||||
ys: int,
|
||||
zs: int,
|
||||
xf: int,
|
||||
yf: int,
|
||||
zf: int,
|
||||
dx: int,
|
||||
dy: int,
|
||||
dz: int,
|
||||
filename: str,
|
||||
grid: FDTDGrid,
|
||||
):
|
||||
"""
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf: ints for extent of geometry view in cells.
|
||||
dx, dy, dz: ints for spatial discretisation of geometry view in cells.
|
||||
filename: string for filename.
|
||||
grid: FDTDGrid class describing a grid in a model.
|
||||
"""
|
||||
|
||||
self.start = np.array([xs, ys, zs], dtype=np.int32)
|
||||
self.stop = np.array([xf, yf, zf], dtype=np.int32)
|
||||
self.step = np.array([dx, dy, dz], dtype=np.int32)
|
||||
self.size = (self.stop - self.start) // self.step
|
||||
|
||||
self.filename = Path(filename)
|
||||
self.filenamebase = filename
|
||||
self.grid = grid
|
||||
self.nbytes = None
|
||||
|
||||
self.material_data = None
|
||||
self.materials = None
|
||||
|
||||
# Properties for backwards compatibility
|
||||
@property
|
||||
def xs(self) -> int:
|
||||
return self.start[0]
|
||||
|
||||
@property
|
||||
def ys(self) -> int:
|
||||
return self.start[1]
|
||||
|
||||
@property
|
||||
def zs(self) -> int:
|
||||
return self.start[2]
|
||||
|
||||
@property
|
||||
def xf(self) -> int:
|
||||
return self.stop[0]
|
||||
|
||||
@property
|
||||
def yf(self) -> int:
|
||||
return self.stop[1]
|
||||
|
||||
@property
|
||||
def zf(self) -> int:
|
||||
return self.stop[2]
|
||||
|
||||
@property
|
||||
def dx(self) -> int:
|
||||
return self.step[0]
|
||||
|
||||
@property
|
||||
def dy(self) -> int:
|
||||
return self.step[1]
|
||||
|
||||
@property
|
||||
def dz(self) -> int:
|
||||
return self.step[2]
|
||||
|
||||
@property
|
||||
def nx(self) -> int:
|
||||
return self.size[0]
|
||||
|
||||
@property
|
||||
def ny(self) -> int:
|
||||
return self.size[1]
|
||||
|
||||
@property
|
||||
def nz(self) -> int:
|
||||
return self.size[2]
|
||||
|
||||
def set_filename(self):
|
||||
"""Construct filename from user-supplied name and model number."""
|
||||
parts = config.get_model_config().output_file_path.parts
|
||||
self.filename = Path(
|
||||
*parts[:-1], self.filenamebase + config.get_model_config().appendmodelnumber
|
||||
).with_suffix(self.FILE_EXTENSION)
|
||||
|
||||
@abstractmethod
|
||||
def prep_vtk(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def write_vtk(self):
|
||||
pass
|
||||
|
||||
|
||||
class GeometryViewLines(GeometryView):
|
||||
"""Unstructured grid for a per-cell-edge geometry view."""
|
||||
|
||||
def prep_vtk(self):
|
||||
"""Prepares data for writing to VTKHDF file."""
|
||||
|
||||
# Sample ID array according to geometry view spatial discretisation
|
||||
# Only create a new array if subsampling is required
|
||||
if (
|
||||
self.grid.ID.shape != (self.xf, self.yf, self.zf)
|
||||
or (self.dx, self.dy, self.dz) != (1, 1, 1)
|
||||
or (self.xs, self.ys, self.zs) != (0, 0, 0)
|
||||
):
|
||||
# Require contiguous array
|
||||
ID = np.ascontiguousarray(
|
||||
self.grid.ID[
|
||||
:,
|
||||
self.xs : self.xf : self.dx,
|
||||
self.ys : self.yf : self.dy,
|
||||
self.zs : self.zf : self.dz,
|
||||
]
|
||||
)
|
||||
else:
|
||||
# This array is contiguous by design
|
||||
ID = self.grid.ID
|
||||
|
||||
x = np.arange(self.nx + 1, dtype=np.float64)
|
||||
y = np.arange(self.ny + 1, dtype=np.float64)
|
||||
z = np.arange(self.nz + 1, dtype=np.float64)
|
||||
coords = np.meshgrid(x, y, z, indexing="ij")
|
||||
self.points = np.vstack(list(map(np.ravel, coords))).T
|
||||
self.points += self.start
|
||||
self.points *= self.step * self.grid.dl
|
||||
|
||||
# Add offset to subgrid geometry to correctly locate within main grid
|
||||
if isinstance(self.grid, SubGridBaseGrid):
|
||||
offset = [self.grid.i0, self.grid.j0, self.grid.k0]
|
||||
self.points += offset * self.grid.dl * self.grid.ratio
|
||||
|
||||
# Each point is the 'source' for 3 lines.
|
||||
# NB: Excluding points at the far edge of the geometry as those
|
||||
# are the 'source' for no lines
|
||||
n_lines = 3 * self.nx * self.ny * self.nz
|
||||
|
||||
self.cell_types = np.full(n_lines, VtkCellType.LINE)
|
||||
self.cell_offsets = np.arange(0, 2 * n_lines + 2, 2, dtype=np.int32)
|
||||
|
||||
self.connectivity, self.material_data = get_line_properties(
|
||||
n_lines, self.nx, self.ny, self.nz, ID
|
||||
)
|
||||
|
||||
assert isinstance(self.connectivity, np.ndarray)
|
||||
assert isinstance(self.material_data, np.ndarray)
|
||||
|
||||
# Write information about any PMLs, sources, receivers
|
||||
self.metadata = Metadata(self.grid, self, averaged_materials=True, materials_only=True)
|
||||
|
||||
# Number of bytes of data to be written to file
|
||||
self.nbytes = (
|
||||
self.points.nbytes
|
||||
+ self.cell_types.nbytes
|
||||
+ self.connectivity.nbytes
|
||||
+ self.cell_offsets.nbytes
|
||||
+ self.material_data.nbytes
|
||||
)
|
||||
|
||||
def write_vtk(self):
|
||||
"""Writes geometry information to a VTKHDF file."""
|
||||
|
||||
# Write the VTK file
|
||||
with VtkUnstructuredGrid(
|
||||
self.filename,
|
||||
self.points,
|
||||
self.cell_types,
|
||||
self.connectivity,
|
||||
self.cell_offsets,
|
||||
) as f:
|
||||
f.add_cell_data("Material", self.material_data)
|
||||
self.metadata.write_to_vtkhdf(f)
|
||||
|
||||
|
||||
class GeometryViewVoxels(GeometryView):
|
||||
"""Image data for a per-cell geometry view."""
|
||||
|
||||
def prep_vtk(self):
|
||||
"""Prepares data for writing to VTKHDF file."""
|
||||
|
||||
# Sample solid array according to geometry view spatial discretisation
|
||||
# Only create a new array if subsampling is required
|
||||
if (
|
||||
self.grid.solid.shape != (self.xf, self.yf, self.zf)
|
||||
or (self.dx, self.dy, self.dz) != (1, 1, 1)
|
||||
or (self.xs, self.ys, self.zs) != (0, 0, 0)
|
||||
):
|
||||
# Require contiguous array
|
||||
self.material_data = np.ascontiguousarray(
|
||||
self.grid.solid[
|
||||
self.xs : self.xf : self.dx,
|
||||
self.ys : self.yf : self.dy,
|
||||
self.zs : self.zf : self.dz,
|
||||
]
|
||||
)
|
||||
else:
|
||||
# This array is contiguous by design
|
||||
self.material_data = self.grid.solid
|
||||
|
||||
if isinstance(self.grid, SubGridBaseGrid):
|
||||
self.origin = np.array(
|
||||
[
|
||||
(self.grid.i0 * self.grid.dx * self.grid.ratio),
|
||||
(self.grid.j0 * self.grid.dy * self.grid.ratio),
|
||||
(self.grid.k0 * self.grid.dz * self.grid.ratio),
|
||||
]
|
||||
)
|
||||
else:
|
||||
self.origin = self.start * self.grid.dl
|
||||
|
||||
self.spacing = self.step * self.grid.dl
|
||||
|
||||
# Write information about any PMLs, sources, receivers
|
||||
self.metadata = Metadata(self.grid, self)
|
||||
|
||||
self.nbytes = self.material_data.nbytes
|
||||
|
||||
def write_vtk(self):
|
||||
"""Writes geometry information to a VTKHDF file."""
|
||||
|
||||
with VtkImageData(self.filename, self.size, self.origin, self.spacing) as f:
|
||||
f.add_cell_data("Material", self.material_data)
|
||||
self.metadata.write_to_vtkhdf(f)
|
||||
|
||||
|
||||
class Metadata:
|
||||
"""Comments can be strings included in the header of XML VTK file, and are
|
||||
used to hold extra (gprMax) information about the VTK data.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
grid: FDTDGrid,
|
||||
gv: GeometryView,
|
||||
averaged_materials: bool = False,
|
||||
materials_only: bool = False,
|
||||
):
|
||||
self.grid = grid
|
||||
self.gv = gv
|
||||
self.averaged_materials = averaged_materials
|
||||
self.materials_only = materials_only
|
||||
|
||||
self.gprmax_version = __version__
|
||||
self.dx_dy_dz = self.grid.dl
|
||||
self.nx_ny_nz = np.array([self.grid.nx, self.grid.ny, self.grid.nz], dtype=np.int32)
|
||||
|
||||
self.materials = self.materials_comment()
|
||||
|
||||
# Write information on PMLs, sources, and receivers
|
||||
if not self.materials_only:
|
||||
# Information on PML thickness
|
||||
if self.grid.pmls["slabs"]:
|
||||
self.pml_thickness = self.pml_gv_comment()
|
||||
else:
|
||||
self.pml_thickness = None
|
||||
srcs = (
|
||||
self.grid.hertziandipoles
|
||||
+ self.grid.magneticdipoles
|
||||
+ self.grid.voltagesources
|
||||
+ self.grid.transmissionlines
|
||||
)
|
||||
if srcs:
|
||||
self.source_ids, self.source_positions = self.srcs_rx_gv_comment(srcs)
|
||||
else:
|
||||
self.source_ids = None
|
||||
self.source_positions = None
|
||||
if self.grid.rxs:
|
||||
self.receiver_ids, self.receiver_positions = self.srcs_rx_gv_comment(self.grid.rxs)
|
||||
else:
|
||||
self.receiver_ids = None
|
||||
self.receiver_positions = None
|
||||
|
||||
def write_to_vtkhdf(self, file_handler: VtkHdfFile):
|
||||
file_handler.add_field_data(
|
||||
"gprMax_version",
|
||||
self.gprmax_version,
|
||||
dtype=h5py.string_dtype(),
|
||||
)
|
||||
file_handler.add_field_data("dx_dy_dz", self.dx_dy_dz)
|
||||
file_handler.add_field_data("nx_ny_nz", self.nx_ny_nz)
|
||||
|
||||
file_handler.add_field_data(
|
||||
"material_ids",
|
||||
self.materials,
|
||||
dtype=h5py.string_dtype(),
|
||||
)
|
||||
|
||||
if not self.materials_only:
|
||||
if self.pml_thickness is not None:
|
||||
file_handler.add_field_data("pml_thickness", self.pml_thickness)
|
||||
|
||||
if self.source_ids is not None and self.source_positions is not None:
|
||||
file_handler.add_field_data(
|
||||
"source_ids", self.source_ids, dtype=h5py.string_dtype()
|
||||
)
|
||||
file_handler.add_field_data("sources", self.source_positions)
|
||||
|
||||
if self.receiver_ids is not None and self.receiver_positions is not None:
|
||||
file_handler.add_field_data(
|
||||
"receiver_ids", self.receiver_ids, dtype=h5py.string_dtype()
|
||||
)
|
||||
file_handler.add_field_data("receivers", self.receiver_positions)
|
||||
|
||||
def pml_gv_comment(self) -> List[int]:
|
||||
grid = self.grid
|
||||
|
||||
# Only render PMLs if they are in the geometry view
|
||||
thickness: Dict[str, int] = grid.pmls["thickness"]
|
||||
gv_pml_depth = dict.fromkeys(thickness, 0)
|
||||
|
||||
if self.gv.xs < thickness["x0"]:
|
||||
gv_pml_depth["x0"] = thickness["x0"] - self.gv.xs
|
||||
if self.gv.ys < thickness["y0"]:
|
||||
gv_pml_depth["y0"] = thickness["y0"] - self.gv.ys
|
||||
if thickness["z0"] - self.gv.zs > 0:
|
||||
gv_pml_depth["z0"] = thickness["z0"] - self.gv.zs
|
||||
if self.gv.xf > grid.nx - thickness["xmax"]:
|
||||
gv_pml_depth["xmax"] = self.gv.xf - (grid.nx - thickness["xmax"])
|
||||
if self.gv.yf > grid.ny - thickness["ymax"]:
|
||||
gv_pml_depth["ymax"] = self.gv.yf - (grid.ny - thickness["ymax"])
|
||||
if self.gv.zf > grid.nz - thickness["zmax"]:
|
||||
gv_pml_depth["zmax"] = self.gv.zf - (grid.nz - thickness["zmax"])
|
||||
|
||||
return list(gv_pml_depth.values())
|
||||
|
||||
def srcs_rx_gv_comment(
|
||||
self, srcs: Union[Sequence[Source], List[Rx]]
|
||||
) -> Tuple[List[str], npt.NDArray[np.float32]]:
|
||||
"""Used to name sources and/or receivers."""
|
||||
names: List[str] = []
|
||||
positions: npt.NDArray[np.float32] = np.empty((len(srcs), 3))
|
||||
for index, src in enumerate(srcs):
|
||||
position = src.coord * self.grid.dl
|
||||
names.append(src.ID)
|
||||
positions[index] = position
|
||||
|
||||
return names, positions
|
||||
|
||||
def dx_dy_dz_comment(self) -> npt.NDArray[np.float64]:
|
||||
return self.grid.dl
|
||||
|
||||
def nx_ny_nz_comment(self) -> npt.NDArray[np.int32]:
|
||||
return np.array([self.grid.nx, self.grid.ny, self.grid.nz], dtype=np.int32)
|
||||
|
||||
def materials_comment(self) -> List[str]:
|
||||
if not self.averaged_materials:
|
||||
return [m.ID for m in self.grid.materials if m.type != "dielectric-smoothed"]
|
||||
else:
|
||||
return [m.ID for m in self.grid.materials]
|
||||
|
||||
|
||||
class GeometryObjects:
|
||||
"""Geometry objects to be written to file."""
|
||||
|
||||
def __init__(self, xs=None, ys=None, zs=None, xf=None, yf=None, zf=None, basefilename=None):
|
||||
"""
|
||||
Args:
|
||||
xs, xf, ys, yf, zs, zf: ints for extent of the volume in cells.
|
||||
filename: string for filename.
|
||||
"""
|
||||
|
||||
self.xs = xs
|
||||
self.ys = ys
|
||||
self.zs = zs
|
||||
self.xf = xf
|
||||
self.yf = yf
|
||||
self.zf = zf
|
||||
self.nx = self.xf - self.xs
|
||||
self.ny = self.yf - self.ys
|
||||
self.nz = self.zf - self.zs
|
||||
self.basefilename = basefilename
|
||||
|
||||
# Set filenames
|
||||
parts = config.sim_config.input_file_path.with_suffix("").parts
|
||||
self.filename_hdf5 = Path(*parts[:-1], self.basefilename)
|
||||
self.filename_hdf5 = self.filename_hdf5.with_suffix(".h5")
|
||||
self.filename_materials = Path(*parts[:-1], f"{self.basefilename}_materials")
|
||||
self.filename_materials = self.filename_materials.with_suffix(".txt")
|
||||
|
||||
# Sizes of arrays to write necessary to update progress bar
|
||||
self.solidsize = (
|
||||
(self.nx + 1) * (self.ny + 1) * (self.nz + 1) * np.dtype(np.uint32).itemsize
|
||||
)
|
||||
self.rigidsize = (
|
||||
18 * (self.nx + 1) * (self.ny + 1) * (self.nz + 1) * np.dtype(np.int8).itemsize
|
||||
)
|
||||
self.IDsize = (
|
||||
6 * (self.nx + 1) * (self.ny + 1) * (self.nz + 1) * np.dtype(np.uint32).itemsize
|
||||
)
|
||||
self.datawritesize = self.solidsize + self.rigidsize + self.IDsize
|
||||
|
||||
def write_hdf5(self, title: str, G: FDTDGrid, pbar: tqdm):
|
||||
"""Writes a geometry objects file in HDF5 format.
|
||||
|
||||
Args:
|
||||
G: FDTDGrid class describing a grid in a model.
|
||||
pbar: Progress bar class instance.
|
||||
"""
|
||||
|
||||
ID = G.ID[:, self.xs : self.xf + 1, self.ys : self.yf + 1, self.zs : self.zf + 1]
|
||||
|
||||
# Get materials present in subset of ID array and sort by material ID
|
||||
material_ids, inverse_map = np.unique(ID, return_inverse=True)
|
||||
get_material = np.vectorize(lambda id: G.materials[id])
|
||||
materials = sorted(get_material(material_ids))
|
||||
|
||||
# Create map from material ID to 0 - number of materials
|
||||
materials_map = {material.numID: index for index, material in enumerate(materials)}
|
||||
map_materials = np.vectorize(lambda id: materials_map[id])
|
||||
|
||||
# Remap ID array to the reduced list of materials
|
||||
ID = np.array(map_materials(material_ids))[inverse_map].reshape(ID.shape)
|
||||
|
||||
data = G.solid[self.xs : self.xf, self.ys : self.yf, self.zs : self.zf].astype("int16")
|
||||
data = map_materials(data)
|
||||
|
||||
rigidE = G.rigidE[:, self.xs : self.xf, self.ys : self.yf, self.zs : self.zf]
|
||||
rigidH = G.rigidH[:, self.xs : self.xf, self.ys : self.yf, self.zs : self.zf]
|
||||
|
||||
with h5py.File(self.filename_hdf5, "w") as fdata:
|
||||
fdata.attrs["gprMax"] = __version__
|
||||
fdata.attrs["Title"] = title
|
||||
fdata.attrs["dx_dy_dz"] = (G.dx, G.dy, G.dz)
|
||||
|
||||
fdata["/data"] = data
|
||||
pbar.update(self.solidsize)
|
||||
|
||||
fdata["/rigidE"] = rigidE
|
||||
fdata["/rigidH"] = rigidH
|
||||
pbar.update(self.rigidsize)
|
||||
|
||||
fdata["/ID"] = ID
|
||||
pbar.update(self.IDsize)
|
||||
|
||||
# Write materials list to a text file
|
||||
with open(self.filename_materials, "w") as fmaterials:
|
||||
for material in materials:
|
||||
self.output_material(material, fmaterials)
|
||||
|
||||
def output_material(self, material: Material, file: TextIOWrapper):
|
||||
file.write(
|
||||
f"#material: {material.er:g} {material.se:g} "
|
||||
f"{material.mr:g} {material.sm:g} {material.ID}\n"
|
||||
)
|
||||
if hasattr(material, "poles"):
|
||||
if "debye" in material.type:
|
||||
dispersionstr = "#add_dispersion_debye: " f"{material.poles:g} "
|
||||
for pole in range(material.poles):
|
||||
dispersionstr += f"{material.deltaer[pole]:g} " f"{material.tau[pole]:g} "
|
||||
elif "lorenz" in material.type:
|
||||
dispersionstr = f"#add_dispersion_lorenz: " f"{material.poles:g} "
|
||||
for pole in range(material.poles):
|
||||
dispersionstr += (
|
||||
f"{material.deltaer[pole]:g} "
|
||||
f"{material.tau[pole]:g} "
|
||||
f"{material.alpha[pole]:g} "
|
||||
)
|
||||
elif "drude" in material.type:
|
||||
dispersionstr = f"#add_dispersion_drude: " f"{material.poles:g} "
|
||||
for pole in range(material.poles):
|
||||
dispersionstr += f"{material.tau[pole]:g} " f"{material.alpha[pole]:g} "
|
||||
dispersionstr += material.ID
|
||||
file.write(dispersionstr + "\n")
|
||||
|
||||
|
||||
class MPIGeometryObjects(GeometryObjects):
|
||||
# def __init__(self, start, stop, global_size, comm):
|
||||
# super().__init__(...)
|
||||
|
||||
def write_hdf5(self, title: str, G: MPIGrid, pbar: tqdm):
|
||||
"""Writes a geometry objects file in HDF5 format.
|
||||
|
||||
Args:
|
||||
G: FDTDGrid class describing a grid in a model.
|
||||
pbar: Progress bar class instance.
|
||||
"""
|
||||
|
||||
# Get neighbours
|
||||
self.neighbours = np.full((3, 2), -1, dtype=int)
|
||||
self.neighbours[0] = self.comm.Shift(direction=0, disp=1)
|
||||
self.neighbours[1] = self.comm.Shift(direction=1, disp=1)
|
||||
self.neighbours[2] = self.comm.Shift(direction=2, disp=1)
|
||||
|
||||
# Make subsection of array one larger if no positive neighbour
|
||||
slice_stop = np.where(
|
||||
self.neighbours[:, 1] == -1,
|
||||
self.stop + 1,
|
||||
self.stop,
|
||||
)
|
||||
array_slice = list(map(slice, self.start, slice_stop))
|
||||
|
||||
ID = G.ID[:, array_slice[0], array_slice[1], array_slice[2]]
|
||||
|
||||
# Get materials present in subset of ID
|
||||
local_material_num_ids, inverse_map = np.unique(ID, return_inverse=True)
|
||||
get_material = np.vectorize(lambda id: G.materials[id])
|
||||
local_materials = get_material(local_material_num_ids)
|
||||
|
||||
# Send all materials to the coordinating rank
|
||||
materials = self.comm.gather(local_materials, root=0)
|
||||
|
||||
if self.comm.rank == 0:
|
||||
# Filter out duplicate materials and sort by material ID
|
||||
materials = np.fromiter(chain.from_iterable(materials), dtype=Material)
|
||||
global_materials = np.unique(materials)
|
||||
|
||||
global_material_ids = [m.ID for m in global_materials]
|
||||
else:
|
||||
global_material_ids = None
|
||||
|
||||
global_material_ids = self.comm.bcast(global_material_ids, root=0)
|
||||
|
||||
# Create map from material ID (str) to global material numID
|
||||
materials_map = {
|
||||
material_id: index for index, material_id in enumerate(global_material_ids)
|
||||
}
|
||||
|
||||
# Remap ID array to the global material numID
|
||||
ID = np.array([materials_map[m.ID] for m in local_materials])[inverse_map].reshape(ID.shape)
|
||||
|
||||
# Other geometry arrays do not have halos, so adjustment to
|
||||
# 'stop' is not necessary
|
||||
array_slice = list(map(slice, self.start, self.stop))
|
||||
|
||||
data = G.solid[array_slice[0], array_slice[1], array_slice[2]]
|
||||
map_local_materials = np.vectorize(lambda id: materials_map[G.materials[id].ID])
|
||||
data = map_local_materials(data)
|
||||
|
||||
rigidE = G.rigidE[:, array_slice[0], array_slice[1], array_slice[2]]
|
||||
rigidH = G.rigidH[:, array_slice[0], array_slice[1], array_slice[2]]
|
||||
|
||||
start = self.offset
|
||||
stop = start + self.size
|
||||
|
||||
with h5py.File(self.filename_hdf5, "w", driver="mpio", comm=self.comm) as fdata:
|
||||
fdata.attrs["gprMax"] = __version__
|
||||
fdata.attrs["Title"] = title
|
||||
fdata.attrs["dx_dy_dz"] = (G.dx, G.dy, G.dz)
|
||||
|
||||
dset = fdata.create_dataset("/data", self.global_size, dtype=data.dtype)
|
||||
dset[start[0] : stop[0], start[1] : stop[1], start[2] : stop[2]] = data
|
||||
pbar.update(self.solidsize)
|
||||
|
||||
rigid_E_dataset = fdata.create_dataset(
|
||||
"/rigidE", (12, *self.global_size), dtype=rigidE.dtype
|
||||
)
|
||||
rigid_E_dataset[:, start[0] : stop[0], start[1] : stop[1], start[2] : stop[2]] = rigidE
|
||||
|
||||
rigid_H_dataset = fdata.create_dataset(
|
||||
"/rigidH", (6, *self.global_size), dtype=rigidH.dtype
|
||||
)
|
||||
rigid_H_dataset[:, start[0] : stop[0], start[1] : stop[1], start[2] : stop[2]] = rigidH
|
||||
pbar.update(self.rigidsize)
|
||||
|
||||
stop = np.where(
|
||||
self.neighbours[:, 1] == -1,
|
||||
stop + 1,
|
||||
stop,
|
||||
)
|
||||
|
||||
dset = fdata.create_dataset("/ID", (6, *(self.global_size + 1)), dtype=ID.dtype)
|
||||
dset[:, start[0] : stop[0], start[1] : stop[1], start[2] : stop[2]] = ID
|
||||
pbar.update(self.IDsize)
|
||||
|
||||
# Write materials list to a text file
|
||||
if self.comm.rank == 0:
|
||||
with open(self.filename_materials, "w") as materials_file:
|
||||
for material in global_materials:
|
||||
self.output_material(material, materials_file)
|
@@ -28,10 +28,10 @@ from tqdm import tqdm
|
||||
|
||||
from gprMax import config
|
||||
from gprMax._version import __version__
|
||||
from gprMax.geometry_outputs.grid_view import GridType, GridView, MPIGridView
|
||||
from gprMax.grid.fdtd_grid import FDTDGrid
|
||||
from gprMax.grid.mpi_grid import MPIGrid
|
||||
from gprMax.materials import Material
|
||||
from gprMax.output_controllers.grid_view import GridType, GridView, MPIGridView
|
||||
|
||||
|
||||
class GeometryObject(Generic[GridType]):
|
@@ -0,0 +1,170 @@
|
||||
# Copyright (C) 2015-2025: The University of Edinburgh, United Kingdom
|
||||
# Authors: Craig Warren, Antonis Giannopoulos, John Hartley,
|
||||
# and Nathan Mannall
|
||||
#
|
||||
# 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 contextlib import AbstractContextManager
|
||||
from os import PathLike
|
||||
from types import TracebackType
|
||||
from typing import Optional
|
||||
|
||||
import h5py
|
||||
import numpy as np
|
||||
import numpy.typing as npt
|
||||
from mpi4py import MPI
|
||||
|
||||
from gprMax.geometry_outputs.grid_view import GridView, MPIGridView
|
||||
from gprMax.grid.fdtd_grid import FDTDGrid
|
||||
from gprMax.grid.mpi_grid import MPIGrid
|
||||
|
||||
|
||||
class ReadGeometryObject(AbstractContextManager):
|
||||
def __init__(
|
||||
self,
|
||||
filename: PathLike,
|
||||
grid: FDTDGrid,
|
||||
start: npt.NDArray[np.int32],
|
||||
num_existing_materials: int,
|
||||
) -> None:
|
||||
self.file_handler = h5py.File(filename)
|
||||
|
||||
data = self.file_handler["/data"]
|
||||
assert isinstance(data, h5py.Dataset)
|
||||
stop = start + data.shape
|
||||
|
||||
if isinstance(grid, MPIGrid):
|
||||
if grid.local_bounds_overlap_grid(start, stop):
|
||||
self.grid_view = MPIGridView(
|
||||
grid, start[0], start[1], start[2], stop[0], stop[1], stop[2]
|
||||
)
|
||||
else:
|
||||
# The MPIGridView will create a new communicator using
|
||||
# MPI_Split. Calling this here prevents deadlock if not
|
||||
# all ranks need to read the geometry object.
|
||||
grid.comm.Split(MPI.UNDEFINED)
|
||||
self.grid_view = None
|
||||
|
||||
else:
|
||||
self.grid_view = GridView(grid, start[0], start[1], start[2], stop[0], stop[1], stop[2])
|
||||
|
||||
self.num_existing_materials = num_existing_materials
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(
|
||||
self,
|
||||
exc_type: Optional[type[BaseException]],
|
||||
exc_value: Optional[BaseException],
|
||||
traceback: Optional[TracebackType],
|
||||
) -> Optional[bool]:
|
||||
"""Close the file when the context is exited.
|
||||
|
||||
The parameters describe the exception that caused the context to
|
||||
be exited. If the context was exited without an exception, all
|
||||
three arguments will be None. Any exception will be
|
||||
processed normally upon exit from this method.
|
||||
|
||||
Returns:
|
||||
suppress_exception (optional): Returns True if the exception
|
||||
should be suppressed (i.e. not propagated). Otherwise,
|
||||
the exception will be processed normally upon exit from
|
||||
this method.
|
||||
"""
|
||||
self.close()
|
||||
|
||||
def close(self) -> None:
|
||||
"""Close the file handler"""
|
||||
self.file_handler.close()
|
||||
|
||||
def has_valid_discritisation(self) -> bool:
|
||||
if self.grid_view is None:
|
||||
return True
|
||||
|
||||
dx_dy_dz = self.file_handler.attrs["dx_dy_dz"]
|
||||
return not isinstance(dx_dy_dz, h5py.Empty) and all(dx_dy_dz == self.grid_view.grid.dl)
|
||||
|
||||
def has_ID_array(self) -> bool:
|
||||
ID_class = self.file_handler.get("ID", getclass=True)
|
||||
return ID_class == h5py.Dataset
|
||||
|
||||
def has_rigid_arrays(self) -> bool:
|
||||
rigidE_class = self.file_handler.get("rigidE", getclass=True)
|
||||
rigidH_class = self.file_handler.get("rigidH", getclass=True)
|
||||
return rigidE_class == h5py.Dataset and rigidH_class == h5py.Dataset
|
||||
|
||||
def read_data(self):
|
||||
if self.grid_view is None:
|
||||
return
|
||||
|
||||
data = self.file_handler["/data"]
|
||||
assert isinstance(data, h5py.Dataset)
|
||||
data = data[self.grid_view.get_3d_read_slice()]
|
||||
|
||||
# Should be int16 to allow for -1 which indicates background, i.e.
|
||||
# don't build anything, but AustinMan/Woman maybe uint16
|
||||
if data.dtype != "int16":
|
||||
data = data.astype("int16")
|
||||
|
||||
self.grid_view.set_solid(data + self.num_existing_materials)
|
||||
|
||||
def get_data(self) -> Optional[npt.NDArray[np.int16]]:
|
||||
if self.grid_view is None:
|
||||
return None
|
||||
|
||||
data = self.file_handler["/data"]
|
||||
assert isinstance(data, h5py.Dataset)
|
||||
data = data[self.grid_view.get_3d_read_slice()]
|
||||
|
||||
# Should be int16 to allow for -1 which indicates background, i.e.
|
||||
# don't build anything, but AustinMan/Woman maybe uint16
|
||||
if data.dtype != "int16":
|
||||
data = data.astype("int16")
|
||||
|
||||
return data + self.num_existing_materials
|
||||
|
||||
def read_rigidE(self):
|
||||
if self.grid_view is None:
|
||||
return
|
||||
|
||||
rigidE = self.file_handler["/rigidE"]
|
||||
assert isinstance(rigidE, h5py.Dataset)
|
||||
|
||||
dset_slice = self.grid_view.get_3d_read_slice()
|
||||
self.grid_view.set_rigidE(rigidE[:, dset_slice[0], dset_slice[1], dset_slice[2]])
|
||||
|
||||
def read_rigidH(self):
|
||||
if self.grid_view is None:
|
||||
return
|
||||
|
||||
rigidH = self.file_handler["/rigidH"]
|
||||
assert isinstance(rigidH, h5py.Dataset)
|
||||
|
||||
dset_slice = self.grid_view.get_3d_read_slice()
|
||||
self.grid_view.set_rigidH(rigidH[:, dset_slice[0], dset_slice[1], dset_slice[2]])
|
||||
|
||||
def read_ID(self):
|
||||
if self.grid_view is None:
|
||||
return
|
||||
|
||||
ID = self.file_handler["/ID"]
|
||||
assert isinstance(ID, h5py.Dataset)
|
||||
|
||||
dset_slice = self.grid_view.get_3d_read_slice(upper_bound_exclusive=False)
|
||||
self.grid_view.set_ID(
|
||||
ID[:, dset_slice[0], dset_slice[1], dset_slice[2]] + self.num_existing_materials
|
||||
)
|
@@ -23,13 +23,13 @@ import numpy as np
|
||||
|
||||
from gprMax._version import __version__
|
||||
from gprMax.cython.geometry_outputs import get_line_properties
|
||||
from gprMax.geometry_outputs.geometry_views import GeometryView, Metadata, MPIMetadata
|
||||
from gprMax.geometry_outputs.grid_view import GridType, MPIGridView
|
||||
from gprMax.grid.fdtd_grid import FDTDGrid
|
||||
from gprMax.grid.mpi_grid import MPIGrid
|
||||
from gprMax.output_controllers.geometry_views import GeometryView, Metadata, MPIMetadata
|
||||
from gprMax.output_controllers.grid_view import GridType, MPIGridView
|
||||
from gprMax.subgrids.grid import SubGridBaseGrid
|
||||
from gprMax.vtkhdf_filehandlers.vtk_unstructured_grid import VtkUnstructuredGrid
|
||||
from gprMax.vtkhdf_filehandlers.vtkhdf import VtkCellType
|
||||
from gprMax.vtkhdf_filehandlers.vtkhdf import VtkCellType, VtkHdfFile
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -131,18 +131,18 @@ class MPIGeometryViewLines(GeometryViewLines[MPIGrid]):
|
||||
|
||||
ID = self.grid_view.get_ID()
|
||||
|
||||
x = np.arange(self.grid_view.gx + 1, dtype=np.float64)
|
||||
y = np.arange(self.grid_view.gy + 1, dtype=np.float64)
|
||||
z = np.arange(self.grid_view.gz + 1, dtype=np.float64)
|
||||
x = np.arange(self.grid_view.nx + 1, dtype=np.float64)
|
||||
y = np.arange(self.grid_view.ny + 1, dtype=np.float64)
|
||||
z = np.arange(self.grid_view.nz + 1, dtype=np.float64)
|
||||
coords = np.meshgrid(x, y, z, indexing="ij")
|
||||
self.points = np.vstack(list(map(np.ravel, coords))).T
|
||||
self.points += self.grid_view.global_start
|
||||
self.points += self.grid_view.global_start + self.grid_view.offset
|
||||
self.points *= self.grid_view.step * self.grid.dl
|
||||
|
||||
# Each point is the 'source' for 3 lines.
|
||||
# NB: Excluding points at the far edge of the geometry as those
|
||||
# are the 'source' for no lines
|
||||
n_lines = 3 * np.prod(self.grid_view.global_size)
|
||||
n_lines = 3 * np.prod(self.grid_view.size)
|
||||
|
||||
self.cell_types = np.full(n_lines, VtkCellType.LINE)
|
||||
self.cell_offsets = np.arange(0, 2 * n_lines + 2, 2, dtype=np.intc)
|
||||
@@ -182,5 +182,11 @@ class MPIGeometryViewLines(GeometryViewLines[MPIGrid]):
|
||||
self.cell_offsets,
|
||||
comm=self.grid_view.comm,
|
||||
) as f:
|
||||
self.metadata.write_to_vtkhdf(f)
|
||||
f.add_cell_data("Material", self.material_data, self.grid_view.offset)
|
||||
f.add_cell_data("Material", self.material_data)
|
||||
|
||||
# Write metadata in serial as it contains variable length
|
||||
# strings which currently cannot be written by HDF5 using
|
||||
# parallel I/O
|
||||
if self.grid_view.comm.rank == 0:
|
||||
with VtkHdfFile(self.filename, VtkUnstructuredGrid.TYPE, mode="r+") as f:
|
||||
self.metadata.write_to_vtkhdf(f)
|
@@ -22,11 +22,12 @@ import logging
|
||||
import numpy as np
|
||||
|
||||
from gprMax._version import __version__
|
||||
from gprMax.geometry_outputs.geometry_views import GeometryView, Metadata, MPIMetadata
|
||||
from gprMax.geometry_outputs.grid_view import GridType, MPIGridView
|
||||
from gprMax.grid.mpi_grid import MPIGrid
|
||||
from gprMax.output_controllers.geometry_views import GeometryView, Metadata, MPIMetadata
|
||||
from gprMax.output_controllers.grid_view import GridType, MPIGridView
|
||||
from gprMax.subgrids.grid import SubGridBaseGrid
|
||||
from gprMax.vtkhdf_filehandlers.vtk_image_data import VtkImageData
|
||||
from gprMax.vtkhdf_filehandlers.vtkhdf import VtkHdfFile
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -99,5 +100,11 @@ class MPIGeometryViewVoxels(GeometryViewVoxels[MPIGrid]):
|
||||
self.spacing,
|
||||
comm=self.grid_view.comm,
|
||||
) as f:
|
||||
self.metadata.write_to_vtkhdf(f)
|
||||
f.add_cell_data("Material", self.material_data, self.grid_view.offset)
|
||||
|
||||
# Write metadata in serial as it contains variable length
|
||||
# strings which currently cannot be written by HDF5 using
|
||||
# parallel I/O
|
||||
if self.grid_view.comm.rank == 0:
|
||||
with VtkHdfFile(self.filename, VtkImageData.TYPE, mode="r+") as f:
|
||||
self.metadata.write_to_vtkhdf(f)
|
@@ -31,8 +31,8 @@ from tqdm import tqdm
|
||||
|
||||
import gprMax.config as config
|
||||
from gprMax._version import __version__
|
||||
from gprMax.geometry_outputs.grid_view import GridType, GridView, MPIGridView
|
||||
from gprMax.grid.mpi_grid import MPIGrid
|
||||
from gprMax.output_controllers.grid_view import GridType, GridView, MPIGridView
|
||||
from gprMax.receivers import Rx
|
||||
from gprMax.sources import Source
|
||||
from gprMax.utilities.utilities import get_terminal_width
|
||||
@@ -179,7 +179,7 @@ class Metadata(Generic[GridType]):
|
||||
file_handler.add_field_data("dx_dy_dz", self.dx_dy_dz)
|
||||
file_handler.add_field_data("nx_ny_nz", self.nx_ny_nz)
|
||||
|
||||
self.write_material_ids(file_handler)
|
||||
file_handler.add_field_data("material_ids", self.materials)
|
||||
|
||||
if not self.materials_only:
|
||||
if self.pml_thickness is not None:
|
||||
@@ -193,9 +193,6 @@ class Metadata(Generic[GridType]):
|
||||
file_handler.add_field_data("receiver_ids", self.receiver_ids)
|
||||
file_handler.add_field_data("receivers", self.receiver_positions)
|
||||
|
||||
def write_material_ids(self, file_handler: VtkHdfFile):
|
||||
file_handler.add_field_data("material_ids", self.materials)
|
||||
|
||||
def pml_gv_comment(self) -> Optional[npt.NDArray[np.int64]]:
|
||||
grid = self.grid
|
||||
|
||||
@@ -292,22 +289,3 @@ class MPIMetadata(Metadata[MPIGrid]):
|
||||
objects = dict(sorted(objects.items()))
|
||||
|
||||
return (list(objects.keys()), np.array(list(objects.values()))) if objects else None
|
||||
|
||||
def write_material_ids(self, file_handler: VtkHdfFile):
|
||||
assert isinstance(self.grid_view, MPIGridView)
|
||||
|
||||
# Only rank 0 has all the material data. However, creating the
|
||||
# 'material_ids' dataset is a collective operation, so all ranks
|
||||
# need to know the shape and datatype of the dataset.
|
||||
if self.materials is None:
|
||||
buffer = np.empty(2, dtype=np.int32)
|
||||
else:
|
||||
shape = len(self.materials)
|
||||
max_length = max([len(m) for m in self.materials])
|
||||
buffer = np.array([shape, max_length], dtype=np.int32)
|
||||
|
||||
self.grid_view.comm.Bcast([buffer, MPI.INT32_T])
|
||||
shape, max_length = buffer
|
||||
dtype = h5py.string_dtype(length=int(max_length))
|
||||
|
||||
file_handler.add_field_data("material_ids", self.materials, shape=(shape,), dtype=dtype)
|
@@ -19,7 +19,7 @@
|
||||
|
||||
import logging
|
||||
from itertools import chain
|
||||
from typing import Generic, Tuple
|
||||
from typing import Generic, List, Tuple
|
||||
|
||||
import numpy as np
|
||||
import numpy.typing as npt
|
||||
@@ -117,9 +117,12 @@ class GridView(Generic[GridType]):
|
||||
def nz(self) -> int:
|
||||
return self.size[2]
|
||||
|
||||
def get_slice(self, dimension: int, upper_bound_exclusive: bool = True) -> slice:
|
||||
def getter_slice(self, dimension: int, upper_bound_exclusive: bool = True) -> slice:
|
||||
"""Create a slice object for the specified dimension.
|
||||
|
||||
This is used to slice and get a view of arrays owned by the
|
||||
grid.
|
||||
|
||||
Args:
|
||||
dimension: Dimension to create the slice object for. Values
|
||||
0, 1, and 2 map to the x, y, and z dimensions
|
||||
@@ -138,7 +141,150 @@ class GridView(Generic[GridType]):
|
||||
|
||||
return slice(self.start[dimension], stop, self.step[dimension])
|
||||
|
||||
def slice_array(self, array: npt.NDArray, upper_bound_exclusive: bool = True) -> npt.NDArray:
|
||||
def setter_slice(self, dimension: int, upper_bound_exclusive: bool = True) -> slice:
|
||||
"""Create a slice object for the specified dimension.
|
||||
|
||||
This is used to slice arrays owned by the grid in order to set
|
||||
their value.
|
||||
|
||||
Args:
|
||||
dimension: Dimension to create the slice object for. Values
|
||||
0, 1, and 2 map to the x, y, and z dimensions
|
||||
respectively.
|
||||
upper_bound_exclusive: Optionally specify if the upper bound
|
||||
of the slice should be exclusive or inclusive. Defaults
|
||||
to True.
|
||||
|
||||
Returns:
|
||||
slice: Slice object
|
||||
"""
|
||||
return self.getter_slice(dimension, upper_bound_exclusive)
|
||||
|
||||
def get_output_slice(self, dimension: int, upper_bound_exclusive: bool = True) -> slice:
|
||||
"""Create an output slice object for the specified dimension.
|
||||
|
||||
This provides a slice of the grid view for the section of the
|
||||
grid view managed by this process. This can be used when writing
|
||||
out arrays provided by the grid view as part of a collective
|
||||
operation.
|
||||
|
||||
For example:
|
||||
```
|
||||
dset_slice = (
|
||||
grid_view.get_output_slice(0),
|
||||
grid_view.get_output_slice(1),
|
||||
grid_view.get_output_slice(2),
|
||||
)
|
||||
|
||||
dset[dset_slice] = grid_view.get_solid()
|
||||
```
|
||||
|
||||
Args:
|
||||
dimension: Dimension to create the slice object for. Values
|
||||
0, 1, and 2 map to the x, y, and z dimensions
|
||||
respectively.
|
||||
upper_bound_exclusive: Optionally specify if the upper bound
|
||||
of the slice should be exclusive or inclusive. Defaults
|
||||
to True.
|
||||
|
||||
Returns:
|
||||
slice: Slice object
|
||||
"""
|
||||
if upper_bound_exclusive:
|
||||
size = self.size[dimension]
|
||||
else:
|
||||
size = self.size[dimension] + 1
|
||||
|
||||
return slice(0, size)
|
||||
|
||||
def get_3d_output_slice(self, upper_bound_exclusive: bool = True) -> Tuple[slice, slice, slice]:
|
||||
"""Create a 3D output slice object.
|
||||
|
||||
This provides a slice of the grid view for the section of the
|
||||
grid view managed by this process. This can be used when writing
|
||||
out arrays provided by the grid view as part of a collective
|
||||
operation.
|
||||
|
||||
For example:
|
||||
`dset[grid_view.get_3d_output_slice()] = grid_view.get_solid()`
|
||||
|
||||
Args:
|
||||
upper_bound_exclusive: Optionally specify if the upper bound
|
||||
of the slice should be exclusive or inclusive. Defaults
|
||||
to True.
|
||||
|
||||
Returns:
|
||||
slice: 3D Slice object
|
||||
"""
|
||||
return (
|
||||
self.get_output_slice(0, upper_bound_exclusive),
|
||||
self.get_output_slice(1, upper_bound_exclusive),
|
||||
self.get_output_slice(2, upper_bound_exclusive),
|
||||
)
|
||||
|
||||
def get_read_slice(self, dimension: int, upper_bound_exclusive: bool = True) -> slice:
|
||||
"""Create a read slice object for the specified dimension.
|
||||
|
||||
This provides a slice of the grid view for the section of the
|
||||
grid view managed by this rank. This can be used when reading
|
||||
arrays provided by the grid view as part of a collective
|
||||
operation.
|
||||
|
||||
For example:
|
||||
```
|
||||
dset_slice = (
|
||||
grid_view.get_read_slice(0),
|
||||
grid_view.get_read_slice(1),
|
||||
grid_view.get_read_slice(2),
|
||||
)
|
||||
|
||||
grid_view.set_solid(dset[dset_slice])
|
||||
```
|
||||
|
||||
Args:
|
||||
dimension: Dimension to create the slice object for. Values
|
||||
0, 1, and 2 map to the x, y, and z dimensions
|
||||
respectively.
|
||||
upper_bound_exclusive: Optionally specify if the upper bound
|
||||
of the slice should be exclusive or inclusive. Defaults
|
||||
to True.
|
||||
|
||||
Returns:
|
||||
slice: Slice object
|
||||
"""
|
||||
return self.get_output_slice(dimension, upper_bound_exclusive)
|
||||
|
||||
def get_3d_read_slice(self, upper_bound_exclusive: bool = True) -> Tuple[slice, slice, slice]:
|
||||
"""Create a 3D read slice object.
|
||||
|
||||
This provides a slice of the grid view for the section of the
|
||||
grid view managed by this rank. This can be used when reading
|
||||
arrays provided by the grid view as part of a collective
|
||||
operation.
|
||||
|
||||
For example:
|
||||
```
|
||||
solid = dset[grid_view.get_3d_read_slice()]
|
||||
grid_view.set_solid(solid)
|
||||
```
|
||||
|
||||
Args:
|
||||
upper_bound_exclusive: Optionally specify if the upper bound
|
||||
of the slice should be exclusive or inclusive. Defaults
|
||||
to True.
|
||||
|
||||
Returns:
|
||||
slice: 3D Slice object
|
||||
"""
|
||||
return (
|
||||
self.get_read_slice(0, upper_bound_exclusive),
|
||||
self.get_read_slice(1, upper_bound_exclusive),
|
||||
self.get_read_slice(2, upper_bound_exclusive),
|
||||
)
|
||||
|
||||
def get_array_slice(
|
||||
self, array: npt.NDArray, upper_bound_exclusive: bool = True
|
||||
) -> npt.NDArray:
|
||||
"""Slice an array according to the dimensions of the grid view.
|
||||
|
||||
It is assumed the last 3 dimensions of the provided array
|
||||
@@ -161,12 +307,41 @@ class GridView(Generic[GridType]):
|
||||
return np.ascontiguousarray(
|
||||
array[
|
||||
...,
|
||||
self.get_slice(0, upper_bound_exclusive),
|
||||
self.get_slice(1, upper_bound_exclusive),
|
||||
self.get_slice(2, upper_bound_exclusive),
|
||||
self.getter_slice(0, upper_bound_exclusive),
|
||||
self.getter_slice(1, upper_bound_exclusive),
|
||||
self.getter_slice(2, upper_bound_exclusive),
|
||||
]
|
||||
)
|
||||
|
||||
def set_array_slice(
|
||||
self, array: npt.NDArray, value: npt.NDArray, upper_bound_exclusive: bool = True
|
||||
):
|
||||
"""Set value of an array according to the dimensions of the grid view.
|
||||
|
||||
It is assumed the last 3 dimensions of the array represent the
|
||||
x, y, z spacial information. Other dimensions will not be
|
||||
sliced.
|
||||
|
||||
E.g. If setting the value of an array of shape (10, 100, 50, 50)
|
||||
the new values should have shape (10, x, y, z) where x, y, and z
|
||||
are specified by the size/shape of the grid view.
|
||||
|
||||
Args:
|
||||
array: Array to set the values of. Must have at least 3
|
||||
dimensions.
|
||||
value: New values. Its shape must match 'array' after
|
||||
'array' has been sliced.
|
||||
upper_bound_exclusive: Optionally specify if the upper bound
|
||||
of the slice should be exclusive or inclusive. Defaults
|
||||
to True.
|
||||
"""
|
||||
array[
|
||||
...,
|
||||
self.setter_slice(0, upper_bound_exclusive),
|
||||
self.setter_slice(1, upper_bound_exclusive),
|
||||
self.setter_slice(2, upper_bound_exclusive),
|
||||
] = value
|
||||
|
||||
def initialise_materials(self, filter_materials: bool = True):
|
||||
"""Create a new ID map for materials in the grid view.
|
||||
|
||||
@@ -228,32 +403,64 @@ class GridView(Generic[GridType]):
|
||||
ID: View of the ID array.
|
||||
"""
|
||||
if self._ID is None or force_refresh:
|
||||
self._ID = self.slice_array(self.grid.ID, upper_bound_exclusive=False)
|
||||
self._ID = self.get_array_slice(self.grid.ID, upper_bound_exclusive=False)
|
||||
return self._ID
|
||||
|
||||
def set_ID(self, value: npt.NDArray[np.uint32]):
|
||||
"""Set the value of the ID array.
|
||||
|
||||
Args:
|
||||
value: Array of new values.
|
||||
"""
|
||||
self.set_array_slice(self.grid.ID, value, upper_bound_exclusive=False)
|
||||
|
||||
def get_solid(self) -> npt.NDArray[np.uint32]:
|
||||
"""Get a view of the solid array.
|
||||
|
||||
Returns:
|
||||
solid: View of the solid array
|
||||
solid: View of the solid array.
|
||||
"""
|
||||
return self.slice_array(self.grid.solid)
|
||||
return self.get_array_slice(self.grid.solid)
|
||||
|
||||
def set_solid(self, value: npt.NDArray[np.uint32]):
|
||||
"""Set the value of the solid array.
|
||||
|
||||
Args:
|
||||
value: Array of new values.
|
||||
"""
|
||||
self.set_array_slice(self.grid.solid, value)
|
||||
|
||||
def get_rigidE(self) -> npt.NDArray[np.int8]:
|
||||
"""Get a view of the rigidE array.
|
||||
|
||||
Returns:
|
||||
rigidE: View of the rigidE array
|
||||
rigidE: View of the rigidE array.
|
||||
"""
|
||||
return self.slice_array(self.grid.rigidE)
|
||||
return self.get_array_slice(self.grid.rigidE)
|
||||
|
||||
def set_rigidE(self, value: npt.NDArray[np.uint32]):
|
||||
"""Set the value of the rigidE array.
|
||||
|
||||
Args:
|
||||
value: Array of new values.
|
||||
"""
|
||||
self.set_array_slice(self.grid.rigidE, value)
|
||||
|
||||
def get_rigidH(self) -> npt.NDArray[np.int8]:
|
||||
"""Get a view of the rigidH array.
|
||||
|
||||
Returns:
|
||||
rigidH: View of the rigidH array
|
||||
rigidH: View of the rigidH array.
|
||||
"""
|
||||
return self.slice_array(self.grid.rigidH)
|
||||
return self.get_array_slice(self.grid.rigidH)
|
||||
|
||||
def set_rigidH(self, value: npt.NDArray[np.uint32]):
|
||||
"""Set the value of the rigidH array.
|
||||
|
||||
Args:
|
||||
value: Array of new values.
|
||||
"""
|
||||
self.set_array_slice(self.grid.rigidH, value)
|
||||
|
||||
def get_Ex(self) -> npt.NDArray[np.float32]:
|
||||
"""Get a view of the Ex array.
|
||||
@@ -261,7 +468,7 @@ class GridView(Generic[GridType]):
|
||||
Returns:
|
||||
Ex: View of the Ex array
|
||||
"""
|
||||
return self.slice_array(self.grid.Ex, upper_bound_exclusive=False)
|
||||
return self.get_array_slice(self.grid.Ex, upper_bound_exclusive=False)
|
||||
|
||||
def get_Ey(self) -> npt.NDArray[np.float32]:
|
||||
"""Get a view of the Ey array.
|
||||
@@ -269,7 +476,7 @@ class GridView(Generic[GridType]):
|
||||
Returns:
|
||||
Ey: View of the Ey array
|
||||
"""
|
||||
return self.slice_array(self.grid.Ey, upper_bound_exclusive=False)
|
||||
return self.get_array_slice(self.grid.Ey, upper_bound_exclusive=False)
|
||||
|
||||
def get_Ez(self) -> npt.NDArray[np.float32]:
|
||||
"""Get a view of the Ez array.
|
||||
@@ -277,7 +484,7 @@ class GridView(Generic[GridType]):
|
||||
Returns:
|
||||
Ez: View of the Ez array
|
||||
"""
|
||||
return self.slice_array(self.grid.Ez, upper_bound_exclusive=False)
|
||||
return self.get_array_slice(self.grid.Ez, upper_bound_exclusive=False)
|
||||
|
||||
def get_Hx(self) -> npt.NDArray[np.float32]:
|
||||
"""Get a view of the Hx array.
|
||||
@@ -285,7 +492,7 @@ class GridView(Generic[GridType]):
|
||||
Returns:
|
||||
Hx: View of the Hx array
|
||||
"""
|
||||
return self.slice_array(self.grid.Hx, upper_bound_exclusive=False)
|
||||
return self.get_array_slice(self.grid.Hx, upper_bound_exclusive=False)
|
||||
|
||||
def get_Hy(self) -> npt.NDArray[np.float32]:
|
||||
"""Get a view of the Hy array.
|
||||
@@ -293,7 +500,7 @@ class GridView(Generic[GridType]):
|
||||
Returns:
|
||||
Hy: View of the Hy array
|
||||
"""
|
||||
return self.slice_array(self.grid.Hy, upper_bound_exclusive=False)
|
||||
return self.get_array_slice(self.grid.Hy, upper_bound_exclusive=False)
|
||||
|
||||
def get_Hz(self) -> npt.NDArray[np.float32]:
|
||||
"""Get a view of the Hz array.
|
||||
@@ -301,7 +508,7 @@ class GridView(Generic[GridType]):
|
||||
Returns:
|
||||
Hz: View of the Hz array
|
||||
"""
|
||||
return self.slice_array(self.grid.Hz, upper_bound_exclusive=False)
|
||||
return self.get_array_slice(self.grid.Hz, upper_bound_exclusive=False)
|
||||
|
||||
|
||||
class MPIGridView(GridView[MPIGrid]):
|
||||
@@ -382,7 +589,9 @@ class MPIGridView(GridView[MPIGrid]):
|
||||
)
|
||||
|
||||
# Calculate offset for the local grid view
|
||||
self.offset = self.grid.local_to_global_coordinate(self.start) - self.global_start
|
||||
self.offset = (
|
||||
self.grid.local_to_global_coordinate(self.start) - self.global_start
|
||||
) // self.step
|
||||
|
||||
# Update local size
|
||||
self.size = np.ceil((self.stop - self.start) / self.step).astype(np.int32)
|
||||
@@ -405,9 +614,12 @@ class MPIGridView(GridView[MPIGrid]):
|
||||
def gz(self) -> int:
|
||||
return self.global_size[2]
|
||||
|
||||
def get_slice(self, dimension: int, upper_bound_exclusive: bool = True) -> slice:
|
||||
def getter_slice(self, dimension: int, upper_bound_exclusive: bool = True) -> slice:
|
||||
"""Create a slice object for the specified dimension.
|
||||
|
||||
This is used to slice and get a view of arrays owned by the
|
||||
grid.
|
||||
|
||||
Args:
|
||||
dimension: Dimension to create the slice object for. Values
|
||||
0, 1, and 2 map to the x, y, and z dimensions
|
||||
@@ -428,6 +640,35 @@ class MPIGridView(GridView[MPIGrid]):
|
||||
|
||||
return slice(self.start[dimension], stop, self.step[dimension])
|
||||
|
||||
def setter_slice(self, dimension: int, upper_bound_exclusive: bool = True) -> slice:
|
||||
"""Create a slice object for the specified dimension.
|
||||
|
||||
This is used to slice arrays owned by the grid in order to set
|
||||
their value.
|
||||
|
||||
Args:
|
||||
dimension: Dimension to create the slice object for. Values
|
||||
0, 1, and 2 map to the x, y, and z dimensions
|
||||
respectively.
|
||||
upper_bound_exclusive: Optionally specify if the upper bound
|
||||
of the slice should be exclusive or inclusive. Defaults
|
||||
to True.
|
||||
|
||||
Returns:
|
||||
slice: Slice object
|
||||
"""
|
||||
if upper_bound_exclusive:
|
||||
stop = self.stop[dimension]
|
||||
else:
|
||||
stop = self.stop[dimension] + self.step[dimension]
|
||||
|
||||
if self.has_negative_neighbour[dimension]:
|
||||
start = self.start[dimension] - self.step[dimension]
|
||||
else:
|
||||
start = self.start[dimension]
|
||||
|
||||
return slice(start, stop, self.step[dimension])
|
||||
|
||||
def get_output_slice(self, dimension: int, upper_bound_exclusive: bool = True) -> slice:
|
||||
"""Create an output slice object for the specified dimension.
|
||||
|
||||
@@ -465,34 +706,52 @@ class MPIGridView(GridView[MPIGrid]):
|
||||
# have a positive neighbour
|
||||
size = self.size[dimension] + 1
|
||||
|
||||
offset = self.offset[dimension] // self.step[dimension]
|
||||
offset = self.offset[dimension]
|
||||
|
||||
return slice(offset, offset + size)
|
||||
|
||||
def get_3d_output_slice(self, upper_bound_exclusive: bool = True) -> Tuple[slice, slice, slice]:
|
||||
"""Create a 3D output slice object.
|
||||
def get_read_slice(self, dimension: int, upper_bound_exclusive: bool = True) -> slice:
|
||||
"""Create a read slice object for the specified dimension.
|
||||
|
||||
This provides a slice of the grid view for the section of the
|
||||
grid view managed by this rank. This can be used when writing
|
||||
out arrays provided by the grid view as part of a collective
|
||||
grid view managed by this rank. This can be used when reading
|
||||
arrays provided by the grid view as part of a collective
|
||||
operation.
|
||||
|
||||
For example:
|
||||
`dset[grid_view.get_3d_output_slice()] = grid_view.get_solid()`
|
||||
```
|
||||
dset_slice = (
|
||||
grid_view.get_read_slice(0),
|
||||
grid_view.get_read_slice(1),
|
||||
grid_view.get_read_slice(2),
|
||||
)
|
||||
|
||||
grid_view.get_solid()[:] = dset[dset_slice]
|
||||
```
|
||||
|
||||
Args:
|
||||
dimension: Dimension to create the slice object for. Values
|
||||
0, 1, and 2 map to the x, y, and z dimensions
|
||||
respectively.
|
||||
upper_bound_exclusive: Optionally specify if the upper bound
|
||||
of the slice should be exclusive or inclusive. Defaults
|
||||
to True.
|
||||
|
||||
Returns:
|
||||
slice: 3D Slice object
|
||||
slice: Slice object
|
||||
"""
|
||||
return (
|
||||
self.get_output_slice(0, upper_bound_exclusive),
|
||||
self.get_output_slice(1, upper_bound_exclusive),
|
||||
self.get_output_slice(2, upper_bound_exclusive),
|
||||
)
|
||||
if upper_bound_exclusive:
|
||||
size = self.size[dimension]
|
||||
else:
|
||||
size = self.size[dimension] + 1
|
||||
|
||||
offset = self.offset[dimension]
|
||||
|
||||
if self.has_negative_neighbour[dimension]:
|
||||
offset -= 1
|
||||
size += 1
|
||||
|
||||
return slice(offset, offset + size)
|
||||
|
||||
def initialise_materials(self, filter_materials: bool = True):
|
||||
"""Create a new ID map for materials in the grid view.
|
||||
@@ -520,6 +779,8 @@ class MPIGridView(GridView[MPIGrid]):
|
||||
# Send all materials to the coordinating rank
|
||||
materials_by_rank = self.comm.gather(local_materials, root=0)
|
||||
|
||||
requests: List[MPI.Request] = []
|
||||
|
||||
if materials_by_rank is not None:
|
||||
# Filter out duplicate materials and sort by material ID
|
||||
all_materials = np.fromiter(chain.from_iterable(materials_by_rank), dtype=Material)
|
||||
@@ -530,7 +791,10 @@ class MPIGridView(GridView[MPIGrid]):
|
||||
# new IDs of each material it sent to send back
|
||||
for rank in range(1, self.comm.size):
|
||||
new_material_ids = np.where(np.isin(self.materials, materials_by_rank[rank]))[0]
|
||||
self.comm.Isend([new_material_ids.astype(np.int32), MPI.INT], rank)
|
||||
|
||||
# astype() always returns a copy, so it should be safe to use Isend here
|
||||
request = self.comm.Isend([new_material_ids.astype(np.int32), MPI.INT], rank)
|
||||
requests.append(request)
|
||||
|
||||
new_material_ids = np.where(np.isin(self.materials, materials_by_rank[0]))[0]
|
||||
new_material_ids = new_material_ids.astype(np.int32)
|
||||
@@ -548,3 +812,6 @@ class MPIGridView(GridView[MPIGrid]):
|
||||
|
||||
# Create map from material ID to 0 - number of materials
|
||||
self.map_materials_func = np.vectorize(lambda id: materials_map[id])
|
||||
|
||||
if len(requests) > 0:
|
||||
requests[0].Waitall(requests)
|
@@ -22,7 +22,7 @@ import itertools
|
||||
import logging
|
||||
import sys
|
||||
from collections import OrderedDict
|
||||
from typing import Any, Iterable, List, Tuple, Union
|
||||
from typing import Any, Iterable, List, Optional, Tuple, Union
|
||||
|
||||
import numpy as np
|
||||
import numpy.typing as npt
|
||||
@@ -33,7 +33,8 @@ from typing_extensions import TypeVar
|
||||
from gprMax import config
|
||||
from gprMax.cython.pml_build import pml_average_er_mr
|
||||
from gprMax.cython.yee_cell_build import build_electric_components, build_magnetic_components
|
||||
from gprMax.fractals import FractalVolume
|
||||
from gprMax.fractals.fractal_surface import FractalSurface
|
||||
from gprMax.fractals.fractal_volume import FractalVolume
|
||||
from gprMax.materials import ListMaterial, Material, PeplinskiSoil, RangeMaterial, process_materials
|
||||
from gprMax.pml import CFS, PML, print_pml_info
|
||||
from gprMax.receivers import Rx
|
||||
@@ -186,6 +187,34 @@ class FDTDGrid:
|
||||
self.pmls["thickness"]["ymax"] = int(thickness[4])
|
||||
self.pmls["thickness"]["zmax"] = int(thickness[5])
|
||||
|
||||
def add_fractal_volume(
|
||||
self,
|
||||
xs: int,
|
||||
xf: int,
|
||||
ys: int,
|
||||
yf: int,
|
||||
zs: int,
|
||||
zf: int,
|
||||
frac_dim: float,
|
||||
seed: Optional[int],
|
||||
) -> FractalVolume:
|
||||
volume = FractalVolume(xs, xf, ys, yf, zs, zf, frac_dim, seed)
|
||||
self.fractalvolumes.append(volume)
|
||||
return volume
|
||||
|
||||
def create_fractal_surface(
|
||||
self,
|
||||
xs: int,
|
||||
xf: int,
|
||||
ys: int,
|
||||
yf: int,
|
||||
zs: int,
|
||||
zf: int,
|
||||
frac_dim: float,
|
||||
seed: Optional[int],
|
||||
) -> FractalSurface:
|
||||
return FractalSurface(xs, xf, ys, yf, zs, zf, frac_dim, seed)
|
||||
|
||||
def add_source(self, source: Source):
|
||||
if isinstance(source, VoltageSource):
|
||||
self.voltagesources.append(source)
|
||||
@@ -748,7 +777,7 @@ class FDTDGrid:
|
||||
mem_use = 0
|
||||
|
||||
for vol in self.fractalvolumes:
|
||||
mem_use += vol.nx * vol.ny * vol.nz * vol.dtype.itemsize
|
||||
mem_use += np.prod(vol.start) * vol.dtype.itemsize
|
||||
for surface in vol.fractalsurfaces:
|
||||
surfacedims = surface.get_surface_dims()
|
||||
mem_use += surfacedims[0] * surfacedims[1] * surface.dtype.itemsize
|
||||
|
@@ -19,7 +19,6 @@
|
||||
|
||||
import itertools
|
||||
import logging
|
||||
from enum import IntEnum, unique
|
||||
from typing import List, Optional, Tuple, TypeVar, Union
|
||||
|
||||
import numpy as np
|
||||
@@ -29,29 +28,19 @@ from numpy import ndarray
|
||||
|
||||
from gprMax import config
|
||||
from gprMax.cython.pml_build import pml_sum_er_mr
|
||||
from gprMax.fractals.fractal_surface import MPIFractalSurface
|
||||
from gprMax.fractals.fractal_volume import MPIFractalVolume
|
||||
from gprMax.grid.fdtd_grid import FDTDGrid
|
||||
from gprMax.pml import MPIPML, PML
|
||||
from gprMax.receivers import Rx
|
||||
from gprMax.sources import Source
|
||||
from gprMax.utilities.mpi import Dim, Dir
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
CoordType = TypeVar("CoordType", bound=Union[Rx, Source])
|
||||
|
||||
|
||||
@unique
|
||||
class Dim(IntEnum):
|
||||
X = 0
|
||||
Y = 1
|
||||
Z = 2
|
||||
|
||||
|
||||
@unique
|
||||
class Dir(IntEnum):
|
||||
NEG = 0
|
||||
POS = 1
|
||||
|
||||
|
||||
class MPIGrid(FDTDGrid):
|
||||
HALO_SIZE = 1
|
||||
COORDINATOR_RANK = 0
|
||||
@@ -70,13 +59,15 @@ class MPIGrid(FDTDGrid):
|
||||
self.negative_halo_offset = np.zeros(3, dtype=np.bool_)
|
||||
self.global_size = np.zeros(3, dtype=np.int32)
|
||||
|
||||
self.neighbours = np.full((3, 2), -1, dtype=int)
|
||||
self.neighbours = np.full((3, 2), -1, dtype=np.int32)
|
||||
self.neighbours[Dim.X] = self.comm.Shift(direction=Dim.X, disp=1)
|
||||
self.neighbours[Dim.Y] = self.comm.Shift(direction=Dim.Y, disp=1)
|
||||
self.neighbours[Dim.Z] = self.comm.Shift(direction=Dim.Z, disp=1)
|
||||
|
||||
self.send_halo_map = np.empty((3, 2), dtype=MPI.Datatype)
|
||||
self.recv_halo_map = np.empty((3, 2), dtype=MPI.Datatype)
|
||||
self.send_requests: List[MPI.Request] = []
|
||||
self.recv_requests: List[MPI.Request] = []
|
||||
|
||||
super().__init__()
|
||||
|
||||
@@ -129,6 +120,34 @@ class MPIGrid(FDTDGrid):
|
||||
if self.has_neighbour(Dim.Z, Dir.POS):
|
||||
self.pmls["thickness"]["zmax"] = 0
|
||||
|
||||
def add_fractal_volume(
|
||||
self,
|
||||
xs: int,
|
||||
xf: int,
|
||||
ys: int,
|
||||
yf: int,
|
||||
zs: int,
|
||||
zf: int,
|
||||
frac_dim: float,
|
||||
seed: Optional[int],
|
||||
) -> MPIFractalVolume:
|
||||
volume = MPIFractalVolume(xs, xf, ys, yf, zs, zf, frac_dim, seed, self.comm, self.size)
|
||||
self.fractalvolumes.append(volume)
|
||||
return volume
|
||||
|
||||
def create_fractal_surface(
|
||||
self,
|
||||
xs: int,
|
||||
xf: int,
|
||||
ys: int,
|
||||
yf: int,
|
||||
zs: int,
|
||||
zf: int,
|
||||
frac_dim: float,
|
||||
seed: Optional[int],
|
||||
) -> MPIFractalSurface:
|
||||
return MPIFractalSurface(xs, xf, ys, yf, zs, zf, frac_dim, seed, self.comm, self.size)
|
||||
|
||||
def is_coordinator(self) -> bool:
|
||||
"""Test if the current rank is the coordinator.
|
||||
|
||||
@@ -352,15 +371,10 @@ class MPIGrid(FDTDGrid):
|
||||
"""
|
||||
neighbour = self.neighbours[dim][dir]
|
||||
if neighbour != -1:
|
||||
self.comm.Sendrecv(
|
||||
[array, self.send_halo_map[dim][dir]],
|
||||
neighbour,
|
||||
0,
|
||||
[array, self.recv_halo_map[dim][dir]],
|
||||
neighbour,
|
||||
0,
|
||||
None,
|
||||
)
|
||||
send_request = self.comm.Isend([array, self.send_halo_map[dim][dir]], neighbour)
|
||||
recv_request = self.comm.Irecv([array, self.recv_halo_map[dim][dir]], neighbour)
|
||||
self.send_requests.append(send_request)
|
||||
self.recv_requests.append(recv_request)
|
||||
|
||||
def _halo_swap_by_dimension(self, array: ndarray, dim: Dim):
|
||||
"""Perform halo swaps in the specifed dimension.
|
||||
@@ -393,17 +407,45 @@ class MPIGrid(FDTDGrid):
|
||||
def halo_swap_electric(self):
|
||||
"""Perform halo swaps for electric field arrays."""
|
||||
|
||||
# Ensure send requests for the magnetic field have completed
|
||||
# The magnetic field arrays may change after this halo swap in
|
||||
# the magnetic update step
|
||||
if len(self.send_requests) > 0:
|
||||
self.send_requests[0].Waitall(self.send_requests)
|
||||
self.send_requests = []
|
||||
|
||||
self._halo_swap_array(self.Ex)
|
||||
self._halo_swap_array(self.Ey)
|
||||
self._halo_swap_array(self.Ez)
|
||||
|
||||
# Wait for all receive requests to complete
|
||||
# Don't need to wait for send requests yet as the electric
|
||||
# field arrays won't be changed during the magnetic update steps
|
||||
if len(self.recv_requests) > 0:
|
||||
self.recv_requests[0].Waitall(self.recv_requests)
|
||||
self.recv_requests = []
|
||||
|
||||
def halo_swap_magnetic(self):
|
||||
"""Perform halo swaps for magnetic field arrays."""
|
||||
|
||||
# Ensure send requests for the electric field have completed
|
||||
# The electric field arrays will change after this halo swap in
|
||||
# the electric update step
|
||||
if len(self.send_requests) > 0:
|
||||
self.send_requests[0].Waitall(self.send_requests)
|
||||
self.send_requests = []
|
||||
|
||||
self._halo_swap_array(self.Hx)
|
||||
self._halo_swap_array(self.Hy)
|
||||
self._halo_swap_array(self.Hz)
|
||||
|
||||
# Wait for all receive requests to complete
|
||||
# Don't need to wait for send requests yet as the magnetic
|
||||
# field arrays won't be changed during the electric update steps
|
||||
if len(self.recv_requests) > 0:
|
||||
self.recv_requests[0].Waitall(self.recv_requests)
|
||||
self.recv_requests = []
|
||||
|
||||
def _construct_pml(self, pml_ID: str, thickness: int) -> MPIPML:
|
||||
"""Build instance of MPIPML and set the MPI communicator.
|
||||
|
||||
|
@@ -422,6 +422,10 @@ def process_geometrycmds(geometry):
|
||||
)
|
||||
raise ValueError
|
||||
|
||||
# Only build objects attached to the current fractal box
|
||||
if tmp[12] != ID:
|
||||
continue
|
||||
|
||||
p1 = (float(tmp[1]), float(tmp[2]), float(tmp[3]))
|
||||
p2 = (float(tmp[4]), float(tmp[5]), float(tmp[6]))
|
||||
frac_dim = float(tmp[7])
|
||||
@@ -463,6 +467,10 @@ def process_geometrycmds(geometry):
|
||||
)
|
||||
raise ValueError
|
||||
|
||||
# Only build objects attached to the current fractal box
|
||||
if tmp[8] != ID:
|
||||
continue
|
||||
|
||||
p1 = (float(tmp[1]), float(tmp[2]), float(tmp[3]))
|
||||
p2 = (float(tmp[4]), float(tmp[5]), float(tmp[6]))
|
||||
depth = float(tmp[7])
|
||||
@@ -478,6 +486,10 @@ def process_geometrycmds(geometry):
|
||||
)
|
||||
raise ValueError
|
||||
|
||||
# Only build objects attached to the current fractal box
|
||||
if tmp[11] != ID:
|
||||
continue
|
||||
|
||||
p1 = (float(tmp[1]), float(tmp[2]), float(tmp[3]))
|
||||
p2 = (float(tmp[4]), float(tmp[5]), float(tmp[6]))
|
||||
frac_dim = float(tmp[7])
|
||||
|
@@ -73,8 +73,10 @@ class Material:
|
||||
)
|
||||
elif self.is_compound_material() and value.is_compound_material():
|
||||
return self.ID < value.ID
|
||||
elif not self.is_compound_material() and not value.is_compound_material():
|
||||
return self.numID < value.numID
|
||||
else:
|
||||
return value.is_compound_material() or self.numID < value.numID
|
||||
return value.is_compound_material()
|
||||
|
||||
def __gt__(self, value: "Material") -> bool:
|
||||
"""Greater than comparator for two Materials.
|
||||
@@ -90,8 +92,10 @@ class Material:
|
||||
)
|
||||
elif self.is_compound_material() and value.is_compound_material():
|
||||
return self.ID > value.ID
|
||||
elif not self.is_compound_material() and not value.is_compound_material():
|
||||
return self.numID > value.numID
|
||||
else:
|
||||
return self.is_compound_material() or self.numID > value.numID
|
||||
return self.is_compound_material()
|
||||
|
||||
def is_compound_material(self) -> bool:
|
||||
"""Check if a material is a compound material.
|
||||
|
@@ -27,12 +27,12 @@ import numpy.typing as npt
|
||||
import psutil
|
||||
from colorama import Fore, Style, init
|
||||
|
||||
from gprMax.geometry_outputs.geometry_objects import GeometryObject
|
||||
from gprMax.geometry_outputs.geometry_view_lines import GeometryViewLines
|
||||
from gprMax.geometry_outputs.geometry_view_voxels import GeometryViewVoxels
|
||||
from gprMax.geometry_outputs.geometry_views import GeometryView, save_geometry_views
|
||||
from gprMax.grid.cuda_grid import CUDAGrid
|
||||
from gprMax.grid.opencl_grid import OpenCLGrid
|
||||
from gprMax.output_controllers.geometry_objects import GeometryObject
|
||||
from gprMax.output_controllers.geometry_view_lines import GeometryViewLines
|
||||
from gprMax.output_controllers.geometry_view_voxels import GeometryViewVoxels
|
||||
from gprMax.output_controllers.geometry_views import GeometryView, save_geometry_views
|
||||
from gprMax.subgrids.grid import SubGridBaseGrid
|
||||
|
||||
init()
|
||||
@@ -98,6 +98,10 @@ class Model:
|
||||
def nz(self, value: int):
|
||||
self.G.nz = value
|
||||
|
||||
@property
|
||||
def cells(self) -> np.uint64:
|
||||
return np.prod(self.G.size, dtype=np.uint64)
|
||||
|
||||
@property
|
||||
def dx(self) -> float:
|
||||
return self.G.dl[0]
|
||||
@@ -472,10 +476,16 @@ class Model:
|
||||
|
||||
# Print information about and check OpenMP threads
|
||||
if config.sim_config.general["solver"] == "cpu":
|
||||
if config.sim_config.mpi:
|
||||
backend = "MPI+OpenMP"
|
||||
layout = f"{np.prod(config.sim_config.mpi)} MPI rank(s) and {config.get_model_config().ompthreads} thread(s) per rank"
|
||||
else:
|
||||
backend = "OpenMP"
|
||||
layout = f"{config.get_model_config().ompthreads} thread(s)"
|
||||
logger.basic(
|
||||
f"Model {config.sim_config.current_model + 1}/{config.sim_config.model_end} "
|
||||
f"on {config.sim_config.hostinfo['hostname']} "
|
||||
f"with OpenMP backend using {config.get_model_config().ompthreads} thread(s)"
|
||||
f"with {backend} backend using {layout}"
|
||||
)
|
||||
if config.get_model_config().ompthreads > config.sim_config.hostinfo["physicalcores"]:
|
||||
logger.warning(
|
||||
|
@@ -7,11 +7,11 @@ from mpi4py import MPI
|
||||
|
||||
from gprMax import config
|
||||
from gprMax.fields_outputs import write_hdf5_outputfile
|
||||
from gprMax.geometry_outputs.geometry_objects import MPIGeometryObject
|
||||
from gprMax.geometry_outputs.geometry_view_lines import MPIGeometryViewLines
|
||||
from gprMax.geometry_outputs.geometry_view_voxels import MPIGeometryViewVoxels
|
||||
from gprMax.grid.mpi_grid import MPIGrid
|
||||
from gprMax.model import Model
|
||||
from gprMax.output_controllers.geometry_objects import MPIGeometryObject
|
||||
from gprMax.output_controllers.geometry_view_lines import MPIGeometryViewLines
|
||||
from gprMax.output_controllers.geometry_view_voxels import MPIGeometryViewVoxels
|
||||
from gprMax.snapshots import MPISnapshot, Snapshot, save_snapshots
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
@@ -1,5 +1,5 @@
|
||||
# Copyright (C) 2015-2025: The University of Edinburgh, United Kingdom
|
||||
# Authors: Craig Warren, Antonis Giannopoulos, John Hartley,
|
||||
# Authors: Craig Warren, Antonis Giannopoulos, John Hartley,
|
||||
# and Nathan Mannall
|
||||
#
|
||||
# This file is part of gprMax.
|
||||
@@ -57,7 +57,7 @@ class Scene:
|
||||
|
||||
Args:
|
||||
user_object: user object to add to the scene. For example,
|
||||
`gprMax.user_objects.cmds_singleuse.Domain`
|
||||
`gprMax.Domain`
|
||||
"""
|
||||
# Check for
|
||||
if isinstance(user_object, SubGridUserBase):
|
||||
|
@@ -1,5 +1,5 @@
|
||||
# Copyright (C) 2015-2025: The University of Edinburgh, United Kingdom
|
||||
# Authors: Craig Warren, Antonis Giannopoulos, John Hartley,
|
||||
# Authors: Craig Warren, Antonis Giannopoulos, John Hartley,
|
||||
# and Nathan Mannall
|
||||
#
|
||||
# This file is part of gprMax.
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
import logging
|
||||
import sys
|
||||
from enum import IntEnum, unique
|
||||
from pathlib import Path
|
||||
from typing import Dict, Generic, List
|
||||
|
||||
@@ -30,8 +29,9 @@ from mpi4py import MPI
|
||||
from tqdm import tqdm
|
||||
|
||||
import gprMax.config as config
|
||||
from gprMax.geometry_outputs.grid_view import GridType, GridView, MPIGridView
|
||||
from gprMax.grid.mpi_grid import MPIGrid
|
||||
from gprMax.output_controllers.grid_view import GridType, GridView, MPIGridView
|
||||
from gprMax.utilities.mpi import Dim, Dir
|
||||
|
||||
from ._version import __version__
|
||||
from .cython.snapshots import calculate_snapshot_fields
|
||||
@@ -305,19 +305,6 @@ class Snapshot(Generic[GridType]):
|
||||
f.close()
|
||||
|
||||
|
||||
@unique
|
||||
class Dim(IntEnum):
|
||||
X = 0
|
||||
Y = 1
|
||||
Z = 2
|
||||
|
||||
|
||||
@unique
|
||||
class Dir(IntEnum):
|
||||
NEG = 0
|
||||
POS = 1
|
||||
|
||||
|
||||
class MPISnapshot(Snapshot[MPIGrid]):
|
||||
H_TAG = 0
|
||||
EX_TAG = 1
|
||||
|
@@ -21,7 +21,8 @@ import logging
|
||||
|
||||
import numpy as np
|
||||
|
||||
from gprMax.fractals import FractalSurface, Grass
|
||||
from gprMax.fractals.fractal_surface import FractalSurface
|
||||
from gprMax.fractals.grass import Grass
|
||||
from gprMax.grid.fdtd_grid import FDTDGrid
|
||||
from gprMax.materials import create_grass
|
||||
from gprMax.user_objects.rotatable import RotatableMixin
|
||||
@@ -93,134 +94,106 @@ class AddGrass(RotatableMixin, GeometryUserObject):
|
||||
|
||||
# Get the correct fractal volume
|
||||
volumes = [volume for volume in grid.fractalvolumes if volume.ID == fractal_box_id]
|
||||
try:
|
||||
if volumes:
|
||||
volume = volumes[0]
|
||||
except NameError:
|
||||
logger.exception(f"{self.__str__()} cannot find FractalBox {fractal_box_id}")
|
||||
raise
|
||||
else:
|
||||
raise ValueError(f"{self.__str__()} cannot find FractalBox {fractal_box_id}")
|
||||
|
||||
uip = self._create_uip(grid)
|
||||
_, p1, p2 = uip.check_box_points(p1, p2, self.__str__())
|
||||
xs, ys, zs = p1
|
||||
xf, yf, zf = p2
|
||||
discretised_p1, discretised_p2 = uip.check_output_object_bounds(p1, p2, self.__str__())
|
||||
xs, ys, zs = discretised_p1
|
||||
xf, yf, zf = discretised_p2
|
||||
|
||||
if frac_dim < 0:
|
||||
logger.exception(
|
||||
raise ValueError(
|
||||
f"{self.__str__()} requires a positive value for the fractal dimension"
|
||||
)
|
||||
raise ValueError
|
||||
if limits[0] < 0 or limits[1] < 0:
|
||||
logger.exception(
|
||||
raise ValueError(
|
||||
f"{self.__str__()} requires a positive value for the minimum and maximum heights for grass blades"
|
||||
)
|
||||
raise ValueError
|
||||
|
||||
# Check for valid orientations
|
||||
if np.count_nonzero(discretised_p1 == discretised_p2) != 1:
|
||||
raise ValueError(f"{self.__str__()} dimensions are not specified correctly")
|
||||
|
||||
if xs == xf:
|
||||
if ys == yf or zs == zf:
|
||||
logger.exception(f"{self.__str__()} dimensions are not specified correctly")
|
||||
raise ValueError
|
||||
if xs not in [volume.xs, volume.xf]:
|
||||
logger.exception(
|
||||
f"{self.__str__()} must specify external surfaces on a fractal box"
|
||||
)
|
||||
raise ValueError
|
||||
fractalrange = (
|
||||
round_value(limits[0] / grid.dx),
|
||||
round_value(limits[1] / grid.dx),
|
||||
)
|
||||
# xminus surface
|
||||
if xs == volume.xs:
|
||||
logger.exception(
|
||||
raise ValueError(
|
||||
f"{self.__str__()} grass can only be specified on surfaces in the positive axis direction"
|
||||
)
|
||||
raise ValueError
|
||||
# xplus surface
|
||||
elif xf == volume.xf:
|
||||
if fractalrange[1] > grid.nx:
|
||||
logger.exception(
|
||||
f"{self.__str__()} cannot apply grass to "
|
||||
"fractal box as it would exceed the domain "
|
||||
"size in the x direction"
|
||||
)
|
||||
raise ValueError
|
||||
lower_bound = uip.discretise_point((limits[0], 0, 0))
|
||||
upper_bound = uip.discretise_point((limits[1], p2[1], p2[2]))
|
||||
uip.point_within_bounds(upper_bound, self.__str__())
|
||||
fractalrange = (lower_bound[0], upper_bound[0])
|
||||
requestedsurface = "xplus"
|
||||
else:
|
||||
raise ValueError(
|
||||
f"{self.__str__()} must specify external surfaces on a fractal box"
|
||||
)
|
||||
|
||||
elif ys == yf:
|
||||
if zs == zf:
|
||||
logger.exception(f"{self.__str__()} dimensions are not specified correctly")
|
||||
raise ValueError
|
||||
if ys not in [volume.ys, volume.yf]:
|
||||
logger.exception(
|
||||
f"{self.__str__()} must specify external surfaces on a fractal box"
|
||||
)
|
||||
raise ValueError
|
||||
fractalrange = (
|
||||
round_value(limits[0] / grid.dy),
|
||||
round_value(limits[1] / grid.dy),
|
||||
)
|
||||
# yminus surface
|
||||
if ys == volume.ys:
|
||||
logger.exception(
|
||||
raise ValueError(
|
||||
f"{self.__str__()} grass can only be specified on surfaces in the positive axis direction"
|
||||
)
|
||||
raise ValueError
|
||||
# yplus surface
|
||||
elif yf == volume.yf:
|
||||
if fractalrange[1] > grid.ny:
|
||||
logger.exception(
|
||||
f"{self.__str__()} cannot apply grass to "
|
||||
"fractal box as it would exceed the domain "
|
||||
"size in the y direction"
|
||||
)
|
||||
raise ValueError
|
||||
lower_bound = uip.discretise_point((0, limits[0], 0))
|
||||
upper_bound = uip.discretise_point((p2[0], limits[1], p2[2]))
|
||||
uip.point_within_bounds(upper_bound, self.__str__())
|
||||
fractalrange = (lower_bound[1], upper_bound[1])
|
||||
requestedsurface = "yplus"
|
||||
|
||||
elif zs == zf:
|
||||
if zs not in [volume.zs, volume.zf]:
|
||||
logger.exception(
|
||||
else:
|
||||
raise ValueError(
|
||||
f"{self.__str__()} must specify external surfaces on a fractal box"
|
||||
)
|
||||
raise ValueError
|
||||
fractalrange = (
|
||||
round_value(limits[0] / grid.dz),
|
||||
round_value(limits[1] / grid.dz),
|
||||
)
|
||||
|
||||
elif zs == zf:
|
||||
# zminus surface
|
||||
if zs == volume.zs:
|
||||
logger.exception(
|
||||
raise ValueError(
|
||||
f"{self.__str__()} grass can only be specified on surfaces in the positive axis direction"
|
||||
)
|
||||
raise ValueError
|
||||
# zplus surface
|
||||
elif zf == volume.zf:
|
||||
if fractalrange[1] > grid.nz:
|
||||
logger.exception(
|
||||
f"{self.__str__()} cannot apply grass to "
|
||||
"fractal box as it would exceed the domain "
|
||||
"size in the z direction"
|
||||
)
|
||||
raise ValueError
|
||||
lower_bound = uip.discretise_point((0, 0, limits[0]))
|
||||
upper_bound = uip.discretise_point((p2[0], p2[1], limits[1]))
|
||||
uip.point_within_bounds(upper_bound, self.__str__())
|
||||
fractalrange = (lower_bound[2], upper_bound[2])
|
||||
requestedsurface = "zplus"
|
||||
|
||||
else:
|
||||
raise ValueError(
|
||||
f"{self.__str__()} must specify external surfaces on a fractal box"
|
||||
)
|
||||
else:
|
||||
logger.exception(f"{self.__str__()} dimensions are not specified correctly")
|
||||
raise ValueError
|
||||
raise ValueError(f"{self.__str__()} dimensions are not specified correctly")
|
||||
|
||||
surface = FractalSurface(xs, xf, ys, yf, zs, zf, frac_dim, seed)
|
||||
surface = grid.create_fractal_surface(xs, xf, ys, yf, zs, zf, frac_dim, seed)
|
||||
surface.ID = "grass"
|
||||
surface.surfaceID = requestedsurface
|
||||
|
||||
# Create grass geometry parameters
|
||||
# Add grass to the surface here as an MPIFractalSurface needs to
|
||||
# know if grass is present when generate_fractal_surface() is
|
||||
# called
|
||||
g = Grass(n_blades, surface.seed)
|
||||
surface.grass.append(g)
|
||||
|
||||
# Set the fractal range to scale the fractal distribution between zero and one
|
||||
surface.fractalrange = (0, 1)
|
||||
surface.operatingonID = volume.ID
|
||||
surface.generate_fractal_surface()
|
||||
if not surface.generate_fractal_surface():
|
||||
return
|
||||
if n_blades > surface.fractalsurface.shape[0] * surface.fractalsurface.shape[1]:
|
||||
logger.exception(
|
||||
raise ValueError(
|
||||
f"{self.__str__()} the specified surface is not large "
|
||||
"enough for the number of grass blades/roots specified"
|
||||
)
|
||||
raise ValueError
|
||||
|
||||
# Scale the distribution so that the summation is equal to one,
|
||||
# i.e. a probability distribution
|
||||
@@ -255,10 +228,6 @@ class AddGrass(RotatableMixin, GeometryUserObject):
|
||||
surface.fractalrange[0], surface.fractalrange[1], size=1
|
||||
)
|
||||
|
||||
# Create grass geometry parameters
|
||||
g = Grass(n_blades, surface.seed)
|
||||
surface.grass.append(g)
|
||||
|
||||
# Check to see if grass has been already defined as a material
|
||||
if not any(x.ID == "grass" for x in grid.materials):
|
||||
create_grass(grid)
|
||||
@@ -267,18 +236,20 @@ class AddGrass(RotatableMixin, GeometryUserObject):
|
||||
grass = next((x for x in grid.materials if x.ID == "grass"))
|
||||
testgrass = next((x for x in grass.tau if x < grid.dt), None)
|
||||
if testgrass:
|
||||
logger.exception(
|
||||
raise ValueError(
|
||||
f"{self.__str__()} requires the time step for the "
|
||||
"model to be less than the relaxation time required to model grass."
|
||||
)
|
||||
raise ValueError
|
||||
|
||||
volume.fractalsurfaces.append(surface)
|
||||
|
||||
p3 = uip.round_to_grid_static_point(p1)
|
||||
p4 = uip.round_to_grid_static_point(p2)
|
||||
|
||||
logger.info(
|
||||
f"{self.grid_name(grid)}{n_blades} blades of grass on surface from "
|
||||
f"{xs * grid.dx:g}m, {ys * grid.dy:g}m, {zs * grid.dz:g}m, "
|
||||
f"to {xf * grid.dx:g}m, {yf * grid.dy:g}m, {zf * grid.dz:g}m "
|
||||
f"{p3[0]:g}m, {p3[1]:g}m, {p3[2]:g}m, "
|
||||
f"to {p4[0]:g}m, {p4[1]:g}m, {p4[2]:g}m "
|
||||
f"with fractal dimension {surface.dimension:g}, fractal seeding "
|
||||
f"{surface.seed}, and range {limits[0]:g}m to {limits[1]:g}m, "
|
||||
f"added to {surface.operatingonID}."
|
||||
|
@@ -21,11 +21,9 @@ import logging
|
||||
|
||||
import numpy as np
|
||||
|
||||
from gprMax.fractals import FractalSurface
|
||||
from gprMax.grid.fdtd_grid import FDTDGrid
|
||||
from gprMax.user_objects.rotatable import RotatableMixin
|
||||
from gprMax.user_objects.user_objects import GeometryUserObject
|
||||
from gprMax.utilities.utilities import round_value
|
||||
|
||||
from .cmds_geometry import rotate_2point_object
|
||||
|
||||
@@ -38,18 +36,19 @@ class AddSurfaceRoughness(RotatableMixin, GeometryUserObject):
|
||||
Attributes:
|
||||
p1: list of the lower left (x,y,z) coordinates of a surface on a
|
||||
FractalBox class.
|
||||
p2: list of the upper right (x,y,z) coordinates of a surface on a
|
||||
FractalBox class.
|
||||
frac_dim: float for the fractal dimension which, for an orthogonal
|
||||
parallelepiped, should take values between zero and three.
|
||||
weighting: list with weightings in the first and second direction of
|
||||
the surface.
|
||||
limits: ist to define lower and upper limits for a range over which
|
||||
the surface roughness can vary.
|
||||
fractal_box_id: string identifier for the FractalBox class
|
||||
that the surface roughness should be applied to.
|
||||
seed: (optional) float parameter which controls the seeding of the random
|
||||
number generator used to create the fractals.
|
||||
p2: list of the upper right (x,y,z) coordinates of a surface on
|
||||
a FractalBox class.
|
||||
frac_dim: float for the fractal dimension which, for an
|
||||
orthogonal parallelepiped, should take values between zero
|
||||
and three.
|
||||
weighting: list with weightings in the first and second
|
||||
direction of the surface.
|
||||
limits: list to define lower and upper limits for a range over
|
||||
which the surface roughness can vary.
|
||||
fractal_box_id: string identifier for the FractalBox class that
|
||||
the surface roughness should be applied to.
|
||||
seed: (optional) float parameter which controls the seeding of
|
||||
the random number generator used to create the fractals.
|
||||
"""
|
||||
|
||||
@property
|
||||
@@ -96,145 +95,111 @@ class AddSurfaceRoughness(RotatableMixin, GeometryUserObject):
|
||||
if volumes:
|
||||
volume = volumes[0]
|
||||
else:
|
||||
logger.exception(f"{self.__str__()} cannot find FractalBox {fractal_box_id}")
|
||||
raise ValueError
|
||||
raise ValueError(f"{self.__str__()} cannot find FractalBox {fractal_box_id}")
|
||||
|
||||
uip = self._create_uip(grid)
|
||||
_, p1, p2 = uip.check_box_points(p1, p2, self.__str__())
|
||||
xs, ys, zs = p1
|
||||
xf, yf, zf = p2
|
||||
discretised_p1, discretised_p2 = uip.check_output_object_bounds(p1, p2, self.__str__())
|
||||
xs, ys, zs = discretised_p1
|
||||
xf, yf, zf = discretised_p2
|
||||
|
||||
if frac_dim < 0:
|
||||
logger.exception(
|
||||
raise ValueError(
|
||||
f"{self.__str__()} requires a positive value for the fractal dimension"
|
||||
)
|
||||
raise ValueError
|
||||
if weighting[0] < 0:
|
||||
logger.exception(
|
||||
f"{self.__str__()} requires a positive value for the "
|
||||
"fractal weighting in the first direction of the surface"
|
||||
raise ValueError(
|
||||
f"{self.__str__()} requires a positive value for the fractal weighting in the first"
|
||||
" direction of the surface"
|
||||
)
|
||||
raise ValueError
|
||||
if weighting[1] < 0:
|
||||
logger.exception(
|
||||
f"{self.__str__()} requires a positive value for the "
|
||||
"fractal weighting in the second direction of the surface"
|
||||
raise ValueError(
|
||||
f"{self.__str__()} requires a positive value for the fractal weighting in the"
|
||||
" second direction of the surface"
|
||||
)
|
||||
raise ValueError
|
||||
|
||||
# Check for valid orientations
|
||||
if np.count_nonzero(discretised_p1 == discretised_p2) != 1:
|
||||
raise ValueError(f"{self.__str__()} dimensions are not specified correctly")
|
||||
|
||||
if xs == xf:
|
||||
if ys == yf or zs == zf:
|
||||
logger.exception(f"{self.__str__()} dimensions are not specified correctly")
|
||||
raise ValueError
|
||||
if xs not in [volume.xs, volume.xf]:
|
||||
logger.exception(
|
||||
f"{self.__str__()} can only be used on the external surfaces of a fractal box"
|
||||
)
|
||||
raise ValueError
|
||||
fractalrange = (
|
||||
round_value(limits[0] / grid.dx),
|
||||
round_value(limits[1] / grid.dx),
|
||||
)
|
||||
# xminus surface
|
||||
if xs == volume.xs:
|
||||
if fractalrange[0] < 0 or fractalrange[1] > volume.xf:
|
||||
logger.exception(
|
||||
f"{self.__str__()} cannot apply fractal surface "
|
||||
"to fractal box as it would exceed either the "
|
||||
"upper coordinates of the fractal box or the "
|
||||
"domain in the x direction"
|
||||
)
|
||||
raise ValueError
|
||||
lower_bound = discretised_p1
|
||||
upper_bound = uip.discretise_point((limits[1], p2[1], p2[2]))
|
||||
grid_bound = uip.discretise_point((limits[0], p1[1], p1[2]))
|
||||
fractalrange = (grid_bound[0], upper_bound[0])
|
||||
requestedsurface = "xminus"
|
||||
# xplus surface
|
||||
elif xf == volume.xf:
|
||||
if fractalrange[0] < volume.xs or fractalrange[1] > grid.nx:
|
||||
logger.exception(
|
||||
f"{self.__str__()} cannot apply fractal surface "
|
||||
"to fractal box as it would exceed either the "
|
||||
"lower coordinates of the fractal box or the "
|
||||
"domain in the x direction"
|
||||
)
|
||||
raise ValueError
|
||||
lower_bound = uip.discretise_point((limits[0], p1[1], p1[2]))
|
||||
upper_bound = discretised_p2
|
||||
grid_bound = uip.discretise_point((limits[1], p2[1], p2[2]))
|
||||
fractalrange = (lower_bound[0], grid_bound[0])
|
||||
requestedsurface = "xplus"
|
||||
|
||||
elif ys == yf:
|
||||
if zs == zf:
|
||||
logger.exception(f"{self.__str__()} dimensions are not specified correctly")
|
||||
raise ValueError
|
||||
if ys not in [volume.ys, volume.yf]:
|
||||
logger.exception(
|
||||
f"{self.__str__()} can only be used on the external "
|
||||
+ "surfaces of a fractal box"
|
||||
else:
|
||||
raise ValueError(
|
||||
f"{self.__str__()} can only be used on the external surfaces of a fractal box"
|
||||
)
|
||||
raise ValueError
|
||||
fractalrange = (
|
||||
round_value(limits[0] / grid.dy),
|
||||
round_value(limits[1] / grid.dy),
|
||||
)
|
||||
elif ys == yf:
|
||||
# yminus surface
|
||||
if ys == volume.ys:
|
||||
if fractalrange[0] < 0 or fractalrange[1] > volume.yf:
|
||||
logger.exception(
|
||||
f"{self.__str__()} cannot apply fractal surface "
|
||||
"to fractal box as it would exceed either the "
|
||||
"upper coordinates of the fractal box or the "
|
||||
"domain in the y direction"
|
||||
)
|
||||
raise ValueError
|
||||
lower_bound = discretised_p1
|
||||
upper_bound = uip.discretise_point((p2[0], limits[1], p2[2]))
|
||||
grid_bound = uip.discretise_point((p1[0], limits[0], p1[2]))
|
||||
fractalrange = (grid_bound[1], upper_bound[1])
|
||||
requestedsurface = "yminus"
|
||||
# yplus surface
|
||||
elif yf == volume.yf:
|
||||
if fractalrange[0] < volume.ys or fractalrange[1] > grid.ny:
|
||||
logger.exception(
|
||||
f"{self.__str__()} cannot apply fractal surface "
|
||||
"to fractal box as it would exceed either the "
|
||||
"lower coordinates of the fractal box or the "
|
||||
"domain in the y direction"
|
||||
)
|
||||
raise ValueError
|
||||
lower_bound = uip.discretise_point((p1[0], limits[0], p1[2]))
|
||||
upper_bound = discretised_p2
|
||||
grid_bound = uip.discretise_point((p2[0], limits[1], p2[2]))
|
||||
fractalrange = (lower_bound[1], grid_bound[1])
|
||||
requestedsurface = "yplus"
|
||||
|
||||
elif zs == zf:
|
||||
if zs not in [volume.zs, volume.zf]:
|
||||
logger.exception(
|
||||
f"{self.__str__()} can only be used on the external "
|
||||
+ "surfaces of a fractal box"
|
||||
else:
|
||||
raise ValueError(
|
||||
f"{self.__str__()} can only be used on the external surfaces of a fractal box"
|
||||
)
|
||||
raise ValueError
|
||||
fractalrange = (
|
||||
round_value(limits[0] / grid.dz),
|
||||
round_value(limits[1] / grid.dz),
|
||||
)
|
||||
elif zs == zf:
|
||||
# zminus surface
|
||||
if zs == volume.zs:
|
||||
if fractalrange[0] < 0 or fractalrange[1] > volume.zf:
|
||||
logger.exception(
|
||||
f"{self.__str__()} cannot apply fractal surface "
|
||||
"to fractal box as it would exceed either the "
|
||||
"upper coordinates of the fractal box or the "
|
||||
"domain in the x direction"
|
||||
)
|
||||
raise ValueError
|
||||
lower_bound = discretised_p1
|
||||
upper_bound = uip.discretise_point((p2[0], p2[1], limits[1]))
|
||||
grid_bound = uip.discretise_point((p1[0], p1[1], limits[0]))
|
||||
fractalrange = (grid_bound[2], upper_bound[2])
|
||||
requestedsurface = "zminus"
|
||||
# zplus surface
|
||||
elif zf == volume.zf:
|
||||
if fractalrange[0] < volume.zs or fractalrange[1] > grid.nz:
|
||||
logger.exception(
|
||||
f"{self.__str__()} cannot apply fractal surface "
|
||||
"to fractal box as it would exceed either the "
|
||||
"lower coordinates of the fractal box or the "
|
||||
"domain in the z direction"
|
||||
)
|
||||
raise ValueError
|
||||
lower_bound = uip.discretise_point((p1[0], p1[1], limits[0]))
|
||||
upper_bound = discretised_p2
|
||||
grid_bound = uip.discretise_point((p2[0], p2[1], limits[1]))
|
||||
fractalrange = (lower_bound[2], grid_bound[2])
|
||||
requestedsurface = "zplus"
|
||||
|
||||
else:
|
||||
raise ValueError(
|
||||
f"{self.__str__()} can only be used on the external surfaces of a fractal box"
|
||||
)
|
||||
else:
|
||||
logger.exception(f"{self.__str__()} dimensions are not specified correctly")
|
||||
raise ValueError
|
||||
raise ValueError(f"{self.__str__()} dimensions are not specified correctly")
|
||||
|
||||
surface = FractalSurface(xs, xf, ys, yf, zs, zf, frac_dim, seed)
|
||||
if any(lower_bound < volume.start):
|
||||
raise ValueError(
|
||||
f"{self.__str__()} cannot apply fractal surface to"
|
||||
" fractal box as it would exceed the lower coordinates"
|
||||
" of the fractal box."
|
||||
)
|
||||
elif any(upper_bound > volume.stop):
|
||||
raise ValueError(
|
||||
f"{self.__str__()} cannot apply fractal surface to"
|
||||
" fractal box as it would exceed the upper coordinates"
|
||||
" of the fractal box."
|
||||
)
|
||||
|
||||
# Check lower or upper extent of the fractal surface (depending
|
||||
# if the fractal surface has been applied in the minus or plus
|
||||
# direction).
|
||||
uip.point_within_bounds(grid_bound, f"{self.__str__()}")
|
||||
|
||||
surface = grid.create_fractal_surface(xs, xf, ys, yf, zs, zf, frac_dim, seed)
|
||||
surface.surfaceID = requestedsurface
|
||||
surface.fractalrange = fractalrange
|
||||
surface.operatingonID = volume.ID
|
||||
@@ -243,18 +208,21 @@ class AddSurfaceRoughness(RotatableMixin, GeometryUserObject):
|
||||
# List of existing surfaces IDs
|
||||
existingsurfaceIDs = [x.surfaceID for x in volume.fractalsurfaces]
|
||||
if surface.surfaceID in existingsurfaceIDs:
|
||||
logger.exception(
|
||||
raise ValueError(
|
||||
f"{self.__str__()} has already been used on the {surface.surfaceID} surface"
|
||||
)
|
||||
raise ValueError
|
||||
|
||||
surface.generate_fractal_surface()
|
||||
|
||||
volume.fractalsurfaces.append(surface)
|
||||
|
||||
p3 = uip.round_to_grid_static_point(p1)
|
||||
p4 = uip.round_to_grid_static_point(p2)
|
||||
|
||||
logger.info(
|
||||
f"{self.grid_name(grid)}Fractal surface from {xs * grid.dx:g}m, "
|
||||
f"{ys * grid.dy:g}m, {zs * grid.dz:g}m, to {xf * grid.dx:g}m, "
|
||||
f"{yf * grid.dy:g}m, {zf * grid.dz:g}m with fractal dimension "
|
||||
f"{self.grid_name(grid)}Fractal surface from {p3[0]:g}m, "
|
||||
f"{p3[1]:g}m, {p3[2]:g}m, to {p4[0]:g}m, "
|
||||
f"{p4[1]:g}m, {p4[2]:g}m with fractal dimension "
|
||||
f"{surface.dimension:g}, fractal weightings {surface.weighting[0]:g}, "
|
||||
f"{surface.weighting[1]:g}, fractal seeding {surface.seed}, "
|
||||
f"and range {limits[0]:g}m to {limits[1]:g}m, added to "
|
||||
|
@@ -25,7 +25,6 @@ from gprMax.grid.fdtd_grid import FDTDGrid
|
||||
from gprMax.materials import create_water
|
||||
from gprMax.user_objects.rotatable import RotatableMixin
|
||||
from gprMax.user_objects.user_objects import GeometryUserObject
|
||||
from gprMax.utilities.utilities import round_value
|
||||
|
||||
from .cmds_geometry import rotate_2point_object
|
||||
|
||||
@@ -78,80 +77,70 @@ class AddSurfaceWater(RotatableMixin, GeometryUserObject):
|
||||
if volumes := [volume for volume in grid.fractalvolumes if volume.ID == fractal_box_id]:
|
||||
volume = volumes[0]
|
||||
else:
|
||||
logger.exception(f"{self.__str__()} cannot find FractalBox {fractal_box_id}")
|
||||
raise ValueError
|
||||
raise ValueError(f"{self.__str__()} cannot find FractalBox {fractal_box_id}")
|
||||
|
||||
uip = self._create_uip(grid)
|
||||
_, p1, p2 = uip.check_box_points(p1, p2, self.__str__())
|
||||
xs, ys, zs = p1
|
||||
xf, yf, zf = p2
|
||||
discretised_p1, discretised_p2 = uip.check_output_object_bounds(p1, p2, self.__str__())
|
||||
xs, ys, zs = discretised_p1
|
||||
xf, yf, zf = discretised_p2
|
||||
|
||||
if depth <= 0:
|
||||
logger.exception(f"{self.__str__()} requires a positive value for the depth of water")
|
||||
raise ValueError
|
||||
raise ValueError(f"{self.__str__()} requires a positive value for the depth of water")
|
||||
|
||||
# Check for valid orientations
|
||||
if np.count_nonzero(discretised_p1 == discretised_p2) != 1:
|
||||
raise ValueError(f"{self.__str__()} dimensions are not specified correctly")
|
||||
|
||||
if xs == xf:
|
||||
if ys == yf or zs == zf:
|
||||
logger.exception(f"{self.__str__()} dimensions are not specified correctly")
|
||||
raise ValueError
|
||||
if xs not in [volume.xs, volume.xf]:
|
||||
logger.exception(
|
||||
f"{self.__str__()} can only be used on the external surfaces of a fractal box"
|
||||
)
|
||||
raise ValueError
|
||||
# xminus surface
|
||||
if xs == volume.xs:
|
||||
requestedsurface = "xminus"
|
||||
# xplus surface
|
||||
elif xf == volume.xf:
|
||||
requestedsurface = "xplus"
|
||||
filldepthcells = round_value(depth / grid.dx)
|
||||
filldepth = filldepthcells * grid.dx
|
||||
|
||||
elif ys == yf:
|
||||
if zs == zf:
|
||||
logger.exception(f"{self.__str__()} dimensions are not specified correctly")
|
||||
raise ValueError
|
||||
if ys not in [volume.ys, volume.yf]:
|
||||
logger.exception(
|
||||
else:
|
||||
raise ValueError(
|
||||
f"{self.__str__()} can only be used on the external surfaces of a fractal box"
|
||||
)
|
||||
raise ValueError
|
||||
filldepthcells = uip.discretise_point((depth, 0, 0))[0]
|
||||
filldepth = uip.round_to_grid_static_point((depth, 0, 0))[0]
|
||||
|
||||
elif ys == yf:
|
||||
# yminus surface
|
||||
if ys == volume.ys:
|
||||
requestedsurface = "yminus"
|
||||
# yplus surface
|
||||
elif yf == volume.yf:
|
||||
requestedsurface = "yplus"
|
||||
filldepthcells = round_value(depth / grid.dy)
|
||||
filldepth = filldepthcells * grid.dy
|
||||
|
||||
elif zs == zf:
|
||||
if zs not in [volume.zs, volume.zf]:
|
||||
logger.exception(
|
||||
else:
|
||||
raise ValueError(
|
||||
f"{self.__str__()} can only be used on the external surfaces of a fractal box"
|
||||
)
|
||||
raise ValueError
|
||||
filldepthcells = uip.discretise_point((0, depth, 0))[1]
|
||||
filldepth = uip.round_to_grid_static_point((0, depth, 0))[1]
|
||||
|
||||
elif zs == zf:
|
||||
# zminus surface
|
||||
if zs == volume.zs:
|
||||
requestedsurface = "zminus"
|
||||
# zplus surface
|
||||
elif zf == volume.zf:
|
||||
requestedsurface = "zplus"
|
||||
filldepthcells = round_value(depth / grid.dz)
|
||||
filldepth = filldepthcells * grid.dz
|
||||
else:
|
||||
raise ValueError(
|
||||
f"{self.__str__()} can only be used on the external surfaces of a fractal box"
|
||||
)
|
||||
filldepthcells = uip.discretise_point((0, 0, depth))[2]
|
||||
filldepth = uip.round_to_grid_static_point((0, 0, depth))[2]
|
||||
|
||||
else:
|
||||
logger.exception(f"{self.__str__()} dimensions are not specified correctly")
|
||||
raise ValueError
|
||||
raise ValueError(f"{self.__str__()} dimensions are not specified correctly")
|
||||
|
||||
surface = next((x for x in volume.fractalsurfaces if x.surfaceID == requestedsurface), None)
|
||||
if not surface:
|
||||
logger.exception(
|
||||
raise ValueError(
|
||||
f"{self.__str__()} specified surface {requestedsurface} does not have a rough surface applied"
|
||||
)
|
||||
raise ValueError
|
||||
|
||||
surface.filldepth = filldepthcells
|
||||
|
||||
@@ -160,11 +149,10 @@ class AddSurfaceWater(RotatableMixin, GeometryUserObject):
|
||||
surface.filldepth < surface.fractalrange[0]
|
||||
or surface.filldepth > surface.fractalrange[1]
|
||||
):
|
||||
logger.exception(
|
||||
raise ValueError(
|
||||
f"{self.__str__()} requires a value for the depth of water that lies with the "
|
||||
f"range of the requested surface roughness"
|
||||
)
|
||||
raise ValueError
|
||||
|
||||
# Check to see if water has been already defined as a material
|
||||
if not any(x.ID == "water" for x in grid.materials):
|
||||
@@ -173,15 +161,17 @@ class AddSurfaceWater(RotatableMixin, GeometryUserObject):
|
||||
# Check if time step for model is suitable for using water
|
||||
water = next((x for x in grid.materials if x.ID == "water"))
|
||||
if testwater := next((x for x in water.tau if x < grid.dt), None):
|
||||
logger.exception(
|
||||
raise ValueError(
|
||||
f"{self.__str__()} requires the time step for the model "
|
||||
f"to be less than the relaxation time required to model water."
|
||||
)
|
||||
raise ValueError
|
||||
|
||||
p3 = uip.round_to_grid_static_point(p1)
|
||||
p4 = uip.round_to_grid_static_point(p2)
|
||||
|
||||
logger.info(
|
||||
f"{self.grid_name(grid)}Water on surface from {xs * grid.dx:g}m, "
|
||||
f"{ys * grid.dy:g}m, {zs * grid.dz:g}m, to {xf * grid.dx:g}m, "
|
||||
f"{yf * grid.dy:g}m, {zf * grid.dz:g}m with depth {filldepth:g}m, "
|
||||
f"added to {surface.operatingonID}."
|
||||
f"{self.grid_name(grid)}Water on surface from {p3[0]:g}m,"
|
||||
f" {p3[1]:g}m, {p3[2]:g}m, to {p4[0]:g}m, {p4[1]:g}m,"
|
||||
f" {p4[2]:g}m with depth {filldepth:g}m, added to"
|
||||
f" {surface.operatingonID}."
|
||||
)
|
||||
|
@@ -23,7 +23,6 @@ import numpy as np
|
||||
|
||||
import gprMax.config as config
|
||||
from gprMax.cython.geometry_primitives import build_voxels_from_array, build_voxels_from_array_mask
|
||||
from gprMax.fractals import FractalVolume
|
||||
from gprMax.grid.fdtd_grid import FDTDGrid
|
||||
from gprMax.materials import ListMaterial
|
||||
from gprMax.user_objects.cmds_geometry.cmds_geometry import check_averaging, rotate_2point_object
|
||||
@@ -111,38 +110,29 @@ class FractalBox(RotatableMixin, GeometryUserObject):
|
||||
p3 = uip.round_to_grid_static_point(p1)
|
||||
p4 = uip.round_to_grid_static_point(p2)
|
||||
|
||||
grid_contains_fractal_box, p1, p2 = uip.check_box_points(p1, p2, self.__str__())
|
||||
|
||||
# Exit early if none of the fractal box is in this grid as there
|
||||
# is nothing else to do.
|
||||
if not grid_contains_fractal_box:
|
||||
return
|
||||
p1, p2 = uip.check_output_object_bounds(p1, p2, self.__str__())
|
||||
|
||||
xs, ys, zs = p1
|
||||
xf, yf, zf = p2
|
||||
|
||||
if frac_dim < 0:
|
||||
logger.exception(
|
||||
raise ValueError(
|
||||
f"{self.__str__()} requires a positive value for the fractal dimension"
|
||||
)
|
||||
raise ValueError
|
||||
if weighting[0] < 0:
|
||||
logger.exception(
|
||||
raise ValueError(
|
||||
f"{self.__str__()} requires a positive value for the fractal weighting in the x direction"
|
||||
)
|
||||
raise ValueError
|
||||
if weighting[1] < 0:
|
||||
logger.exception(
|
||||
raise ValueError(
|
||||
f"{self.__str__()} requires a positive value for the fractal weighting in the y direction"
|
||||
)
|
||||
raise ValueError
|
||||
if weighting[2] < 0:
|
||||
logger.exception(
|
||||
raise ValueError(
|
||||
f"{self.__str__()} requires a positive value for the fractal weighting in the z direction"
|
||||
)
|
||||
if n_materials < 0:
|
||||
logger.exception(f"{self.__str__()} requires a positive value for the number of bins")
|
||||
raise ValueError
|
||||
raise ValueError(f"{self.__str__()} requires a positive value for the number of bins")
|
||||
|
||||
# Find materials to use to build fractal volume, either from mixing
|
||||
# models or normal materials.
|
||||
@@ -152,28 +142,25 @@ class FractalBox(RotatableMixin, GeometryUserObject):
|
||||
|
||||
if mixingmodel:
|
||||
if nbins == 1:
|
||||
logger.exception(
|
||||
raise ValueError(
|
||||
f"{self.__str__()} must be used with more than one material from the mixing model."
|
||||
)
|
||||
raise ValueError
|
||||
if isinstance(mixingmodel, ListMaterial) and nbins > len(mixingmodel.mat):
|
||||
logger.exception(
|
||||
raise ValueError(
|
||||
f"{self.__str__()} too many materials/bins "
|
||||
"requested compared to materials in "
|
||||
"mixing model."
|
||||
)
|
||||
raise ValueError
|
||||
# Create materials from mixing model as number of bins now known
|
||||
# from fractal_box command.
|
||||
mixingmodel.calculate_properties(nbins, grid)
|
||||
elif not material:
|
||||
logger.exception(
|
||||
raise ValueError(
|
||||
f"{self.__str__()} mixing model or material with "
|
||||
+ "ID {mixing_model_id} does not exist"
|
||||
)
|
||||
raise ValueError
|
||||
|
||||
self.volume = FractalVolume(xs, xf, ys, yf, zs, zf, frac_dim, seed)
|
||||
self.volume = grid.add_fractal_volume(xs, xf, ys, yf, zs, zf, frac_dim, seed)
|
||||
self.volume.ID = ID
|
||||
self.volume.operatingonID = mixing_model_id
|
||||
self.volume.nbins = nbins
|
||||
@@ -200,39 +187,26 @@ class FractalBox(RotatableMixin, GeometryUserObject):
|
||||
self.do_pre_build = False
|
||||
else:
|
||||
if self.volume.fractalsurfaces:
|
||||
self.volume.originalxs = self.volume.xs
|
||||
self.volume.originalxf = self.volume.xf
|
||||
self.volume.originalys = self.volume.ys
|
||||
self.volume.originalyf = self.volume.yf
|
||||
self.volume.originalzs = self.volume.zs
|
||||
self.volume.originalzf = self.volume.zf
|
||||
|
||||
# Extend the volume to accomodate any rough surfaces, grass,
|
||||
# or roots
|
||||
for surface in self.volume.fractalsurfaces:
|
||||
if surface.surfaceID == "xminus":
|
||||
if surface.fractalrange[0] < self.volume.xs:
|
||||
self.volume.nx += self.volume.xs - surface.fractalrange[0]
|
||||
self.volume.xs = surface.fractalrange[0]
|
||||
elif surface.surfaceID == "xplus":
|
||||
if surface.fractalrange[1] > self.volume.xf:
|
||||
self.volume.nx += surface.fractalrange[1] - self.volume.xf
|
||||
self.volume.xf = surface.fractalrange[1]
|
||||
elif surface.surfaceID == "yminus":
|
||||
if surface.fractalrange[0] < self.volume.ys:
|
||||
self.volume.ny += self.volume.ys - surface.fractalrange[0]
|
||||
self.volume.ys = surface.fractalrange[0]
|
||||
elif surface.surfaceID == "yplus":
|
||||
if surface.fractalrange[1] > self.volume.yf:
|
||||
self.volume.ny += surface.fractalrange[1] - self.volume.yf
|
||||
self.volume.yf = surface.fractalrange[1]
|
||||
elif surface.surfaceID == "zminus":
|
||||
if surface.fractalrange[0] < self.volume.zs:
|
||||
self.volume.nz += self.volume.zs - surface.fractalrange[0]
|
||||
self.volume.zs = surface.fractalrange[0]
|
||||
elif surface.surfaceID == "zplus":
|
||||
if surface.fractalrange[1] > self.volume.zf:
|
||||
self.volume.nz += surface.fractalrange[1] - self.volume.zf
|
||||
self.volume.zf = surface.fractalrange[1]
|
||||
|
||||
# If there is only 1 bin then a normal material is being used,
|
||||
@@ -247,7 +221,8 @@ class FractalBox(RotatableMixin, GeometryUserObject):
|
||||
)
|
||||
self.volume.fractalvolume *= materialnumID
|
||||
else:
|
||||
self.volume.generate_fractal_volume()
|
||||
if not self.volume.generate_fractal_volume():
|
||||
return
|
||||
for i in range(0, self.volume.nx):
|
||||
for j in range(0, self.volume.ny):
|
||||
for k in range(0, self.volume.nz):
|
||||
@@ -263,6 +238,10 @@ class FractalBox(RotatableMixin, GeometryUserObject):
|
||||
# TODO: Allow extract of rough surface profile (to print/file?)
|
||||
for surface in self.volume.fractalsurfaces:
|
||||
if surface.surfaceID == "xminus":
|
||||
surface.fractalrange = (
|
||||
max(surface.fractalrange[0], 0),
|
||||
min(surface.fractalrange[1], grid.nx),
|
||||
)
|
||||
for i in range(surface.fractalrange[0], surface.fractalrange[1]):
|
||||
for j in range(surface.ys, surface.yf):
|
||||
for k in range(surface.zs, surface.zf):
|
||||
@@ -286,6 +265,10 @@ class FractalBox(RotatableMixin, GeometryUserObject):
|
||||
] = 0
|
||||
|
||||
elif surface.surfaceID == "xplus":
|
||||
surface.fractalrange = (
|
||||
max(surface.fractalrange[0], 0),
|
||||
min(surface.fractalrange[1], grid.nx),
|
||||
)
|
||||
if not surface.ID:
|
||||
for i in range(surface.fractalrange[0], surface.fractalrange[1]):
|
||||
for j in range(surface.ys, surface.yf):
|
||||
@@ -394,6 +377,10 @@ class FractalBox(RotatableMixin, GeometryUserObject):
|
||||
root += 1
|
||||
|
||||
elif surface.surfaceID == "yminus":
|
||||
surface.fractalrange = (
|
||||
max(surface.fractalrange[0], 0),
|
||||
min(surface.fractalrange[1], grid.ny),
|
||||
)
|
||||
for i in range(surface.xs, surface.xf):
|
||||
for j in range(surface.fractalrange[0], surface.fractalrange[1]):
|
||||
for k in range(surface.zs, surface.zf):
|
||||
@@ -417,6 +404,10 @@ class FractalBox(RotatableMixin, GeometryUserObject):
|
||||
] = 0
|
||||
|
||||
elif surface.surfaceID == "yplus":
|
||||
surface.fractalrange = (
|
||||
max(surface.fractalrange[0], 0),
|
||||
min(surface.fractalrange[1], grid.ny),
|
||||
)
|
||||
if not surface.ID:
|
||||
for i in range(surface.xs, surface.xf):
|
||||
for j in range(surface.fractalrange[0], surface.fractalrange[1]):
|
||||
@@ -525,6 +516,10 @@ class FractalBox(RotatableMixin, GeometryUserObject):
|
||||
root += 1
|
||||
|
||||
elif surface.surfaceID == "zminus":
|
||||
surface.fractalrange = (
|
||||
max(surface.fractalrange[0], 0),
|
||||
min(surface.fractalrange[1], grid.nz),
|
||||
)
|
||||
for i in range(surface.xs, surface.xf):
|
||||
for j in range(surface.ys, surface.yf):
|
||||
for k in range(surface.fractalrange[0], surface.fractalrange[1]):
|
||||
@@ -548,6 +543,10 @@ class FractalBox(RotatableMixin, GeometryUserObject):
|
||||
] = 0
|
||||
|
||||
elif surface.surfaceID == "zplus":
|
||||
surface.fractalrange = (
|
||||
max(surface.fractalrange[0], 0),
|
||||
min(surface.fractalrange[1], grid.nz),
|
||||
)
|
||||
if not surface.ID:
|
||||
for i in range(surface.xs, surface.xf):
|
||||
for j in range(surface.ys, surface.yf):
|
||||
@@ -679,14 +678,14 @@ class FractalBox(RotatableMixin, GeometryUserObject):
|
||||
|
||||
else:
|
||||
if self.volume.nbins == 1:
|
||||
logger.exception(
|
||||
raise ValueError(
|
||||
f"{self.__str__()} is being used with a "
|
||||
"single material and no modifications, "
|
||||
"therefore please use a #box command instead."
|
||||
)
|
||||
raise ValueError
|
||||
else:
|
||||
self.volume.generate_fractal_volume()
|
||||
if not self.volume.generate_fractal_volume():
|
||||
return
|
||||
for i in range(0, self.volume.nx):
|
||||
for j in range(0, self.volume.ny):
|
||||
for k in range(0, self.volume.nz):
|
||||
|
@@ -24,10 +24,10 @@ import h5py
|
||||
|
||||
import gprMax.config as config
|
||||
from gprMax.cython.geometry_primitives import build_voxels_from_array
|
||||
from gprMax.geometry_outputs.geometry_objects_read import ReadGeometryObject
|
||||
from gprMax.grid.fdtd_grid import FDTDGrid
|
||||
from gprMax.hash_cmds_file import get_user_objects
|
||||
from gprMax.user_objects.user_objects import GeometryUserObject
|
||||
from gprMax.utilities.utilities import round_value
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -50,12 +50,6 @@ class GeometryObjectsRead(GeometryUserObject):
|
||||
logger.exception(f"{self.__str__()} requires exactly five parameters")
|
||||
raise
|
||||
|
||||
# Discretise the point using uip object. This has different behaviour
|
||||
# depending on the type of uip object. So we can use it for
|
||||
# the main grid or the subgrid.
|
||||
uip = self._create_uip(grid)
|
||||
xs, ys, zs = uip.discretise_point(p1)
|
||||
|
||||
# See if material file exists at specified path and if not try input
|
||||
# file directory
|
||||
matfile = Path(matfile)
|
||||
@@ -76,9 +70,21 @@ class GeometryObjectsRead(GeometryUserObject):
|
||||
if (line.startswith("#") and not line.startswith("##") and line.rstrip("\n"))
|
||||
]
|
||||
|
||||
# Avoid redefining default builtin materials
|
||||
pec = f"#material: 1 inf 1 0 pec{{{matstr}}}\n"
|
||||
free_space = f"#material: 1 0 1 0 free_space{{{matstr}}}\n"
|
||||
if materials[0] == pec and materials[1] == free_space:
|
||||
materials.pop(0)
|
||||
materials.pop(1)
|
||||
numexistmaterials -= 2
|
||||
elif materials[0] == pec or materials[0] == free_space:
|
||||
materials.pop(0)
|
||||
numexistmaterials -= 1
|
||||
|
||||
# Build scene
|
||||
# API for multiple scenes / model runs
|
||||
scene = config.get_model_config().get_scene()
|
||||
assert scene is not None
|
||||
material_objs = get_user_objects(materials, checkessential=False)
|
||||
for material_obj in material_objs:
|
||||
scene.add(material_obj)
|
||||
@@ -100,69 +106,53 @@ class GeometryObjectsRead(GeometryUserObject):
|
||||
if not geofile.exists():
|
||||
geofile = Path(config.sim_config.input_file_path.parent, geofile)
|
||||
|
||||
# Open geometry object file and read/check spatial resolution attribute
|
||||
f = h5py.File(geofile, "r")
|
||||
dx_dy_dz = f.attrs["dx_dy_dz"]
|
||||
if round_value(
|
||||
(dx_dy_dz[0] / grid.dx) != 1
|
||||
or round_value(dx_dy_dz[1] / grid.dy) != 1
|
||||
or round_value(dx_dy_dz[2] / grid.dz) != 1
|
||||
):
|
||||
logger.exception(
|
||||
f"{self.__str__()} requires the spatial resolution "
|
||||
"of the geometry objects file to match the spatial "
|
||||
"resolution of the model"
|
||||
)
|
||||
raise ValueError
|
||||
# Discretise the point using uip object. This has different behaviour
|
||||
# depending on the type of uip object. So we can use it for
|
||||
# the main grid, MPI grids or the subgrid.
|
||||
uip = self._create_uip(grid)
|
||||
discretised_p1 = uip.discretise_point(p1)
|
||||
p2 = uip.round_to_grid_static_point(p1)
|
||||
|
||||
data = f["/data"][:]
|
||||
with ReadGeometryObject(geofile, grid, discretised_p1, numexistmaterials) as f:
|
||||
# Check spatial resolution attribute
|
||||
if not f.has_valid_discritisation():
|
||||
raise ValueError(
|
||||
f"{self.__str__()} requires the spatial resolution "
|
||||
"of the geometry objects file to match the spatial "
|
||||
"resolution of the model"
|
||||
)
|
||||
|
||||
# Should be int16 to allow for -1 which indicates background, i.e.
|
||||
# don't build anything, but AustinMan/Woman maybe uint16
|
||||
if data.dtype != "int16":
|
||||
data = data.astype("int16")
|
||||
if f.has_rigid_arrays() and f.has_ID_array():
|
||||
f.read_data()
|
||||
f.read_ID()
|
||||
f.read_rigidE()
|
||||
f.read_rigidH()
|
||||
|
||||
# Look to see if rigid and ID arrays are present (these should be
|
||||
# present if the original geometry objects were written from gprMax)
|
||||
try:
|
||||
rigidE = f["/rigidE"][:]
|
||||
rigidH = f["/rigidH"][:]
|
||||
ID = f["/ID"][:]
|
||||
grid.solid[
|
||||
xs : xs + data.shape[0], ys : ys + data.shape[1], zs : zs + data.shape[2]
|
||||
] = (data + numexistmaterials)
|
||||
grid.rigidE[
|
||||
:, xs : xs + rigidE.shape[1], ys : ys + rigidE.shape[2], zs : zs + rigidE.shape[3]
|
||||
] = rigidE
|
||||
grid.rigidH[
|
||||
:, xs : xs + rigidH.shape[1], ys : ys + rigidH.shape[2], zs : zs + rigidH.shape[3]
|
||||
] = rigidH
|
||||
grid.ID[:, xs : xs + ID.shape[1], ys : ys + ID.shape[2], zs : zs + ID.shape[3]] = (
|
||||
ID + numexistmaterials
|
||||
)
|
||||
logger.info(
|
||||
f"{self.grid_name(grid)}Geometry objects from file {geofile} "
|
||||
f"inserted at {xs * grid.dx:g}m, {ys * grid.dy:g}m, "
|
||||
f"{zs * grid.dz:g}m, with corresponding materials file "
|
||||
f"{matfile}."
|
||||
)
|
||||
except KeyError:
|
||||
averaging = False
|
||||
build_voxels_from_array(
|
||||
xs,
|
||||
ys,
|
||||
zs,
|
||||
numexistmaterials,
|
||||
averaging,
|
||||
data,
|
||||
grid.solid,
|
||||
grid.rigidE,
|
||||
grid.rigidH,
|
||||
grid.ID,
|
||||
)
|
||||
logger.info(
|
||||
f"{self.grid_name(grid)}Geometry objects from file "
|
||||
f"(voxels only){geofile} inserted at {xs * grid.dx:g}m, "
|
||||
f"{ys * grid.dy:g}m, {zs * grid.dz:g}m, with corresponding "
|
||||
f"materials file {matfile}."
|
||||
)
|
||||
logger.info(
|
||||
f"{self.grid_name(grid)}Geometry objects from file {geofile}"
|
||||
f" inserted at {p2[0]:g}m, {p2[1]:g}m, {p2[2]:g}m,"
|
||||
f" with corresponding materials file"
|
||||
f" {matfile}."
|
||||
)
|
||||
else:
|
||||
data = f.get_data()
|
||||
if data is not None:
|
||||
averaging = False
|
||||
build_voxels_from_array(
|
||||
discretised_p1[0],
|
||||
discretised_p1[1],
|
||||
discretised_p1[2],
|
||||
numexistmaterials,
|
||||
averaging,
|
||||
data,
|
||||
grid.solid,
|
||||
grid.rigidE,
|
||||
grid.rigidH,
|
||||
grid.ID,
|
||||
)
|
||||
logger.info(
|
||||
f"{self.grid_name(grid)}Geometry objects from file "
|
||||
f"(voxels only){geofile} inserted at {p2[0]:g}m, "
|
||||
f"{p2[1]:g}m, {p2[2]:g}m, with corresponding "
|
||||
f"materials file {matfile}."
|
||||
)
|
||||
|
@@ -890,7 +890,7 @@ class DiscretePlaneWave(GridUserObject):
|
||||
rational angle.
|
||||
p1: tuple required for the lower left position (x, y, z) of the total
|
||||
field, scattered field (TFSF) box.
|
||||
p1: tuple required for the upper right position (x, y, z) of the total
|
||||
p2: tuple required for the upper right position (x, y, z) of the total
|
||||
field, scattered field (TFSF) box.
|
||||
waveform_id: string required for identifier of waveform used with source.
|
||||
material_id: string optional of material identifier to use as the
|
||||
|
@@ -274,7 +274,7 @@ class GeometryView(OutputUserObject):
|
||||
p2: tuple required for upper right (x,y,z) coordinates of volume of
|
||||
geometry view in metres.
|
||||
dl: tuple required for spatial discretisation of geometry view in metres.
|
||||
output_tuple: string required for per-cell 'n' (normal) or per-cell-edge
|
||||
output_type: string required for per-cell 'n' (normal) or per-cell-edge
|
||||
'f' (fine) geometry views.
|
||||
filename: string required for filename where geometry view will be
|
||||
stored in the same directory as input file.
|
||||
@@ -303,18 +303,6 @@ class GeometryView(OutputUserObject):
|
||||
self.filename = filename
|
||||
self.output_type = output_type
|
||||
|
||||
def geometry_view_constructor(self, output_type):
|
||||
"""Selects appropriate class for geometry view dependent on geometry
|
||||
view type, i.e. normal or fine.
|
||||
"""
|
||||
|
||||
if output_type == "n":
|
||||
from gprMax.geometry_outputs import GeometryViewVoxels as GeometryViewUser
|
||||
else:
|
||||
from gprMax.geometry_outputs import GeometryViewLines as GeometryViewUser
|
||||
|
||||
return GeometryViewUser
|
||||
|
||||
def build(self, model: Model, grid: FDTDGrid):
|
||||
uip = self._create_uip(grid)
|
||||
discretised_lower_bound, discretised_upper_bound = uip.check_output_object_bounds(
|
||||
|
@@ -1,5 +1,5 @@
|
||||
# Copyright (C) 2015-2025: The University of Edinburgh, United Kingdom
|
||||
# Authors: Craig Warren, Antonis Giannopoulos, John Hartley,
|
||||
# Authors: Craig Warren, Antonis Giannopoulos, John Hartley,
|
||||
# and Nathan Mannall
|
||||
#
|
||||
# This file is part of gprMax.
|
||||
@@ -21,10 +21,8 @@ import logging
|
||||
from typing import Optional, Tuple, Union
|
||||
|
||||
import numpy as np
|
||||
import numpy.typing as npt
|
||||
|
||||
from gprMax import config
|
||||
from gprMax.grid.mpi_grid import MPIGrid
|
||||
from gprMax.model import Model
|
||||
from gprMax.pml import PML
|
||||
from gprMax.user_objects.user_objects import ModelUserObject
|
||||
@@ -66,7 +64,7 @@ class Discretisation(ModelUserObject):
|
||||
"""Spatial discretisation of the model in the x, y, and z dimensions.
|
||||
|
||||
Attributes:
|
||||
discretisation (np.array): Spatial discretisation of the model
|
||||
discretisation (tuple): Spatial discretisation of the model
|
||||
(x, y, z)
|
||||
"""
|
||||
|
||||
@@ -135,7 +133,7 @@ class Domain(ModelUserObject):
|
||||
logger.info(
|
||||
f"Domain size: {self.domain_size[0]:g} x {self.domain_size[1]:g} x "
|
||||
+ f"{self.domain_size[2]:g}m ({model.nx:d} x {model.ny:d} x {model.nz:d} = "
|
||||
+ f"{(model.nx * model.ny * model.nz):g} cells)"
|
||||
+ f"{(model.cells):g} cells)"
|
||||
)
|
||||
|
||||
# Set mode and switch off appropriate PMLs for 2D models
|
||||
@@ -172,7 +170,7 @@ class TimeStepStabilityFactor(ModelUserObject):
|
||||
"""Factor by which to reduce the time step from the CFL limit.
|
||||
|
||||
Attributes:
|
||||
stability_factor (flaot): Factor to multiply time step by.
|
||||
stability_factor (float): Factor to multiply time step by.
|
||||
"""
|
||||
|
||||
@property
|
||||
@@ -212,8 +210,8 @@ class TimeWindow(ModelUserObject):
|
||||
time takes precedence.
|
||||
|
||||
Attributes:
|
||||
time: float of required simulated time in seconds.
|
||||
iterations: int of required number of iterations.
|
||||
time (float | None): Simulated time in seconds.
|
||||
iterations (int | None): Number of iterations.
|
||||
"""
|
||||
|
||||
@property
|
||||
|
47
gprMax/utilities/mpi.py
普通文件
47
gprMax/utilities/mpi.py
普通文件
@@ -0,0 +1,47 @@
|
||||
from enum import IntEnum, unique
|
||||
from typing import Union
|
||||
|
||||
import numpy as np
|
||||
import numpy.typing as npt
|
||||
from mpi4py import MPI
|
||||
|
||||
|
||||
@unique
|
||||
class Dim(IntEnum):
|
||||
X = 0
|
||||
Y = 1
|
||||
Z = 2
|
||||
|
||||
|
||||
@unique
|
||||
class Dir(IntEnum):
|
||||
NONE = -1
|
||||
NEG = 0
|
||||
POS = 1
|
||||
|
||||
|
||||
def get_neighbours(comm: MPI.Cartcomm) -> npt.NDArray[np.int32]:
|
||||
neighbours = np.full((3, 2), -1, dtype=np.int32)
|
||||
neighbours[Dim.X] = comm.Shift(direction=Dim.X, disp=1)
|
||||
neighbours[Dim.Y] = comm.Shift(direction=Dim.Y, disp=1)
|
||||
neighbours[Dim.Z] = comm.Shift(direction=Dim.Z, disp=1)
|
||||
|
||||
return neighbours
|
||||
|
||||
|
||||
def get_neighbour(comm: MPI.Cartcomm, dim: Dim, dir: Dir) -> int:
|
||||
neighbours = comm.Shift(direction=dim, disp=1)
|
||||
return neighbours[dir]
|
||||
|
||||
|
||||
def get_relative_neighbour(
|
||||
comm: MPI.Cartcomm, dirs: npt.NDArray[np.int32], disp: Union[int, npt.NDArray[np.int32]] = 1
|
||||
) -> int:
|
||||
offset = np.select([dirs == Dir.NEG, dirs == Dir.POS], [-disp, disp], default=0)
|
||||
|
||||
coord = comm.coords + offset
|
||||
|
||||
if any(coord < 0) or any(coord >= comm.dims):
|
||||
return -1
|
||||
|
||||
return comm.Get_cart_rank(coord.tolist())
|
@@ -18,13 +18,13 @@
|
||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from os import PathLike
|
||||
from typing import Literal, Optional, Union
|
||||
from typing import Optional, Union
|
||||
|
||||
import numpy as np
|
||||
import numpy.typing as npt
|
||||
from mpi4py import MPI
|
||||
from mpi4py.MPI import Intracomm
|
||||
|
||||
from gprMax.vtkhdf_filehandlers.vtkhdf import VtkHdfFile
|
||||
from gprMax.vtkhdf_filehandlers.vtkhdf import VtkFileType, VtkHdfFile
|
||||
|
||||
|
||||
class VtkImageData(VtkHdfFile):
|
||||
@@ -34,6 +34,8 @@ class VtkImageData(VtkHdfFile):
|
||||
https://docs.vtk.org/en/latest/design_documents/VTKFileFormats.html#image-data
|
||||
"""
|
||||
|
||||
TYPE = VtkFileType.IMAGE_DATA
|
||||
|
||||
DIRECTION_ATTR = "Direction"
|
||||
ORIGIN_ATTR = "Origin"
|
||||
SPACING_ATTR = "Spacing"
|
||||
@@ -41,10 +43,6 @@ class VtkImageData(VtkHdfFile):
|
||||
|
||||
DIMENSIONS = 3
|
||||
|
||||
@property
|
||||
def TYPE(self) -> Literal["ImageData"]:
|
||||
return "ImageData"
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
filename: Union[str, PathLike],
|
||||
@@ -52,7 +50,7 @@ class VtkImageData(VtkHdfFile):
|
||||
origin: Optional[npt.NDArray[np.float32]] = None,
|
||||
spacing: Optional[npt.NDArray[np.float32]] = None,
|
||||
direction: Optional[npt.NDArray[np.float32]] = None,
|
||||
comm: Optional[MPI.Comm] = None,
|
||||
comm: Optional[Intracomm] = None,
|
||||
):
|
||||
"""Create a new VtkImageData file.
|
||||
|
||||
@@ -80,7 +78,7 @@ class VtkImageData(VtkHdfFile):
|
||||
comm (optional): MPI communicator containing all ranks that
|
||||
want to write to the file.
|
||||
"""
|
||||
super().__init__(filename, comm)
|
||||
super().__init__(filename, self.TYPE, "w", comm)
|
||||
|
||||
if len(shape) == 0:
|
||||
raise ValueError(f"Shape must not be empty.")
|
||||
@@ -179,7 +177,7 @@ class VtkImageData(VtkHdfFile):
|
||||
"If no offset is specified, data.shape must be one larger in each dimension than"
|
||||
f" this vtkImageData object. {data.shape} != {points_shape}"
|
||||
)
|
||||
return super().add_point_data(name, data, points_shape, offset)
|
||||
return super()._add_point_data(name, data, points_shape, offset)
|
||||
|
||||
def add_cell_data(
|
||||
self, name: str, data: npt.NDArray, offset: Optional[npt.NDArray[np.int32]] = None
|
||||
@@ -200,4 +198,4 @@ class VtkImageData(VtkHdfFile):
|
||||
"If no offset is specified, data.shape must match the dimensions of this"
|
||||
f" VtkImageData object. {data.shape} != {self.shape}"
|
||||
)
|
||||
return super().add_cell_data(name, data, self.shape, offset)
|
||||
return super()._add_cell_data(name, data, self.shape, offset)
|
||||
|
@@ -19,13 +19,13 @@
|
||||
|
||||
import logging
|
||||
from os import PathLike
|
||||
from typing import Literal, Optional, Union
|
||||
from typing import Optional, Union
|
||||
|
||||
import numpy as np
|
||||
import numpy.typing as npt
|
||||
from mpi4py import MPI
|
||||
|
||||
from gprMax.vtkhdf_filehandlers.vtkhdf import VtkCellType, VtkHdfFile
|
||||
from gprMax.vtkhdf_filehandlers.vtkhdf import VtkCellType, VtkFileType, VtkHdfFile
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -37,6 +37,8 @@ class VtkUnstructuredGrid(VtkHdfFile):
|
||||
https://docs.vtk.org/en/latest/design_documents/VTKFileFormats.html#unstructured-grid
|
||||
"""
|
||||
|
||||
TYPE = VtkFileType.UNSTRUCTURED_GRID
|
||||
|
||||
class Dataset(VtkHdfFile.Dataset):
|
||||
CONNECTIVITY = "Connectivity"
|
||||
NUMBER_OF_CELLS = "NumberOfCells"
|
||||
@@ -46,10 +48,6 @@ class VtkUnstructuredGrid(VtkHdfFile):
|
||||
POINTS = "Points"
|
||||
TYPES = "Types"
|
||||
|
||||
@property
|
||||
def TYPE(self) -> Literal["UnstructuredGrid"]:
|
||||
return "UnstructuredGrid"
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
filename: Union[str, PathLike],
|
||||
@@ -57,7 +55,7 @@ class VtkUnstructuredGrid(VtkHdfFile):
|
||||
cell_types: npt.NDArray[VtkCellType],
|
||||
connectivity: npt.NDArray,
|
||||
cell_offsets: npt.NDArray,
|
||||
comm: Optional[MPI.Comm] = None,
|
||||
comm: Optional[MPI.Intracomm] = None,
|
||||
) -> None:
|
||||
"""Create a new VtkUnstructuredGrid file.
|
||||
|
||||
@@ -88,7 +86,7 @@ class VtkUnstructuredGrid(VtkHdfFile):
|
||||
Raises:
|
||||
Value Error: Raised if argument dimensions are invalid.
|
||||
"""
|
||||
super().__init__(filename, comm)
|
||||
super().__init__(filename, self.TYPE, "w", comm)
|
||||
|
||||
if len(cell_offsets) != len(cell_types) + 1:
|
||||
raise ValueError(
|
||||
@@ -109,39 +107,140 @@ class VtkUnstructuredGrid(VtkHdfFile):
|
||||
" Some connectivity data will be ignored"
|
||||
)
|
||||
|
||||
self._write_root_dataset(self.Dataset.CONNECTIVITY, connectivity)
|
||||
self._write_root_dataset(self.Dataset.NUMBER_OF_CELLS, len(cell_types))
|
||||
self._write_root_dataset(self.Dataset.NUMBER_OF_CONNECTIVITY_IDS, len(connectivity))
|
||||
self._write_root_dataset(self.Dataset.NUMBER_OF_POINTS, len(points))
|
||||
self._write_root_dataset(self.Dataset.OFFSETS, cell_offsets)
|
||||
self._write_root_dataset(self.Dataset.POINTS, points, xyz_data_ordering=False)
|
||||
self._write_root_dataset(self.Dataset.TYPES, cell_types)
|
||||
self._number_of_cells = len(cell_types)
|
||||
self._number_of_connectivity_ids = len(connectivity)
|
||||
self._number_of_points = len(points)
|
||||
|
||||
if self.comm is None:
|
||||
self.partition = 0
|
||||
self._global_number_of_cells = self._number_of_cells
|
||||
self._global_number_of_points = self._number_of_points
|
||||
self._cells_offset = np.zeros(1, dtype=np.int32)
|
||||
self._points_offsets = np.zeros(2, dtype=np.int32)
|
||||
self._write_root_dataset(self.Dataset.NUMBER_OF_CELLS, self._number_of_cells)
|
||||
self._write_root_dataset(
|
||||
self.Dataset.NUMBER_OF_CONNECTIVITY_IDS, self._number_of_connectivity_ids
|
||||
)
|
||||
self._write_root_dataset(self.Dataset.NUMBER_OF_POINTS, self._number_of_points)
|
||||
self._write_root_dataset(self.Dataset.TYPES, cell_types)
|
||||
self._write_root_dataset(self.Dataset.POINTS, points, xyz_data_ordering=False)
|
||||
self._write_root_dataset(self.Dataset.CONNECTIVITY, connectivity)
|
||||
self._write_root_dataset(self.Dataset.OFFSETS, cell_offsets)
|
||||
else:
|
||||
# Write partition information for each rank
|
||||
self.partition = self.comm.rank
|
||||
partition_offset = np.array([self.partition], dtype=np.int32)
|
||||
partition_shape = np.array([self.comm.size], dtype=np.int32)
|
||||
|
||||
self._write_root_dataset(
|
||||
self.Dataset.NUMBER_OF_CELLS,
|
||||
self._number_of_cells,
|
||||
shape=partition_shape,
|
||||
offset=partition_offset,
|
||||
)
|
||||
self._write_root_dataset(
|
||||
self.Dataset.NUMBER_OF_CONNECTIVITY_IDS,
|
||||
self._number_of_connectivity_ids,
|
||||
shape=partition_shape,
|
||||
offset=partition_offset,
|
||||
)
|
||||
self._write_root_dataset(
|
||||
self.Dataset.NUMBER_OF_POINTS,
|
||||
self._number_of_points,
|
||||
shape=partition_shape,
|
||||
offset=partition_offset,
|
||||
)
|
||||
|
||||
self._global_number_of_cells = self.comm.allreduce(self._number_of_cells, MPI.SUM)
|
||||
self._global_number_of_points = self.comm.allreduce(self._number_of_points, MPI.SUM)
|
||||
|
||||
self._cells_offset = np.full(1, self._number_of_cells, dtype=np.int32)
|
||||
self.comm.Exscan(MPI.IN_PLACE, self._cells_offset)
|
||||
|
||||
self._points_offsets = np.array([self._number_of_points, 0], dtype=np.int32)
|
||||
self.comm.Exscan(MPI.IN_PLACE, self._points_offsets)
|
||||
|
||||
connectivity_shape = np.array([self._number_of_connectivity_ids], dtype=np.int32)
|
||||
self.comm.Allreduce(MPI.IN_PLACE, connectivity_shape)
|
||||
|
||||
connectivity_offset = np.array([self._number_of_connectivity_ids], dtype=np.int32)
|
||||
self.comm.Exscan(MPI.IN_PLACE, connectivity_offset)
|
||||
|
||||
# Exscan leaves these undefined for rank 0
|
||||
if self.comm.rank == 0:
|
||||
connectivity_offset = np.zeros(1, dtype=np.int32)
|
||||
self._cells_offset = np.zeros(1, dtype=np.int32)
|
||||
self._points_offsets = np.zeros(2, dtype=np.int32)
|
||||
|
||||
cells_shape = np.array([self.global_number_of_cells], dtype=np.int32)
|
||||
self._write_root_dataset(
|
||||
self.Dataset.TYPES, cell_types, shape=cells_shape, offset=self.cells_offset
|
||||
)
|
||||
|
||||
points_shape = np.array([self.global_number_of_points, 3], dtype=np.int32)
|
||||
self._write_root_dataset(
|
||||
self.Dataset.POINTS,
|
||||
points,
|
||||
shape=points_shape,
|
||||
offset=self.points_offset,
|
||||
xyz_data_ordering=False,
|
||||
)
|
||||
|
||||
self._write_root_dataset(
|
||||
self.Dataset.CONNECTIVITY,
|
||||
connectivity,
|
||||
shape=connectivity_shape,
|
||||
offset=connectivity_offset,
|
||||
)
|
||||
|
||||
# The OFFSETS dataset has size C + 1 for each partition.
|
||||
# Account for the +1 by addding the partition index to the
|
||||
# offset and MPI communicator size to the shape
|
||||
cell_offsets_offset = self.cells_offset + self.partition
|
||||
cell_offsets_shape = cells_shape + self.comm.size
|
||||
self._write_root_dataset(
|
||||
self.Dataset.OFFSETS,
|
||||
cell_offsets,
|
||||
shape=cell_offsets_shape,
|
||||
offset=cell_offsets_offset,
|
||||
)
|
||||
|
||||
@property
|
||||
def number_of_cells(self) -> int:
|
||||
number_of_cells = self._get_root_dataset(self.Dataset.NUMBER_OF_CELLS)
|
||||
return np.sum(number_of_cells, dtype=np.int32)
|
||||
return self._number_of_cells
|
||||
|
||||
@property
|
||||
def global_number_of_cells(self) -> int:
|
||||
return self._global_number_of_cells
|
||||
|
||||
@property
|
||||
def cells_offset(self) -> npt.NDArray[np.int32]:
|
||||
return self._cells_offset
|
||||
|
||||
@property
|
||||
def number_of_connectivity_ids(self) -> int:
|
||||
number_of_connectivity_ids = self._get_root_dataset(self.Dataset.NUMBER_OF_CONNECTIVITY_IDS)
|
||||
return np.sum(number_of_connectivity_ids, dtype=np.int32)
|
||||
return self._number_of_connectivity_ids
|
||||
|
||||
@property
|
||||
def number_of_points(self) -> int:
|
||||
number_of_points = self._get_root_dataset(self.Dataset.NUMBER_OF_POINTS)
|
||||
return np.sum(number_of_points, dtype=np.int32)
|
||||
return self._number_of_points
|
||||
|
||||
def add_point_data(
|
||||
self, name: str, data: npt.NDArray, offset: Optional[npt.NDArray[np.int32]] = None
|
||||
):
|
||||
@property
|
||||
def global_number_of_points(self) -> int:
|
||||
return self._global_number_of_points
|
||||
|
||||
@property
|
||||
def points_offset(self) -> npt.NDArray[np.int32]:
|
||||
return self._points_offsets
|
||||
|
||||
def add_point_data(self, name: str, data: npt.NDArray):
|
||||
"""Add point data to the VTKHDF file.
|
||||
|
||||
Args:
|
||||
name: Name of the dataset.
|
||||
data: Data to be saved.
|
||||
offset (optional): Offset to store the provided data at. Can
|
||||
be omitted if data provides the full dataset.
|
||||
data: Data to be saved. The length of the date must match
|
||||
the number of points in the partition owned by this
|
||||
rank.
|
||||
|
||||
Raises:
|
||||
ValueError: Raised if data has invalid dimensions.
|
||||
@@ -159,18 +258,17 @@ class VtkUnstructuredGrid(VtkHdfFile):
|
||||
elif number_of_dimensions == 2 and shape[1] != 1 and shape[1] != 3:
|
||||
raise ValueError(f"The second dimension should have shape 1 or 3, not {shape[1]}")
|
||||
|
||||
return super().add_point_data(name, data, shape, offset)
|
||||
shape[0] = self.global_number_of_points
|
||||
|
||||
def add_cell_data(
|
||||
self, name: str, data: npt.NDArray, offset: Optional[npt.NDArray[np.int32]] = None
|
||||
):
|
||||
return super()._add_point_data(name, data, shape, self.points_offset)
|
||||
|
||||
def add_cell_data(self, name: str, data: npt.NDArray):
|
||||
"""Add cell data to the VTKHDF file.
|
||||
|
||||
Args:
|
||||
name: Name of the dataset.
|
||||
data: Data to be saved.
|
||||
offset (optional): Offset to store the provided data at. Can
|
||||
be omitted if data provides the full dataset.
|
||||
data: Data to be saved. The length of the date must match
|
||||
the number of cells in the partition owned by this rank.
|
||||
|
||||
Raises:
|
||||
ValueError: Raised if data has invalid dimensions.
|
||||
@@ -182,10 +280,12 @@ class VtkUnstructuredGrid(VtkHdfFile):
|
||||
raise ValueError(f"Data must have 1 or 2 dimensions, not {number_of_dimensions}.")
|
||||
elif len(data) != self.number_of_cells:
|
||||
raise ValueError(
|
||||
"Length of data must match the number of cells in the vtkUnstructuredGrid."
|
||||
f" {len(data)} != {self.number_of_cells}"
|
||||
f"Length of data must match the number of cells in partition {self.partition} of the"
|
||||
f" vtkUnstructuredGrid. {len(data)} != {self.number_of_cells}"
|
||||
)
|
||||
elif number_of_dimensions == 2 and shape[1] != 1 and shape[1] != 3:
|
||||
raise ValueError(f"The second dimension should have shape 1 or 3, not {shape[1]}")
|
||||
|
||||
return super().add_cell_data(name, data, shape, offset)
|
||||
shape[0] = self.global_number_of_cells
|
||||
|
||||
return super()._add_cell_data(name, data, shape, self.cells_offset)
|
||||
|
@@ -29,11 +29,16 @@ from typing import Optional, Tuple, Union
|
||||
import h5py
|
||||
import numpy as np
|
||||
import numpy.typing as npt
|
||||
from mpi4py import MPI
|
||||
from mpi4py.MPI import Intracomm
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class VtkFileType(str, Enum):
|
||||
IMAGE_DATA = "ImageData"
|
||||
UNSTRUCTURED_GRID = "UnstructuredGrid"
|
||||
|
||||
|
||||
class VtkHdfFile(AbstractContextManager):
|
||||
VERSION = [2, 2]
|
||||
FILE_EXTENSION = ".vtkhdf"
|
||||
@@ -48,15 +53,16 @@ class VtkHdfFile(AbstractContextManager):
|
||||
class Dataset(str, Enum):
|
||||
pass
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def TYPE(self) -> str:
|
||||
pass
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __init__(self, filename: Union[str, PathLike], comm: Optional[MPI.Comm] = None) -> None:
|
||||
def __init__(
|
||||
self,
|
||||
filename: Union[str, PathLike],
|
||||
vtk_file_type: VtkFileType,
|
||||
mode: str = "r",
|
||||
comm: Optional[Intracomm] = None,
|
||||
) -> None:
|
||||
"""Create a new VtkHdfFile.
|
||||
|
||||
If the file already exists, it will be overriden. Required
|
||||
@@ -68,6 +74,12 @@ class VtkHdfFile(AbstractContextManager):
|
||||
Args:
|
||||
filename: Name of the file (can be a file path). The file
|
||||
extension will be set to '.vtkhdf'.
|
||||
mode (optional): Mode to open the file. Valid modes are
|
||||
- r Readonly, file must exist (default)
|
||||
- r+ Read/write, file must exist
|
||||
- w Create file, truncate if exists
|
||||
- w- or x Create file, fail if exists
|
||||
- a Read/write if exists, create otherwise
|
||||
comm (optional): MPI communicator containing all ranks that
|
||||
want to write to the file.
|
||||
|
||||
@@ -85,18 +97,20 @@ class VtkHdfFile(AbstractContextManager):
|
||||
|
||||
# Check if the filehandler should use an MPI driver
|
||||
if self.comm is None:
|
||||
self.file_handler = h5py.File(self.filename, "w")
|
||||
self.file_handler = h5py.File(self.filename, mode)
|
||||
else:
|
||||
self.file_handler = h5py.File(self.filename, "w", driver="mpio", comm=self.comm)
|
||||
self.file_handler = h5py.File(self.filename, mode, driver="mpio", comm=self.comm)
|
||||
|
||||
self.root_group = self.file_handler.create_group(self.ROOT_GROUP)
|
||||
logger.debug(f"Opened file '{self.filename}'")
|
||||
|
||||
self.root_group = self.file_handler.require_group(self.ROOT_GROUP)
|
||||
|
||||
# Set required Version and Type root attributes
|
||||
self._set_root_attribute(self.VERSION_ATTR, self.VERSION)
|
||||
self._check_root_attribute(self.VERSION_ATTR, self.VERSION)
|
||||
|
||||
type_as_ascii = self.TYPE.encode("ascii")
|
||||
self._set_root_attribute(
|
||||
self.TYPE_ATTR, type_as_ascii, h5py.string_dtype("ascii", len(type_as_ascii))
|
||||
type_as_ascii = vtk_file_type.encode("ascii")
|
||||
self._check_root_attribute(
|
||||
self.TYPE_ATTR, type_as_ascii, dtype=h5py.string_dtype("ascii", len(type_as_ascii))
|
||||
)
|
||||
|
||||
def __exit__(
|
||||
@@ -122,8 +136,58 @@ class VtkHdfFile(AbstractContextManager):
|
||||
|
||||
def close(self) -> None:
|
||||
"""Close the file handler"""
|
||||
logger.debug(f"Closed file '{self.filename}'")
|
||||
self.file_handler.close()
|
||||
|
||||
def _check_root_attribute(
|
||||
self,
|
||||
attribute: str,
|
||||
expected_value: npt.ArrayLike,
|
||||
dtype: npt.DTypeLike = None,
|
||||
):
|
||||
"""Check root attribute is present and warn if not valid.
|
||||
|
||||
If the attribute exists in the file that has been opened, the
|
||||
value will be checked against the expected value with a warning
|
||||
produced if they differ. If the attribute has not been set, it
|
||||
will be set to the expected value unless the file has been
|
||||
opened in readonly mode.
|
||||
|
||||
Args:
|
||||
attribute: Name of the attribute.
|
||||
expected_value: Expected value of the attribute.
|
||||
dtype (optional): Data type of the attribute. Overrides
|
||||
expected_value.dtype if the attribute is set by
|
||||
this function.
|
||||
|
||||
Returns:
|
||||
value: True if the attribute is present in the root VTKHDF
|
||||
group. False otherwise.
|
||||
"""
|
||||
if self._has_root_attribute(attribute):
|
||||
value = self._get_root_attribute(attribute)
|
||||
if np.any(value != expected_value):
|
||||
logger.warning(
|
||||
f"VTKHDF version mismatch. Expected '{expected_value}', but found '{value}'."
|
||||
)
|
||||
elif self.file_handler.mode == "r+":
|
||||
self._set_root_attribute(attribute, expected_value, dtype=dtype)
|
||||
else:
|
||||
logger.warning(f"Required VTKHDF attribute '{attribute}' not found.")
|
||||
|
||||
def _has_root_attribute(self, attribute: str) -> bool:
|
||||
"""Check if attribute is present in the root VTKHDF group.
|
||||
|
||||
Args:
|
||||
attribute: Name of the attribute.
|
||||
|
||||
Returns:
|
||||
value: True if the attribute is present in the root VTKHDF
|
||||
group. False otherwise.
|
||||
"""
|
||||
value = self.root_group.attrs.get(attribute)
|
||||
return value is not None
|
||||
|
||||
def _get_root_attribute(self, attribute: str) -> npt.NDArray:
|
||||
"""Get attribute from the root VTKHDF group if it exists.
|
||||
|
||||
@@ -136,8 +200,8 @@ class VtkHdfFile(AbstractContextManager):
|
||||
Raises:
|
||||
KeyError: Raised if the attribute is not present as a key.
|
||||
"""
|
||||
value = self.root_group.attrs[attribute]
|
||||
if isinstance(value, h5py.Empty):
|
||||
value = self.root_group.attrs.get(attribute)
|
||||
if value is None:
|
||||
raise KeyError(f"Attribute '{attribute}' not present in /{self.ROOT_GROUP} group")
|
||||
return value
|
||||
|
||||
@@ -258,48 +322,71 @@ class VtkHdfFile(AbstractContextManager):
|
||||
and offset are invalid.
|
||||
"""
|
||||
|
||||
# If dtype is a string and using parallel I/O, ensure using
|
||||
# fixed length strings
|
||||
if isinstance(dtype, np.dtype) and self.comm is not None:
|
||||
string_info = h5py.check_string_dtype(dtype)
|
||||
if string_info is not None and string_info.length is None:
|
||||
logger.warning(
|
||||
"HDF5 does not support variable length strings with parallel I/O."
|
||||
" Using fixed length strings instead."
|
||||
)
|
||||
dtype = h5py.string_dtype(encoding="ascii", length=0)
|
||||
|
||||
# Ensure data is a numpy array
|
||||
if not isinstance(data, np.ndarray):
|
||||
data = np.array(data, dtype=dtype)
|
||||
if data.ndim < 1:
|
||||
data = np.expand_dims(data, axis=-1)
|
||||
|
||||
if data.dtype.kind == "U":
|
||||
if dtype is not None: # Only log warning if user specified a data type
|
||||
string_info = None
|
||||
|
||||
# Warn if string data type will be converted from unicode to a
|
||||
# byte array (ascii). Only output a warning if the user
|
||||
# specified dtype
|
||||
if dtype is not None and np.dtype(dtype).kind == "U":
|
||||
logger.warning(
|
||||
"NumPy UTF-32 ('U' dtype) is not supported by HDF5."
|
||||
" Converting to bytes array ('S' dtype)."
|
||||
)
|
||||
|
||||
# Ensure dtype is a numpy dtype
|
||||
if dtype is None:
|
||||
dtype = data.dtype
|
||||
elif isinstance(dtype, np.dtype):
|
||||
string_info = h5py.check_string_dtype(dtype)
|
||||
|
||||
# Warn if user specified h5py string data type is invalid
|
||||
if string_info is not None and string_info.encoding == "utf-8":
|
||||
logger.warning(
|
||||
"NumPy UTF-32 ('U' dtype) is not supported by HDF5."
|
||||
" Converting to bytes array ('S' dtype)."
|
||||
"utf-8 encoding is not supported by VTKHDF. Converting to ascii encoding."
|
||||
)
|
||||
data = data.astype("S")
|
||||
|
||||
if string_info is not None and string_info.length is not None:
|
||||
if self.comm is None:
|
||||
logger.warning(
|
||||
"Fixed length strings are not supported by VTKHDF."
|
||||
" Converting to variable length strings."
|
||||
)
|
||||
else:
|
||||
logger.warning(
|
||||
"HDF5 does not support variable length strings with parallel I/O."
|
||||
" Using fixed length strings instead."
|
||||
)
|
||||
logger.warning(
|
||||
"VTKHDF does not support fixed length strings. File readers may generate"
|
||||
" error messages when reading in a VTKHDF file containing fixed length"
|
||||
" strings."
|
||||
)
|
||||
else:
|
||||
dtype = np.dtype(dtype)
|
||||
|
||||
# Explicitly define string datatype
|
||||
# VTKHDF only supports ascii strings (not UTF-8)
|
||||
if data.dtype.kind == "S":
|
||||
dtype = h5py.string_dtype(encoding="ascii", length=data.dtype.itemsize)
|
||||
# VTKHDF only supports variable length ascii strings (not UTF-8)
|
||||
if dtype.kind == "U" or dtype.kind == "S" or string_info is not None:
|
||||
# If using parallel I/O, use fixed length strings
|
||||
length = None if self.comm is None else 0
|
||||
dtype = h5py.string_dtype(encoding="ascii", length=length)
|
||||
data = data.astype(dtype)
|
||||
|
||||
elif dtype is None:
|
||||
dtype = data.dtype
|
||||
|
||||
# VTKHDF stores datasets using ZYX ordering rather than XYZ
|
||||
if xyz_data_ordering:
|
||||
data = data.transpose()
|
||||
|
||||
if shape is not None:
|
||||
shape = np.flip(shape)
|
||||
if shape is not None:
|
||||
shape = np.flip(shape)
|
||||
|
||||
if offset is not None:
|
||||
offset = np.flip(offset)
|
||||
if offset is not None:
|
||||
offset = np.flip(offset)
|
||||
|
||||
logger.debug(
|
||||
f"Writing dataset '{path}', shape: {shape}, data.shape: {data.shape}, dtype: {dtype}"
|
||||
@@ -367,25 +454,36 @@ class VtkHdfFile(AbstractContextManager):
|
||||
if string_info is not None and string_info.length is None:
|
||||
raise TypeError(
|
||||
"HDF5 does not support variable length strings with parallel I/O."
|
||||
" Use fixed length strings instead."
|
||||
" Use a serial driver or fixed length strings instead."
|
||||
)
|
||||
|
||||
string_info = h5py.check_string_dtype(dtype)
|
||||
|
||||
if dtype.kind == "U":
|
||||
logger.warning(
|
||||
"NumPy UTF-32 ('U' dtype) is not supported by HDF5."
|
||||
" Converting to bytes array ('S' dtype)."
|
||||
)
|
||||
|
||||
if string_info is not None and string_info.encoding == "utf-8":
|
||||
logger.warning(
|
||||
"utf-8 encoding is not supported by VTKHDF. Converting to ascii encoding."
|
||||
)
|
||||
|
||||
# Explicitly define string datatype
|
||||
# VTKHDF only supports ascii strings (not UTF-8)
|
||||
if dtype.kind == "U" or dtype.kind == "S":
|
||||
dtype = h5py.string_dtype(encoding="ascii", length=dtype.itemsize)
|
||||
# VTKHDF only supports variable length ascii strings (not UTF-8)
|
||||
if (
|
||||
dtype.kind == "U"
|
||||
or dtype.kind == "S"
|
||||
or (string_info is not None and string_info.encoding == "utf-8")
|
||||
):
|
||||
dtype = h5py.string_dtype(encoding="ascii", length=None)
|
||||
|
||||
logger.debug(f"Creating dataset '{path}', shape: {shape}, dtype: {dtype}")
|
||||
|
||||
self.file_handler.create_dataset(path, shape=shape, dtype=dtype)
|
||||
|
||||
def add_point_data(
|
||||
def _add_point_data(
|
||||
self,
|
||||
name: str,
|
||||
data: npt.NDArray,
|
||||
@@ -405,7 +503,7 @@ class VtkHdfFile(AbstractContextManager):
|
||||
dataset_path = self._build_dataset_path("PointData", name)
|
||||
self._write_dataset(dataset_path, data, shape=shape, offset=offset)
|
||||
|
||||
def add_cell_data(
|
||||
def _add_cell_data(
|
||||
self,
|
||||
name: str,
|
||||
data: npt.NDArray,
|
||||
|
0
reframe_tests/__init__.py
普通文件
0
reframe_tests/__init__.py
普通文件
二进制文件未显示。
@@ -0,0 +1,4 @@
|
||||
#material: 1 0 1 0 free_space
|
||||
#material: 8 0 1 0 half_space
|
||||
#material: 12.7174 0 1 0 grass
|
||||
#add_dispersion_debye: 1 5.7913 1.0793e-11 grass
|
二进制文件未显示。
@@ -0,0 +1,4 @@
|
||||
#material: 1 0 1 0 free_space
|
||||
#material: 8 0 1 0 half_space
|
||||
#material: 12.7174 0 1 0 grass
|
||||
#add_dispersion_debye: 1 5.7913 1.0793e-11 grass
|
二进制文件未显示。
@@ -0,0 +1,95 @@
|
||||
#material: 1 0 1 0 free_space
|
||||
#material: 10.1009 0.0737926 1 0 |10.1009+0.0738+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 7.57011 8.0994e-12 |10.1009+0.0738+1.0000+0.0000|
|
||||
#material: 10.224 0.0745944 1 0 |10.2240+0.0746+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 7.83158 8.0994e-12 |10.2240+0.0746+1.0000+0.0000|
|
||||
#material: 10.3465 0.0753865 1 0 |10.3465+0.0754+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 8.09586 8.0994e-12 |10.3465+0.0754+1.0000+0.0000|
|
||||
#material: 10.4684 0.0761693 1 0 |10.4684+0.0762+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 8.36291 8.0994e-12 |10.4684+0.0762+1.0000+0.0000|
|
||||
#material: 10.5897 0.0769429 1 0 |10.5897+0.0769+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 8.6327 8.0994e-12 |10.5897+0.0769+1.0000+0.0000|
|
||||
#material: 10.7105 0.0777078 1 0 |10.7105+0.0777+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 8.9052 8.0994e-12 |10.7105+0.0777+1.0000+0.0000|
|
||||
#material: 10.8308 0.0784642 1 0 |10.8308+0.0785+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 9.18039 8.0994e-12 |10.8308+0.0785+1.0000+0.0000|
|
||||
#material: 10.9505 0.0792123 1 0 |10.9505+0.0792+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 9.45822 8.0994e-12 |10.9505+0.0792+1.0000+0.0000|
|
||||
#material: 4.35657 0.0235572 1 0 |4.3566+0.0236+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.209447 8.0994e-12 |4.3566+0.0236+1.0000+0.0000|
|
||||
#material: 4.55835 0.0263403 1 0 |4.5583+0.0263+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.297473 8.0994e-12 |4.5583+0.0263+1.0000+0.0000|
|
||||
#material: 4.75224 0.0288223 1 0 |4.7522+0.0288+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.394747 8.0994e-12 |4.7522+0.0288+1.0000+0.0000|
|
||||
#material: 4.93963 0.0310813 1 0 |4.9396+0.0311+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.500357 8.0994e-12 |4.9396+0.0311+1.0000+0.0000|
|
||||
#material: 5.1215 0.0331667 1 0 |5.1215+0.0332+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.61361 8.0994e-12 |5.1215+0.0332+1.0000+0.0000|
|
||||
#material: 5.2986 0.0351122 1 0 |5.2986+0.0351+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.733958 8.0994e-12 |5.2986+0.0351+1.0000+0.0000|
|
||||
#material: 5.4715 0.0369417 1 0 |5.4715+0.0369+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.860952 8.0994e-12 |5.4715+0.0369+1.0000+0.0000|
|
||||
#material: 5.64067 0.0386732 1 0 |5.6407+0.0387+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.994215 8.0994e-12 |5.6407+0.0387+1.0000+0.0000|
|
||||
#material: 5.80649 0.0403204 1 0 |5.8065+0.0403+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.13343 8.0994e-12 |5.8065+0.0403+1.0000+0.0000|
|
||||
#material: 5.96926 0.0418941 1 0 |5.9693+0.0419+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.27831 8.0994e-12 |5.9693+0.0419+1.0000+0.0000|
|
||||
#material: 6.12926 0.043403 1 0 |6.1293+0.0434+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.42863 8.0994e-12 |6.1293+0.0434+1.0000+0.0000|
|
||||
#material: 6.28671 0.0448543 1 0 |6.2867+0.0449+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.58416 8.0994e-12 |6.2867+0.0449+1.0000+0.0000|
|
||||
#material: 6.44181 0.0462539 1 0 |6.4418+0.0463+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.74471 8.0994e-12 |6.4418+0.0463+1.0000+0.0000|
|
||||
#material: 6.59474 0.0476066 1 0 |6.5947+0.0476+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.91011 8.0994e-12 |6.5947+0.0476+1.0000+0.0000|
|
||||
#material: 6.74564 0.0489169 1 0 |6.7456+0.0489+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.0802 8.0994e-12 |6.7456+0.0489+1.0000+0.0000|
|
||||
#material: 6.89465 0.0501882 1 0 |6.8946+0.0502+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.25484 8.0994e-12 |6.8946+0.0502+1.0000+0.0000|
|
||||
#material: 7.04188 0.0514238 1 0 |7.0419+0.0514+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.4339 8.0994e-12 |7.0419+0.0514+1.0000+0.0000|
|
||||
#material: 7.18745 0.0526264 1 0 |7.1875+0.0526+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.61725 8.0994e-12 |7.1875+0.0526+1.0000+0.0000|
|
||||
#material: 7.33146 0.0537984 1 0 |7.3315+0.0538+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.80478 8.0994e-12 |7.3315+0.0538+1.0000+0.0000|
|
||||
#material: 7.47398 0.0549419 1 0 |7.4740+0.0549+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.99639 8.0994e-12 |7.4740+0.0549+1.0000+0.0000|
|
||||
#material: 7.61511 0.0560589 1 0 |7.6151+0.0561+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 3.19199 8.0994e-12 |7.6151+0.0561+1.0000+0.0000|
|
||||
#material: 7.7549 0.0571511 1 0 |7.7549+0.0572+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 3.39148 8.0994e-12 |7.7549+0.0572+1.0000+0.0000|
|
||||
#material: 7.89344 0.0582199 1 0 |7.8934+0.0582+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 3.59477 8.0994e-12 |7.8934+0.0582+1.0000+0.0000|
|
||||
#material: 8.03078 0.0592667 1 0 |8.0308+0.0593+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 3.8018 8.0994e-12 |8.0308+0.0593+1.0000+0.0000|
|
||||
#material: 8.16697 0.0602929 1 0 |8.1670+0.0603+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.01247 8.0994e-12 |8.1670+0.0603+1.0000+0.0000|
|
||||
#material: 8.30207 0.0612995 1 0 |8.3021+0.0613+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.22673 8.0994e-12 |8.3021+0.0613+1.0000+0.0000|
|
||||
#material: 8.43613 0.0622875 1 0 |8.4361+0.0623+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.4445 8.0994e-12 |8.4361+0.0623+1.0000+0.0000|
|
||||
#material: 8.5692 0.063258 1 0 |8.5692+0.0633+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.66572 8.0994e-12 |8.5692+0.0633+1.0000+0.0000|
|
||||
#material: 8.7013 0.0642118 1 0 |8.7013+0.0642+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.89034 8.0994e-12 |8.7013+0.0642+1.0000+0.0000|
|
||||
#material: 8.83249 0.0651496 1 0 |8.8325+0.0651+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 5.11828 8.0994e-12 |8.8325+0.0651+1.0000+0.0000|
|
||||
#material: 8.9628 0.0660723 1 0 |8.9628+0.0661+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 5.3495 8.0994e-12 |8.9628+0.0661+1.0000+0.0000|
|
||||
#material: 9.09226 0.0669805 1 0 |9.0923+0.0670+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 5.58395 8.0994e-12 |9.0923+0.0670+1.0000+0.0000|
|
||||
#material: 9.22091 0.0678749 1 0 |9.2209+0.0679+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 5.82158 8.0994e-12 |9.2209+0.0679+1.0000+0.0000|
|
||||
#material: 9.34877 0.068756 1 0 |9.3488+0.0688+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 6.06233 8.0994e-12 |9.3488+0.0688+1.0000+0.0000|
|
||||
#material: 9.47588 0.0696244 1 0 |9.4759+0.0696+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 6.30617 8.0994e-12 |9.4759+0.0696+1.0000+0.0000|
|
||||
#material: 9.60226 0.0704806 1 0 |9.6023+0.0705+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 6.55304 8.0994e-12 |9.6023+0.0705+1.0000+0.0000|
|
||||
#material: 9.72793 0.0713251 1 0 |9.7279+0.0713+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 6.80292 8.0994e-12 |9.7279+0.0713+1.0000+0.0000|
|
||||
#material: 9.85292 0.0721583 1 0 |9.8529+0.0722+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 7.05574 8.0994e-12 |9.8529+0.0722+1.0000+0.0000|
|
||||
#material: 9.97725 0.0729807 1 0 |9.9772+0.0730+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 7.31149 8.0994e-12 |9.9772+0.0730+1.0000+0.0000|
|
二进制文件未显示。
@@ -0,0 +1,97 @@
|
||||
#material: 1 0 1 0 free_space
|
||||
#material: 10.1009 0.0737926 1 0 |10.1009+0.0738+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 7.57011 8.0994e-12 |10.1009+0.0738+1.0000+0.0000|
|
||||
#material: 10.224 0.0745944 1 0 |10.2240+0.0746+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 7.83158 8.0994e-12 |10.2240+0.0746+1.0000+0.0000|
|
||||
#material: 10.3465 0.0753865 1 0 |10.3465+0.0754+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 8.09586 8.0994e-12 |10.3465+0.0754+1.0000+0.0000|
|
||||
#material: 10.4684 0.0761693 1 0 |10.4684+0.0762+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 8.36291 8.0994e-12 |10.4684+0.0762+1.0000+0.0000|
|
||||
#material: 10.5897 0.0769429 1 0 |10.5897+0.0769+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 8.6327 8.0994e-12 |10.5897+0.0769+1.0000+0.0000|
|
||||
#material: 10.7105 0.0777078 1 0 |10.7105+0.0777+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 8.9052 8.0994e-12 |10.7105+0.0777+1.0000+0.0000|
|
||||
#material: 10.8308 0.0784642 1 0 |10.8308+0.0785+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 9.18039 8.0994e-12 |10.8308+0.0785+1.0000+0.0000|
|
||||
#material: 10.9505 0.0792123 1 0 |10.9505+0.0792+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 9.45822 8.0994e-12 |10.9505+0.0792+1.0000+0.0000|
|
||||
#material: 3.67252 0.0108321 1 0 |3.6725+0.0108+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.0182374 8.0994e-12 |3.6725+0.0108+1.0000+0.0000|
|
||||
#material: 4.35657 0.0235572 1 0 |4.3566+0.0236+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.209447 8.0994e-12 |4.3566+0.0236+1.0000+0.0000|
|
||||
#material: 4.55835 0.0263403 1 0 |4.5583+0.0263+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.297473 8.0994e-12 |4.5583+0.0263+1.0000+0.0000|
|
||||
#material: 4.75224 0.0288223 1 0 |4.7522+0.0288+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.394747 8.0994e-12 |4.7522+0.0288+1.0000+0.0000|
|
||||
#material: 4.93963 0.0310813 1 0 |4.9396+0.0311+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.500357 8.0994e-12 |4.9396+0.0311+1.0000+0.0000|
|
||||
#material: 5.1215 0.0331667 1 0 |5.1215+0.0332+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.61361 8.0994e-12 |5.1215+0.0332+1.0000+0.0000|
|
||||
#material: 5.2986 0.0351122 1 0 |5.2986+0.0351+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.733958 8.0994e-12 |5.2986+0.0351+1.0000+0.0000|
|
||||
#material: 5.4715 0.0369417 1 0 |5.4715+0.0369+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.860952 8.0994e-12 |5.4715+0.0369+1.0000+0.0000|
|
||||
#material: 5.64067 0.0386732 1 0 |5.6407+0.0387+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.994215 8.0994e-12 |5.6407+0.0387+1.0000+0.0000|
|
||||
#material: 5.80649 0.0403204 1 0 |5.8065+0.0403+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.13343 8.0994e-12 |5.8065+0.0403+1.0000+0.0000|
|
||||
#material: 5.96926 0.0418941 1 0 |5.9693+0.0419+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.27831 8.0994e-12 |5.9693+0.0419+1.0000+0.0000|
|
||||
#material: 6.12926 0.043403 1 0 |6.1293+0.0434+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.42863 8.0994e-12 |6.1293+0.0434+1.0000+0.0000|
|
||||
#material: 6.28671 0.0448543 1 0 |6.2867+0.0449+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.58416 8.0994e-12 |6.2867+0.0449+1.0000+0.0000|
|
||||
#material: 6.44181 0.0462539 1 0 |6.4418+0.0463+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.74471 8.0994e-12 |6.4418+0.0463+1.0000+0.0000|
|
||||
#material: 6.59474 0.0476066 1 0 |6.5947+0.0476+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.91011 8.0994e-12 |6.5947+0.0476+1.0000+0.0000|
|
||||
#material: 6.74564 0.0489169 1 0 |6.7456+0.0489+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.0802 8.0994e-12 |6.7456+0.0489+1.0000+0.0000|
|
||||
#material: 6.89465 0.0501882 1 0 |6.8946+0.0502+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.25484 8.0994e-12 |6.8946+0.0502+1.0000+0.0000|
|
||||
#material: 7.04188 0.0514238 1 0 |7.0419+0.0514+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.4339 8.0994e-12 |7.0419+0.0514+1.0000+0.0000|
|
||||
#material: 7.18745 0.0526264 1 0 |7.1875+0.0526+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.61725 8.0994e-12 |7.1875+0.0526+1.0000+0.0000|
|
||||
#material: 7.33146 0.0537984 1 0 |7.3315+0.0538+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.80478 8.0994e-12 |7.3315+0.0538+1.0000+0.0000|
|
||||
#material: 7.47398 0.0549419 1 0 |7.4740+0.0549+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.99639 8.0994e-12 |7.4740+0.0549+1.0000+0.0000|
|
||||
#material: 7.61511 0.0560589 1 0 |7.6151+0.0561+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 3.19199 8.0994e-12 |7.6151+0.0561+1.0000+0.0000|
|
||||
#material: 7.7549 0.0571511 1 0 |7.7549+0.0572+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 3.39148 8.0994e-12 |7.7549+0.0572+1.0000+0.0000|
|
||||
#material: 7.89344 0.0582199 1 0 |7.8934+0.0582+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 3.59477 8.0994e-12 |7.8934+0.0582+1.0000+0.0000|
|
||||
#material: 8.03078 0.0592667 1 0 |8.0308+0.0593+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 3.8018 8.0994e-12 |8.0308+0.0593+1.0000+0.0000|
|
||||
#material: 8.16697 0.0602929 1 0 |8.1670+0.0603+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.01247 8.0994e-12 |8.1670+0.0603+1.0000+0.0000|
|
||||
#material: 8.30207 0.0612995 1 0 |8.3021+0.0613+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.22673 8.0994e-12 |8.3021+0.0613+1.0000+0.0000|
|
||||
#material: 8.43613 0.0622875 1 0 |8.4361+0.0623+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.4445 8.0994e-12 |8.4361+0.0623+1.0000+0.0000|
|
||||
#material: 8.5692 0.063258 1 0 |8.5692+0.0633+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.66572 8.0994e-12 |8.5692+0.0633+1.0000+0.0000|
|
||||
#material: 8.7013 0.0642118 1 0 |8.7013+0.0642+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.89034 8.0994e-12 |8.7013+0.0642+1.0000+0.0000|
|
||||
#material: 8.83249 0.0651496 1 0 |8.8325+0.0651+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 5.11828 8.0994e-12 |8.8325+0.0651+1.0000+0.0000|
|
||||
#material: 8.9628 0.0660723 1 0 |8.9628+0.0661+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 5.3495 8.0994e-12 |8.9628+0.0661+1.0000+0.0000|
|
||||
#material: 9.09226 0.0669805 1 0 |9.0923+0.0670+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 5.58395 8.0994e-12 |9.0923+0.0670+1.0000+0.0000|
|
||||
#material: 9.22091 0.0678749 1 0 |9.2209+0.0679+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 5.82158 8.0994e-12 |9.2209+0.0679+1.0000+0.0000|
|
||||
#material: 9.34877 0.068756 1 0 |9.3488+0.0688+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 6.06233 8.0994e-12 |9.3488+0.0688+1.0000+0.0000|
|
||||
#material: 9.47588 0.0696244 1 0 |9.4759+0.0696+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 6.30617 8.0994e-12 |9.4759+0.0696+1.0000+0.0000|
|
||||
#material: 9.60226 0.0704806 1 0 |9.6023+0.0705+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 6.55304 8.0994e-12 |9.6023+0.0705+1.0000+0.0000|
|
||||
#material: 9.72793 0.0713251 1 0 |9.7279+0.0713+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 6.80292 8.0994e-12 |9.7279+0.0713+1.0000+0.0000|
|
||||
#material: 9.85292 0.0721583 1 0 |9.8529+0.0722+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 7.05574 8.0994e-12 |9.8529+0.0722+1.0000+0.0000|
|
||||
#material: 9.97725 0.0729807 1 0 |9.9772+0.0730+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 7.31149 8.0994e-12 |9.9772+0.0730+1.0000+0.0000|
|
二进制文件未显示。
@@ -0,0 +1,91 @@
|
||||
#material: 1 0 1 0 free_space
|
||||
#material: 10.1009 0.0737926 1 0 |10.1009+0.0738+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 7.57011 8.0994e-12 |10.1009+0.0738+1.0000+0.0000|
|
||||
#material: 10.224 0.0745944 1 0 |10.2240+0.0746+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 7.83158 8.0994e-12 |10.2240+0.0746+1.0000+0.0000|
|
||||
#material: 10.3465 0.0753865 1 0 |10.3465+0.0754+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 8.09586 8.0994e-12 |10.3465+0.0754+1.0000+0.0000|
|
||||
#material: 10.9505 0.0792123 1 0 |10.9505+0.0792+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 9.45822 8.0994e-12 |10.9505+0.0792+1.0000+0.0000|
|
||||
#material: 3.67252 0.0108321 1 0 |3.6725+0.0108+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.0182374 8.0994e-12 |3.6725+0.0108+1.0000+0.0000|
|
||||
#material: 3.91944 0.0163865 1 0 |3.9194+0.0164+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.0669568 8.0994e-12 |3.9194+0.0164+1.0000+0.0000|
|
||||
#material: 4.35657 0.0235572 1 0 |4.3566+0.0236+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.209447 8.0994e-12 |4.3566+0.0236+1.0000+0.0000|
|
||||
#material: 4.55835 0.0263403 1 0 |4.5583+0.0263+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.297473 8.0994e-12 |4.5583+0.0263+1.0000+0.0000|
|
||||
#material: 4.75224 0.0288223 1 0 |4.7522+0.0288+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.394747 8.0994e-12 |4.7522+0.0288+1.0000+0.0000|
|
||||
#material: 4.93963 0.0310813 1 0 |4.9396+0.0311+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.500357 8.0994e-12 |4.9396+0.0311+1.0000+0.0000|
|
||||
#material: 5.1215 0.0331667 1 0 |5.1215+0.0332+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.61361 8.0994e-12 |5.1215+0.0332+1.0000+0.0000|
|
||||
#material: 5.2986 0.0351122 1 0 |5.2986+0.0351+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.733958 8.0994e-12 |5.2986+0.0351+1.0000+0.0000|
|
||||
#material: 5.4715 0.0369417 1 0 |5.4715+0.0369+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.860952 8.0994e-12 |5.4715+0.0369+1.0000+0.0000|
|
||||
#material: 5.64067 0.0386732 1 0 |5.6407+0.0387+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.994215 8.0994e-12 |5.6407+0.0387+1.0000+0.0000|
|
||||
#material: 5.80649 0.0403204 1 0 |5.8065+0.0403+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.13343 8.0994e-12 |5.8065+0.0403+1.0000+0.0000|
|
||||
#material: 5.96926 0.0418941 1 0 |5.9693+0.0419+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.27831 8.0994e-12 |5.9693+0.0419+1.0000+0.0000|
|
||||
#material: 6.12926 0.043403 1 0 |6.1293+0.0434+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.42863 8.0994e-12 |6.1293+0.0434+1.0000+0.0000|
|
||||
#material: 6.28671 0.0448543 1 0 |6.2867+0.0449+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.58416 8.0994e-12 |6.2867+0.0449+1.0000+0.0000|
|
||||
#material: 6.44181 0.0462539 1 0 |6.4418+0.0463+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.74471 8.0994e-12 |6.4418+0.0463+1.0000+0.0000|
|
||||
#material: 6.59474 0.0476066 1 0 |6.5947+0.0476+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.91011 8.0994e-12 |6.5947+0.0476+1.0000+0.0000|
|
||||
#material: 6.74564 0.0489169 1 0 |6.7456+0.0489+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.0802 8.0994e-12 |6.7456+0.0489+1.0000+0.0000|
|
||||
#material: 6.89465 0.0501882 1 0 |6.8946+0.0502+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.25484 8.0994e-12 |6.8946+0.0502+1.0000+0.0000|
|
||||
#material: 7.04188 0.0514238 1 0 |7.0419+0.0514+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.4339 8.0994e-12 |7.0419+0.0514+1.0000+0.0000|
|
||||
#material: 7.18745 0.0526264 1 0 |7.1875+0.0526+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.61725 8.0994e-12 |7.1875+0.0526+1.0000+0.0000|
|
||||
#material: 7.33146 0.0537984 1 0 |7.3315+0.0538+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.80478 8.0994e-12 |7.3315+0.0538+1.0000+0.0000|
|
||||
#material: 7.47398 0.0549419 1 0 |7.4740+0.0549+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.99639 8.0994e-12 |7.4740+0.0549+1.0000+0.0000|
|
||||
#material: 7.61511 0.0560589 1 0 |7.6151+0.0561+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 3.19199 8.0994e-12 |7.6151+0.0561+1.0000+0.0000|
|
||||
#material: 7.7549 0.0571511 1 0 |7.7549+0.0572+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 3.39148 8.0994e-12 |7.7549+0.0572+1.0000+0.0000|
|
||||
#material: 7.89344 0.0582199 1 0 |7.8934+0.0582+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 3.59477 8.0994e-12 |7.8934+0.0582+1.0000+0.0000|
|
||||
#material: 8.03078 0.0592667 1 0 |8.0308+0.0593+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 3.8018 8.0994e-12 |8.0308+0.0593+1.0000+0.0000|
|
||||
#material: 8.16697 0.0602929 1 0 |8.1670+0.0603+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.01247 8.0994e-12 |8.1670+0.0603+1.0000+0.0000|
|
||||
#material: 8.30207 0.0612995 1 0 |8.3021+0.0613+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.22673 8.0994e-12 |8.3021+0.0613+1.0000+0.0000|
|
||||
#material: 8.43613 0.0622875 1 0 |8.4361+0.0623+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.4445 8.0994e-12 |8.4361+0.0623+1.0000+0.0000|
|
||||
#material: 8.5692 0.063258 1 0 |8.5692+0.0633+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.66572 8.0994e-12 |8.5692+0.0633+1.0000+0.0000|
|
||||
#material: 8.7013 0.0642118 1 0 |8.7013+0.0642+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.89034 8.0994e-12 |8.7013+0.0642+1.0000+0.0000|
|
||||
#material: 8.83249 0.0651496 1 0 |8.8325+0.0651+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 5.11828 8.0994e-12 |8.8325+0.0651+1.0000+0.0000|
|
||||
#material: 8.9628 0.0660723 1 0 |8.9628+0.0661+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 5.3495 8.0994e-12 |8.9628+0.0661+1.0000+0.0000|
|
||||
#material: 9.09226 0.0669805 1 0 |9.0923+0.0670+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 5.58395 8.0994e-12 |9.0923+0.0670+1.0000+0.0000|
|
||||
#material: 9.22091 0.0678749 1 0 |9.2209+0.0679+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 5.82158 8.0994e-12 |9.2209+0.0679+1.0000+0.0000|
|
||||
#material: 9.34877 0.068756 1 0 |9.3488+0.0688+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 6.06233 8.0994e-12 |9.3488+0.0688+1.0000+0.0000|
|
||||
#material: 9.47588 0.0696244 1 0 |9.4759+0.0696+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 6.30617 8.0994e-12 |9.4759+0.0696+1.0000+0.0000|
|
||||
#material: 9.60226 0.0704806 1 0 |9.6023+0.0705+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 6.55304 8.0994e-12 |9.6023+0.0705+1.0000+0.0000|
|
||||
#material: 9.72793 0.0713251 1 0 |9.7279+0.0713+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 6.80292 8.0994e-12 |9.7279+0.0713+1.0000+0.0000|
|
||||
#material: 9.85292 0.0721583 1 0 |9.8529+0.0722+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 7.05574 8.0994e-12 |9.8529+0.0722+1.0000+0.0000|
|
||||
#material: 9.97725 0.0729807 1 0 |9.9772+0.0730+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 7.31149 8.0994e-12 |9.9772+0.0730+1.0000+0.0000|
|
二进制文件未显示。
@@ -0,0 +1,99 @@
|
||||
#material: 1 0 1 0 free_space
|
||||
#material: 10.1009 0.0737926 1 0 |10.1009+0.0738+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 7.57011 8.0994e-12 |10.1009+0.0738+1.0000+0.0000|
|
||||
#material: 10.224 0.0745944 1 0 |10.2240+0.0746+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 7.83158 8.0994e-12 |10.2240+0.0746+1.0000+0.0000|
|
||||
#material: 10.3465 0.0753865 1 0 |10.3465+0.0754+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 8.09586 8.0994e-12 |10.3465+0.0754+1.0000+0.0000|
|
||||
#material: 10.4684 0.0761693 1 0 |10.4684+0.0762+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 8.36291 8.0994e-12 |10.4684+0.0762+1.0000+0.0000|
|
||||
#material: 10.5897 0.0769429 1 0 |10.5897+0.0769+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 8.6327 8.0994e-12 |10.5897+0.0769+1.0000+0.0000|
|
||||
#material: 10.7105 0.0777078 1 0 |10.7105+0.0777+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 8.9052 8.0994e-12 |10.7105+0.0777+1.0000+0.0000|
|
||||
#material: 10.8308 0.0784642 1 0 |10.8308+0.0785+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 9.18039 8.0994e-12 |10.8308+0.0785+1.0000+0.0000|
|
||||
#material: 10.9505 0.0792123 1 0 |10.9505+0.0792+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 9.45822 8.0994e-12 |10.9505+0.0792+1.0000+0.0000|
|
||||
#material: 3.67252 0.0108321 1 0 |3.6725+0.0108+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.0182374 8.0994e-12 |3.6725+0.0108+1.0000+0.0000|
|
||||
#material: 4.1448 0.0203355 1 0 |4.1448+0.0203+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.131947 8.0994e-12 |4.1448+0.0203+1.0000+0.0000|
|
||||
#material: 4.35657 0.0235572 1 0 |4.3566+0.0236+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.209447 8.0994e-12 |4.3566+0.0236+1.0000+0.0000|
|
||||
#material: 4.55835 0.0263403 1 0 |4.5583+0.0263+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.297473 8.0994e-12 |4.5583+0.0263+1.0000+0.0000|
|
||||
#material: 4.75224 0.0288223 1 0 |4.7522+0.0288+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.394747 8.0994e-12 |4.7522+0.0288+1.0000+0.0000|
|
||||
#material: 4.93963 0.0310813 1 0 |4.9396+0.0311+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.500357 8.0994e-12 |4.9396+0.0311+1.0000+0.0000|
|
||||
#material: 5.1215 0.0331667 1 0 |5.1215+0.0332+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.61361 8.0994e-12 |5.1215+0.0332+1.0000+0.0000|
|
||||
#material: 5.2986 0.0351122 1 0 |5.2986+0.0351+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.733958 8.0994e-12 |5.2986+0.0351+1.0000+0.0000|
|
||||
#material: 5.4715 0.0369417 1 0 |5.4715+0.0369+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.860952 8.0994e-12 |5.4715+0.0369+1.0000+0.0000|
|
||||
#material: 5.64067 0.0386732 1 0 |5.6407+0.0387+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.994215 8.0994e-12 |5.6407+0.0387+1.0000+0.0000|
|
||||
#material: 5.80649 0.0403204 1 0 |5.8065+0.0403+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.13343 8.0994e-12 |5.8065+0.0403+1.0000+0.0000|
|
||||
#material: 5.96926 0.0418941 1 0 |5.9693+0.0419+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.27831 8.0994e-12 |5.9693+0.0419+1.0000+0.0000|
|
||||
#material: 6.12926 0.043403 1 0 |6.1293+0.0434+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.42863 8.0994e-12 |6.1293+0.0434+1.0000+0.0000|
|
||||
#material: 6.28671 0.0448543 1 0 |6.2867+0.0449+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.58416 8.0994e-12 |6.2867+0.0449+1.0000+0.0000|
|
||||
#material: 6.44181 0.0462539 1 0 |6.4418+0.0463+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.74471 8.0994e-12 |6.4418+0.0463+1.0000+0.0000|
|
||||
#material: 6.59474 0.0476066 1 0 |6.5947+0.0476+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.91011 8.0994e-12 |6.5947+0.0476+1.0000+0.0000|
|
||||
#material: 6.74564 0.0489169 1 0 |6.7456+0.0489+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.0802 8.0994e-12 |6.7456+0.0489+1.0000+0.0000|
|
||||
#material: 6.89465 0.0501882 1 0 |6.8946+0.0502+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.25484 8.0994e-12 |6.8946+0.0502+1.0000+0.0000|
|
||||
#material: 7.04188 0.0514238 1 0 |7.0419+0.0514+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.4339 8.0994e-12 |7.0419+0.0514+1.0000+0.0000|
|
||||
#material: 7.18745 0.0526264 1 0 |7.1875+0.0526+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.61725 8.0994e-12 |7.1875+0.0526+1.0000+0.0000|
|
||||
#material: 7.33146 0.0537984 1 0 |7.3315+0.0538+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.80478 8.0994e-12 |7.3315+0.0538+1.0000+0.0000|
|
||||
#material: 7.47398 0.0549419 1 0 |7.4740+0.0549+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.99639 8.0994e-12 |7.4740+0.0549+1.0000+0.0000|
|
||||
#material: 7.61511 0.0560589 1 0 |7.6151+0.0561+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 3.19199 8.0994e-12 |7.6151+0.0561+1.0000+0.0000|
|
||||
#material: 7.7549 0.0571511 1 0 |7.7549+0.0572+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 3.39148 8.0994e-12 |7.7549+0.0572+1.0000+0.0000|
|
||||
#material: 7.89344 0.0582199 1 0 |7.8934+0.0582+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 3.59477 8.0994e-12 |7.8934+0.0582+1.0000+0.0000|
|
||||
#material: 8.03078 0.0592667 1 0 |8.0308+0.0593+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 3.8018 8.0994e-12 |8.0308+0.0593+1.0000+0.0000|
|
||||
#material: 8.16697 0.0602929 1 0 |8.1670+0.0603+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.01247 8.0994e-12 |8.1670+0.0603+1.0000+0.0000|
|
||||
#material: 8.30207 0.0612995 1 0 |8.3021+0.0613+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.22673 8.0994e-12 |8.3021+0.0613+1.0000+0.0000|
|
||||
#material: 8.43613 0.0622875 1 0 |8.4361+0.0623+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.4445 8.0994e-12 |8.4361+0.0623+1.0000+0.0000|
|
||||
#material: 8.5692 0.063258 1 0 |8.5692+0.0633+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.66572 8.0994e-12 |8.5692+0.0633+1.0000+0.0000|
|
||||
#material: 8.7013 0.0642118 1 0 |8.7013+0.0642+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.89034 8.0994e-12 |8.7013+0.0642+1.0000+0.0000|
|
||||
#material: 8.83249 0.0651496 1 0 |8.8325+0.0651+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 5.11828 8.0994e-12 |8.8325+0.0651+1.0000+0.0000|
|
||||
#material: 8.9628 0.0660723 1 0 |8.9628+0.0661+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 5.3495 8.0994e-12 |8.9628+0.0661+1.0000+0.0000|
|
||||
#material: 9.09226 0.0669805 1 0 |9.0923+0.0670+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 5.58395 8.0994e-12 |9.0923+0.0670+1.0000+0.0000|
|
||||
#material: 9.22091 0.0678749 1 0 |9.2209+0.0679+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 5.82158 8.0994e-12 |9.2209+0.0679+1.0000+0.0000|
|
||||
#material: 9.34877 0.068756 1 0 |9.3488+0.0688+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 6.06233 8.0994e-12 |9.3488+0.0688+1.0000+0.0000|
|
||||
#material: 9.47588 0.0696244 1 0 |9.4759+0.0696+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 6.30617 8.0994e-12 |9.4759+0.0696+1.0000+0.0000|
|
||||
#material: 9.60226 0.0704806 1 0 |9.6023+0.0705+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 6.55304 8.0994e-12 |9.6023+0.0705+1.0000+0.0000|
|
||||
#material: 9.72793 0.0713251 1 0 |9.7279+0.0713+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 6.80292 8.0994e-12 |9.7279+0.0713+1.0000+0.0000|
|
||||
#material: 9.85292 0.0721583 1 0 |9.8529+0.0722+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 7.05574 8.0994e-12 |9.8529+0.0722+1.0000+0.0000|
|
||||
#material: 9.97725 0.0729807 1 0 |9.9772+0.0730+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 7.31149 8.0994e-12 |9.9772+0.0730+1.0000+0.0000|
|
二进制文件未显示。
@@ -0,0 +1,95 @@
|
||||
#material: 1 0 1 0 free_space
|
||||
#material: 4.9 0 1 0 water
|
||||
#add_dispersion_debye: 1 73.3389 8.0994e-12 water
|
||||
#material: 10.1009 0.0737926 1 0 |10.1009+0.0738+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 7.57011 8.0994e-12 |10.1009+0.0738+1.0000+0.0000|
|
||||
#material: 10.224 0.0745944 1 0 |10.2240+0.0746+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 7.83158 8.0994e-12 |10.2240+0.0746+1.0000+0.0000|
|
||||
#material: 10.3465 0.0753865 1 0 |10.3465+0.0754+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 8.09586 8.0994e-12 |10.3465+0.0754+1.0000+0.0000|
|
||||
#material: 10.4684 0.0761693 1 0 |10.4684+0.0762+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 8.36291 8.0994e-12 |10.4684+0.0762+1.0000+0.0000|
|
||||
#material: 10.5897 0.0769429 1 0 |10.5897+0.0769+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 8.6327 8.0994e-12 |10.5897+0.0769+1.0000+0.0000|
|
||||
#material: 10.7105 0.0777078 1 0 |10.7105+0.0777+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 8.9052 8.0994e-12 |10.7105+0.0777+1.0000+0.0000|
|
||||
#material: 10.9505 0.0792123 1 0 |10.9505+0.0792+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 9.45822 8.0994e-12 |10.9505+0.0792+1.0000+0.0000|
|
||||
#material: 3.67252 0.0108321 1 0 |3.6725+0.0108+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.0182374 8.0994e-12 |3.6725+0.0108+1.0000+0.0000|
|
||||
#material: 4.55835 0.0263403 1 0 |4.5583+0.0263+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.297473 8.0994e-12 |4.5583+0.0263+1.0000+0.0000|
|
||||
#material: 4.75224 0.0288223 1 0 |4.7522+0.0288+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.394747 8.0994e-12 |4.7522+0.0288+1.0000+0.0000|
|
||||
#material: 4.93963 0.0310813 1 0 |4.9396+0.0311+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.500357 8.0994e-12 |4.9396+0.0311+1.0000+0.0000|
|
||||
#material: 5.1215 0.0331667 1 0 |5.1215+0.0332+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.61361 8.0994e-12 |5.1215+0.0332+1.0000+0.0000|
|
||||
#material: 5.2986 0.0351122 1 0 |5.2986+0.0351+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.733958 8.0994e-12 |5.2986+0.0351+1.0000+0.0000|
|
||||
#material: 5.4715 0.0369417 1 0 |5.4715+0.0369+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.860952 8.0994e-12 |5.4715+0.0369+1.0000+0.0000|
|
||||
#material: 5.64067 0.0386732 1 0 |5.6407+0.0387+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.994215 8.0994e-12 |5.6407+0.0387+1.0000+0.0000|
|
||||
#material: 5.80649 0.0403204 1 0 |5.8065+0.0403+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.13343 8.0994e-12 |5.8065+0.0403+1.0000+0.0000|
|
||||
#material: 5.96926 0.0418941 1 0 |5.9693+0.0419+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.27831 8.0994e-12 |5.9693+0.0419+1.0000+0.0000|
|
||||
#material: 6.12926 0.043403 1 0 |6.1293+0.0434+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.42863 8.0994e-12 |6.1293+0.0434+1.0000+0.0000|
|
||||
#material: 6.28671 0.0448543 1 0 |6.2867+0.0449+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.58416 8.0994e-12 |6.2867+0.0449+1.0000+0.0000|
|
||||
#material: 6.44181 0.0462539 1 0 |6.4418+0.0463+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.74471 8.0994e-12 |6.4418+0.0463+1.0000+0.0000|
|
||||
#material: 6.59474 0.0476066 1 0 |6.5947+0.0476+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.91011 8.0994e-12 |6.5947+0.0476+1.0000+0.0000|
|
||||
#material: 6.74564 0.0489169 1 0 |6.7456+0.0489+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.0802 8.0994e-12 |6.7456+0.0489+1.0000+0.0000|
|
||||
#material: 6.89465 0.0501882 1 0 |6.8946+0.0502+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.25484 8.0994e-12 |6.8946+0.0502+1.0000+0.0000|
|
||||
#material: 7.04188 0.0514238 1 0 |7.0419+0.0514+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.4339 8.0994e-12 |7.0419+0.0514+1.0000+0.0000|
|
||||
#material: 7.18745 0.0526264 1 0 |7.1875+0.0526+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.61725 8.0994e-12 |7.1875+0.0526+1.0000+0.0000|
|
||||
#material: 7.33146 0.0537984 1 0 |7.3315+0.0538+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.80478 8.0994e-12 |7.3315+0.0538+1.0000+0.0000|
|
||||
#material: 7.47398 0.0549419 1 0 |7.4740+0.0549+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.99639 8.0994e-12 |7.4740+0.0549+1.0000+0.0000|
|
||||
#material: 7.61511 0.0560589 1 0 |7.6151+0.0561+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 3.19199 8.0994e-12 |7.6151+0.0561+1.0000+0.0000|
|
||||
#material: 7.7549 0.0571511 1 0 |7.7549+0.0572+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 3.39148 8.0994e-12 |7.7549+0.0572+1.0000+0.0000|
|
||||
#material: 7.89344 0.0582199 1 0 |7.8934+0.0582+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 3.59477 8.0994e-12 |7.8934+0.0582+1.0000+0.0000|
|
||||
#material: 8.03078 0.0592667 1 0 |8.0308+0.0593+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 3.8018 8.0994e-12 |8.0308+0.0593+1.0000+0.0000|
|
||||
#material: 8.16697 0.0602929 1 0 |8.1670+0.0603+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.01247 8.0994e-12 |8.1670+0.0603+1.0000+0.0000|
|
||||
#material: 8.30207 0.0612995 1 0 |8.3021+0.0613+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.22673 8.0994e-12 |8.3021+0.0613+1.0000+0.0000|
|
||||
#material: 8.43613 0.0622875 1 0 |8.4361+0.0623+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.4445 8.0994e-12 |8.4361+0.0623+1.0000+0.0000|
|
||||
#material: 8.5692 0.063258 1 0 |8.5692+0.0633+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.66572 8.0994e-12 |8.5692+0.0633+1.0000+0.0000|
|
||||
#material: 8.7013 0.0642118 1 0 |8.7013+0.0642+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.89034 8.0994e-12 |8.7013+0.0642+1.0000+0.0000|
|
||||
#material: 8.83249 0.0651496 1 0 |8.8325+0.0651+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 5.11828 8.0994e-12 |8.8325+0.0651+1.0000+0.0000|
|
||||
#material: 8.9628 0.0660723 1 0 |8.9628+0.0661+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 5.3495 8.0994e-12 |8.9628+0.0661+1.0000+0.0000|
|
||||
#material: 9.09226 0.0669805 1 0 |9.0923+0.0670+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 5.58395 8.0994e-12 |9.0923+0.0670+1.0000+0.0000|
|
||||
#material: 9.22091 0.0678749 1 0 |9.2209+0.0679+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 5.82158 8.0994e-12 |9.2209+0.0679+1.0000+0.0000|
|
||||
#material: 9.34877 0.068756 1 0 |9.3488+0.0688+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 6.06233 8.0994e-12 |9.3488+0.0688+1.0000+0.0000|
|
||||
#material: 9.47588 0.0696244 1 0 |9.4759+0.0696+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 6.30617 8.0994e-12 |9.4759+0.0696+1.0000+0.0000|
|
||||
#material: 9.60226 0.0704806 1 0 |9.6023+0.0705+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 6.55304 8.0994e-12 |9.6023+0.0705+1.0000+0.0000|
|
||||
#material: 9.72793 0.0713251 1 0 |9.7279+0.0713+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 6.80292 8.0994e-12 |9.7279+0.0713+1.0000+0.0000|
|
||||
#material: 9.85292 0.0721583 1 0 |9.8529+0.0722+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 7.05574 8.0994e-12 |9.8529+0.0722+1.0000+0.0000|
|
||||
#material: 9.97725 0.0729807 1 0 |9.9772+0.0730+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 7.31149 8.0994e-12 |9.9772+0.0730+1.0000+0.0000|
|
二进制文件未显示。
@@ -0,0 +1,97 @@
|
||||
#material: 1 0 1 0 free_space
|
||||
#material: 4.9 0 1 0 water
|
||||
#add_dispersion_debye: 1 73.3389 8.0994e-12 water
|
||||
#material: 10.1009 0.0737926 1 0 |10.1009+0.0738+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 7.57011 8.0994e-12 |10.1009+0.0738+1.0000+0.0000|
|
||||
#material: 10.224 0.0745944 1 0 |10.2240+0.0746+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 7.83158 8.0994e-12 |10.2240+0.0746+1.0000+0.0000|
|
||||
#material: 10.3465 0.0753865 1 0 |10.3465+0.0754+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 8.09586 8.0994e-12 |10.3465+0.0754+1.0000+0.0000|
|
||||
#material: 10.4684 0.0761693 1 0 |10.4684+0.0762+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 8.36291 8.0994e-12 |10.4684+0.0762+1.0000+0.0000|
|
||||
#material: 10.5897 0.0769429 1 0 |10.5897+0.0769+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 8.6327 8.0994e-12 |10.5897+0.0769+1.0000+0.0000|
|
||||
#material: 10.7105 0.0777078 1 0 |10.7105+0.0777+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 8.9052 8.0994e-12 |10.7105+0.0777+1.0000+0.0000|
|
||||
#material: 10.8308 0.0784642 1 0 |10.8308+0.0785+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 9.18039 8.0994e-12 |10.8308+0.0785+1.0000+0.0000|
|
||||
#material: 10.9505 0.0792123 1 0 |10.9505+0.0792+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 9.45822 8.0994e-12 |10.9505+0.0792+1.0000+0.0000|
|
||||
#material: 4.35657 0.0235572 1 0 |4.3566+0.0236+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.209447 8.0994e-12 |4.3566+0.0236+1.0000+0.0000|
|
||||
#material: 4.55835 0.0263403 1 0 |4.5583+0.0263+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.297473 8.0994e-12 |4.5583+0.0263+1.0000+0.0000|
|
||||
#material: 4.75224 0.0288223 1 0 |4.7522+0.0288+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.394747 8.0994e-12 |4.7522+0.0288+1.0000+0.0000|
|
||||
#material: 4.93963 0.0310813 1 0 |4.9396+0.0311+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.500357 8.0994e-12 |4.9396+0.0311+1.0000+0.0000|
|
||||
#material: 5.1215 0.0331667 1 0 |5.1215+0.0332+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.61361 8.0994e-12 |5.1215+0.0332+1.0000+0.0000|
|
||||
#material: 5.2986 0.0351122 1 0 |5.2986+0.0351+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.733958 8.0994e-12 |5.2986+0.0351+1.0000+0.0000|
|
||||
#material: 5.4715 0.0369417 1 0 |5.4715+0.0369+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.860952 8.0994e-12 |5.4715+0.0369+1.0000+0.0000|
|
||||
#material: 5.64067 0.0386732 1 0 |5.6407+0.0387+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.994215 8.0994e-12 |5.6407+0.0387+1.0000+0.0000|
|
||||
#material: 5.80649 0.0403204 1 0 |5.8065+0.0403+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.13343 8.0994e-12 |5.8065+0.0403+1.0000+0.0000|
|
||||
#material: 5.96926 0.0418941 1 0 |5.9693+0.0419+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.27831 8.0994e-12 |5.9693+0.0419+1.0000+0.0000|
|
||||
#material: 6.12926 0.043403 1 0 |6.1293+0.0434+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.42863 8.0994e-12 |6.1293+0.0434+1.0000+0.0000|
|
||||
#material: 6.28671 0.0448543 1 0 |6.2867+0.0449+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.58416 8.0994e-12 |6.2867+0.0449+1.0000+0.0000|
|
||||
#material: 6.44181 0.0462539 1 0 |6.4418+0.0463+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.74471 8.0994e-12 |6.4418+0.0463+1.0000+0.0000|
|
||||
#material: 6.59474 0.0476066 1 0 |6.5947+0.0476+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.91011 8.0994e-12 |6.5947+0.0476+1.0000+0.0000|
|
||||
#material: 6.74564 0.0489169 1 0 |6.7456+0.0489+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.0802 8.0994e-12 |6.7456+0.0489+1.0000+0.0000|
|
||||
#material: 6.89465 0.0501882 1 0 |6.8946+0.0502+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.25484 8.0994e-12 |6.8946+0.0502+1.0000+0.0000|
|
||||
#material: 7.04188 0.0514238 1 0 |7.0419+0.0514+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.4339 8.0994e-12 |7.0419+0.0514+1.0000+0.0000|
|
||||
#material: 7.18745 0.0526264 1 0 |7.1875+0.0526+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.61725 8.0994e-12 |7.1875+0.0526+1.0000+0.0000|
|
||||
#material: 7.33146 0.0537984 1 0 |7.3315+0.0538+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.80478 8.0994e-12 |7.3315+0.0538+1.0000+0.0000|
|
||||
#material: 7.47398 0.0549419 1 0 |7.4740+0.0549+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.99639 8.0994e-12 |7.4740+0.0549+1.0000+0.0000|
|
||||
#material: 7.61511 0.0560589 1 0 |7.6151+0.0561+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 3.19199 8.0994e-12 |7.6151+0.0561+1.0000+0.0000|
|
||||
#material: 7.7549 0.0571511 1 0 |7.7549+0.0572+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 3.39148 8.0994e-12 |7.7549+0.0572+1.0000+0.0000|
|
||||
#material: 7.89344 0.0582199 1 0 |7.8934+0.0582+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 3.59477 8.0994e-12 |7.8934+0.0582+1.0000+0.0000|
|
||||
#material: 8.03078 0.0592667 1 0 |8.0308+0.0593+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 3.8018 8.0994e-12 |8.0308+0.0593+1.0000+0.0000|
|
||||
#material: 8.16697 0.0602929 1 0 |8.1670+0.0603+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.01247 8.0994e-12 |8.1670+0.0603+1.0000+0.0000|
|
||||
#material: 8.30207 0.0612995 1 0 |8.3021+0.0613+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.22673 8.0994e-12 |8.3021+0.0613+1.0000+0.0000|
|
||||
#material: 8.43613 0.0622875 1 0 |8.4361+0.0623+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.4445 8.0994e-12 |8.4361+0.0623+1.0000+0.0000|
|
||||
#material: 8.5692 0.063258 1 0 |8.5692+0.0633+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.66572 8.0994e-12 |8.5692+0.0633+1.0000+0.0000|
|
||||
#material: 8.7013 0.0642118 1 0 |8.7013+0.0642+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.89034 8.0994e-12 |8.7013+0.0642+1.0000+0.0000|
|
||||
#material: 8.83249 0.0651496 1 0 |8.8325+0.0651+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 5.11828 8.0994e-12 |8.8325+0.0651+1.0000+0.0000|
|
||||
#material: 8.9628 0.0660723 1 0 |8.9628+0.0661+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 5.3495 8.0994e-12 |8.9628+0.0661+1.0000+0.0000|
|
||||
#material: 9.09226 0.0669805 1 0 |9.0923+0.0670+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 5.58395 8.0994e-12 |9.0923+0.0670+1.0000+0.0000|
|
||||
#material: 9.22091 0.0678749 1 0 |9.2209+0.0679+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 5.82158 8.0994e-12 |9.2209+0.0679+1.0000+0.0000|
|
||||
#material: 9.34877 0.068756 1 0 |9.3488+0.0688+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 6.06233 8.0994e-12 |9.3488+0.0688+1.0000+0.0000|
|
||||
#material: 9.47588 0.0696244 1 0 |9.4759+0.0696+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 6.30617 8.0994e-12 |9.4759+0.0696+1.0000+0.0000|
|
||||
#material: 9.60226 0.0704806 1 0 |9.6023+0.0705+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 6.55304 8.0994e-12 |9.6023+0.0705+1.0000+0.0000|
|
||||
#material: 9.72793 0.0713251 1 0 |9.7279+0.0713+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 6.80292 8.0994e-12 |9.7279+0.0713+1.0000+0.0000|
|
||||
#material: 9.85292 0.0721583 1 0 |9.8529+0.0722+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 7.05574 8.0994e-12 |9.8529+0.0722+1.0000+0.0000|
|
||||
#material: 9.97725 0.0729807 1 0 |9.9772+0.0730+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 7.31149 8.0994e-12 |9.9772+0.0730+1.0000+0.0000|
|
二进制文件未显示。
@@ -0,0 +1,99 @@
|
||||
#material: 1 0 1 0 free_space
|
||||
#material: 10.1009 0.0737926 1 0 |10.1009+0.0738+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 7.57011 8.0994e-12 |10.1009+0.0738+1.0000+0.0000|
|
||||
#material: 10.224 0.0745944 1 0 |10.2240+0.0746+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 7.83158 8.0994e-12 |10.2240+0.0746+1.0000+0.0000|
|
||||
#material: 10.3465 0.0753865 1 0 |10.3465+0.0754+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 8.09586 8.0994e-12 |10.3465+0.0754+1.0000+0.0000|
|
||||
#material: 10.4684 0.0761693 1 0 |10.4684+0.0762+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 8.36291 8.0994e-12 |10.4684+0.0762+1.0000+0.0000|
|
||||
#material: 10.5897 0.0769429 1 0 |10.5897+0.0769+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 8.6327 8.0994e-12 |10.5897+0.0769+1.0000+0.0000|
|
||||
#material: 10.7105 0.0777078 1 0 |10.7105+0.0777+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 8.9052 8.0994e-12 |10.7105+0.0777+1.0000+0.0000|
|
||||
#material: 10.8308 0.0784642 1 0 |10.8308+0.0785+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 9.18039 8.0994e-12 |10.8308+0.0785+1.0000+0.0000|
|
||||
#material: 10.9505 0.0792123 1 0 |10.9505+0.0792+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 9.45822 8.0994e-12 |10.9505+0.0792+1.0000+0.0000|
|
||||
#material: 3.67252 0.0108321 1 0 |3.6725+0.0108+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.0182374 8.0994e-12 |3.6725+0.0108+1.0000+0.0000|
|
||||
#material: 4.1448 0.0203355 1 0 |4.1448+0.0203+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.131947 8.0994e-12 |4.1448+0.0203+1.0000+0.0000|
|
||||
#material: 4.35657 0.0235572 1 0 |4.3566+0.0236+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.209447 8.0994e-12 |4.3566+0.0236+1.0000+0.0000|
|
||||
#material: 4.55835 0.0263403 1 0 |4.5583+0.0263+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.297473 8.0994e-12 |4.5583+0.0263+1.0000+0.0000|
|
||||
#material: 4.75224 0.0288223 1 0 |4.7522+0.0288+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.394747 8.0994e-12 |4.7522+0.0288+1.0000+0.0000|
|
||||
#material: 4.93963 0.0310813 1 0 |4.9396+0.0311+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.500357 8.0994e-12 |4.9396+0.0311+1.0000+0.0000|
|
||||
#material: 5.1215 0.0331667 1 0 |5.1215+0.0332+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.61361 8.0994e-12 |5.1215+0.0332+1.0000+0.0000|
|
||||
#material: 5.2986 0.0351122 1 0 |5.2986+0.0351+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.733958 8.0994e-12 |5.2986+0.0351+1.0000+0.0000|
|
||||
#material: 5.4715 0.0369417 1 0 |5.4715+0.0369+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.860952 8.0994e-12 |5.4715+0.0369+1.0000+0.0000|
|
||||
#material: 5.64067 0.0386732 1 0 |5.6407+0.0387+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.994215 8.0994e-12 |5.6407+0.0387+1.0000+0.0000|
|
||||
#material: 5.80649 0.0403204 1 0 |5.8065+0.0403+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.13343 8.0994e-12 |5.8065+0.0403+1.0000+0.0000|
|
||||
#material: 5.96926 0.0418941 1 0 |5.9693+0.0419+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.27831 8.0994e-12 |5.9693+0.0419+1.0000+0.0000|
|
||||
#material: 6.12926 0.043403 1 0 |6.1293+0.0434+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.42863 8.0994e-12 |6.1293+0.0434+1.0000+0.0000|
|
||||
#material: 6.28671 0.0448543 1 0 |6.2867+0.0449+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.58416 8.0994e-12 |6.2867+0.0449+1.0000+0.0000|
|
||||
#material: 6.44181 0.0462539 1 0 |6.4418+0.0463+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.74471 8.0994e-12 |6.4418+0.0463+1.0000+0.0000|
|
||||
#material: 6.59474 0.0476066 1 0 |6.5947+0.0476+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.91011 8.0994e-12 |6.5947+0.0476+1.0000+0.0000|
|
||||
#material: 6.74564 0.0489169 1 0 |6.7456+0.0489+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.0802 8.0994e-12 |6.7456+0.0489+1.0000+0.0000|
|
||||
#material: 6.89465 0.0501882 1 0 |6.8946+0.0502+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.25484 8.0994e-12 |6.8946+0.0502+1.0000+0.0000|
|
||||
#material: 7.04188 0.0514238 1 0 |7.0419+0.0514+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.4339 8.0994e-12 |7.0419+0.0514+1.0000+0.0000|
|
||||
#material: 7.18745 0.0526264 1 0 |7.1875+0.0526+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.61725 8.0994e-12 |7.1875+0.0526+1.0000+0.0000|
|
||||
#material: 7.33146 0.0537984 1 0 |7.3315+0.0538+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.80478 8.0994e-12 |7.3315+0.0538+1.0000+0.0000|
|
||||
#material: 7.47398 0.0549419 1 0 |7.4740+0.0549+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.99639 8.0994e-12 |7.4740+0.0549+1.0000+0.0000|
|
||||
#material: 7.61511 0.0560589 1 0 |7.6151+0.0561+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 3.19199 8.0994e-12 |7.6151+0.0561+1.0000+0.0000|
|
||||
#material: 7.7549 0.0571511 1 0 |7.7549+0.0572+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 3.39148 8.0994e-12 |7.7549+0.0572+1.0000+0.0000|
|
||||
#material: 7.89344 0.0582199 1 0 |7.8934+0.0582+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 3.59477 8.0994e-12 |7.8934+0.0582+1.0000+0.0000|
|
||||
#material: 8.03078 0.0592667 1 0 |8.0308+0.0593+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 3.8018 8.0994e-12 |8.0308+0.0593+1.0000+0.0000|
|
||||
#material: 8.16697 0.0602929 1 0 |8.1670+0.0603+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.01247 8.0994e-12 |8.1670+0.0603+1.0000+0.0000|
|
||||
#material: 8.30207 0.0612995 1 0 |8.3021+0.0613+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.22673 8.0994e-12 |8.3021+0.0613+1.0000+0.0000|
|
||||
#material: 8.43613 0.0622875 1 0 |8.4361+0.0623+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.4445 8.0994e-12 |8.4361+0.0623+1.0000+0.0000|
|
||||
#material: 8.5692 0.063258 1 0 |8.5692+0.0633+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.66572 8.0994e-12 |8.5692+0.0633+1.0000+0.0000|
|
||||
#material: 8.7013 0.0642118 1 0 |8.7013+0.0642+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.89034 8.0994e-12 |8.7013+0.0642+1.0000+0.0000|
|
||||
#material: 8.83249 0.0651496 1 0 |8.8325+0.0651+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 5.11828 8.0994e-12 |8.8325+0.0651+1.0000+0.0000|
|
||||
#material: 8.9628 0.0660723 1 0 |8.9628+0.0661+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 5.3495 8.0994e-12 |8.9628+0.0661+1.0000+0.0000|
|
||||
#material: 9.09226 0.0669805 1 0 |9.0923+0.0670+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 5.58395 8.0994e-12 |9.0923+0.0670+1.0000+0.0000|
|
||||
#material: 9.22091 0.0678749 1 0 |9.2209+0.0679+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 5.82158 8.0994e-12 |9.2209+0.0679+1.0000+0.0000|
|
||||
#material: 9.34877 0.068756 1 0 |9.3488+0.0688+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 6.06233 8.0994e-12 |9.3488+0.0688+1.0000+0.0000|
|
||||
#material: 9.47588 0.0696244 1 0 |9.4759+0.0696+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 6.30617 8.0994e-12 |9.4759+0.0696+1.0000+0.0000|
|
||||
#material: 9.60226 0.0704806 1 0 |9.6023+0.0705+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 6.55304 8.0994e-12 |9.6023+0.0705+1.0000+0.0000|
|
||||
#material: 9.72793 0.0713251 1 0 |9.7279+0.0713+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 6.80292 8.0994e-12 |9.7279+0.0713+1.0000+0.0000|
|
||||
#material: 9.85292 0.0721583 1 0 |9.8529+0.0722+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 7.05574 8.0994e-12 |9.8529+0.0722+1.0000+0.0000|
|
||||
#material: 9.97725 0.0729807 1 0 |9.9772+0.0730+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 7.31149 8.0994e-12 |9.9772+0.0730+1.0000+0.0000|
|
二进制文件未显示。
@@ -0,0 +1,97 @@
|
||||
#material: 1 0 1 0 free_space
|
||||
#material: 10.1009 0.0737926 1 0 |10.1009+0.0738+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 7.57011 8.0994e-12 |10.1009+0.0738+1.0000+0.0000|
|
||||
#material: 10.224 0.0745944 1 0 |10.2240+0.0746+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 7.83158 8.0994e-12 |10.2240+0.0746+1.0000+0.0000|
|
||||
#material: 10.3465 0.0753865 1 0 |10.3465+0.0754+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 8.09586 8.0994e-12 |10.3465+0.0754+1.0000+0.0000|
|
||||
#material: 10.4684 0.0761693 1 0 |10.4684+0.0762+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 8.36291 8.0994e-12 |10.4684+0.0762+1.0000+0.0000|
|
||||
#material: 10.5897 0.0769429 1 0 |10.5897+0.0769+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 8.6327 8.0994e-12 |10.5897+0.0769+1.0000+0.0000|
|
||||
#material: 10.7105 0.0777078 1 0 |10.7105+0.0777+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 8.9052 8.0994e-12 |10.7105+0.0777+1.0000+0.0000|
|
||||
#material: 10.8308 0.0784642 1 0 |10.8308+0.0785+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 9.18039 8.0994e-12 |10.8308+0.0785+1.0000+0.0000|
|
||||
#material: 10.9505 0.0792123 1 0 |10.9505+0.0792+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 9.45822 8.0994e-12 |10.9505+0.0792+1.0000+0.0000|
|
||||
#material: 3.67252 0.0108321 1 0 |3.6725+0.0108+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.0182374 8.0994e-12 |3.6725+0.0108+1.0000+0.0000|
|
||||
#material: 4.35657 0.0235572 1 0 |4.3566+0.0236+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.209447 8.0994e-12 |4.3566+0.0236+1.0000+0.0000|
|
||||
#material: 4.55835 0.0263403 1 0 |4.5583+0.0263+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.297473 8.0994e-12 |4.5583+0.0263+1.0000+0.0000|
|
||||
#material: 4.75224 0.0288223 1 0 |4.7522+0.0288+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.394747 8.0994e-12 |4.7522+0.0288+1.0000+0.0000|
|
||||
#material: 4.93963 0.0310813 1 0 |4.9396+0.0311+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.500357 8.0994e-12 |4.9396+0.0311+1.0000+0.0000|
|
||||
#material: 5.1215 0.0331667 1 0 |5.1215+0.0332+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.61361 8.0994e-12 |5.1215+0.0332+1.0000+0.0000|
|
||||
#material: 5.2986 0.0351122 1 0 |5.2986+0.0351+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.733958 8.0994e-12 |5.2986+0.0351+1.0000+0.0000|
|
||||
#material: 5.4715 0.0369417 1 0 |5.4715+0.0369+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.860952 8.0994e-12 |5.4715+0.0369+1.0000+0.0000|
|
||||
#material: 5.64067 0.0386732 1 0 |5.6407+0.0387+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.994215 8.0994e-12 |5.6407+0.0387+1.0000+0.0000|
|
||||
#material: 5.80649 0.0403204 1 0 |5.8065+0.0403+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.13343 8.0994e-12 |5.8065+0.0403+1.0000+0.0000|
|
||||
#material: 5.96926 0.0418941 1 0 |5.9693+0.0419+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.27831 8.0994e-12 |5.9693+0.0419+1.0000+0.0000|
|
||||
#material: 6.12926 0.043403 1 0 |6.1293+0.0434+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.42863 8.0994e-12 |6.1293+0.0434+1.0000+0.0000|
|
||||
#material: 6.28671 0.0448543 1 0 |6.2867+0.0449+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.58416 8.0994e-12 |6.2867+0.0449+1.0000+0.0000|
|
||||
#material: 6.44181 0.0462539 1 0 |6.4418+0.0463+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.74471 8.0994e-12 |6.4418+0.0463+1.0000+0.0000|
|
||||
#material: 6.59474 0.0476066 1 0 |6.5947+0.0476+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.91011 8.0994e-12 |6.5947+0.0476+1.0000+0.0000|
|
||||
#material: 6.74564 0.0489169 1 0 |6.7456+0.0489+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.0802 8.0994e-12 |6.7456+0.0489+1.0000+0.0000|
|
||||
#material: 6.89465 0.0501882 1 0 |6.8946+0.0502+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.25484 8.0994e-12 |6.8946+0.0502+1.0000+0.0000|
|
||||
#material: 7.04188 0.0514238 1 0 |7.0419+0.0514+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.4339 8.0994e-12 |7.0419+0.0514+1.0000+0.0000|
|
||||
#material: 7.18745 0.0526264 1 0 |7.1875+0.0526+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.61725 8.0994e-12 |7.1875+0.0526+1.0000+0.0000|
|
||||
#material: 7.33146 0.0537984 1 0 |7.3315+0.0538+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.80478 8.0994e-12 |7.3315+0.0538+1.0000+0.0000|
|
||||
#material: 7.47398 0.0549419 1 0 |7.4740+0.0549+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.99639 8.0994e-12 |7.4740+0.0549+1.0000+0.0000|
|
||||
#material: 7.61511 0.0560589 1 0 |7.6151+0.0561+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 3.19199 8.0994e-12 |7.6151+0.0561+1.0000+0.0000|
|
||||
#material: 7.7549 0.0571511 1 0 |7.7549+0.0572+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 3.39148 8.0994e-12 |7.7549+0.0572+1.0000+0.0000|
|
||||
#material: 7.89344 0.0582199 1 0 |7.8934+0.0582+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 3.59477 8.0994e-12 |7.8934+0.0582+1.0000+0.0000|
|
||||
#material: 8.03078 0.0592667 1 0 |8.0308+0.0593+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 3.8018 8.0994e-12 |8.0308+0.0593+1.0000+0.0000|
|
||||
#material: 8.16697 0.0602929 1 0 |8.1670+0.0603+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.01247 8.0994e-12 |8.1670+0.0603+1.0000+0.0000|
|
||||
#material: 8.30207 0.0612995 1 0 |8.3021+0.0613+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.22673 8.0994e-12 |8.3021+0.0613+1.0000+0.0000|
|
||||
#material: 8.43613 0.0622875 1 0 |8.4361+0.0623+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.4445 8.0994e-12 |8.4361+0.0623+1.0000+0.0000|
|
||||
#material: 8.5692 0.063258 1 0 |8.5692+0.0633+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.66572 8.0994e-12 |8.5692+0.0633+1.0000+0.0000|
|
||||
#material: 8.7013 0.0642118 1 0 |8.7013+0.0642+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.89034 8.0994e-12 |8.7013+0.0642+1.0000+0.0000|
|
||||
#material: 8.83249 0.0651496 1 0 |8.8325+0.0651+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 5.11828 8.0994e-12 |8.8325+0.0651+1.0000+0.0000|
|
||||
#material: 8.9628 0.0660723 1 0 |8.9628+0.0661+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 5.3495 8.0994e-12 |8.9628+0.0661+1.0000+0.0000|
|
||||
#material: 9.09226 0.0669805 1 0 |9.0923+0.0670+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 5.58395 8.0994e-12 |9.0923+0.0670+1.0000+0.0000|
|
||||
#material: 9.22091 0.0678749 1 0 |9.2209+0.0679+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 5.82158 8.0994e-12 |9.2209+0.0679+1.0000+0.0000|
|
||||
#material: 9.34877 0.068756 1 0 |9.3488+0.0688+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 6.06233 8.0994e-12 |9.3488+0.0688+1.0000+0.0000|
|
||||
#material: 9.47588 0.0696244 1 0 |9.4759+0.0696+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 6.30617 8.0994e-12 |9.4759+0.0696+1.0000+0.0000|
|
||||
#material: 9.60226 0.0704806 1 0 |9.6023+0.0705+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 6.55304 8.0994e-12 |9.6023+0.0705+1.0000+0.0000|
|
||||
#material: 9.72793 0.0713251 1 0 |9.7279+0.0713+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 6.80292 8.0994e-12 |9.7279+0.0713+1.0000+0.0000|
|
||||
#material: 9.85292 0.0721583 1 0 |9.8529+0.0722+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 7.05574 8.0994e-12 |9.8529+0.0722+1.0000+0.0000|
|
||||
#material: 9.97725 0.0729807 1 0 |9.9772+0.0730+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 7.31149 8.0994e-12 |9.9772+0.0730+1.0000+0.0000|
|
二进制文件未显示。
@@ -0,0 +1,97 @@
|
||||
#material: 1 0 1 0 free_space
|
||||
#material: 10.1009 0.0737926 1 0 |10.1009+0.0738+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 7.57011 8.0994e-12 |10.1009+0.0738+1.0000+0.0000|
|
||||
#material: 10.224 0.0745944 1 0 |10.2240+0.0746+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 7.83158 8.0994e-12 |10.2240+0.0746+1.0000+0.0000|
|
||||
#material: 10.3465 0.0753865 1 0 |10.3465+0.0754+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 8.09586 8.0994e-12 |10.3465+0.0754+1.0000+0.0000|
|
||||
#material: 10.4684 0.0761693 1 0 |10.4684+0.0762+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 8.36291 8.0994e-12 |10.4684+0.0762+1.0000+0.0000|
|
||||
#material: 10.5897 0.0769429 1 0 |10.5897+0.0769+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 8.6327 8.0994e-12 |10.5897+0.0769+1.0000+0.0000|
|
||||
#material: 10.7105 0.0777078 1 0 |10.7105+0.0777+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 8.9052 8.0994e-12 |10.7105+0.0777+1.0000+0.0000|
|
||||
#material: 10.8308 0.0784642 1 0 |10.8308+0.0785+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 9.18039 8.0994e-12 |10.8308+0.0785+1.0000+0.0000|
|
||||
#material: 10.9505 0.0792123 1 0 |10.9505+0.0792+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 9.45822 8.0994e-12 |10.9505+0.0792+1.0000+0.0000|
|
||||
#material: 3.67252 0.0108321 1 0 |3.6725+0.0108+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.0182374 8.0994e-12 |3.6725+0.0108+1.0000+0.0000|
|
||||
#material: 4.35657 0.0235572 1 0 |4.3566+0.0236+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.209447 8.0994e-12 |4.3566+0.0236+1.0000+0.0000|
|
||||
#material: 4.55835 0.0263403 1 0 |4.5583+0.0263+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.297473 8.0994e-12 |4.5583+0.0263+1.0000+0.0000|
|
||||
#material: 4.75224 0.0288223 1 0 |4.7522+0.0288+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.394747 8.0994e-12 |4.7522+0.0288+1.0000+0.0000|
|
||||
#material: 4.93963 0.0310813 1 0 |4.9396+0.0311+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.500357 8.0994e-12 |4.9396+0.0311+1.0000+0.0000|
|
||||
#material: 5.1215 0.0331667 1 0 |5.1215+0.0332+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.61361 8.0994e-12 |5.1215+0.0332+1.0000+0.0000|
|
||||
#material: 5.2986 0.0351122 1 0 |5.2986+0.0351+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.733958 8.0994e-12 |5.2986+0.0351+1.0000+0.0000|
|
||||
#material: 5.4715 0.0369417 1 0 |5.4715+0.0369+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.860952 8.0994e-12 |5.4715+0.0369+1.0000+0.0000|
|
||||
#material: 5.64067 0.0386732 1 0 |5.6407+0.0387+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.994215 8.0994e-12 |5.6407+0.0387+1.0000+0.0000|
|
||||
#material: 5.80649 0.0403204 1 0 |5.8065+0.0403+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.13343 8.0994e-12 |5.8065+0.0403+1.0000+0.0000|
|
||||
#material: 5.96926 0.0418941 1 0 |5.9693+0.0419+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.27831 8.0994e-12 |5.9693+0.0419+1.0000+0.0000|
|
||||
#material: 6.12926 0.043403 1 0 |6.1293+0.0434+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.42863 8.0994e-12 |6.1293+0.0434+1.0000+0.0000|
|
||||
#material: 6.28671 0.0448543 1 0 |6.2867+0.0449+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.58416 8.0994e-12 |6.2867+0.0449+1.0000+0.0000|
|
||||
#material: 6.44181 0.0462539 1 0 |6.4418+0.0463+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.74471 8.0994e-12 |6.4418+0.0463+1.0000+0.0000|
|
||||
#material: 6.59474 0.0476066 1 0 |6.5947+0.0476+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.91011 8.0994e-12 |6.5947+0.0476+1.0000+0.0000|
|
||||
#material: 6.74564 0.0489169 1 0 |6.7456+0.0489+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.0802 8.0994e-12 |6.7456+0.0489+1.0000+0.0000|
|
||||
#material: 6.89465 0.0501882 1 0 |6.8946+0.0502+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.25484 8.0994e-12 |6.8946+0.0502+1.0000+0.0000|
|
||||
#material: 7.04188 0.0514238 1 0 |7.0419+0.0514+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.4339 8.0994e-12 |7.0419+0.0514+1.0000+0.0000|
|
||||
#material: 7.18745 0.0526264 1 0 |7.1875+0.0526+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.61725 8.0994e-12 |7.1875+0.0526+1.0000+0.0000|
|
||||
#material: 7.33146 0.0537984 1 0 |7.3315+0.0538+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.80478 8.0994e-12 |7.3315+0.0538+1.0000+0.0000|
|
||||
#material: 7.47398 0.0549419 1 0 |7.4740+0.0549+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.99639 8.0994e-12 |7.4740+0.0549+1.0000+0.0000|
|
||||
#material: 7.61511 0.0560589 1 0 |7.6151+0.0561+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 3.19199 8.0994e-12 |7.6151+0.0561+1.0000+0.0000|
|
||||
#material: 7.7549 0.0571511 1 0 |7.7549+0.0572+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 3.39148 8.0994e-12 |7.7549+0.0572+1.0000+0.0000|
|
||||
#material: 7.89344 0.0582199 1 0 |7.8934+0.0582+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 3.59477 8.0994e-12 |7.8934+0.0582+1.0000+0.0000|
|
||||
#material: 8.03078 0.0592667 1 0 |8.0308+0.0593+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 3.8018 8.0994e-12 |8.0308+0.0593+1.0000+0.0000|
|
||||
#material: 8.16697 0.0602929 1 0 |8.1670+0.0603+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.01247 8.0994e-12 |8.1670+0.0603+1.0000+0.0000|
|
||||
#material: 8.30207 0.0612995 1 0 |8.3021+0.0613+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.22673 8.0994e-12 |8.3021+0.0613+1.0000+0.0000|
|
||||
#material: 8.43613 0.0622875 1 0 |8.4361+0.0623+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.4445 8.0994e-12 |8.4361+0.0623+1.0000+0.0000|
|
||||
#material: 8.5692 0.063258 1 0 |8.5692+0.0633+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.66572 8.0994e-12 |8.5692+0.0633+1.0000+0.0000|
|
||||
#material: 8.7013 0.0642118 1 0 |8.7013+0.0642+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.89034 8.0994e-12 |8.7013+0.0642+1.0000+0.0000|
|
||||
#material: 8.83249 0.0651496 1 0 |8.8325+0.0651+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 5.11828 8.0994e-12 |8.8325+0.0651+1.0000+0.0000|
|
||||
#material: 8.9628 0.0660723 1 0 |8.9628+0.0661+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 5.3495 8.0994e-12 |8.9628+0.0661+1.0000+0.0000|
|
||||
#material: 9.09226 0.0669805 1 0 |9.0923+0.0670+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 5.58395 8.0994e-12 |9.0923+0.0670+1.0000+0.0000|
|
||||
#material: 9.22091 0.0678749 1 0 |9.2209+0.0679+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 5.82158 8.0994e-12 |9.2209+0.0679+1.0000+0.0000|
|
||||
#material: 9.34877 0.068756 1 0 |9.3488+0.0688+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 6.06233 8.0994e-12 |9.3488+0.0688+1.0000+0.0000|
|
||||
#material: 9.47588 0.0696244 1 0 |9.4759+0.0696+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 6.30617 8.0994e-12 |9.4759+0.0696+1.0000+0.0000|
|
||||
#material: 9.60226 0.0704806 1 0 |9.6023+0.0705+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 6.55304 8.0994e-12 |9.6023+0.0705+1.0000+0.0000|
|
||||
#material: 9.72793 0.0713251 1 0 |9.7279+0.0713+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 6.80292 8.0994e-12 |9.7279+0.0713+1.0000+0.0000|
|
||||
#material: 9.85292 0.0721583 1 0 |9.8529+0.0722+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 7.05574 8.0994e-12 |9.8529+0.0722+1.0000+0.0000|
|
||||
#material: 9.97725 0.0729807 1 0 |9.9772+0.0730+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 7.31149 8.0994e-12 |9.9772+0.0730+1.0000+0.0000|
|
二进制文件未显示。
@@ -0,0 +1,101 @@
|
||||
#material: 1 0 1 0 free_space
|
||||
#material: 10.1009 0.0737926 1 0 |10.1009+0.0738+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 7.57011 8.0994e-12 |10.1009+0.0738+1.0000+0.0000|
|
||||
#material: 10.224 0.0745944 1 0 |10.2240+0.0746+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 7.83158 8.0994e-12 |10.2240+0.0746+1.0000+0.0000|
|
||||
#material: 10.3465 0.0753865 1 0 |10.3465+0.0754+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 8.09586 8.0994e-12 |10.3465+0.0754+1.0000+0.0000|
|
||||
#material: 10.4684 0.0761693 1 0 |10.4684+0.0762+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 8.36291 8.0994e-12 |10.4684+0.0762+1.0000+0.0000|
|
||||
#material: 10.5897 0.0769429 1 0 |10.5897+0.0769+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 8.6327 8.0994e-12 |10.5897+0.0769+1.0000+0.0000|
|
||||
#material: 10.7105 0.0777078 1 0 |10.7105+0.0777+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 8.9052 8.0994e-12 |10.7105+0.0777+1.0000+0.0000|
|
||||
#material: 10.8308 0.0784642 1 0 |10.8308+0.0785+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 9.18039 8.0994e-12 |10.8308+0.0785+1.0000+0.0000|
|
||||
#material: 10.9505 0.0792123 1 0 |10.9505+0.0792+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 9.45822 8.0994e-12 |10.9505+0.0792+1.0000+0.0000|
|
||||
#material: 3.67252 0.0108321 1 0 |3.6725+0.0108+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.0182374 8.0994e-12 |3.6725+0.0108+1.0000+0.0000|
|
||||
#material: 3.91944 0.0163865 1 0 |3.9194+0.0164+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.0669568 8.0994e-12 |3.9194+0.0164+1.0000+0.0000|
|
||||
#material: 4.1448 0.0203355 1 0 |4.1448+0.0203+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.131947 8.0994e-12 |4.1448+0.0203+1.0000+0.0000|
|
||||
#material: 4.35657 0.0235572 1 0 |4.3566+0.0236+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.209447 8.0994e-12 |4.3566+0.0236+1.0000+0.0000|
|
||||
#material: 4.55835 0.0263403 1 0 |4.5583+0.0263+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.297473 8.0994e-12 |4.5583+0.0263+1.0000+0.0000|
|
||||
#material: 4.75224 0.0288223 1 0 |4.7522+0.0288+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.394747 8.0994e-12 |4.7522+0.0288+1.0000+0.0000|
|
||||
#material: 4.93963 0.0310813 1 0 |4.9396+0.0311+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.500357 8.0994e-12 |4.9396+0.0311+1.0000+0.0000|
|
||||
#material: 5.1215 0.0331667 1 0 |5.1215+0.0332+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.61361 8.0994e-12 |5.1215+0.0332+1.0000+0.0000|
|
||||
#material: 5.2986 0.0351122 1 0 |5.2986+0.0351+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.733958 8.0994e-12 |5.2986+0.0351+1.0000+0.0000|
|
||||
#material: 5.4715 0.0369417 1 0 |5.4715+0.0369+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.860952 8.0994e-12 |5.4715+0.0369+1.0000+0.0000|
|
||||
#material: 5.64067 0.0386732 1 0 |5.6407+0.0387+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 0.994215 8.0994e-12 |5.6407+0.0387+1.0000+0.0000|
|
||||
#material: 5.80649 0.0403204 1 0 |5.8065+0.0403+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.13343 8.0994e-12 |5.8065+0.0403+1.0000+0.0000|
|
||||
#material: 5.96926 0.0418941 1 0 |5.9693+0.0419+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.27831 8.0994e-12 |5.9693+0.0419+1.0000+0.0000|
|
||||
#material: 6.12926 0.043403 1 0 |6.1293+0.0434+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.42863 8.0994e-12 |6.1293+0.0434+1.0000+0.0000|
|
||||
#material: 6.28671 0.0448543 1 0 |6.2867+0.0449+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.58416 8.0994e-12 |6.2867+0.0449+1.0000+0.0000|
|
||||
#material: 6.44181 0.0462539 1 0 |6.4418+0.0463+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.74471 8.0994e-12 |6.4418+0.0463+1.0000+0.0000|
|
||||
#material: 6.59474 0.0476066 1 0 |6.5947+0.0476+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 1.91011 8.0994e-12 |6.5947+0.0476+1.0000+0.0000|
|
||||
#material: 6.74564 0.0489169 1 0 |6.7456+0.0489+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.0802 8.0994e-12 |6.7456+0.0489+1.0000+0.0000|
|
||||
#material: 6.89465 0.0501882 1 0 |6.8946+0.0502+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.25484 8.0994e-12 |6.8946+0.0502+1.0000+0.0000|
|
||||
#material: 7.04188 0.0514238 1 0 |7.0419+0.0514+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.4339 8.0994e-12 |7.0419+0.0514+1.0000+0.0000|
|
||||
#material: 7.18745 0.0526264 1 0 |7.1875+0.0526+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.61725 8.0994e-12 |7.1875+0.0526+1.0000+0.0000|
|
||||
#material: 7.33146 0.0537984 1 0 |7.3315+0.0538+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.80478 8.0994e-12 |7.3315+0.0538+1.0000+0.0000|
|
||||
#material: 7.47398 0.0549419 1 0 |7.4740+0.0549+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 2.99639 8.0994e-12 |7.4740+0.0549+1.0000+0.0000|
|
||||
#material: 7.61511 0.0560589 1 0 |7.6151+0.0561+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 3.19199 8.0994e-12 |7.6151+0.0561+1.0000+0.0000|
|
||||
#material: 7.7549 0.0571511 1 0 |7.7549+0.0572+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 3.39148 8.0994e-12 |7.7549+0.0572+1.0000+0.0000|
|
||||
#material: 7.89344 0.0582199 1 0 |7.8934+0.0582+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 3.59477 8.0994e-12 |7.8934+0.0582+1.0000+0.0000|
|
||||
#material: 8.03078 0.0592667 1 0 |8.0308+0.0593+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 3.8018 8.0994e-12 |8.0308+0.0593+1.0000+0.0000|
|
||||
#material: 8.16697 0.0602929 1 0 |8.1670+0.0603+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.01247 8.0994e-12 |8.1670+0.0603+1.0000+0.0000|
|
||||
#material: 8.30207 0.0612995 1 0 |8.3021+0.0613+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.22673 8.0994e-12 |8.3021+0.0613+1.0000+0.0000|
|
||||
#material: 8.43613 0.0622875 1 0 |8.4361+0.0623+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.4445 8.0994e-12 |8.4361+0.0623+1.0000+0.0000|
|
||||
#material: 8.5692 0.063258 1 0 |8.5692+0.0633+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.66572 8.0994e-12 |8.5692+0.0633+1.0000+0.0000|
|
||||
#material: 8.7013 0.0642118 1 0 |8.7013+0.0642+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 4.89034 8.0994e-12 |8.7013+0.0642+1.0000+0.0000|
|
||||
#material: 8.83249 0.0651496 1 0 |8.8325+0.0651+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 5.11828 8.0994e-12 |8.8325+0.0651+1.0000+0.0000|
|
||||
#material: 8.9628 0.0660723 1 0 |8.9628+0.0661+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 5.3495 8.0994e-12 |8.9628+0.0661+1.0000+0.0000|
|
||||
#material: 9.09226 0.0669805 1 0 |9.0923+0.0670+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 5.58395 8.0994e-12 |9.0923+0.0670+1.0000+0.0000|
|
||||
#material: 9.22091 0.0678749 1 0 |9.2209+0.0679+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 5.82158 8.0994e-12 |9.2209+0.0679+1.0000+0.0000|
|
||||
#material: 9.34877 0.068756 1 0 |9.3488+0.0688+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 6.06233 8.0994e-12 |9.3488+0.0688+1.0000+0.0000|
|
||||
#material: 9.47588 0.0696244 1 0 |9.4759+0.0696+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 6.30617 8.0994e-12 |9.4759+0.0696+1.0000+0.0000|
|
||||
#material: 9.60226 0.0704806 1 0 |9.6023+0.0705+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 6.55304 8.0994e-12 |9.6023+0.0705+1.0000+0.0000|
|
||||
#material: 9.72793 0.0713251 1 0 |9.7279+0.0713+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 6.80292 8.0994e-12 |9.7279+0.0713+1.0000+0.0000|
|
||||
#material: 9.85292 0.0721583 1 0 |9.8529+0.0722+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 7.05574 8.0994e-12 |9.8529+0.0722+1.0000+0.0000|
|
||||
#material: 9.97725 0.0729807 1 0 |9.9772+0.0730+1.0000+0.0000|
|
||||
#add_dispersion_debye: 1 7.31149 8.0994e-12 |9.9772+0.0730+1.0000+0.0000|
|
二进制文件未显示。
二进制文件未显示。
二进制文件未显示。
二进制文件未显示。
二进制文件未显示。
二进制文件未显示。
二进制文件未显示。
二进制文件未显示。
二进制文件未显示。
二进制文件未显示。
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:c7c7303daffcd4debb8df4c0c5e6cd62a6fd07c6e4b33e8c47c9e190c42d75cf
|
||||
size 75736481
|
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:a0a195bfeec73f72083e6dbeb5e3713259721d2d4e9118bf019ee9905f02f5a8
|
||||
size 4927361
|
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:67c7c15c0025feac5b5899c3a691929ae1d7338c68714708c7a41e51a7f71441
|
||||
size 4009216
|
@@ -161,9 +161,11 @@ class GprMaxBaseTest(RunOnlyRegressionTest):
|
||||
if self.test_dependency is None:
|
||||
return None
|
||||
|
||||
# Always filter by the model parameter, but allow child classes
|
||||
# Always filter by the model parameter (unless the test
|
||||
# dependency only runs a single model), but allow child classes
|
||||
# (or mixins) to override how models are filtered.
|
||||
kwargs.setdefault("model", self.model)
|
||||
if len(self.test_dependency.model.values) > 1:
|
||||
kwargs.setdefault("model", self.model)
|
||||
|
||||
variant_nums = self.test_dependency.get_variant_nums(**kwargs)
|
||||
|
||||
@@ -246,6 +248,20 @@ class GprMaxBaseTest(RunOnlyRegressionTest):
|
||||
# Set the matplotlib cache to the work filesystem
|
||||
self.env_vars["MPLCONFIGDIR"] = "${HOME/home/work}/.config/matplotlib"
|
||||
|
||||
def build_output_file_path(self, filename: str) -> Path:
|
||||
"""Build output file Path object from filename.
|
||||
|
||||
Using a function to build this allows mixins to reuse or
|
||||
override it if needed.
|
||||
|
||||
Args:
|
||||
filename: Name of output file with no file extension.
|
||||
|
||||
Returns:
|
||||
Path: Output file Path object
|
||||
"""
|
||||
return Path(f"{filename}.h5")
|
||||
|
||||
@run_after("init")
|
||||
def set_file_paths(self):
|
||||
"""Set default test input and output files.
|
||||
@@ -254,7 +270,7 @@ class GprMaxBaseTest(RunOnlyRegressionTest):
|
||||
later in the pipeline.
|
||||
"""
|
||||
self.input_file = Path(f"{self.model}.in")
|
||||
self.output_file = Path(f"{self.model}.h5")
|
||||
self.output_file = self.build_output_file_path(self.model)
|
||||
|
||||
@run_before("run")
|
||||
def configure_test_run(self):
|
||||
|
@@ -1,10 +1,12 @@
|
||||
from pathlib import Path
|
||||
from shutil import copyfile
|
||||
from typing import Optional
|
||||
|
||||
import reframe.utility.sanity as sn
|
||||
import reframe.utility.typecheck as typ
|
||||
from numpy import prod
|
||||
from reframe import RegressionMixin
|
||||
from reframe.core.builtins import parameter, required, run_after, variable
|
||||
from reframe.core.builtins import parameter, run_after, variable
|
||||
from typing_extensions import TYPE_CHECKING
|
||||
|
||||
from reframe_tests.tests.base_tests import GprMaxBaseTest
|
||||
@@ -29,9 +31,14 @@ else:
|
||||
class ReceiverMixin(GprMaxMixin):
|
||||
number_of_receivers = variable(int, value=-1)
|
||||
|
||||
@run_after("setup")
|
||||
@run_after("setup", always_last=True)
|
||||
def add_receiver_regression_checks(self):
|
||||
reference_file = self.build_reference_filepath(self.output_file)
|
||||
test_dependency = self.get_test_dependency()
|
||||
if test_dependency is not None:
|
||||
output_file = self.build_output_file_path(test_dependency.model)
|
||||
reference_file = self.build_reference_filepath(output_file)
|
||||
else:
|
||||
reference_file = self.build_reference_filepath(self.output_file)
|
||||
|
||||
if self.number_of_receivers > 0:
|
||||
for i in range(self.number_of_receivers):
|
||||
@@ -88,16 +95,7 @@ class GeometryOnlyMixin(GprMaxMixin):
|
||||
self.executable_opts += ["--geometry-only"]
|
||||
|
||||
|
||||
class GeometryObjectMixin(GprMaxMixin):
|
||||
"""Add regression tests for geometry objects.
|
||||
|
||||
Attributes:
|
||||
geometry_objects (list[str]): List of geometry objects to run
|
||||
regression checks on.
|
||||
"""
|
||||
|
||||
geometry_objects = variable(typ.List[str], value=[])
|
||||
|
||||
class GeometryObjectMixinBase(GprMaxMixin):
|
||||
def build_geometry_object_filepath(self, geometry_object: str) -> Path:
|
||||
"""Build filepath to the specified geometry object.
|
||||
|
||||
@@ -114,6 +112,63 @@ class GeometryObjectMixin(GprMaxMixin):
|
||||
"""
|
||||
return Path(f"{geometry_object}_materials").with_suffix(".txt")
|
||||
|
||||
|
||||
class GeometryObjectsReadMixin(GeometryObjectMixinBase):
|
||||
geometry_objects_read = variable(typ.Dict[str, str], value={})
|
||||
|
||||
@run_after("setup")
|
||||
def copy_geometry_objects_from_test_dependency(self):
|
||||
self.skip_if(
|
||||
len(self.geometry_objects_read) < 0,
|
||||
f"Must provide a list of geometry objects being read by the test.",
|
||||
)
|
||||
|
||||
test_dependency = self.get_test_dependency()
|
||||
|
||||
self.skip_if(
|
||||
test_dependency is None,
|
||||
f"GeometryObjectsReadMixin must be used with a test dependency.",
|
||||
)
|
||||
|
||||
for geometry_object_input, geometry_object_output in self.geometry_objects_read.items():
|
||||
geometry_object_input_file = self.build_geometry_object_filepath(geometry_object_input)
|
||||
geometry_object_input_file = Path(test_dependency.stagedir, geometry_object_input_file)
|
||||
|
||||
materials_input_file = self.build_materials_filepath(geometry_object_input)
|
||||
materials_input_file = Path(test_dependency.stagedir, materials_input_file)
|
||||
|
||||
self.skip_if(
|
||||
not sn.path_isfile(geometry_object_input_file),
|
||||
f"Test dependency did not create geometry object file.",
|
||||
)
|
||||
|
||||
self.skip_if(
|
||||
not sn.path_isfile(materials_input_file),
|
||||
f"Test dependency did not create geometry object materials file.",
|
||||
)
|
||||
|
||||
geometry_object_output_file = self.build_geometry_object_filepath(
|
||||
geometry_object_output
|
||||
)
|
||||
geometry_object_output_file = Path(self.stagedir, geometry_object_output_file)
|
||||
|
||||
materials_output_file = self.build_materials_filepath(geometry_object_output)
|
||||
materials_output_file = Path(self.stagedir, materials_output_file)
|
||||
|
||||
copyfile(geometry_object_input_file, geometry_object_output_file)
|
||||
copyfile(materials_input_file, materials_output_file)
|
||||
|
||||
|
||||
class GeometryObjectsWriteMixin(GeometryObjectMixinBase):
|
||||
"""Add regression tests for geometry objects.
|
||||
|
||||
Attributes:
|
||||
geometry_objects_write (list[str]): List of geometry objects to
|
||||
run regression checks on.
|
||||
"""
|
||||
|
||||
geometry_objects_write = variable(typ.List[str], value=[])
|
||||
|
||||
@run_after("setup")
|
||||
def add_geometry_object_regression_checks(self):
|
||||
"""Add a regression check for each geometry object.
|
||||
@@ -121,11 +176,11 @@ class GeometryObjectMixin(GprMaxMixin):
|
||||
The test will be skipped if no geometry objects have been specified.
|
||||
"""
|
||||
self.skip_if(
|
||||
len(self.geometry_objects) < 0,
|
||||
f"Must provide a list of geometry objects.",
|
||||
len(self.geometry_objects_write) < 0,
|
||||
f"Must provide a list of geometry objects being written by the test.",
|
||||
)
|
||||
|
||||
for geometry_object in self.geometry_objects:
|
||||
for geometry_object in self.geometry_objects_write:
|
||||
# Add materials regression check first as if this fails,
|
||||
# checking the .h5 file will almost definitely fail.
|
||||
materials_file = self.build_materials_filepath(geometry_object)
|
||||
@@ -138,7 +193,9 @@ class GeometryObjectMixin(GprMaxMixin):
|
||||
self.regression_checks.append(materials_regression_check)
|
||||
|
||||
geometry_object_file = self.build_geometry_object_filepath(geometry_object)
|
||||
reference_file = self.build_reference_filepath(geometry_object)
|
||||
reference_file = self.build_reference_filepath(
|
||||
geometry_object, suffix=geometry_object_file.suffix
|
||||
)
|
||||
regression_check = GeometryObjectRegressionCheck(geometry_object_file, reference_file)
|
||||
self.regression_checks.append(regression_check)
|
||||
|
||||
|
@@ -0,0 +1,14 @@
|
||||
#title: Hertzian dipole in free-space
|
||||
#domain: 0.100 0.100 0.100
|
||||
#dx_dy_dz: 0.002 0.005 0.005
|
||||
#time_window: 3e-9
|
||||
|
||||
#pml_cells: 5 2 2 5 2 2
|
||||
|
||||
#waveform: gaussiandot 1 1e9 myWave
|
||||
#hertzian_dipole: z 0.050 0.050 0.050 myWave
|
||||
|
||||
#rx: 0.08 0.08 0.08
|
||||
|
||||
#geometry_objects_read: 0.03 0.03 0.03 full_volume_read.h5 full_volume_read_materials.txt
|
||||
#geometry_objects_write: 0.05 0.05 0.05 0.09 0.09 0.09 partial_volume
|
@@ -0,0 +1,13 @@
|
||||
#title: Hertzian dipole in free-space
|
||||
#domain: 0.100 0.100 0.100
|
||||
#dx_dy_dz: 0.002 0.005 0.005
|
||||
#time_window: 3e-9
|
||||
|
||||
#pml_cells: 5 2 2 5 2 2
|
||||
|
||||
#waveform: gaussiandot 1 1e9 myWave
|
||||
#hertzian_dipole: z 0.050 0.050 0.050 myWave
|
||||
|
||||
#rx: 0.08 0.08 0.08
|
||||
|
||||
#geometry_objects_read: 0 0 0 full_volume_read.h5 full_volume_read_materials.txt
|
@@ -0,0 +1,15 @@
|
||||
#title: Hertzian dipole in free-space
|
||||
#domain: 0.100 0.100 0.100
|
||||
#dx_dy_dz: 0.002 0.005 0.005
|
||||
#time_window: 3e-9
|
||||
|
||||
#pml_cells: 5 2 2 5 2 2
|
||||
|
||||
#waveform: gaussiandot 1 1e9 myWave
|
||||
#hertzian_dipole: z 0.050 0.050 0.050 myWave
|
||||
|
||||
#rx: 0.08 0.08 0.08
|
||||
|
||||
#geometry_objects_read: 0 0 0 full_volume_read.h5 full_volume_read_materials.txt
|
||||
#geometry_objects_write: 0.02 0.02 0.02 0.06 0.06 0.06 partial_volume
|
||||
#geometry_objects_write: 0 0 0 0.1 0.1 0.1 full_volume
|
@@ -1,11 +1,15 @@
|
||||
#title: Hertzian dipole in free-space
|
||||
#domain: 0.100 0.100 0.100
|
||||
#dx_dy_dz: 0.001 0.001 0.001
|
||||
#dx_dy_dz: 0.002 0.005 0.005
|
||||
#time_window: 3e-9
|
||||
|
||||
#pml_cells: 5 2 2 5 2 2
|
||||
|
||||
#waveform: gaussiandot 1 1e9 myWave
|
||||
#hertzian_dipole: z 0.050 0.050 0.050 myWave
|
||||
|
||||
#rx: 0.08 0.08 0.08
|
||||
|
||||
#material: 4.9 0 1 0 myWater
|
||||
#material: 2 0 1.4 0 unusedMaterial
|
||||
#material: 3 0 2 0 boxMaterial
|
||||
|
@@ -0,0 +1,14 @@
|
||||
#title: Heterogeneous soil using a stochastic distribution of dielectric properties given by a mixing model from Peplinski
|
||||
#domain: 0.100 0.100 0.100
|
||||
#dx_dy_dz: 0.001 0.001 0.001
|
||||
#time_window: 3e-9
|
||||
|
||||
#waveform: ricker 1 1.5e9 my_ricker
|
||||
#hertzian_dipole: y 0.02 0.02 0.02 my_ricker
|
||||
#rx: 0.080 0.080 0.080
|
||||
|
||||
#material: 8 0 1 0 half_space
|
||||
#fractal_box: 0 0 0 0.1 0.1 0.05 1.5 1 1 1 1 half_space my_fractal_box 42
|
||||
#add_grass: 0 0 0.05 0.1 0.1 0.05 1.5 0.05 0.1 100 my_fractal_box 22
|
||||
|
||||
#geometry_objects_write: 0 0 0 0.1 0.1 0.1 full_volume
|
@@ -0,0 +1,15 @@
|
||||
#title: Heterogeneous soil using a stochastic distribution of dielectric properties given by a mixing model from Peplinski
|
||||
#domain: 0.100 0.100 0.100
|
||||
#dx_dy_dz: 0.001 0.001 0.001
|
||||
#time_window: 3e-9
|
||||
|
||||
#waveform: ricker 1 1.5e9 my_ricker
|
||||
#hertzian_dipole: y 0.02 0.02 0.02 my_ricker
|
||||
#rx: 0.080 0.080 0.080
|
||||
|
||||
#material: 8 0 1 0 half_space
|
||||
#fractal_box: 0.06 0.06 0.02 0.08 0.08 0.045 1.5 1 1 1 1 half_space my_fractal_box 42
|
||||
#add_surface_roughness: 0.06 0.08 0.02 0.08 0.08 0.045 1 1 1 0.07 0.08 my_fractal_box 22
|
||||
#add_grass: 0.06 0.08 0.02 0.08 0.08 0.045 1.5 0.075 0.09 100 my_fractal_box 17
|
||||
|
||||
#geometry_objects_write: 0 0 0 0.1 0.1 0.1 full_volume
|
@@ -0,0 +1,19 @@
|
||||
#title: Heterogeneous soil using a stochastic distribution of dielectric properties given by a mixing model from Peplinski
|
||||
#domain: 0.100 0.100 0.100
|
||||
#dx_dy_dz: 0.001 0.001 0.001
|
||||
#time_window: 3e-9
|
||||
|
||||
#waveform: ricker 1 1.5e9 my_ricker
|
||||
#hertzian_dipole: y 0.02 0.02 0.02 my_ricker
|
||||
#rx: 0.080 0.080 0.080
|
||||
|
||||
#soil_peplinski: 0.5 0.5 2.0 2.66 0.001 0.25 my_soil
|
||||
|
||||
#fractal_box: 0 0 0 0.049 0.05 0.051 1.5 1 1 1 50 my_soil box_1 42
|
||||
#fractal_box: 0.049 0.05 0.051 0.1 0.1 0.1 1.5 1 1 1 50 my_soil box_2 22
|
||||
|
||||
#add_surface_roughness: 0.049 0 0 0.049 0.05 0.05 1 1 1 0.025 0.05 box_1 43
|
||||
#add_surface_roughness: 0.049 0.05 0.051 0.049 0.1 0.1 1 1 1 0.049 0.074 box_2 23
|
||||
|
||||
|
||||
#geometry_objects_write: 0 0 0 0.1 0.1 0.1 full_volume
|
@@ -0,0 +1,14 @@
|
||||
#title: Heterogeneous soil using a stochastic distribution of dielectric properties given by a mixing model from Peplinski
|
||||
#domain: 0.100 0.100 0.100
|
||||
#dx_dy_dz: 0.001 0.001 0.001
|
||||
#time_window: 3e-9
|
||||
|
||||
#waveform: ricker 1 1.5e9 my_ricker
|
||||
#hertzian_dipole: y 0.02 0.02 0.02 my_ricker
|
||||
#rx: 0.080 0.080 0.080
|
||||
|
||||
#soil_peplinski: 0.5 0.5 2.0 2.66 0.001 0.25 my_soil
|
||||
#fractal_box: 0 0 0 0.1 0.1 0.07 1.5 1 1 1 50 my_soil my_soil_box 42
|
||||
#add_surface_roughness: 0 0 0.07 0.1 0.1 0.07 1 1 1 0.05 0.1 my_soil_box 22
|
||||
|
||||
#geometry_objects_write: 0 0 0 0.1 0.1 0.1 full_volume
|
@@ -0,0 +1,14 @@
|
||||
#title: Heterogeneous soil using a stochastic distribution of dielectric properties given by a mixing model from Peplinski
|
||||
#domain: 0.100 0.100 0.100
|
||||
#dx_dy_dz: 0.001 0.001 0.001
|
||||
#time_window: 3e-9
|
||||
|
||||
#waveform: ricker 1 1.5e9 my_ricker
|
||||
#hertzian_dipole: y 0.02 0.02 0.02 my_ricker
|
||||
#rx: 0.080 0.080 0.080
|
||||
|
||||
#soil_peplinski: 0.5 0.5 2.0 2.66 0.001 0.25 my_soil
|
||||
#fractal_box: 0.03 0.03 0.03 0.045 0.045 0.045 1.5 1 1 1 50 my_soil my_soil_box 42
|
||||
#add_surface_roughness: 0.03 0.03 0.03 0.045 0.03 0.045 1 1 1 0.01 0.02 my_soil_box 22
|
||||
|
||||
#geometry_objects_write: 0 0 0 0.1 0.1 0.1 full_volume
|
@@ -0,0 +1,14 @@
|
||||
#title: Heterogeneous soil using a stochastic distribution of dielectric properties given by a mixing model from Peplinski
|
||||
#domain: 0.100 0.100 0.100
|
||||
#dx_dy_dz: 0.001 0.001 0.001
|
||||
#time_window: 3e-9
|
||||
|
||||
#waveform: ricker 1 1.5e9 my_ricker
|
||||
#hertzian_dipole: y 0.02 0.02 0.02 my_ricker
|
||||
#rx: 0.080 0.080 0.080
|
||||
|
||||
#soil_peplinski: 0.5 0.5 2.0 2.66 0.001 0.25 my_soil
|
||||
#fractal_box: 0 0 0 0.1 0.1 0.07 1.5 1 1 1 50 my_soil my_soil_box 42
|
||||
#add_surface_roughness: 0 0 0.07 0.1 0.1 0.07 5 1.2 0.2 0.05 0.1 my_soil_box 22
|
||||
|
||||
#geometry_objects_write: 0 0 0 0.1 0.1 0.1 full_volume
|
@@ -0,0 +1,15 @@
|
||||
#title: Heterogeneous soil using a stochastic distribution of dielectric properties given by a mixing model from Peplinski
|
||||
#domain: 0.100 0.100 0.100
|
||||
#dx_dy_dz: 0.001 0.001 0.001
|
||||
#time_window: 3e-9
|
||||
|
||||
#waveform: ricker 1 1.5e9 my_ricker
|
||||
#hertzian_dipole: y 0.02 0.02 0.02 my_ricker
|
||||
#rx: 0.080 0.080 0.080
|
||||
|
||||
#soil_peplinski: 0.5 0.5 2.0 2.66 0.001 0.25 my_soil
|
||||
#fractal_box: 0 0 0 0.1 0.1 0.07 1.5 1 1 1 50 my_soil my_soil_box 42
|
||||
#add_surface_roughness: 0 0 0.07 0.1 0.1 0.07 1 1 1 0.05 0.1 my_soil_box 22
|
||||
#add_surface_water: 0 0 0.07 0.1 0.1 0.07 0.1 my_soil_box
|
||||
|
||||
#geometry_objects_write: 0 0 0 0.1 0.1 0.1 full_volume
|
@@ -0,0 +1,15 @@
|
||||
#title: Heterogeneous soil using a stochastic distribution of dielectric properties given by a mixing model from Peplinski
|
||||
#domain: 0.100 0.100 0.100
|
||||
#dx_dy_dz: 0.001 0.001 0.001
|
||||
#time_window: 3e-9
|
||||
|
||||
#waveform: ricker 1 1.5e9 my_ricker
|
||||
#hertzian_dipole: y 0.02 0.02 0.02 my_ricker
|
||||
#rx: 0.080 0.080 0.080
|
||||
|
||||
#soil_peplinski: 0.5 0.5 2.0 2.66 0.001 0.25 my_soil
|
||||
#fractal_box: 0.015 0.015 0.015 0.03 0.03 0.03 1.5 1 1 1 50 my_soil my_soil_box 42
|
||||
#add_surface_roughness: 0.03 0.015 0.015 0.03 0.03 0.03 1 1 1 0.035 0.045 my_soil_box 22
|
||||
#add_surface_water: 0.03 0.015 0.015 0.03 0.03 0.03 0.04 my_soil_box
|
||||
|
||||
#geometry_objects_write: 0 0 0 0.1 0.1 0.1 full_volume
|
@@ -0,0 +1,14 @@
|
||||
#title: Heterogeneous soil using a stochastic distribution of dielectric properties given by a mixing model from Peplinski
|
||||
#domain: 0.100 0.100 0.100
|
||||
#dx_dy_dz: 0.001 0.001 0.001
|
||||
#time_window: 3e-9
|
||||
|
||||
#waveform: ricker 1 1.5e9 my_ricker
|
||||
#hertzian_dipole: y 0.02 0.02 0.02 my_ricker
|
||||
#rx: 0.080 0.080 0.080
|
||||
|
||||
#soil_peplinski: 0.5 0.5 2.0 2.66 0.001 0.25 my_soil
|
||||
#fractal_box: 0 0 0 0.049 0.05 0.051 1.5 1 1 1 50 my_soil my_soil_box 42
|
||||
#fractal_box: 0.049 0.05 0.051 0.1 0.1 0.1 1.5 1 1 1 50 my_soil my_soil_box 22
|
||||
|
||||
#geometry_objects_write: 0 0 0 0.1 0.1 0.1 full_volume
|
@@ -0,0 +1,13 @@
|
||||
#title: Heterogeneous soil using a stochastic distribution of dielectric properties given by a mixing model from Peplinski
|
||||
#domain: 0.100 0.100 0.100
|
||||
#dx_dy_dz: 0.001 0.001 0.001
|
||||
#time_window: 3e-9
|
||||
|
||||
#waveform: ricker 1 1.5e9 my_ricker
|
||||
#hertzian_dipole: y 0.02 0.02 0.02 my_ricker
|
||||
#rx: 0.080 0.080 0.080
|
||||
|
||||
#soil_peplinski: 0.5 0.5 2.0 2.66 0.001 0.25 my_soil
|
||||
#fractal_box: 0.015 0.015 0.015 0.045 0.045 0.045 1.5 1 1 1 50 my_soil my_soil_box 42
|
||||
|
||||
#geometry_objects_write: 0 0 0 0.1 0.1 0.1 full_volume
|
@@ -0,0 +1,13 @@
|
||||
#title: Heterogeneous soil using a stochastic distribution of dielectric properties given by a mixing model from Peplinski
|
||||
#domain: 0.100 0.100 0.100
|
||||
#dx_dy_dz: 0.001 0.001 0.001
|
||||
#time_window: 3e-9
|
||||
|
||||
#waveform: ricker 1 1.5e9 my_ricker
|
||||
#hertzian_dipole: y 0.02 0.02 0.02 my_ricker
|
||||
#rx: 0.080 0.080 0.080
|
||||
|
||||
#soil_peplinski: 0.5 0.5 2.0 2.66 0.001 0.25 my_soil
|
||||
#fractal_box: 0 0 0 0.1 0.1 0.1 1.5 1.5 1 0.8 50 my_soil my_soil_box 42
|
||||
|
||||
#geometry_objects_write: 0 0 0 0.1 0.1 0.1 full_volume
|
@@ -13,5 +13,7 @@
|
||||
#sphere: 0.05 0.05 0.05 0.03 myWater y
|
||||
#box: 0.01 0.01 0.01 0.09 0.025 0.025 boxMaterial y
|
||||
|
||||
#geometry_view: 0.02 0.02 0.02 0.06 0.06 0.06 0.001 0.001 0.001 partial_volume f
|
||||
#geometry_view: 0 0 0 0.1 0.1 0.1 0.001 0.001 0.001 full_volume f
|
||||
#geometry_view: 0.04 0.04 0.04 0.06 0.06 0.06 0.001 0.001 0.001 partial_volume f
|
||||
#geometry_view: 0 0 0.048 0.1 0.1 0.049 0.001 0.001 0.001 z_plane_48 f
|
||||
#geometry_view: 0 0 0.049 0.1 0.1 0.05 0.001 0.001 0.001 z_plane_49 f
|
||||
#geometry_view: 0 0 0.05 0.1 0.1 0.051 0.001 0.001 0.001 z_plane_50 f
|
||||
|
@@ -14,4 +14,7 @@
|
||||
#box: 0.01 0.01 0.01 0.09 0.025 0.025 boxMaterial y
|
||||
|
||||
#geometry_view: 0.02 0.02 0.02 0.06 0.06 0.06 0.001 0.001 0.001 partial_volume n
|
||||
#geometry_view: 0 0 0 0.1 0.1 0.1 0.001 0.001 0.001 full_volume n
|
||||
#geometry_view: 0 0 0 0.1 0.1 0.1 0.002 0.002 0.002 full_volume n
|
||||
#geometry_view: 0 0 0.048 0.1 0.1 0.049 0.001 0.001 0.001 z_plane_48 n
|
||||
#geometry_view: 0 0 0.049 0.1 0.1 0.05 0.001 0.001 0.001 z_plane_49 n
|
||||
#geometry_view: 0 0 0.05 0.1 0.1 0.051 0.001 0.001 0.001 z_plane_50 n
|
||||
|
某些文件未显示,因为此 diff 中更改的文件太多 显示更多
在新工单中引用
屏蔽一个用户