Overhaul GSoC stltovoxel work into a pure user_lib tool, i.e. not a gprMax command

这个提交包含在:
Craig Warren
2022-01-06 20:50:39 +00:00
父节点 ab72976ec5
当前提交 9983253861
共有 44 个文件被更改,包括 106 次插入114 次删除

查看文件

@@ -17,9 +17,10 @@ dependencies:
- pip:
# - mpi4py
- numpy-stl
# - pycuda
# - pyopencl
- terminaltables
- tqdm
- git+https://github.com/craig-warren/PyEVTK.git
- numpy-stl

查看文件

@@ -19,7 +19,6 @@ from .cmds_geometry.cylindrical_sector import CylindricalSector
from .cmds_geometry.edge import Edge
from .cmds_geometry.fractal_box import FractalBox
from .cmds_geometry.geometry_objects_read import GeometryObjectsRead
from .cmds_geometry.geometry_objects_read import GeometryObjectsReadSTL
from .cmds_geometry.plate import Plate
from .cmds_geometry.sphere import Sphere
from .cmds_geometry.triangle import Triangle

查看文件

@@ -29,58 +29,6 @@ from .cmds_geometry import UserObjectGeometry
logger = logging.getLogger(__name__)
import numpy as np
import matplotlib.pyplot as plt
from user_libs import stltovoxel
class GeometryObjectsReadSTL(UserObjectGeometry):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.hash = '#geometry_objects_stl'
def create(self, G, uip):
try:
stl_file = self.kwargs['stl_file'] # STL file of the model to be voxelized
mat_index = self.kwargs['mat_index'] #material index corresponding to the order of materials in the txt file
discretization = self.kwargs['discretization'] #spacial discretization of the model
except KeyError:
logger.exception(self.__str__() + 'requires exactly three parameters')
raise
# See if stl file exists at specified path and if not try input
# file directory
stl_file=Path(stl_file)
if not stl_file.exists():
stl_file = Path(config.sim_config.input_file_path.parent, stl_file)
model_array = stltovoxel.convert_file(stl_file,discretization)
print()
print("Resolution of the model along (X,Y,Z) axis is",model_array.shape)
parts = config.sim_config.input_file_path.with_suffix('').parts
filename_hdf5 = Path(*parts)
filename_hdf5 = filename_hdf5.with_suffix('.h5')
with h5py.File(filename_hdf5,'w') as hdf:
model_array[model_array==0] = -1
model_array[model_array==1] = mat_index
hdf.create_dataset('data',data=model_array)
hdf.attrs['dx_dy_dz']=(discretization[0],discretization[1],discretization[2])
def visualize(self,model_array):
#visualizer requires the model array to be built of only 0's and 1's
#if you want to use this function call it before the .h5 part
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.voxels(model_array)
plt.show()
class GeometryObjectsRead(UserObjectGeometry):
@@ -91,7 +39,7 @@ class GeometryObjectsRead(UserObjectGeometry):
def rotate(self, axis, angle, origin=None):
pass
def create(self, G, uip):
def create(self, grid, uip):
"""Create the object and add it to the grid."""
try:
p1 = self.kwargs['p1']
@@ -114,7 +62,7 @@ class GeometryObjectsRead(UserObjectGeometry):
matfile = Path(config.sim_config.input_file_path.parent, matfile)
matstr = matfile.with_suffix('').name
numexistmaterials = len(G.materials)
numexistmaterials = len(grid.materials)
# Read materials from file
with open(matfile, 'r') as f:
@@ -130,10 +78,10 @@ class GeometryObjectsRead(UserObjectGeometry):
scene.add(material_obj)
# Creates the internal simulation objects
scene.process_cmds(material_objs, G, sort=False)
scene.process_cmds(material_objs, grid, sort=False)
# Update material type
for material in G.materials:
for material in grid.materials:
if material.numID >= numexistmaterials:
if material.type:
material.type += ',\nimported'
@@ -148,7 +96,7 @@ class GeometryObjectsRead(UserObjectGeometry):
# 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] / G.dx) != 1 or round_value(dx_dy_dz[1] / G.dy) != 1 or round_value(dx_dy_dz[2] / G.dz) != 1:
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(self.__str__() + ' requires the spatial resolution of the geometry objects file to match the spatial resolution of the model')
raise ValueError
@@ -165,12 +113,12 @@ class GeometryObjectsRead(UserObjectGeometry):
rigidE = f['/rigidE'][:]
rigidH = f['/rigidH'][:]
ID = f['/ID'][:]
G.solid[xs:xs + data.shape[0], ys:ys + data.shape[1], zs:zs + data.shape[2]] = data + numexistmaterials
G.rigidE[:, xs:xs + rigidE.shape[1], ys:ys + rigidE.shape[2], zs:zs + rigidE.shape[3]] = rigidE
G.rigidH[:, xs:xs + rigidH.shape[1], ys:ys + rigidH.shape[2], zs:zs + rigidH.shape[3]] = rigidH
G.ID[:, xs:xs + ID.shape[1], ys:ys + ID.shape[2], zs:zs + ID.shape[3]] = ID + numexistmaterials
logger.info(self.grid_name(G) + f'Geometry objects from file {geofile} inserted at {xs * G.dx:g}m, {ys * G.dy:g}m, {zs * G.dz:g}m, with corresponding materials file {matfile}.')
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(self.grid_name(grid) + f'Geometry objects from file {geofile} inserted at {xs * grid.dx:g}m, {ys * grid.dy:g}m, {zs * grid.dz:g}m, with corresponding materials file {matfile}.')
except KeyError:
averaging = False
build_voxels_from_array(xs, ys, zs, numexistmaterials, averaging, data, G.solid, G.rigidE, G.rigidH, G.ID)
logger.info(self.grid_name(G) + f'Geometry objects from file (voxels only){geofile} inserted at {xs * G.dx:g}m, {ys * G.dy:g}m, {zs * G.dz:g}m, with corresponding materials file {matfile}.')
build_voxels_from_array(xs, ys, zs, numexistmaterials, averaging, data, grid.solid, grid.rigidE, grid.rigidH, grid.ID)
logger.info(self.grid_name(grid) + f'Geometry objects from file (voxels only){geofile} inserted at {xs * grid.dx:g}m, {ys * grid.dy:g}m, {zs * grid.dz:g}m, with corresponding materials file {matfile}.')

