Skip to content

Commit ceeee02

Browse files
committed
fix: adding export methods
1 parent d2e7e95 commit ceeee02

File tree

6 files changed

+161
-4
lines changed

6 files changed

+161
-4
lines changed

LoopStructural/datatypes/_structured_grid.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,6 @@ def vtk(self):
3939
)
4040
grid[self.name] = self.data.flatten(order="F")
4141
return grid
42+
43+
def save(self, filename):
44+
raise NotImplementedError("Saving structured grids is not yet implemented")

LoopStructural/datatypes/_surface.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ def save(self, filename):
9595
with open(filename, 'w') as f:
9696
json.dump(self.to_dict(), f)
9797
elif ext == 'vtk':
98-
self.vtk.save(filename)
98+
self.vtk().save(filename)
9999
elif ext == 'obj':
100100
import meshio
101101

LoopStructural/export/geoh5.py

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import geoh5py
2+
import numpy as np
23

34

45
def add_surface_to_geoh5(filename, surface, overwrite=True, groupname="Loop"):
@@ -27,4 +28,56 @@ def add_surface_to_geoh5(filename, surface, overwrite=True, groupname="Loop"):
2728
surface.add_data(data)
2829

2930

30-
# def add_points_to_geoh5(filename, points, overwrite=True, groupname="Loop"):
31+
def add_points_to_geoh5(filename, points, overwrite=True, groupname="Loop"):
32+
with geoh5py.workspace.Workspace(filename) as workspace:
33+
group = workspace.get_entity(groupname)[0]
34+
if not group:
35+
group = geoh5py.groups.ContainerGroup.create(
36+
workspace, name=groupname, allow_delete=True
37+
)
38+
for point in points:
39+
if point.name in workspace.list_entities_name.values():
40+
existing_point = workspace.get_entity(point.name)
41+
existing_point[0].allow_delete = True
42+
if overwrite:
43+
workspace.remove_entity(existing_point[0])
44+
data = {}
45+
if point.properties is not None:
46+
for k, v in point.properties.items():
47+
data[k] = {'association': "VERTEX", "values": v}
48+
point = geoh5py.objects.Points.create(
49+
workspace,
50+
name=point.name,
51+
vertices=point.vertices,
52+
parent=group,
53+
)
54+
point.add_data(data)
55+
56+
57+
def add_block_model_to_geoh5py(filename, block_model, overwrite=True, groupname="Loop"):
58+
with geoh5py.workspace.Workspace(filename) as workspace:
59+
group = workspace.get_entity(groupname)[0]
60+
if not group:
61+
group = geoh5py.groups.ContainerGroup.create(
62+
workspace, name=groupname, allow_delete=True
63+
)
64+
if block_model.name in workspace.list_entities_name.values():
65+
existing_block = workspace.get_entity(block_model.name)
66+
existing_block[0].allow_delete = True
67+
if overwrite:
68+
workspace.remove_entity(existing_block[0])
69+
data = {}
70+
if block_model.properties is not None:
71+
for k, v in block_model.properties.items():
72+
data[k] = {'association': "CELL", "values": v}
73+
block = geoh5py.objects.BlockModel.create(
74+
workspace,
75+
name=block_model.name,
76+
origin=[25, -100, 50],
77+
u_cell_delimiters=np.cumsum(np.ones(16) * 5), # Offsets along u
78+
v_cell_delimiters=np.cumsum(np.ones(32) * 5), # Offsets along v
79+
z_cell_delimiters=np.cumsum(np.ones(16) * -2.5), # Offsets along z (down)
80+
rotation=30.0,
81+
parent=group,
82+
)
83+
block.add_data(data)

LoopStructural/modelling/core/geological_model.py

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import numpy as np
88
import pandas as pd
99
from typing import List
10-
10+
import pathlib
1111
from ...modelling.features.fault import FaultSegment
1212

