LoopStructural 1.0.9__cp39-cp39-win32.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- LoopStructural/__init__.py +36 -0
- LoopStructural/analysis/__init__.py +2 -0
- LoopStructural/analysis/_fault_displacement.py +67 -0
- LoopStructural/analysis/_fault_intersection.py +36 -0
- LoopStructural/analysis/_plane_fit.py +43 -0
- LoopStructural/datasets/__init__.py +12 -0
- LoopStructural/datasets/_base.py +65 -0
- LoopStructural/datasets/data/claudius.csv +21049 -0
- LoopStructural/datasets/data/claudiusbb.txt +2 -0
- LoopStructural/datasets/data/duplex.csv +126 -0
- LoopStructural/datasets/data/duplexbb.txt +2 -0
- LoopStructural/datasets/data/intrusion.csv +1017 -0
- LoopStructural/datasets/data/intrusionbb.txt +2 -0
- LoopStructural/datasets/data/onefoldbb.txt +2 -0
- LoopStructural/datasets/data/onefolddata.csv +2226 -0
- LoopStructural/datasets/data/refolded_bb.txt +2 -0
- LoopStructural/datasets/data/refolded_fold.csv +2126 -0
- LoopStructural/interpolators/__init__.py +34 -0
- LoopStructural/interpolators/base_structured_3d_support.py +101 -0
- LoopStructural/interpolators/cython/__init__.py +0 -0
- LoopStructural/interpolators/cython/dsi_helper.c +31046 -0
- LoopStructural/interpolators/cython/dsi_helper.cp39-win32.pyd +0 -0
- LoopStructural/interpolators/discrete_fold_interpolator.py +202 -0
- LoopStructural/interpolators/discrete_interpolator.py +584 -0
- LoopStructural/interpolators/finite_difference_interpolator.py +399 -0
- LoopStructural/interpolators/geological_interpolator.py +197 -0
- LoopStructural/interpolators/operator.py +61 -0
- LoopStructural/interpolators/piecewiselinear_interpolator.py +437 -0
- LoopStructural/interpolators/structured_grid.py +421 -0
- LoopStructural/interpolators/structured_tetra.py +681 -0
- LoopStructural/interpolators/surfe_wrapper.py +118 -0
- LoopStructural/modelling/__init__.py +46 -0
- LoopStructural/modelling/core/__init__.py +0 -0
- LoopStructural/modelling/core/geological_model.py +1513 -0
- LoopStructural/modelling/core/geological_model_graph.py +880 -0
- LoopStructural/modelling/core/stratigraphic_column.py +5 -0
- LoopStructural/modelling/fault/__init__.py +4 -0
- LoopStructural/modelling/fault/fault_builder.py +143 -0
- LoopStructural/modelling/fault/fault_function.py +188 -0
- LoopStructural/modelling/fault/fault_function_feature.py +76 -0
- LoopStructural/modelling/fault/fault_segment.py +298 -0
- LoopStructural/modelling/features/__init__.py +8 -0
- LoopStructural/modelling/features/cross_product_geological_feature.py +90 -0
- LoopStructural/modelling/features/geological_feature.py +252 -0
- LoopStructural/modelling/features/geological_feature_builder.py +414 -0
- LoopStructural/modelling/features/lambda_geological_feature.py +36 -0
- LoopStructural/modelling/features/region_feature.py +34 -0
- LoopStructural/modelling/features/structural_frame.py +133 -0
- LoopStructural/modelling/features/structural_frame_builder.py +206 -0
- LoopStructural/modelling/features/unconformity_feature.py +74 -0
- LoopStructural/modelling/fold/__init__.py +8 -0
- LoopStructural/modelling/fold/fold.py +143 -0
- LoopStructural/modelling/fold/fold_rotation_angle.py +133 -0
- LoopStructural/modelling/fold/fold_rotation_angle_feature.py +58 -0
- LoopStructural/modelling/fold/foldframe.py +193 -0
- LoopStructural/modelling/fold/svariogram.py +180 -0
- LoopStructural/utils/__init__.py +18 -0
- LoopStructural/utils/bounding_box.py +21 -0
- LoopStructural/utils/exceptions.py +10 -0
- LoopStructural/utils/helper.py +382 -0
- LoopStructural/utils/logging.py +60 -0
- LoopStructural/utils/map2loop.py +353 -0
- LoopStructural/utils/regions.py +11 -0
- LoopStructural/utils/utils.py +69 -0
- LoopStructural/visualisation/__init__.py +31 -0
- LoopStructural/visualisation/map_viewer.py +322 -0
- LoopStructural/visualisation/model_plotter.py +17 -0
- LoopStructural/visualisation/model_visualisation.py +1113 -0
- LoopStructural/visualisation/rotation_angle_plotter.py +83 -0
- LoopStructural/visualisation/sphinx_scraper.py +34 -0
- LoopStructural/visualisation/stratigraphic_column.py +60 -0
- LoopStructural-1.0.9.dist-info/LICENSE +21 -0
- LoopStructural-1.0.9.dist-info/METADATA +19 -0
- LoopStructural-1.0.9.dist-info/RECORD +77 -0
- LoopStructural-1.0.9.dist-info/WHEEL +5 -0
- LoopStructural-1.0.9.dist-info/top_level.txt +2 -0
- tests/__init__.py +0 -0
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
import numpy as np
|
|
3
|
+
import os
|
|
4
|
+
import logging
|
|
5
|
+
import networkx
|
|
6
|
+
|
|
7
|
+
from LoopStructural.utils import getLogger
|
|
8
|
+
logger = getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
def process_map2loop(m2l_directory, flags={}):
|
|
11
|
+
"""
|
|
12
|
+
Extracts relevant information from map2loop outputs
|
|
13
|
+
|
|
14
|
+
Parameters
|
|
15
|
+
----------
|
|
16
|
+
m2l_directory : string
|
|
17
|
+
absolute path to a directory containing map2loop outputs
|
|
18
|
+
Returns
|
|
19
|
+
-------
|
|
20
|
+
m2l_data : dict
|
|
21
|
+
a dictionary containing the extracted and collated data
|
|
22
|
+
"""
|
|
23
|
+
gradient = flags.get('gradient',False)
|
|
24
|
+
vector_scale = flags.get('vector_scale',None)
|
|
25
|
+
tangents = pd.read_csv(m2l_directory + '/tmp/raw_contacts.csv')
|
|
26
|
+
groups = pd.read_csv(m2l_directory + '/tmp/all_sorts_clean.csv', index_col=0)
|
|
27
|
+
contact_orientations = pd.read_csv(m2l_directory + '/output/orientations_clean.csv')
|
|
28
|
+
# formation_thickness = pd.read_csv)
|
|
29
|
+
contacts = pd.read_csv(m2l_directory + '/output/contacts_clean.csv')
|
|
30
|
+
displacements = pd.read_csv(m2l_directory + '/output/fault_displacements3.csv')
|
|
31
|
+
fault_orientations = pd.read_csv(m2l_directory + '/output/fault_orientations.csv')
|
|
32
|
+
fault_locations = pd.read_csv(m2l_directory + '/output/faults.csv')
|
|
33
|
+
fault_fault_relations = pd.read_csv(m2l_directory + '/output/fault-fault-relationships.csv')
|
|
34
|
+
fault_strat_relations = pd.read_csv(m2l_directory + '/output/group-fault-relationships.csv')
|
|
35
|
+
fault_dimensions = pd.read_csv(m2l_directory + '/output/fault_dimensions.csv')
|
|
36
|
+
fault_graph = networkx.read_gml(m2l_directory + '/tmp/fault_network.gml')
|
|
37
|
+
|
|
38
|
+
supergroups = {}
|
|
39
|
+
sgi = 0
|
|
40
|
+
try:
|
|
41
|
+
with open(m2l_directory + '/tmp/super_groups.csv') as f:
|
|
42
|
+
for l in f:
|
|
43
|
+
for g in l.split(','):
|
|
44
|
+
g = g.replace('-','_').replace(' ','_')
|
|
45
|
+
if g.find('\n') > 0:
|
|
46
|
+
g = g[:g.find('\n')]
|
|
47
|
+
supergroups[g] = 'supergroup_{}'.format(sgi)
|
|
48
|
+
if g == '\n':
|
|
49
|
+
sgi += 1
|
|
50
|
+
break
|
|
51
|
+
except:
|
|
52
|
+
for g in groups['group'].unique():
|
|
53
|
+
supergroups[g] = g
|
|
54
|
+
try:
|
|
55
|
+
supergroups.pop('\n')
|
|
56
|
+
except KeyError:
|
|
57
|
+
pass
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
bb = pd.read_csv(m2l_directory+'/tmp/bbox.csv')
|
|
61
|
+
|
|
62
|
+
# process tangent data to be tx, ty, tz
|
|
63
|
+
tangents['tz'] = 0
|
|
64
|
+
tangents['tx'] = tangents['lsx']
|
|
65
|
+
tangents['ty'] = tangents['lsy']
|
|
66
|
+
tangents.drop(['angle', 'lsx', 'lsy'], inplace=True, axis=1)
|
|
67
|
+
|
|
68
|
+
# convert azimuth and dip to gx, gy, gz
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
# calculate scalar field values
|
|
72
|
+
i = 0
|
|
73
|
+
thickness = {}
|
|
74
|
+
max_thickness = 0
|
|
75
|
+
thickness_file = flags.get('thickness',m2l_directory + '/output/formation_summary_thicknesses.csv')
|
|
76
|
+
with open(thickness_file) as file:
|
|
77
|
+
for l in file:
|
|
78
|
+
if i>=1:
|
|
79
|
+
linesplit = l.split(',')
|
|
80
|
+
thickness[linesplit[0]] = float(linesplit[1])
|
|
81
|
+
# normalise the thicknesses
|
|
82
|
+
if float(linesplit[1]) > max_thickness:
|
|
83
|
+
max_thickness=float(linesplit[1])
|
|
84
|
+
# print(l.split(',')[1])
|
|
85
|
+
i+=1
|
|
86
|
+
# for k in thickness.keys():
|
|
87
|
+
# thickness[k] /= max_thickness
|
|
88
|
+
if vector_scale is None:
|
|
89
|
+
vector_scale = max_thickness
|
|
90
|
+
|
|
91
|
+
if gradient:
|
|
92
|
+
from LoopStructural.utils.helper import strike_dip_vector
|
|
93
|
+
contact_orientations['strike'] = contact_orientations['azimuth'] - 90
|
|
94
|
+
contact_orientations['gx'] = np.nan
|
|
95
|
+
contact_orientations['gy'] = np.nan
|
|
96
|
+
contact_orientations['gz'] = np.nan
|
|
97
|
+
contact_orientations[['gx', 'gy', 'gz']] = strike_dip_vector(contact_orientations['strike'],
|
|
98
|
+
contact_orientations['dip'])*max_thickness
|
|
99
|
+
if np.sum(contact_orientations['polarity']==0) >0 and np.sum(contact_orientations['polarity']==-1)==0:
|
|
100
|
+
# contact_orientations['polarity']+=1
|
|
101
|
+
contact_orientations.loc[contact_orientations['polarity']==0]=-1
|
|
102
|
+
if not gradient:
|
|
103
|
+
from LoopStructural.utils.helper import strike_dip_vector
|
|
104
|
+
contact_orientations['strike'] = contact_orientations['azimuth'] - 90
|
|
105
|
+
contact_orientations['nx'] = np.nan
|
|
106
|
+
contact_orientations['ny'] = np.nan
|
|
107
|
+
contact_orientations['nz'] = np.nan
|
|
108
|
+
contact_orientations[['nx', 'ny', 'nz']] = strike_dip_vector(contact_orientations['strike'],
|
|
109
|
+
contact_orientations['dip'])*vector_scale *contact_orientations['polarity'].to_numpy()[:,None]
|
|
110
|
+
contact_orientations.drop(['strike', 'dip', 'azimuth'], inplace=True, axis=1)
|
|
111
|
+
# with open(m2l_directory + '/output/formation_summary_thicknesses.csv') as file:
|
|
112
|
+
|
|
113
|
+
# thickness = {}
|
|
114
|
+
# for f in formation_thickness['formation'].unique():
|
|
115
|
+
# thickness[f] = formation_thickness[formation_thickness['formation'] == f]['thickness'])
|
|
116
|
+
|
|
117
|
+
strat_val = {}
|
|
118
|
+
stratigraphic_column = {}
|
|
119
|
+
unit_id = 0
|
|
120
|
+
val = {}
|
|
121
|
+
for i in groups['group number'].unique():
|
|
122
|
+
g = supergroups[groups.loc[groups['group number'] == i, 'group'].iloc[0]]
|
|
123
|
+
if g not in stratigraphic_column:
|
|
124
|
+
stratigraphic_column[g] = {}
|
|
125
|
+
val[g] = 0
|
|
126
|
+
|
|
127
|
+
for c, colour in zip(groups.loc[groups['group number'] == i, 'code'],groups.loc[groups['group number'] == i, 'colour']):
|
|
128
|
+
strat_val[c] = np.nan
|
|
129
|
+
if c in thickness:
|
|
130
|
+
stratigraphic_column[g][c] = {'max': val[g], 'min': val[g] - thickness[c], 'id': unit_id, 'colour':colour}
|
|
131
|
+
unit_id += 1
|
|
132
|
+
strat_val[c] = val[g] - thickness[c]
|
|
133
|
+
val[g] -= thickness[c]
|
|
134
|
+
group_name = None
|
|
135
|
+
for g, i in stratigraphic_column.items():
|
|
136
|
+
if len(i) ==0:
|
|
137
|
+
for gr, sg in supergroups.items():
|
|
138
|
+
if sg == g:
|
|
139
|
+
group_name = gr
|
|
140
|
+
break
|
|
141
|
+
try:
|
|
142
|
+
if group_name is None:
|
|
143
|
+
continue
|
|
144
|
+
c=groups.loc[groups['group']==group_name,'code'].to_numpy()[0]
|
|
145
|
+
strat_val[c] = 0
|
|
146
|
+
stratigraphic_column[g] = {c:{'min':0,'max':9999,'id':unit_id}}
|
|
147
|
+
unit_id+=1
|
|
148
|
+
group_name = None
|
|
149
|
+
except:
|
|
150
|
+
print('Couldnt process {}'.format(g))
|
|
151
|
+
#whether to use thickness or interface
|
|
152
|
+
use_thickness = flags.get('use_thickness',True)
|
|
153
|
+
if use_thickness:
|
|
154
|
+
contacts['val'] = np.nan
|
|
155
|
+
for o in strat_val:
|
|
156
|
+
contacts.loc[contacts['formation'] == o, 'val'] = strat_val[o]
|
|
157
|
+
if use_thickness == False:
|
|
158
|
+
contacts['interface'] = np.nan
|
|
159
|
+
interface_val = 0
|
|
160
|
+
for u in contacts['formation'].unique():
|
|
161
|
+
contacts.loc[contacts['formation'] == u,'interface'] = interface_val
|
|
162
|
+
interface_val+=1
|
|
163
|
+
tangents['feature_name'] = tangents['group']
|
|
164
|
+
contact_orientations['feature_name'] = None
|
|
165
|
+
contacts['feature_name'] = None
|
|
166
|
+
for g in groups['group'].unique():
|
|
167
|
+
val = 0
|
|
168
|
+
for c in groups.loc[groups['group'] == g, 'code']:
|
|
169
|
+
contact_orientations.loc[contact_orientations['formation'] == c, 'feature_name'] = supergroups[g]
|
|
170
|
+
contacts.loc[contacts['formation'] == c, 'feature_name'] = supergroups[g]
|
|
171
|
+
displacements['dip_dir'] = np.nan
|
|
172
|
+
for fname in fault_orientations['formation'].unique():
|
|
173
|
+
displacements.loc[displacements['fname'] == fname, 'dip_dir'] = np.mean(
|
|
174
|
+
fault_orientations.loc[fault_orientations['formation'] == fname, 'DipDirection'])
|
|
175
|
+
max_displacement = {}
|
|
176
|
+
downthrow_dir = {}
|
|
177
|
+
fault_locations['val'] = 0
|
|
178
|
+
fault_locations['coord'] = 0
|
|
179
|
+
fault_orientations['coord'] = 0
|
|
180
|
+
fault_orientations['gx'] = np.nan
|
|
181
|
+
fault_orientations['gy'] = np.nan
|
|
182
|
+
fault_orientations['gz'] = np.nan
|
|
183
|
+
|
|
184
|
+
stratigraphic_column['faults'] = {}
|
|
185
|
+
for f in displacements['fname'].unique():
|
|
186
|
+
fault_centers = np.zeros(6)
|
|
187
|
+
normal_vector = np.zeros(3)
|
|
188
|
+
strike_vector = np.zeros(3)
|
|
189
|
+
slip_vector = np.zeros(3)
|
|
190
|
+
|
|
191
|
+
fault_edges = np.zeros((2,3))
|
|
192
|
+
fault_tips = np.zeros((2,3))
|
|
193
|
+
fault_depth = np.zeros((2,3))
|
|
194
|
+
displacements_numpy = displacements.loc[
|
|
195
|
+
displacements['fname'] == f, ['vertical_displacement', 'downthrow_dir', 'dip_dir','X','Y']].to_numpy()
|
|
196
|
+
# index = np.argmax(np.abs(displacements_numpy[:, 0]), )
|
|
197
|
+
index = np.argsort(np.abs(displacements_numpy[:, 0]))[len(np.abs(displacements_numpy[:, 0]))//2]
|
|
198
|
+
|
|
199
|
+
max_displacement[f] = displacements_numpy[
|
|
200
|
+
index, 0]
|
|
201
|
+
downthrow_dir[f] = displacements_numpy[index,[1,3,4]]
|
|
202
|
+
if np.abs(displacements_numpy[index, 1] - displacements_numpy[index, 2]) > 90:
|
|
203
|
+
# fault_orientations.loc[fault_orientations['formation'] == f, ['gx','gy','gy']]=-fault_orientations.loc[fault_orientations['formation'] == f, ['gx','gy','gy']]
|
|
204
|
+
fault_orientations.loc[fault_orientations['formation'] == f, 'DipDirection'] -= 180#displacements_numpy[
|
|
205
|
+
# index, 1]
|
|
206
|
+
# find the middle of the fault as the mean of the line, average dip direction and the influence distance
|
|
207
|
+
fault_centers[:3] = np.mean(fault_locations.loc[fault_locations['formation']==f,['X','Y','Z']],axis=0)
|
|
208
|
+
fault_centers[3] = np.mean(fault_orientations.loc[fault_orientations['formation']==f,['DipDirection']])
|
|
209
|
+
fault_centers[4] = fault_dimensions.loc[fault_dimensions['Fault']==f,'InfluenceDistance']
|
|
210
|
+
fault_centers[5] = fault_dimensions.loc[fault_dimensions['Fault']==f,'HorizontalRadius']
|
|
211
|
+
stratigraphic_column['faults'][f] = {'FaultCenter':fault_centers[:3],
|
|
212
|
+
'FaultDipDirection':fault_centers[3],
|
|
213
|
+
'InfluenceDistance':fault_dimensions.loc[fault_dimensions['Fault']==f,'InfluenceDistance'].to_numpy(),
|
|
214
|
+
'HorizontalRadius':fault_dimensions.loc[fault_dimensions['Fault']==f,'HorizontalRadius'].to_numpy(),
|
|
215
|
+
'VerticalRadius':fault_dimensions.loc[fault_dimensions['Fault']==f,'VerticalRadius'].to_numpy(),
|
|
216
|
+
'FaultSlip':np.array([0.,0.,-1.]),
|
|
217
|
+
'FaultNorm':normal_vector}
|
|
218
|
+
|
|
219
|
+
if 'colour' in fault_dimensions.columns:
|
|
220
|
+
stratigraphic_column['faults'][f]['colour'] = fault_dimensions.loc[fault_dimensions['Fault']==f,'colour'].to_numpy()
|
|
221
|
+
normal_vector[0] = np.sin(np.deg2rad(fault_centers[3]))
|
|
222
|
+
normal_vector[1] = np.cos(np.deg2rad(fault_centers[3]))
|
|
223
|
+
strike_vector[0] = normal_vector[1]
|
|
224
|
+
strike_vector[1] = -normal_vector[0]
|
|
225
|
+
slip_vector[2]=1
|
|
226
|
+
fault_edges[0,:] = fault_centers[:3]+normal_vector*fault_centers[4]
|
|
227
|
+
fault_edges[1,:] = fault_centers[:3]-normal_vector*fault_centers[4]
|
|
228
|
+
fault_tips[0,:] = fault_centers[:3]+strike_vector*fault_centers[5]
|
|
229
|
+
fault_tips[1,:] = fault_centers[:3]-strike_vector*fault_centers[5]
|
|
230
|
+
# fault_depth[0,:] = fault_centers[:3]+slip_vector*fault_centers[5]
|
|
231
|
+
# fault_depth[1,:] = fault_centers[:3]-slip_vector*fault_centers[5]
|
|
232
|
+
# fault_locations.loc[len(fault_locations),['X','Y','Z','formation','val','coord']] = [fault_edges[0,0],fault_edges[0,1],fault_edges[0,2],f,1,0]
|
|
233
|
+
# fault_locations.loc[len(fault_locations),['X','Y','Z','formation','val','coord']] = [fault_edges[1,0],fault_edges[1,1],fault_edges[1,2],f,-1,0]
|
|
234
|
+
# fault_locations.loc[len(fault_locations),['X','Y','Z','formation','val','coord']] = [fault_tips[0,0],fault_tips[0,1],fault_tips[0,2],f,1,2]
|
|
235
|
+
# fault_locations.loc[len(fault_locations),['X','Y','Z','formation','val','coord']] = [fault_tips[1,0],fault_tips[1,1],fault_tips[1,2],f,-1,2]
|
|
236
|
+
# # add strike vector to constraint fault extent
|
|
237
|
+
# fault_orientations.loc[len(fault_orientations),['X','Y','Z','formation','DipDirection','coord']] = [fault_centers[0],fault_centers[1],fault_centers[2],f, fault_centers[3]-90,2]
|
|
238
|
+
# fault_orientations.loc[len(fault_orientations),['X','Y','Z','formation','dip','coord']] = [fault_centers[0],fault_centers[1],fault_centers[2],f, 0,2]
|
|
239
|
+
|
|
240
|
+
# print('downthro',displacements_numpy[index, 1])
|
|
241
|
+
|
|
242
|
+
fault_orientations['strike'] = fault_orientations['DipDirection'] - 90
|
|
243
|
+
fault_orientations[['gx', 'gy', 'gz']] = strike_dip_vector(fault_orientations['strike'], fault_orientations['dip'])
|
|
244
|
+
for g in groups['group'].unique():
|
|
245
|
+
groups.loc[groups['group']==g,'group'] = supergroups[g]
|
|
246
|
+
# fault_orientations['strike'] = fault_orientations['DipDirection'] - 90
|
|
247
|
+
# fault_orientations['gx'] = np.nan
|
|
248
|
+
# fault_orientations['gy'] = np.nan
|
|
249
|
+
# fault_orientations['gz'] = np.nan
|
|
250
|
+
|
|
251
|
+
fault_orientations.drop(['strike', 'DipDirection', 'dip', 'DipPolarity'], inplace=True, axis=1)
|
|
252
|
+
fault_orientations['feature_name'] = fault_orientations['formation']
|
|
253
|
+
fault_locations['feature_name'] = fault_locations['formation']
|
|
254
|
+
|
|
255
|
+
data = pd.concat([tangents, contact_orientations, contacts, fault_orientations, fault_locations])
|
|
256
|
+
data.reset_index(inplace=True)
|
|
257
|
+
|
|
258
|
+
return {'data': data,
|
|
259
|
+
'groups': groups,
|
|
260
|
+
'max_displacement': max_displacement,
|
|
261
|
+
'fault_fault': fault_fault_relations,
|
|
262
|
+
'stratigraphic_column': stratigraphic_column,
|
|
263
|
+
'bounding_box':bb,
|
|
264
|
+
'strat_va':strat_val,
|
|
265
|
+
'downthrow_dir':downthrow_dir,
|
|
266
|
+
'fault_graph':fault_graph}
|
|
267
|
+
|
|
268
|
+
def build_model(m2l_data, evaluate=True, skip_faults = False, unconformities=False, fault_params = None, foliation_params=None, rescale = True,**kwargs):
|
|
269
|
+
"""[summary]
|
|
270
|
+
|
|
271
|
+
[extended_summary]
|
|
272
|
+
|
|
273
|
+
Parameters
|
|
274
|
+
----------
|
|
275
|
+
m2l_data : dict
|
|
276
|
+
[description]
|
|
277
|
+
skip_faults : bool, optional
|
|
278
|
+
[description], by default False
|
|
279
|
+
fault_params : dict, optional
|
|
280
|
+
[description], by default None
|
|
281
|
+
foliation_params : dict, optional
|
|
282
|
+
[description], by default None
|
|
283
|
+
|
|
284
|
+
Returns
|
|
285
|
+
-------
|
|
286
|
+
[type]
|
|
287
|
+
[description]
|
|
288
|
+
"""
|
|
289
|
+
from LoopStructural import GeologicalModel
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
boundary_points = np.zeros((2, 3))
|
|
293
|
+
boundary_points[0, 0] = m2l_data['bounding_box']['minx']
|
|
294
|
+
boundary_points[0, 1] = m2l_data['bounding_box']['miny']
|
|
295
|
+
boundary_points[0, 2] = m2l_data['bounding_box']['lower']
|
|
296
|
+
boundary_points[1, 0] = m2l_data['bounding_box']['maxx']
|
|
297
|
+
boundary_points[1, 1] = m2l_data['bounding_box']['maxy']
|
|
298
|
+
boundary_points[1, 2] = m2l_data['bounding_box']['upper']
|
|
299
|
+
|
|
300
|
+
model = GeologicalModel(boundary_points[0, :], boundary_points[1, :], rescale=rescale)
|
|
301
|
+
# m2l_data['data']['val'] /= model.scale_factor
|
|
302
|
+
model.set_model_data(m2l_data['data'])
|
|
303
|
+
if not skip_faults:
|
|
304
|
+
faults = []
|
|
305
|
+
for f in m2l_data['max_displacement'].keys():
|
|
306
|
+
if model.data[model.data['feature_name'] == f].shape[0] == 0:
|
|
307
|
+
continue
|
|
308
|
+
fault_id = f
|
|
309
|
+
# overprints = []
|
|
310
|
+
# try:
|
|
311
|
+
# overprint_id = m2l_data['fault_fault'][m2l_data['fault_fault'][fault_id] == 1]['fault_id'].to_numpy()
|
|
312
|
+
# for i in overprint_id:
|
|
313
|
+
# overprints.append(i)
|
|
314
|
+
# logger.info('Adding fault overprints {}'.format(f))
|
|
315
|
+
# except:
|
|
316
|
+
# logger.info('No entry for %s in fault_fault_relations' % f)
|
|
317
|
+
# # continue
|
|
318
|
+
fault_center = m2l_data['stratigraphic_column']['faults'][f]['FaultCenter']
|
|
319
|
+
fault_influence = m2l_data['stratigraphic_column']['faults'][f]['InfluenceDistance']
|
|
320
|
+
fault_extent = m2l_data['stratigraphic_column']['faults'][f]['HorizontalRadius']
|
|
321
|
+
fault_vertical_radius = m2l_data['stratigraphic_column']['faults'][f]['VerticalRadius']
|
|
322
|
+
fault_slip_vector=m2l_data['stratigraphic_column']['faults'][f]['FaultSlip']
|
|
323
|
+
faults.append(model.create_and_add_fault(f,
|
|
324
|
+
-m2l_data['max_displacement'][f],
|
|
325
|
+
faultfunction='BaseFault',
|
|
326
|
+
fault_slip_vector=fault_slip_vector,
|
|
327
|
+
fault_center=fault_center,
|
|
328
|
+
fault_extent=fault_extent,
|
|
329
|
+
fault_influence=fault_influence,
|
|
330
|
+
fault_vectical_radius=fault_vertical_radius,
|
|
331
|
+
# overprints=overprints,
|
|
332
|
+
**fault_params,
|
|
333
|
+
)
|
|
334
|
+
)
|
|
335
|
+
# for e in networkx.edge_bfs(m2l_data['fault_graph']):
|
|
336
|
+
# model[e[1]].builder.add_fault(model[e[0]])
|
|
337
|
+
# model[e[1]][0].interpolator.reset()
|
|
338
|
+
# model[e[1]][1].interpolator.reset()
|
|
339
|
+
# model[e[1]][2].interpolator.reset()
|
|
340
|
+
|
|
341
|
+
## loop through all of the groups and add them to the model in youngest to oldest.
|
|
342
|
+
group_features = []
|
|
343
|
+
for i in np.sort(m2l_data['groups']['group number'].unique()):
|
|
344
|
+
g = m2l_data['groups'].loc[m2l_data['groups']['group number'] == i, 'group'].unique()[0]
|
|
345
|
+
group_features.append(model.create_and_add_foliation(g,
|
|
346
|
+
**foliation_params))
|
|
347
|
+
# if the group was successfully added (not null) then lets add the base (0 to be unconformity)
|
|
348
|
+
if group_features[-1] and unconformities:
|
|
349
|
+
model.add_unconformity(group_features[-1], 0)
|
|
350
|
+
model.set_stratigraphic_column(m2l_data['stratigraphic_column'])
|
|
351
|
+
if evaluate:
|
|
352
|
+
model.update(verbose=True)
|
|
353
|
+
return model
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
import re
|
|
5
|
+
from LoopStructural.utils import getLogger
|
|
6
|
+
logger = getLogger(__name__)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def strike_symbol(strike):
|
|
10
|
+
R = np.zeros((2, 2))
|
|
11
|
+
R[0, 0] = np.cos(np.deg2rad(-strike))
|
|
12
|
+
R[0, 1] = -np.sin(np.deg2rad(-strike))
|
|
13
|
+
R[1, 0] = np.sin(np.deg2rad(-strike))
|
|
14
|
+
R[1, 1] = np.cos(np.deg2rad(-strike))
|
|
15
|
+
R = np.zeros((2, 2))
|
|
16
|
+
R[0, 0] = np.cos(np.deg2rad(-strike))
|
|
17
|
+
R[0, 1] = -np.sin(np.deg2rad(-strike))
|
|
18
|
+
R[1, 0] = np.sin(np.deg2rad(-strike))
|
|
19
|
+
R[1, 1] = np.cos(np.deg2rad(-strike))
|
|
20
|
+
|
|
21
|
+
vec = np.array([0, 1])
|
|
22
|
+
rotated = R @ vec
|
|
23
|
+
vec2 = np.array([-0.5, 0])
|
|
24
|
+
r2 = R @ vec2
|
|
25
|
+
return rotated, r2
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def read_voxet(voxetname,propertyfile):
|
|
29
|
+
"""
|
|
30
|
+
Read a gocad property file and the geometry information from the .vo file
|
|
31
|
+
voxetname - is the path to the voxet file
|
|
32
|
+
propertyfile is the path to the binary file
|
|
33
|
+
Returns
|
|
34
|
+
origin numpy array
|
|
35
|
+
voxet_extent - is the length of each axis of the voxet
|
|
36
|
+
N is the number of steps in the voxet
|
|
37
|
+
array is the property values
|
|
38
|
+
steps is the size of the step vector for the voxet
|
|
39
|
+
"""
|
|
40
|
+
array = np.fromfile(propertyfile,dtype='float32')
|
|
41
|
+
array = array.astype('<f4') # little endian
|
|
42
|
+
with open(voxetname,'r') as file:
|
|
43
|
+
for l in file:
|
|
44
|
+
if 'AXIS_O ' in l:
|
|
45
|
+
origin = np.array(re.findall(r"[-+]?\d*\.?\d+|[-+]?\d+",l)).astype(float)
|
|
46
|
+
if 'AXIS_U ' in l:
|
|
47
|
+
U = float(re.findall(r'[\d\.\d]+',l)[0])
|
|
48
|
+
if 'AXIS_V ' in l:
|
|
49
|
+
V = float(re.findall(r'[\d\.\d]+',l)[1])
|
|
50
|
+
if 'AXIS_W ' in l:
|
|
51
|
+
W = float(re.findall(r'[\d\.\d]+',l)[2])
|
|
52
|
+
if 'AXIS_N ' in l:
|
|
53
|
+
N = np.array(re.findall(r'[\d\.\d]+',l)).astype(int)
|
|
54
|
+
voxet_extent = np.array([U,V,W])
|
|
55
|
+
steps = (voxet_extent ) / (N-1)
|
|
56
|
+
return origin, voxet_extent, N, array, steps
|
|
57
|
+
|
|
58
|
+
def write_property_to_gocad_voxet(propertyfilename, propertyvalues):
|
|
59
|
+
"""
|
|
60
|
+
This function writes a numpy array into the right format for a gocad
|
|
61
|
+
voxet property file. This assumet there is a property already added to the .vo file,
|
|
62
|
+
and is just updating the file.
|
|
63
|
+
propertyfile - string giving the path to the file to write
|
|
64
|
+
propertyvalues - numpy array nz,ny,nx ordering and in float format
|
|
65
|
+
"""
|
|
66
|
+
propertyvalues = propertyvalues.astype('>f4') #big endian
|
|
67
|
+
# array = propertyvalues.newbyteorder()
|
|
68
|
+
propertyvalues.tofile(propertyfilename)
|
|
69
|
+
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This is the base visualistion module for loop structural
|
|
3
|
+
|
|
4
|
+
Submodules
|
|
5
|
+
==========
|
|
6
|
+
|
|
7
|
+
.. autosummary::
|
|
8
|
+
:toctree: _autosummary
|
|
9
|
+
|
|
10
|
+
map_viewer
|
|
11
|
+
model_visualisation
|
|
12
|
+
rotation_angle_plotter
|
|
13
|
+
|
|
14
|
+
"""
|
|
15
|
+
from ..utils import getLogger
|
|
16
|
+
logger = getLogger(__name__)
|
|
17
|
+
try:
|
|
18
|
+
import matplotlib
|
|
19
|
+
from .map_viewer import MapView
|
|
20
|
+
from .rotation_angle_plotter import RotationAnglePlotter
|
|
21
|
+
except ImportError:
|
|
22
|
+
logger.warning('Cannot use MapView or RotationAnglePlotter as matplotlib is not installed. \n'\
|
|
23
|
+
'Install matplotlib and try again. ')
|
|
24
|
+
try:
|
|
25
|
+
from .sphinx_scraper import _get_loop_visualisation_scraper
|
|
26
|
+
except:
|
|
27
|
+
logger.error('Cannot use sphinx scraper, pip install -r docs/requirements.txt')
|
|
28
|
+
try:
|
|
29
|
+
from .model_visualisation import LavaVuModelViewer
|
|
30
|
+
except:
|
|
31
|
+
logger.error("Missing lavavu, can't import LavaVuModelViewer")
|