查看文件

查看文件

@@ -1,7 +0,0 @@
from .main import convert_file, convert_files,convert_meshes
__all__ = [
'convert_file',
'convert_files',
'convert_meshes',
]

查看文件

@@ -1,14 +1,18 @@
from stl import mesh
import numpy as np
from stl import mesh
from . import slice
def convert_meshes(meshes, discretization, parallel=True):
scale, shift, shape = slice.calculate_scale_shift(meshes, discretization)
vol = np.zeros(shape[::-1], dtype=np.int32)
for mesh_ind, org_mesh in enumerate(meshes):
slice.scale_and_shift_mesh(org_mesh, scale, shift)
cur_vol = slice.mesh_to_plane(org_mesh, shape, parallel)
vol[cur_vol] = mesh_ind + 1
return vol, scale, shift
@@ -18,12 +22,12 @@ def convert_file(input_file_path, discretization, pad=1, parallel=False):
def convert_files(input_file_paths, discretization, colors=[(0, 0, 0)], pad=1, parallel=False):
meshes = []
for input_file_path in input_file_paths:
mesh_obj = mesh.Mesh.from_file(input_file_path)
org_mesh = np.hstack((mesh_obj.v0[:, np.newaxis], mesh_obj.v1[:, np.newaxis], mesh_obj.v2[:, np.newaxis]))
meshes.append(org_mesh)
vol, scale, shift = convert_meshes(meshes, discretization, parallel)
vol=np.transpose(vol)
vol = np.transpose(vol)
return vol

查看文件

之前

宽度:  |  高度:  |  大小: 174 KiB

之后

宽度:  |  高度:  |  大小: 174 KiB

查看文件

之前

宽度:  |  高度:  |  大小: 486 KiB

之后

宽度:  |  高度:  |  大小: 486 KiB

查看文件

之前

宽度:  |  高度:  |  大小: 650 KiB

之后

宽度:  |  高度:  |  大小: 650 KiB

查看文件

之前

宽度:  |  高度:  |  大小: 14 KiB

之后

宽度:  |  高度:  |  大小: 14 KiB

查看文件

之前

宽度:  |  高度:  |  大小: 23 KiB

之后

宽度:  |  高度:  |  大小: 23 KiB

查看文件

之前

宽度:  |  高度:  |  大小: 193 KiB

之后