1313
from ...modelling.features.builders import (
@@ -37,6 +37,7 @@
3737
from ...modelling.intrusions import IntrusionBuilder
3838

3939
from ...modelling.intrusions import IntrusionFrameBuilder
40+
from LoopStructural.modelling.features import fault
4041

4142

4243
logger = getLogger(__name__)
@@ -1807,3 +1808,51 @@ def get_block_model(self):
18071808
self.bounding_box.cell_centers(), scale=False
18081809
)
18091810
return grid, self.stratigraphic_ids()
1811+
1812+
def save(
1813+
self,
1814+
filename: str,
1815+
block_model: bool = False,
1816+
stratigraphic_surfaces=True,
1817+
fault_surfaces=True,
1818+
stratigraphic_data=True,
1819+
fault_data=True,
1820+
):
1821+
path = pathlib.Path(filename)
1822+
extension = path.suffix
1823+
name = path.stem
1824+
stratigraphic_surfaces = self.get_stratigraphic_surfaces()
1825+
if fault_surfaces:
1826+
for s in self.get_fault_surfaces():
1827+
## geoh5 can save everything into the same file
1828+
if extension == ".geoh5":
1829+
s.save(filename)
1830+
else:
1831+
s.save(f'{name}_{s.name}.{extension}')
1832+
if stratigraphic_surfaces:
1833+
for s in self.get_stratigraphic_surfaces():
1834+
if extension == ".geoh5":
1835+
s.save(filename)
1836+
else:
1837+
s.save(f'{name}_{s.name}.{extension}')
1838+
if block_model:
1839+
grid, ids = self.get_block_model()
1840+
if extension == ".geoh5":
1841+
grid.save(filename)
1842+
else:
1843+
grid.save(f'{name}_block_model.{extension}')
1844+
if stratigraphic_data:
1845+
for group in self.stratigraphic_column.keys():
1846+
if group == "faults":
1847+
continue
1848+
for series in self.stratigraphic_column[group].keys():
1849+
if extension == ".geoh5":
1850+
self.__getitem__(series).save(filename)
1851+
else:
1852+
self.__getitem__(series).save(f'{name}_{series}.{extension}')
1853+
if fault_data:
1854+
for f in self.fault_names():
1855+
if extension == ".geoh5":
1856+
self.__getitem__(f).save(filename)
1857+
else:
1858+
self.__getitem__(f).save(f'{name}_{f}.{extension}')

LoopStructural/utils/_surface.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,13 @@ def fit(
102102
values,
103103
)
104104
logger.info(f'Isosurfacing at values: {isovalues}')
105-
for isovalue in isovalues:
105+
if name is None:
106+
names = ["surface"] * len(isovalues)
107+
if isinstance(name, str):
108+
names = [name] * len(isovalues)
109+
if isinstance(name, list):
110+
names = name
111+
for name, isovalue in zip(names, isovalues):
106112
try:
107113
step_vector = (self.bounding_box.maximum - self.bounding_box.origin) / (
108114
np.array(self.bounding_box.nsteps) - 1
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
"""
2+
3+
1j. Exporting models
4+
===============================
5+
6+
Models can be exported to vtk, gocad and geoh5 formats.
7+
"""
8+
9+
from LoopStructural import GeologicalModel
10+
from LoopStructural.datasets import load_claudius
11+
12+
data, bb = load_claudius()
13+
14+
model = GeologicalModel(bb[0, :], bb[1, :])
15+
model.data = data
16+
model.create_and_add_foliation("strati")
17+
18+
19+
######################################################################
20+
# Export surfaces to vtk
21+
# ~~~~~~~~~~~~~~~~~~~~~~
22+
# Isosurfaces can be extracted from a geological feature by calling
23+
# the `.surfaces` method on the feature. The argument for this method
24+
# is the value, values or number of surfaces that are extracted.
25+
# This returns a list of `LoopStructural.datatypes.Surface` objects
26+
# These objects can be interrogated to return the triangles, vertices
27+
# and normals. Or can be exported into another format using the `save`
28+
# method. The supported file formats are `vtk`, `ts` and `geoh5`.
29+
#
30+
31+
surfaces = model['strati'].surfaces(value=0.0)
32+
33+
print(surfaces)
34+
35+
print(surfaces[0].vtk)
36+
37+
surfaces[0].save('text.geoh5')
38+
39+
######################################################################
40+
# Export the model to geoh5
41+
# ~~~~~~~~~~~~~~~~~~~~~~~~~
42+
# The entire model can be exported to a geoh5 file using the `save_model`
43+
# method. This will save all the data, foliations, faults and other objects
44+
# in the model to a geoh5 file. This file can be loaded into LoopStructural
45+
46+
model.save_model('model.geoh5')

0 commit comments

Comments
 (0)