Skip to content

Commit 378f319

Browse files
committed
2 parents 96c8ddb + 54a2f85 commit 378f319

File tree

18 files changed

+2911
-34
lines changed

18 files changed

+2911
-34
lines changed

LoopStructural/datasets/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@
1616
from ._base import value_headers
1717
from ._base import load_unconformity
1818
from ._base import load_duplex
19+
from ._base import load_tabular_intrusion

LoopStructural/datasets/_base.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,3 +142,18 @@ def strike_dip_headers():
142142

143143
def normal_vector_headers():
144144
return ["X", "Y", "Z", "nx", "ny", "nz"]
145+
146+
147+
def load_tabular_intrusion():
148+
"""Model dataset sampled for a model of a tabular intrusion
149+
150+
151+
Returns
152+
-------
153+
tuple
154+
pandas data frame with loopstructural dataset and numpy array for bounding box
155+
"""
156+
module_path = dirname(__file__)
157+
data = pd.read_csv(join(module_path, Path("data/tabular_intrusion.csv")))
158+
bb = np.array([[0, 0, 0], [5, 5, 5]])
159+
return data, bb
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
feature_name,X,Y,Z,coord,val,gx,gy,gz,intrusion_contact_type,intrusion_anisotropy,intrusion_side
2+
stratigraphy,0.00,0.00,2.00,,0,,,,,,
3+
stratigraphy,0.00,5.00,2.00,,0,,,,,,
4+
stratigraphy,5.00,0.00,2.00,,0,,,,,,
5+
stratigraphy,5.00,5.00,2.00,,0,,,,,,
6+
stratigraphy,2.50,2.50,2.00,,,0,0,1,,,
7+
tabular_intrusion,3.04,2.12,2.18,,,,,,roof,stratigraphy,
8+
tabular_intrusion,4.02,3.85,2.14,,,,,,roof,stratigraphy,TRUE
9+
tabular_intrusion,2.02,3.16,2.02,,,,,,roof,stratigraphy,
10+
tabular_intrusion,2.12,2.16,2.02,,,,,,roof,stratigraphy,
11+
tabular_intrusion,1.14,3.50,2.04,,,,,,roof,,TRUE
12+
tabular_intrusion,4.08,3.02,1.18,,,,,,floor,,TRUE
13+
tabular_intrusion,1.14,1.06,1.16,,,,,,floor,,TRUE
14+
tabular_intrusion,4.20,2.18,1.12,,,,,,floor,,TRUE
15+
tabular_intrusion,1.02,3.02,1.12,,,,,,floor,,TRUE
16+
tabular_intrusion_frame,2.00,2.00,2.00,0,,0,0,-1,,,
17+
tabular_intrusion_frame,3.00,1.00,2.00,0,,0,0,-1,,,
18+
tabular_intrusion_frame,1.00,3.00,2.00,0,,0,0,-1,,,
19+
tabular_intrusion_frame,3.00,2.00,1.00,1,0,,,,,,
20+
tabular_intrusion_frame,3.00,2.00,1.00,1,,0,1,0,,,
21+
tabular_intrusion_frame,2.50,1.00,1.00,2,0,,,,,,
22+
tabular_intrusion_frame,2.50,2.00,1.00,2,0,,,,,,
23+
tabular_intrusion_frame,2.50,2.00,1.00,2,,1,0,0,,,

LoopStructural/interpolators/__init__.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,12 @@ class InterpolatorType(IntEnum):
5050
from LoopStructural.interpolators._discrete_fold_interpolator import (
5151
DiscreteFoldInterpolator,
5252
)
53-
from LoopStructural.interpolators._surfe_wrapper import SurfeRBFInterpolator
5453

54+
try:
55+
from LoopStructural.interpolators._surfe_wrapper import SurfeRBFInterpolator
56+
except ImportError:
57+
logger.warning('Can\'t import surfepy - to install "pip install surfe"')
5558

56-
logger.warning(
57-
"Using experimental interpolators: P1Interpolator and P2Interpolator"
58-
)
59+
logger.warning("Using experimental interpolators: P1Interpolator and P2Interpolator")
5960
from ._p1interpolator import P1Interpolator
6061
from ._p2interpolator import P2Interpolator

LoopStructural/interpolators/_discrete_interpolator.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -705,7 +705,6 @@ def _solve(self, solver="cg", **kwargs):
705705
self.c[self.region] = self._solve_chol(A, B)
706706
if solver == "lu":
707707
logger.info("Solving using scipy LU")
708-
print(self.region)
709708
self.c[self.region] = self._solve_lu(A, B)
710709
if solver == "pyamg":
711710
try:

