22Routines to export geological model data to file in a variety of formats
33"""
44import logging
5+ import os
56from pyevtk .hl import unstructuredGridToVTK , pointsToVTK
67from pyevtk .vtk import VtkTriangle
78import numpy as np
89
910from LoopStructural .utils .helper import create_box
1011from LoopStructural .export .file_formats import FileFormat
1112
12-
13+
1314from LoopStructural .utils import getLogger
1415logger = getLogger (__name__ )
1516
@@ -29,7 +30,7 @@ def write_cubeface(model, file_name, data_label, nsteps, file_format):
2930 nsteps : np.array([num-x-steps, num-y-steps, num-z-steps])
3031 3d array dimensions
3132 file_format: export.fileformats.FileFormat object
32- Desired format of exported file
33+ Desired format of exported file. Supports VTK
3334
3435 Returns
3536 -------
@@ -58,7 +59,7 @@ def write_vol(model, file_name, data_label, nsteps, file_format):
5859 nsteps : np.array([num-x-steps, num-y-steps, num-z-steps])
5960 3d array dimensions
6061 file_format: export.fileformats.FileFormat object
61- Desired format of exported file
62+ Desired format of exported file. Supports VTK and GOCAD
6263
6364 Returns
6465 -------
@@ -67,14 +68,16 @@ def write_vol(model, file_name, data_label, nsteps, file_format):
6768 """
6869 if file_format == FileFormat .VTK :
6970 return _write_vol_evtk (model , file_name , data_label , nsteps )
71+ if file_format == FileFormat .GOCAD :
72+ return _write_vol_gocad (model , file_name , data_label , nsteps )
7073
7174 logger .warning ("Cannot export to file - format {} not supported yet" .format (str (file_format )))
7275 return False
7376
7477
7578def _write_cubeface_evtk (model , file_name , data_label , nsteps , real_coords = True ):
7679 """
77- Writes out the model as a cuboid with six rectangular surfaces
80+ Writes out the model as a cuboid with six rectangular surfaces in VTK unstructured grid format
7881
7982 Parameters
8083 ----------
@@ -119,16 +122,17 @@ def _write_cubeface_evtk(model, file_name, data_label, nsteps, real_coords=True)
119122 ctype = np .full (tri .shape [0 ], VtkTriangle .tid )
120123
121124 try :
122- unstructuredGridToVTK (file_name , x , y , z , connectivity = conn , offsets = offset , cell_types = ctype , cellData = None , pointData = {data_label : val })
125+ unstructuredGridToVTK (file_name , x , y , z , connectivity = conn , offsets = offset , cell_types = ctype ,
126+ cellData = None , pointData = {data_label : val })
123127 except Exception as e :
124- logger .warning ("Cannot export cuboid surface to file {}: {}" .format (file_name , str (e )))
128+ logger .warning ("Cannot export cuboid surface to VTK file {}: {}" .format (file_name , str (e )))
125129 return False
126- return True
130+ return True
127131
128132
129133def _write_vol_evtk (model , file_name , data_label , nsteps , real_coords = True ):
130134 """
131- Writes out the model as a 3d volume grid
135+ Writes out the model as a 3d volume grid in VTK points format
132136
133137 Parameters
134138 ----------
@@ -153,12 +157,13 @@ def _write_vol_evtk(model, file_name, data_label, nsteps, real_coords=True):
153157
154158 # Generate model values in 3d grid
155159 xx , yy , zz = np .meshgrid (loop_X , loop_Y , loop_Z , indexing = 'ij' )
160+ # xyz is N x 3 vector array
156161 xyz = np .array ([xx .flatten (), yy .flatten (), zz .flatten ()]).T
157162 vals = model .evaluate_model (xyz , scale = False )
158163 if real_coords :
159164 model .rescale (xyz )
160165
161- # Define vertices
166+ # Define vertices - xyz.shape[0] is length of vector array
162167 x = np .zeros (xyz .shape [0 ])
163168 y = np .zeros (xyz .shape [0 ])
164169 z = np .zeros (xyz .shape [0 ])
@@ -167,10 +172,122 @@ def _write_vol_evtk(model, file_name, data_label, nsteps, real_coords=True):
167172
168173 # Write to grid
169174 try :
170- pointsToVTK (file_name , x , y , z , data = { data_label : vals })
175+ pointsToVTK (file_name , x , y , z , data = { data_label : vals })
171176 except Exception as e :
172- logger .warning ("Cannot export volume to file {}: {}" .format (file_name , str (e )))
177+ logger .warning ("Cannot export volume to VTK file {}: {}" .format (file_name , str (e )))
173178 return False
174- return True
179+ return True
180+
175181
182+ def _write_vol_gocad (model , file_name , data_label , nsteps , real_coords = True ):
183+ """
184+ Writes out the model as a 3d volume grid in GOCAD VOXET object format
185+
186+ Parameters
187+ ----------
188+ model : GeologicalModel object
189+ Geological model to export
190+ file_name : string
191+ Name of file that model is exported to, including path, but without the file extension
192+ data_label : string
193+ A data label to insert into export file
194+ nsteps : np.array([num-x-steps, num-y-steps, num-z-steps])
195+ 3d array dimensions
176196
197+ Returns
198+ -------
199+ True if successful
200+
201+ """
202+ # Define grid spacing in model scale coords
203+ loop_X = np .linspace (model .bounding_box [0 , 0 ], model .bounding_box [1 , 0 ], nsteps [0 ])
204+ loop_Y = np .linspace (model .bounding_box [0 , 1 ], model .bounding_box [1 , 1 ], nsteps [1 ])
205+ loop_Z = np .linspace (model .bounding_box [0 , 2 ], model .bounding_box [1 , 2 ], nsteps [2 ])
206+
207+ # Generate model values in 3d grid
208+ xx , yy , zz = np .meshgrid (loop_X , loop_Y , loop_Z , indexing = 'ij' )
209+ # xyz is N x 3 vector array
210+ xyz = np .array ([xx .flatten (), yy .flatten (), zz .flatten ()]).T
211+ vals = model .evaluate_model (xyz , scale = False )
212+ # Use FORTRAN style indexing for GOCAD VOXET
213+ vol_vals = np .reshape (vals , nsteps , order = 'F' )
214+ bbox = model .bounding_box [:]
215+
216+ # Convert bounding box to real world scale coords
217+ if real_coords :
218+ model .rescale (bbox )
219+
220+ # If integer values
221+ if type (vals [0 ]) is np .int64 :
222+ d_type = np .int8
223+ no_data_val = None
224+ prop_esize = 1
225+ prop_storage_type = "Octet"
226+
227+ # If float values
228+ elif type (vals [0 ]) is np .float32 :
229+ d_type = np .dtype ('>f4' )
230+ no_data_val = - 999999.0
231+ prop_esize = 4
232+ prop_storage_type = "Float"
233+ else :
234+ logger .warning ("Cannot export volume to GOCAD VOXET file: Unsupported type {}" .format (type (vals [0 ])))
235+ return False
236+
237+ # Write out VOXET file
238+ vo_filename = file_name + ".vo"
239+ data_filename = file_name + "@@"
240+ try :
241+ with open (vo_filename , "w" ) as fp :
242+ fp .write ("""GOCAD Voxet 1
243+ HEADER {{
244+ name: {name}
245+ }}
246+ GOCAD_ORIGINAL_COORDINATE_SYSTEM
247+ NAME Default
248+ AXIS_NAME "X" "Y" "Z"
249+ AXIS_UNIT "m" "m" "m"
250+ ZPOSITIVE Elevation
251+ END_ORIGINAL_COORDINATE_SYSTEM
252+ AXIS_O 0.000000 0.000000 0.000000
253+ AXIS_U 1.000000 0.000000 0.000000
254+ AXIS_V 0.000000 1.000000 0.000000
255+ AXIS_W 0.000000 0.000000 1.000000
256+ AXIS_MIN {axismin1} {axismin2} {axismin3}
257+ AXIS_MAX {axismax1} {axismax2} {axismax3}
258+ AXIS_N {nsteps1} {nsteps2} {nsteps3}
259+ AXIS_NAME "X" "Y" "Z"
260+ AXIS_UNIT "m" "m" "m"
261+ AXIS_TYPE even even even
262+ PROPERTY 1 {propname}
263+ PROPERTY_CLASS 1 {propname}
264+ PROP_UNIT 1 {propname}
265+ PROPERTY_CLASS_HEADER 1 {propname} {{
266+ }}
267+ PROPERTY_SUBCLASS 1 QUANTITY {prop_storage_type}
268+ """ .format (name = os .path .basename (file_name ),
269+ nsteps1 = nsteps [0 ], nsteps2 = nsteps [1 ], nsteps3 = nsteps [2 ],
270+ axismin1 = bbox [0 , 0 ], axismin2 = bbox [0 , 1 ], axismin3 = bbox [0 , 2 ],
271+ axismax1 = bbox [1 , 0 ], axismax2 = bbox [1 , 1 ], axismax3 = bbox [1 , 2 ],
272+ propname = data_label , prop_storage_type = prop_storage_type ))
273+ if no_data_val is not None :
274+ fp .write ("PROP_NO_DATA_VALUE 1 {no_data_val}\n " .format (no_data_val = no_data_val ))
275+ fp .write ("""PROP_ETYPE 1 IEEE
276+ PROP_FORMAT 1 RAW
277+ PROP_ESIZE 1 {prop_esize}
278+ PROP_OFFSET 1 0
279+ PROP_FILE 1 {prop_file}
280+ END\n """ .format (prop_file = data_filename , prop_esize = prop_esize ))
281+ except IOError as exc :
282+ logger .warning ("Cannot export volume to GOCAD VOXET file {}: {}" .format (vo_filename , str (exc )))
283+ return False
284+
285+ # Write out accompanying binary data file
286+ export_vals = np .array (vol_vals , dtype = d_type )
287+ try :
288+ with open (data_filename , "wb" ) as fp :
289+ export_vals .tofile (fp )
290+ except IOError as exc :
291+ logger .warning ("Cannot export volume to GOCAD VOXET data file {}: {}" .format (data_filename , str (exc )))
292+ return False
293+ return True
0 commit comments