宽度:  |  高度:  |  大小: 193 KiB

查看文件

之前

宽度:  |  高度:  |  大小: 125 KiB

之后

宽度:  |  高度:  |  大小: 125 KiB

查看文件

之前

宽度:  |  高度:  |  大小: 25 KiB

之后

宽度:  |  高度:  |  大小: 25 KiB

查看文件

之前

宽度:  |  高度:  |  大小: 9.3 KiB

之后

宽度:  |  高度:  |  大小: 9.3 KiB

查看文件

之前

宽度:  |  高度:  |  大小: 17 KiB

之后

宽度:  |  高度:  |  大小: 17 KiB

查看文件

之前

宽度:  |  高度:  |  大小: 13 KiB

之后

宽度:  |  高度:  |  大小: 13 KiB

查看文件

之前

宽度:  |  高度:  |  大小: 29 KiB

之后

宽度:  |  高度:  |  大小: 29 KiB

查看文件

之前

宽度:  |  高度:  |  大小: 59 KiB

之后

宽度:  |  高度:  |  大小: 59 KiB

查看文件

之前

宽度:  |  高度:  |  大小: 74 KiB

之后

宽度:  |  高度:  |  大小: 74 KiB

查看文件

之前

宽度:  |  高度:  |  大小: 244 KiB

之后

宽度:  |  高度:  |  大小: 244 KiB

查看文件

之前

宽度:  |  高度:  |  大小: 48 KiB

之后

宽度:  |  高度:  |  大小: 48 KiB

查看文件

之前

宽度:  |  高度:  |  大小: 40 KiB

之后

宽度:  |  高度:  |  大小: 40 KiB

查看文件

之前

宽度:  |  高度:  |  大小: 6.2 KiB

之后

宽度:  |  高度:  |  大小: 6.2 KiB

二进制文件未显示。

查看文件

@@ -0,0 +1,29 @@
from pathlib import Path
import gprMax
fn = Path(__file__)
title = gprMax.Title(name=fn.with_suffix('').name)
domain = gprMax.Domain(p1=(0.148, 0.128, 0.148))
dl = 0.001
dxdydz = gprMax.Discretisation(p1=(dl, dl, dl))
time_window = gprMax.TimeWindow(time=10e-9)
g_read = gprMax.GeometryObjectsRead(p1=(0.020, 0.020, 0.020), geofile='bunny.h5', matfile= 'materials.txt')
gv = gprMax.GeometryView(p1=(0, 0, 0),
p2=domain.props.p1,
dl=(dl, dl, dl),
filename=fn.with_suffix('').name,
output_type='n')
scene = gprMax.Scene()
scene.add(title)
scene.add(domain)
scene.add(dxdydz)
scene.add(time_window)
scene.add(g_read)
scene.add(gv)
gprMax.run(scenes=[scene], geometry_only=True, n=1, outputfile=fn)

二进制文件未显示。

查看文件

@@ -1,5 +1,6 @@
from functools import reduce
def lines_to_voxels(line_list, pixels):
current_line_indices = set()
x = 0
@@ -22,12 +23,14 @@ def slope_intercept(p1, p2):
x2, y2 = p2[:2]
slope = (y2 - y1) / (x2 - x1)
intercept = y1 - slope * x1
return slope, intercept
def generate_y(p1, p2, x):
slope, intercept = slope_intercept(p1, p2)
y = slope * x + intercept
return y
@@ -56,8 +59,10 @@ def paint_y_axis(lines, pixels, x):
def generate_line_events(line_list):
events = []
for i, line in enumerate(line_list):
first, second = sorted(line, key=lambda pt: pt[0])
events.append((first[0], 'start', i))
events.append((second[0], 'end', i))
return sorted(events, key=lambda tup: tup[0])

查看文件