LoopStructural/interpolators/supports/_3d_unstructured_tetra.py

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -380,12 +380,12 @@ def get_element_for_location(self, points):
380380
npts = 0
381381
npts_step = int(1e4)
382382
# break into blocks of 10k points
383-
while npts<points.shape[0]:
384-
385-
cell_index = np.array(self.aabb_grid.position_to_cell_index(points[:npts+npts_step,:])).swapaxes(
386-
0, 1
387-
)
388-
inside = self.aabb_grid.inside(points[:npts+npts_step,:])
383+
while npts < points.shape[0]:
384+
385+
cell_index = np.array(
386+
self.aabb_grid.position_to_cell_index(points[: npts + npts_step, :])
387+
).swapaxes(0, 1)
388+
inside = self.aabb_grid.inside(points[: npts + npts_step, :])
389389
global_index = (
390390
cell_index[:, 0]
391391
+ self.aabb_grid.nsteps_cells[None, 0] * cell_index[:, 1]
@@ -423,13 +423,12 @@ def get_element_for_location(self, points):
423423
c[:, 3] = vd / v
424424
# inside = np.ones(c.shape[0],dtype=bool)
425425
mask = np.all(c >= 0, axis=1)
426-
427426

428-
verts[:npts+npts_step,:,:][row[mask], :, :] = vertices[mask, :, :]
429-
bc[:npts+npts_step,:][row[mask], :] = c[mask, :]
430-
tetras[:npts+npts_step][row[mask]] = col[mask]
431-
inside[:npts+npts_step][row[mask]] = True
432-
npts+=npts_step
427+
verts[: npts + npts_step, :, :][row[mask], :, :] = vertices[mask, :, :]
428+
bc[: npts + npts_step, :][row[mask], :] = c[mask, :]
429+
tetras[: npts + npts_step][row[mask]] = col[mask]
430+
inside[: npts + npts_step][row[mask]] = True
431+
npts += npts_step
433432
return verts, bc, tetras, inside
434433

435434
def get_element_gradients(self, elements=None):

LoopStructural/modelling/core/geological_model.py

Lines changed: 154 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
# if LoopStructural.experimental:
1515
from LoopStructural.interpolators import P2Interpolator
16+
1617
try:
1718
from LoopStructural.interpolators import SurfeRBFInterpolator as Surfe
1819

@@ -53,6 +54,16 @@
5354
get_vectors,
5455
)
5556

57+
intrusions = True
58+
try:
59+
# from LoopStructural.modelling.intrusions import IntrusionNetwork
60+
from LoopStructural.modelling.intrusions import IntrusionBuilder
61+
62+
# from LoopStructural.modelling.intrusions import IntrusionBody
63+
from LoopStructural.modelling.intrusions import IntrusionFrameBuilder
64+
except ImportError as e:
65+
print(e)
66+
intrusions = False
5667
from LoopStructural.utils import getLogger, log_to_file
5768

