文件
gprMax/gprMax/cmds_geometry/cone.py
Antonis Giannopoulos bec20bbd52 New object building primitives and two new mixing models for fractal box, bug fixes
Introduced object primitives #ellipsoid and #cone. The #ellipsoid works with regular semi-axes
along x, y, and z. The #cone works in a similar way to the cylinder and can be truncated with circular faces of different radii. If one radius is zero then it is a normal cone.
Introduced two new mixing models for using with a fractal box, #material_range and #material_list
The #material_range allows materials to be constructed using ranges of permittivity, conductivity, magnetic permeability and magnetic loss. Ranges can be increasing or decreasing as needed.
The #material_list creates a list of predefined materials that can be used with a fractal box. The order of the listed materials reflects the order of the bins they are allocated to in a fractal box.
The fractal box and associated mixing models have been updated to use a list of material IDs and do not rely on the assumption that are generated sequentially. This gives greater flexibility and
adds little computation burden on the creation of the fractal volume.

Bug fixes for mixing anisotropic volumetric materials where "mr" was used instead of "ms".
Bug fixes on objects that use integer coordinates for centres but where passed floats instead.
2023-04-16 13:51:47 +01:00

148 行
6.1 KiB
Python

# Copyright (C) 2015-2023: The University of Edinburgh, United Kingdom
# Authors: Craig Warren, Antonis Giannopoulos, and John Hartley
#
# 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 numpy as np
from ..cython.geometry_primitives import build_cone
from ..materials import Material
from .cmds_geometry import UserObjectGeometry
logger = logging.getLogger(__name__)
class Cone(UserObjectGeometry):
"""Introduces a circular cone into the model. The difference with the cylinder is that the faces of the cone
can have different radii and one of them can be zero.
Attributes:
p1: list of the coordinates (x,y,z) of the centre of the first face
of the cone.
p2: list of the coordinates (x,y,z) of the centre of the second face
of the cone.
r1: float of the radius of the first face of the cone.
r2: float of the radius of the second face of the cone.
material_id: string for the material identifier that must correspond
to material that has already been defined.
material_ids: list of material identifiers in the x, y, z directions.
averaging: string (y or n) used to switch on and off dielectric smoothing.
"""
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.hash = '#cylinder'
def create(self, grid, uip):
try:
p1 = self.kwargs['p1']
p2 = self.kwargs['p2']
r1 = self.kwargs['r1']
r2 = self.kwargs['r2']
except KeyError:
logger.exception(self.__str__() + ' please specify 2 points and two radii')
raise
# Check averaging
try:
# Try user-specified averaging
averagecylinder = self.kwargs['averaging']
except KeyError:
# Otherwise go with the grid default
averagecylinder = grid.averagevolumeobjects
# Check materials have been specified
# Isotropic case
try:
materialsrequested = [self.kwargs['material_id']]
except KeyError:
# Anisotropic case
try:
materialsrequested = self.kwargs['material_ids']
except KeyError:
logger.exception(self.__str__() + ' no materials have been specified')
raise
p3 = uip.round_to_grid_static_point(p1)
p4 = uip.round_to_grid_static_point(p2)
x1, y1, z1 = uip.round_to_grid(p1)
x2, y2, z2 = uip.round_to_grid(p2)
if r1 < 0:
logger.exception(self.__str__() + f' the radius of the first face {r1:g} should be a positive value.')
raise ValueError
if r2 < 0:
logger.exception(self.__str__() + f' the radius of the second face {r2:g} should be a positive value.')
raise ValueError
if r1 == 0 and r2 == 0:
logger.exception(self.__str__() + f' not both radii can be zero.')
raise ValueError
# Look up requested materials in existing list of material instances
materials = [y for x in materialsrequested for y in grid.materials if y.ID == x]
if len(materials) != len(materialsrequested):
notfound = [x for x in materialsrequested if x not in materials]
logger.exception(self.__str__() + f' material(s) {notfound} do not exist')
raise ValueError
# Isotropic case
if len(materials) == 1:
averaging = materials[0].averagable and averagecylinder
numID = numIDx = numIDy = numIDz = materials[0].numID
# Uniaxial anisotropic case
elif len(materials) == 3:
averaging = False
numIDx = materials[0].numID
numIDy = materials[1].numID
numIDz = materials[2].numID
requiredID = materials[0].ID + '+' + materials[1].ID + '+' + materials[2].ID
averagedmaterial = [x for x in grid.materials if x.ID == requiredID]
if averagedmaterial:
numID = averagedmaterial.numID
else:
numID = len(grid.materials)
m = Material(numID, requiredID)
m.type = 'dielectric-smoothed'
# Create dielectric-smoothed constituents for material
m.er = np.mean((materials[0].er, materials[1].er,
materials[2].er), axis=0)
m.se = np.mean((materials[0].se, materials[1].se,
materials[2].se), axis=0)
m.mr = np.mean((materials[0].mr, materials[1].mr,
materials[2].mr), axis=0)
m.sm = np.mean((materials[0].sm, materials[1].sm,
materials[2].sm), axis=0)
# Append the new material object to the materials list
grid.materials.append(m)
build_cone(x1, y1, z1, x2, y2, z2, r1, r2, grid.dx, grid.dy, grid.dz,
numID, numIDx, numIDy, numIDz, averaging, grid.solid,
grid.rigidE, grid.rigidH, grid.ID)
dielectricsmoothing = 'on' if averaging else 'off'
logger.info(self.grid_name(grid) + f"Cone with face centres {p3[0]:g}m, " +
f"{p3[1]:g}m, {p3[2]:g}m and {p4[0]:g}m, {p4[1]:g}m, {p4[2]:g}m, " +
f"with radii {r1:g}m and {r2:g}, of material(s) {', '.join(materialsrequested)} " +
f"created, dielectric smoothing is {dielectricsmoothing}.")