@@ -1,8 +1,13 @@
import numpy as np
import multiprocessing as mp
import sys
import numpy as np
from gprMax.utilities.utilities import get_terminal_width
from tqdm import tqdm
from . import perimeter
def mesh_to_plane(mesh, bounding_box, parallel):
if parallel:
pool = mp.Pool(mp.cpu_count())
@@ -12,7 +17,7 @@ def mesh_to_plane(mesh, bounding_box, parallel):
current_mesh_indices = set()
z = 0
with tqdm(total=bounding_box[2], desc="Processing Layers", bar_format="{l_bar}{bar:50}{r_bar}{bar:-50b}") as pbar:
with tqdm(total=bounding_box[2], desc="Processing Layers", ncols=get_terminal_width() - 1, file=sys.stdout) as pbar:
for event_z, status, tri_ind in generate_tri_events(mesh):
while event_z - z >= 0:
mesh_subset = [mesh[ind] for ind in current_mesh_indices]
@@ -102,6 +107,7 @@ def where_line_crosses_z(p1, p2, z):
distance = 0
else:
distance = (z - p1[2]) / (p2[2] - p1[2])
return linear_interpolation(p1, p2, distance)
@@ -121,8 +127,8 @@ def calculate_scale_shift(meshes, discretization):
bx=int(amplitude[0]/vx)
by=int(amplitude[1]/vy)
bz=int(amplitude[2]/vz)
print(amplitude)
bounding_box = [bx+1, by+1, bz+1]
return max(1/vx,1/vy,1/vz), mesh_min, bounding_box
@@ -138,4 +144,5 @@ def generate_tri_events(mesh):
bottom, middle, top = sorted(tri, key=lambda pt: pt[2])
events.append((bottom[2], 'start', i))
events.append((top[2], 'end', i))
return sorted(events, key=lambda tup: tup[0])

查看文件

@@ -0,0 +1,40 @@
import argparse
import logging
from pathlib import Path
import h5py
import matplotlib.pyplot as plt
from .convert import convert_file
logger = logging.getLogger(__name__)
logging.basicConfig(format='%(message)s', level=logging.INFO)
if __name__ == "__main__":
# Parse command line arguments
parser = argparse.ArgumentParser(description='Allows the user to convert a STL files to voxelized mesh.', usage='cd gprMax; python -m user_libs.stltovoxel.stltovoxel stlfilename matindex dx_dy_dz')
parser.add_argument('stlfilename', help='name of STL file to convert including path')
parser.add_argument('-matindex', type=int, required=True,
help='index of material to extract from STL file')
parser.add_argument('-dxdydz', nargs='+', type=float, required=True,
help='discretisation to use in voxelisation process')
args = parser.parse_args()
filename_stl = Path(args.stlfilename)
dxdydz = tuple(args.dxdydz)
logger.info(f'\nConverting STL file: {filename_stl.name}')
model_array = convert_file(filename_stl, dxdydz)
model_array[model_array==0] = -1
model_array[model_array==1] = args.matindex
logger.info(f'Number of voxels: {model_array.shape[0]} x {model_array.shape[1]} x {model_array.shape[2]}')
logger.info(f'Spatial discretisation: {dxdydz[0]} x {dxdydz[1]} x {dxdydz[2]}m')
# Write HDF5 file for gprMax using voxels
filename_hdf5 = filename_stl.with_suffix('.h5')
with h5py.File(filename_hdf5, 'w') as f:
f.create_dataset('data', data=model_array)
f.attrs['dx_dy_dz'] = (dxdydz[0], dxdydz[1], dxdydz[2])
logger.info(f'Written geometry object file: {filename_hdf5.name}')

查看文件

@@ -1,34 +0,0 @@
from pathlib import Path
import gprMax
fn = Path(__file__)
title = gprMax.Title(name=fn.with_suffix('').name)
domain = gprMax.Domain(p1=(0.12,0.1,0.12))
dxdydz = gprMax.Discretisation(p1=(0.001, 0.001, 0.001))
time_window = gprMax.TimeWindow(time=10e-9)
g_stl = gprMax.GeometryObjectsReadSTL(stl_file='data_LasoMax/Stanford_Bunny.stl', mat_index=2, discretization=(0.001,0.001,0.001) )
g_read = gprMax.GeometryObjectsRead(p1=(0 ,0 ,0), geofile=fn.with_suffix('.h5') , matfile= 'user_models/materials.txt')
gv = gprMax.GeometryView(p1=(0, 0, 0),
p2=(0.12, 0.1,0.12),
dl=(0.001, 0.001, 0.001),
filename=fn.with_suffix('').name,
output_type='n')
# create a scene
scene = gprMax.Scene()
# add the simulation objects to the scene
scene.add(title)
scene.add(domain)
scene.add(dxdydz)
scene.add(time_window)
scene.add(g_stl)
scene.add(g_read)
scene.add(gv)
# run the simulation
gprMax.run(scenes=[scene], geometry_only=True, n=1, outputfile=fn)