5869
logger = getLogger(__name__)
@@ -1071,7 +1082,143 @@ def create_and_add_folded_fold_frame(
10711082

10721083
self._add_feature(folded_fold_frame)
10731084

1074-
return folded_fold_frame
1085+
return fold_frame
1086+
1087+
def create_and_add_intrusion(
1088+
self,
1089+
intrusion_name,
1090+
intrusion_frame_name,
1091+
intrusion_lateral_extent_model=None,
1092+
intrusion_vertical_extent_model=None,
1093+
intrusion_network_parameters={},
1094+
lateral_extent_sgs_parameters={},
1095+
vertical_extent_sgs_parameters={},
1096+
**kwargs,
1097+
):
1098+
"""
1099+
An intrusion in built in two main steps:
1100+
(1) Intrusion builder: intrusion builder creates the intrusion structural frame.
1101+
This object is curvilinear coordinate system of the intrusion constrained with intrusion network points,
1102+
and flow and inflation measurements (provided by the user).
1103+
The intrusion network is a representation of the approximated location of roof or floor contact of the intrusion.
1104+
This object might be constrained using the anisotropies of the host rock if the roof (or floor) contact is not well constrained.
1105+
1106+
(2) Intrusion feature: simulation of lateral and vertical extent of intrusion within the model volume.
1107+
The simulations outcome consist in thresholds distances along the structural frame coordinates
1108+
that are used to constrained the extent of the intrusion.
1109+
1110+
Parameters
1111+
----------
1112+
intrusion_name : string,
1113+
name of intrusion feature in model data
1114+
intrusion_frame_name : string,
1115+
name of intrusion frame in model data
1116+
intrusion_lateral_extent_model = function,
1117+
geometrical conceptual model for simulation of lateral extent
1118+
intrusion_vertical_extent_model = function,
1119+
geometrical conceptual model for simulation of vertical extent
1120+
intrusion_network_parameters : dictionary, optional
1121+
contact : string, contact of the intrusion to be used to create the network (roof or floor)
1122+
type : string, type of algorithm to create the intrusion network (interpolated or shortest path).
1123+
Shortest path is recommended when intrusion contact is not well constrained
1124+
contacts_anisotropies : list of series-type features involved in intrusion emplacement
1125+
structures_anisotropies : list of fault-type features involved in intrusion emplacement
1126+
sequence_anisotropies : list of anisotropies to look for the shortest path. It could be only starting and end point.
1127+
lateral_extent_sgs_parameters = dictionary, optional
1128+
parameters for sequential gaussian simulation of lateral extent
1129+
vertical_extent_sgs_parameters = dictionary, optional
1130+
parameters for sequential gaussian simulation of vertical extent
1131+
1132+
kwargs
1133+
1134+
Returns
1135+
-------
1136+
intrusion feature
1137+
1138+
"""
1139+
if intrusions == False:
1140+
logger.error("Libraries not installed")
1141+
raise Exception("Libraries not installed")
1142+
1143+
intrusion_data = self.data[self.data["feature_name"] == intrusion_name].copy()
1144+
intrusion_frame_data = self.data[
1145+
self.data["feature_name"] == intrusion_frame_name
1146+
].copy()
1147+
1148+
# -- get variables for intrusion frame interpolation
1149+
gxxgz = kwargs.get("gxxgz", 0)
1150+
gxxgy = kwargs.get("gxxgy", 0)
1151+
gyxgz = kwargs.get("gyxgz", 0)
1152+
1153+
interpolatortype = kwargs.get("interpolatortype", "FDI")
1154+
nelements = kwargs.get("nelements", 1e2)
1155+
1156+
weights = [gxxgz, gxxgy, gyxgz]
1157+
interpolator = self.get_interpolator(interpolatortype=interpolatortype)
1158+
1159+
intrusion_frame_builder = IntrusionFrameBuilder(
1160+
interpolator, name=intrusion_frame_name, model=self, **kwargs
1161+
)
1162+
1163+
# -- create intrusion network
1164+
intrusion_frame_builder.set_intrusion_network_parameters(
1165+
intrusion_data, intrusion_network_parameters
1166+
)
1167+
intrusion_network_geometry = intrusion_frame_builder.create_intrusion_network()
1168+
1169+
# -- create intrusion frame using intrusion network points and flow/inflation measurements
1170+
intrusion_frame_builder.set_intrusion_frame_data(
1171+
intrusion_frame_data, intrusion_network_geometry
1172+
)
1173+
1174+
## -- create intrusion frame
1175+
intrusion_frame_builder.setup(
1176+
nelements=nelements,
1177+
w2=weights[0],
1178+
w1=weights[1],
1179+
gxygz=weights[2],
1180+
)
1181+
1182+
intrusion_frame = intrusion_frame_builder.frame
1183+
intrusion_builder = IntrusionBuilder(
1184+
intrusion_frame, model=self, name=f"{intrusion_frame_name}_feature"
1185+
)
1186+
intrusion_builder.lateral_extent_model = intrusion_lateral_extent_model
1187+
intrusion_builder.vertical_extent_model = intrusion_vertical_extent_model
1188+
1189+
# # -- Create intrusion feature
1190+
# intrusion_feature = IntrusionFeature(
1191+
# intrusion_name, model=self
1192+
# )
1193+
1194+
# if intrusion_lateral_extent_model == None:
1195+
# logger.error(
1196+
# "Specify conceptual model function for intrusion lateral extent"
1197+
# )
1198+
# else:
1199+
# intrusion_feature.lateral_extent_model = intrusion_lateral_extent_model
1200+
1201+
# if intrusion_vertical_extent_model == None:
1202+
# logger.error(
1203+
# "Specify conceptual model function for intrusion vertical extent"
1204+
# )
1205+
# else:
1206+
# intrusion_feature.vertical_extent_model = intrusion_vertical_extent_model
1207+
1208+
# logger.info("setting data for thresholds simulation")
1209+
intrusion_builder.set_data_for_extent_simulation(intrusion_data)
1210+
intrusion_builder.build_arguments = {
1211+
"lateral_extent_sgs_parameters": lateral_extent_sgs_parameters,
1212+
"vertical_extent_sgs_parameters": vertical_extent_sgs_parameters,
1213+
}
1214+
# intrusion_builder.vertical_extent_sgs_parameters = vertical_extent_sgs_parameters
1215+
# intrusion_builder.lateral_extent_sgs_parameters = lateral_extent_sgs_parameters
1216+
# intrusion_builder.set_l_sgs_GSLIBparameters(lateral_extent_sgs_parameters)
1217+
# intrusion_builder.set_g_sgs_GSLIBparameters(vertical_extent_sgs_parameters)
1218+
intrusion_feature = intrusion_builder.feature
1219+
self._add_feature(intrusion_feature)
1220+
1221+
return intrusion_feature
10751222

10761223
def _add_faults(self, feature_builder, features=None):
10771224
"""Adds all existing faults to a geological feature builder
@@ -1360,12 +1507,12 @@ def create_and_add_fault(
13601507
fault : FaultSegment
13611508
created fault
13621509
"""
1363-
if 'fault_extent' in kwargs and major_axis == None:
1364-
major_axis = kwargs['fault_extent']
1365-
if 'fault_influence' in kwargs and minor_axis == None:
1366-
minor_axis = kwargs['fault_influence']
1367-
if 'fault_vectical_radius' in kwargs and intermediate_axis == None:
1368-
intermediate_axis = kwargs['fault_vectical_radius']
1510+
if "fault_extent" in kwargs and major_axis == None:
1511+
major_axis = kwargs["fault_extent"]
1512+
if "fault_influence" in kwargs and minor_axis == None:
1513+
minor_axis = kwargs["fault_influence"]
1514+
if "fault_vectical_radius" in kwargs and intermediate_axis == None:
1515+
intermediate_axis = kwargs["fault_vectical_radius"]
13691516

13701517
logger.info(f'Creating fault "{fault_surface_data}"')
13711518
logger.info(f"Displacement: {displacement}")

LoopStructural/modelling/fault/fault_function.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@ def __init__(self):
2121
self.w = None
2222

2323
def add_cstr(self, x, y):
24-
self.A.append([x ** 3, x ** 2, x, 1.0])
24+
self.A.append([x**3, x**2, x, 1.0])
2525
self.B.append(y)
2626

2727
def add_grad(self, x, g):
28-
self.A.append([3 * x ** 2, 2 * x, 1.0, 0.0])
28+
self.A.append([3 * x**2, 2 * x, 1.0, 0.0])
2929
self.B.append(g)
3030

3131
def add_max(self, max_v):
@@ -44,16 +44,16 @@ def __call__(self, v):
4444
ATA = A.T @ A
4545
ATB = A.T @ B
4646
self.w = np.linalg.lstsq(ATA, ATB, rcond=None)[0]
47-
eva = self.w[0] * v ** 3 + self.w[1] * v ** 2 + self.w[2] * v + self.w[3]
47+
eva = self.w[0] * v**3 + self.w[1] * v**2 + self.w[2] * v + self.w[3]
4848
eva[v > self.max_v] = (
49-
self.w[0] * self.max_v ** 3
50-
+ self.w[1] * self.max_v ** 2
49+
self.w[0] * self.max_v**3
50+
+ self.w[1] * self.max_v**2
5151
+ self.w[2] * self.max_v
5252
+ self.w[3]
5353
)
5454
eva[v < self.min_v] = (
55-
self.w[0] * self.min_v ** 3
56-
+ self.w[1] * self.min_v ** 2
55+
self.w[0] * self.min_v**3
56+
+ self.w[1] * self.min_v**2
5757
+ self.w[2] * self.min_v
5858
+ self.w[3]
5959
)

LoopStructural/modelling/features/structural_frame_builder.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ def __init__(
9090
],
9191
fold=kwargs.get("fold", None),
9292
)
93+
self._frame.builder = self
9394

9495
@property
9596
def frame(self):

LoopStructural/modelling/input/process_data.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,9 @@ def stratigraphic_column(self):
141141
"id": unit_id,
142142
"colour": self.colours[g],
143143
}
144-
if i==0:
144+
if i == 0:
145145
stratigraphic_column[name][g]["min"] = -np.inf
146-
if i==len(sg)-1:
146+
if i == len(sg) - 1:
147147
stratigraphic_column[name][g]["max"] = np.inf
148148

149149
unit_id += 1

0 commit comments

Comments
 (0)