From f9e4de9e1796f166a2ae9baf3067ccbe541ea151 Mon Sep 17 00:00:00 2001 From: Vincent Fazio Date: Sat, 22 Aug 2020 12:27:09 +1000 Subject: [PATCH 1/4] Add export to file of 6-face cuboid volumes --- LoopStructural/export/exporters.py | 59 +++++++++++++++++++++++++++ LoopStructural/export/file_formats.py | 9 ++++ 2 files changed, 68 insertions(+) create mode 100644 LoopStructural/export/exporters.py create mode 100644 LoopStructural/export/file_formats.py diff --git a/LoopStructural/export/exporters.py b/LoopStructural/export/exporters.py new file mode 100644 index 000000000..d8dfbe2a0 --- /dev/null +++ b/LoopStructural/export/exporters.py @@ -0,0 +1,59 @@ +import logging +import meshio +import numpy as np + +from LoopStructural.utils.helper import create_box +from LoopStructural.export.file_formats import FileFormat + + +logger = logging.getLogger(__name__) + + +def write_cubeface_vol(model, file_name, nsteps, file_format): + """ Writes out a GeologicalModel as a 6-faced cuboid volume to a file + + Parameters + ---------- + model : model object + 'GeologicalModel' object + file_name : name of file + Name of file that model is exported to, including path + nsteps : number of steps in volume + NumPy 3x1 array specifying the point density of the cube in three dimensions + file_format : exported file format + An 'export.file_formats.FileFormat' object e.g. 'FileFormat.OBJ' + + Returns + ------- + True if successful + """ + points, tri = create_box(model.bounding_box, nsteps) + model.rescale(points) + + val = model.evaluate_model(points, scale=True) + + # Use meshio to output cube faces + if file_format in [FileFormat.OBJ, FileFormat.VTK]: + + # Remove 'FileFormat.' + out_fmt = str(file_format)[11:].lower() + + # Write out mesh + cells = [("triangle", tri)] + try: + meshio.write_points_cells(file_name, points, cells, file_format=out_fmt) + except Exception as e: + logger.error("Cannot export file {}: {}".format(file_name, str(e))) + return False + + # Use pyassimp to output cube faces + elif file_format == FileFormat.GLTF: + # Not supported yet + logger.warning("Cannot export to file - GLTF not supported yet") + return False + + # Unknown file type + else: + logger.error("Cannot export to file - unknown FileType") + return False + return True diff --git a/LoopStructural/export/file_formats.py b/LoopStructural/export/file_formats.py new file mode 100644 index 000000000..6636a297a --- /dev/null +++ b/LoopStructural/export/file_formats.py @@ -0,0 +1,9 @@ +from enum import Enum + +class FileFormat(Enum): + """ Enumeration of file export formats + """ + OBJ = 1 + VTK = 2 + GZ = 3 + GLTF = 4 From 2de74be7d27d3ca6db95c94468f66251c5356b7a Mon Sep 17 00:00:00 2001 From: Vincent Fazio Date: Sat, 29 Aug 2020 12:33:11 +1000 Subject: [PATCH 2/4] Add documentation --- LoopStructural/export/file_formats.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/LoopStructural/export/file_formats.py b/LoopStructural/export/file_formats.py index 6636a297a..23f736f24 100644 --- a/LoopStructural/export/file_formats.py +++ b/LoopStructural/export/file_formats.py @@ -1,3 +1,6 @@ +""" +Exported file formats +""" from enum import Enum class FileFormat(Enum): @@ -5,5 +8,5 @@ class FileFormat(Enum): """ OBJ = 1 VTK = 2 - GZ = 3 - GLTF = 4 + GZ = 3 # Not supported yet + GLTF = 4 # Not supported yet From 951dceeecafc307aea2311f7aa4f1e31d9258b5d Mon Sep 17 00:00:00 2001 From: Vincent Fazio Date: Sat, 26 Sep 2020 12:53:24 +1000 Subject: [PATCH 3/4] Export cube surfaces and volumes in vtk format --- LoopStructural/export/exporters.py | 180 ++++++++++++++++++++++++----- 1 file changed, 148 insertions(+), 32 deletions(-) diff --git a/LoopStructural/export/exporters.py b/LoopStructural/export/exporters.py index d8dfbe2a0..2655fe182 100644 --- a/LoopStructural/export/exporters.py +++ b/LoopStructural/export/exporters.py @@ -1,5 +1,9 @@ +""" +Routines to export geological model data to file in a variety of formats +""" import logging -import meshio +from pyevtk.hl import unstructuredGridToVTK, pointsToVTK +from pyevtk.vtk import VtkTriangle import numpy as np from LoopStructural.utils.helper import create_box @@ -9,51 +13,163 @@ logger = logging.getLogger(__name__) -def write_cubeface_vol(model, file_name, nsteps, file_format): - """ Writes out a GeologicalModel as a 6-faced cuboid volume to a file +def write_cubeface(model, file_name, data_label, nsteps, file_format): + """ + Writes out the model as a cuboid with six rectangular surfaces + + Parameters + ---------- + model : GeologicalModel object + Geological model to export + file_name : string + Name of file that model is exported to, including path + data_label : string + A data label to insert into export file + nsteps : np.array([num-x-steps, num-y-steps, num-z-steps]) + 3d array dimensions + file_format: export.fileformats.FileFormat object + Desired format of exported file + + Returns + ------- + True if successful + + """ + if file_format == FileFormat.VTK: + return _write_cubeface_evtk(model, file_name, data_label, nsteps) + + logger.warning("Cannot export to file - format {} not supported yet".format(str(file_format))) + return False + + +def write_vol(model, file_name, data_label, nsteps, file_format): + """ + Writes out the model as a 3d volume grid + + Parameters + ---------- + model : GeologicalModel object + Geological model to export + file_name : string + Name of file that model is exported to, including path + data_label : string + A data label to insert into export file + nsteps : np.array([num-x-steps, num-y-steps, num-z-steps]) + 3d array dimensions + file_format: export.fileformats.FileFormat object + Desired format of exported file + + Returns + ------- + True if successful + + """ + if file_format == FileFormat.VTK: + return _write_vol_evtk(model, file_name, data_label, nsteps) + + logger.warning("Cannot export to file - format {} not supported yet".format(str(file_format))) + return False + + +def _write_cubeface_evtk(model, file_name, data_label, nsteps, real_coords=True): + """ + Writes out the model as a cuboid with six rectangular surfaces Parameters ---------- - model : model object - 'GeologicalModel' object - file_name : name of file - Name of file that model is exported to, including path - nsteps : number of steps in volume - NumPy 3x1 array specifying the point density of the cube in three dimensions - file_format : exported file format - An 'export.file_formats.FileFormat' object e.g. 'FileFormat.OBJ' + model : GeologicalModel object + Geological model to export + file_name : string + Name of file that model is exported to, including path + data_label : string + A data label to insert into export file + nsteps : np.array([num-x-steps, num-y-steps, num-z-steps]) + 3d array dimensions Returns ------- True if successful + """ + # Evaluate model at points points, tri = create_box(model.bounding_box, nsteps) - model.rescale(points) + val = model.evaluate_model(points, scale=False) + if real_coords: + model.rescale(points) - val = model.evaluate_model(points, scale=True) + # Define vertices + x = np.zeros(points.shape[0]) + y = np.zeros(points.shape[0]) + z = np.zeros(points.shape[0]) + for i in range(points.shape[0]): + x[i], y[i], z[i] = points[i][0], points[i][1], points[i][2] - # Use meshio to output cube faces - if file_format in [FileFormat.OBJ, FileFormat.VTK]: + # Define connectivity or vertices that belongs to each element + conn = np.zeros(tri.shape[0] * 3) + for i in range(tri.shape[0]): + conn[i*3], conn[i*3+1], conn[i*3+2] = tri[i][0], tri[i][1], tri[i][2] - # Remove 'FileFormat.' - out_fmt = str(file_format)[11:].lower() + # Define offset of last vertex of each element + offset = np.zeros(tri.shape[0]) + for i in range(tri.shape[0]): + offset[i] = (i+1)*3 - # Write out mesh - cells = [("triangle", tri)] - try: - meshio.write_points_cells(file_name, points, cells, file_format=out_fmt) - except Exception as e: - logger.error("Cannot export file {}: {}".format(file_name, str(e))) - return False + # Define cell types + ctype = np.full(tri.shape[0], VtkTriangle.tid) - # Use pyassimp to output cube faces - elif file_format == FileFormat.GLTF: - # Not supported yet - logger.warning("Cannot export to file - GLTF not supported yet") + try: + unstructuredGridToVTK(file_name, x, y, z, connectivity = conn, offsets = offset, cell_types = ctype, cellData = None, pointData = {data_label: val}) + except Exception as e: + logger.warning("Cannot export cuboid surface to file {}: {}".format(file_name, str(e))) return False + return True + + +def _write_vol_evtk(model, file_name, data_label, nsteps, real_coords=True): + """ + Writes out the model as a 3d volume grid + + Parameters + ---------- + model : GeologicalModel object + Geological model to export + file_name : string + Name of file that model is exported to, including path + data_label : string + A data label to insert into export file + nsteps : np.array([num-x-steps, num-y-steps, num-z-steps]) + 3d array dimensions + + Returns + ------- + True if successful - # Unknown file type - else: - logger.error("Cannot export to file - unknown FileType") + """ + # Define grid spacing + loop_X = np.linspace(model.bounding_box[0, 0], model.bounding_box[1, 0], nsteps[0]) + loop_Y = np.linspace(model.bounding_box[0, 1], model.bounding_box[1, 1], nsteps[1]) + loop_Z = np.linspace(model.bounding_box[0, 2], model.bounding_box[1, 2], nsteps[2]) + + # Generate model values in 3d grid + xx, yy, zz = np.meshgrid(loop_X, loop_Y, loop_Z, indexing='ij') + xyz = np.array([xx.flatten(), yy.flatten(), zz.flatten()]).T + vals = model.evaluate_model(xyz, scale=False) + if real_coords: + model.rescale(xyz) + + # Define vertices + x = np.zeros(xyz.shape[0]) + y = np.zeros(xyz.shape[0]) + z = np.zeros(xyz.shape[0]) + for i in range(xyz.shape[0]): + x[i], y[i], z[i] = xyz[i][0], xyz[i][1], xyz[i][2] + + # Write to grid + try: + pointsToVTK(file_name, x, y, z, data= { data_label: vals}) + except Exception as e: + logger.warning("Cannot export volume to file {}: {}".format(file_name, str(e))) return False - return True + return True + + From 7da6f1d488acebc4d07cb6e62a9c39ddb9ecfdd9 Mon Sep 17 00:00:00 2001 From: Vincent Fazio Date: Mon, 28 Sep 2020 09:19:36 +1000 Subject: [PATCH 4/4] Add missing package & improve exporter comments --- LoopStructural/export/exporters.py | 8 ++++---- requirements.txt | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/LoopStructural/export/exporters.py b/LoopStructural/export/exporters.py index 2655fe182..e18f7ff53 100644 --- a/LoopStructural/export/exporters.py +++ b/LoopStructural/export/exporters.py @@ -22,7 +22,7 @@ def write_cubeface(model, file_name, data_label, nsteps, file_format): model : GeologicalModel object Geological model to export file_name : string - Name of file that model is exported to, including path + Name of file that model is exported to, including path, but without the file extension data_label : string A data label to insert into export file nsteps : np.array([num-x-steps, num-y-steps, num-z-steps]) @@ -51,7 +51,7 @@ def write_vol(model, file_name, data_label, nsteps, file_format): model : GeologicalModel object Geological model to export file_name : string - Name of file that model is exported to, including path + Name of file that model is exported to, including path, but without the file extension data_label : string A data label to insert into export file nsteps : np.array([num-x-steps, num-y-steps, num-z-steps]) @@ -80,7 +80,7 @@ def _write_cubeface_evtk(model, file_name, data_label, nsteps, real_coords=True) model : GeologicalModel object Geological model to export file_name : string - Name of file that model is exported to, including path + Name of file that model is exported to, including path, but without the file extension data_label : string A data label to insert into export file nsteps : np.array([num-x-steps, num-y-steps, num-z-steps]) @@ -134,7 +134,7 @@ def _write_vol_evtk(model, file_name, data_label, nsteps, real_coords=True): model : GeologicalModel object Geological model to export file_name : string - Name of file that model is exported to, including path + Name of file that model is exported to, including path, but without the file extension data_label : string A data label to insert into export file nsteps : np.array([num-x-steps, num-y-steps, num-z-steps]) diff --git a/requirements.txt b/requirements.txt index 39ae9e0fb..12dae86a6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,5 +6,6 @@ numpy matplotlib setuptools pandas +pyevtk