LoopStructural 1.0.9__cp36-cp36m-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.
Files changed (77) hide show
  1. LoopStructural/__init__.py +36 -0
  2. LoopStructural/analysis/__init__.py +2 -0
  3. LoopStructural/analysis/_fault_displacement.py +67 -0
  4. LoopStructural/analysis/_fault_intersection.py +36 -0
  5. LoopStructural/analysis/_plane_fit.py +43 -0
  6. LoopStructural/datasets/__init__.py +12 -0
  7. LoopStructural/datasets/_base.py +65 -0
  8. LoopStructural/datasets/data/claudius.csv +21049 -0
  9. LoopStructural/datasets/data/claudiusbb.txt +2 -0
  10. LoopStructural/datasets/data/duplex.csv +126 -0
  11. LoopStructural/datasets/data/duplexbb.txt +2 -0
  12. LoopStructural/datasets/data/intrusion.csv +1017 -0
  13. LoopStructural/datasets/data/intrusionbb.txt +2 -0
  14. LoopStructural/datasets/data/onefoldbb.txt +2 -0
  15. LoopStructural/datasets/data/onefolddata.csv +2226 -0
  16. LoopStructural/datasets/data/refolded_bb.txt +2 -0
  17. LoopStructural/datasets/data/refolded_fold.csv +2126 -0
  18. LoopStructural/interpolators/__init__.py +34 -0
  19. LoopStructural/interpolators/base_structured_3d_support.py +101 -0
  20. LoopStructural/interpolators/cython/__init__.py +0 -0
  21. LoopStructural/interpolators/cython/dsi_helper.c +31046 -0
  22. LoopStructural/interpolators/cython/dsi_helper.cp36-win32.pyd +0 -0
  23. LoopStructural/interpolators/discrete_fold_interpolator.py +202 -0
  24. LoopStructural/interpolators/discrete_interpolator.py +584 -0
  25. LoopStructural/interpolators/finite_difference_interpolator.py +399 -0
  26. LoopStructural/interpolators/geological_interpolator.py +197 -0
  27. LoopStructural/interpolators/operator.py +61 -0
  28. LoopStructural/interpolators/piecewiselinear_interpolator.py +437 -0
  29. LoopStructural/interpolators/structured_grid.py +421 -0
  30. LoopStructural/interpolators/structured_tetra.py +681 -0
  31. LoopStructural/interpolators/surfe_wrapper.py +118 -0
  32. LoopStructural/modelling/__init__.py +46 -0
  33. LoopStructural/modelling/core/__init__.py +0 -0
  34. LoopStructural/modelling/core/geological_model.py +1513 -0
  35. LoopStructural/modelling/core/geological_model_graph.py +880 -0
  36. LoopStructural/modelling/core/stratigraphic_column.py +5 -0
  37. LoopStructural/modelling/fault/__init__.py +4 -0
  38. LoopStructural/modelling/fault/fault_builder.py +143 -0
  39. LoopStructural/modelling/fault/fault_function.py +188 -0
  40. LoopStructural/modelling/fault/fault_function_feature.py +76 -0
  41. LoopStructural/modelling/fault/fault_segment.py +298 -0
  42. LoopStructural/modelling/features/__init__.py +8 -0
  43. LoopStructural/modelling/features/cross_product_geological_feature.py +90 -0
  44. LoopStructural/modelling/features/geological_feature.py +252 -0
  45. LoopStructural/modelling/features/geological_feature_builder.py +414 -0
  46. LoopStructural/modelling/features/lambda_geological_feature.py +36 -0
  47. LoopStructural/modelling/features/region_feature.py +34 -0
  48. LoopStructural/modelling/features/structural_frame.py +133 -0
  49. LoopStructural/modelling/features/structural_frame_builder.py +206 -0
  50. LoopStructural/modelling/features/unconformity_feature.py +74 -0
  51. LoopStructural/modelling/fold/__init__.py +8 -0
  52. LoopStructural/modelling/fold/fold.py +143 -0
  53. LoopStructural/modelling/fold/fold_rotation_angle.py +133 -0
  54. LoopStructural/modelling/fold/fold_rotation_angle_feature.py +58 -0
  55. LoopStructural/modelling/fold/foldframe.py +193 -0
  56. LoopStructural/modelling/fold/svariogram.py +180 -0
  57. LoopStructural/utils/__init__.py +18 -0
  58. LoopStructural/utils/bounding_box.py +21 -0
  59. LoopStructural/utils/exceptions.py +10 -0
  60. LoopStructural/utils/helper.py +382 -0
  61. LoopStructural/utils/logging.py +60 -0
  62. LoopStructural/utils/map2loop.py +353 -0
  63. LoopStructural/utils/regions.py +11 -0
  64. LoopStructural/utils/utils.py +69 -0
  65. LoopStructural/visualisation/__init__.py +31 -0
  66. LoopStructural/visualisation/map_viewer.py +322 -0
  67. LoopStructural/visualisation/model_plotter.py +17 -0
  68. LoopStructural/visualisation/model_visualisation.py +1113 -0
  69. LoopStructural/visualisation/rotation_angle_plotter.py +83 -0
  70. LoopStructural/visualisation/sphinx_scraper.py +34 -0
  71. LoopStructural/visualisation/stratigraphic_column.py +60 -0
  72. LoopStructural-1.0.9.dist-info/LICENSE +21 -0
  73. LoopStructural-1.0.9.dist-info/METADATA +19 -0
  74. LoopStructural-1.0.9.dist-info/RECORD +77 -0
  75. LoopStructural-1.0.9.dist-info/WHEEL +5 -0
  76. LoopStructural-1.0.9.dist-info/top_level.txt +2 -0
  77. tests/__init__.py +0 -0
@@ -0,0 +1,206 @@
1
+ """
2
+ structural frame builder
3
+ """
4
+
5
+ import logging
6
+
7
+ import numpy as np
8
+
9
+ from LoopStructural.utils import getLogger
10
+ logger = getLogger(__name__)
11
+
12
+ from LoopStructural.modelling.features.cross_product_geological_feature \
13
+ import \
14
+ CrossProductGeologicalFeature
15
+ from LoopStructural.modelling.features import \
16
+ GeologicalFeatureInterpolator
17
+ from LoopStructural.modelling.features import StructuralFrame
18
+
19
+
20
+ class StructuralFrameBuilder:
21
+ """[summary]
22
+
23
+ [extended_summary]
24
+ """
25
+ def __init__(self, interpolator=None, interpolators=None, **kwargs):
26
+ """
27
+ Class for building a structural frame - has functions to set up the
28
+ interpolator with
29
+ data and also orthogonality constraints. Can build a generic
30
+ structural frame or a
31
+ subclass of the structural frame if the kwarg `frame` is specified
32
+
33
+ Parameters
34
+ ----------
35
+ interpolator - a template interpolator for the frame
36
+ kwargs
37
+ """
38
+ self.support = None
39
+ self.fault_event = None
40
+ self.name = 'Undefined'
41
+ # self.region = 'everywhere'
42
+ self.builders = []
43
+ if 'name' in kwargs:
44
+ self.name = kwargs['name']
45
+ kwargs.pop('name')
46
+ self.data = [[], [], []]
47
+ # list of interpolators
48
+ # self.interpolators = []
49
+ # Create the interpolation objects by copying the template
50
+ if interpolators is None:
51
+ if interpolator is not None:
52
+ interpolators = []
53
+ interpolators.append(interpolator)
54
+ interpolators.append(interpolator.copy())
55
+ interpolators.append(interpolator.copy())
56
+ else:
57
+ raise BaseException("Missing interpolator")
58
+ # self.builders
59
+ self.builders.append(
60
+ GeologicalFeatureInterpolator(interpolators[0],
61
+ name=self.name + '_0',
62
+ **kwargs)) # ,region=self.region))
63
+ self.builders.append(
64
+ GeologicalFeatureInterpolator(interpolators[1],
65
+ name=self.name + '_1',
66
+ **kwargs)) # ,region=self.region))
67
+ self.builders.append(
68
+ GeologicalFeatureInterpolator(interpolators[2],
69
+ name=self.name + '_2',
70
+ **kwargs)) # ,region=self.region))
71
+
72
+ def __getitem__(self, item):
73
+ return self.builders[item]
74
+
75
+ def add_fault(self, fault):
76
+ """
77
+ Add a fault to the geological feature builder
78
+
79
+ Parameters
80
+ ----------
81
+ fault : FaultSegment
82
+ A faultsegment to add to the geological feature
83
+
84
+ Returns
85
+ -------
86
+
87
+ """
88
+ for i in range(3):
89
+ self.builders[i].add_fault(fault)
90
+
91
+
92
+ def add_data_from_data_frame(self, data_frame):
93
+ """
94
+ extract the data for a fault from a data frame
95
+
96
+ Parameters
97
+ ----------
98
+ data_frame
99
+
100
+ Returns
101
+ -------
102
+
103
+ """
104
+ for i in range(3):
105
+ self.builders[i].add_data_from_data_frame(data_frame.loc[data_frame['coord'] == i,:])
106
+
107
+
108
+ def build(self, w1=1., w2=1., w3=1., frame=StructuralFrame, **kwargs):
109
+ """
110
+ Build the structural frame
111
+ Parameters
112
+ ----------
113
+ solver solver to use
114
+ frame - type of frame to build StructuralFrame or FoldFrame
115
+ w3
116
+ w2
117
+ w1
118
+ kwargs
119
+
120
+ Returns
121
+ -------
122
+
123
+ """
124
+ gxxgy = 1
125
+ gxxgz = 1
126
+ gyxgz = 1
127
+ step = kwargs.get('step', 10)
128
+ if 'gxxgy' in kwargs:
129
+ gxxgy = kwargs['gxxgy']
130
+ if 'gxxgz' in kwargs:
131
+ gxxgz = kwargs['gxxgz']
132
+ if 'gyxgz' in kwargs:
133
+ gyxgz = kwargs['gyxgz']
134
+
135
+ # set regularisation so the the main surface (foliation, fault) is smooth
136
+ # and the fields are allowed to vary more
137
+ regularisation = kwargs.pop('regularisation', [1., 1., 1.])
138
+ # initialise features as none then where data exists build
139
+ gx_feature = None
140
+ gy_feature = None
141
+ gz_feature = None
142
+ fold = None
143
+ if len(self.builders[0].data) > 0:
144
+ logger.info("Building %s coordinate 0"%self.name)
145
+ gx_feature = self.builders[0].feature
146
+ kwargs['regularisation']=regularisation[0]
147
+ self.builders[0].build_arguments = kwargs
148
+
149
+ # remove fold from kwargs
150
+
151
+ fold = kwargs.pop('fold', None)
152
+ if gx_feature is None:
153
+ logger.warning(
154
+ "Not enough constraints for structural frame coordinate 0, \n"
155
+ "Add some more and try again.")
156
+ # make sure that all of the coordinates are using the same region
157
+ if gx_feature is not None and gx_feature.interpolator.region_function is not None:
158
+ self.builders[1].interpolator.set_region(gx_feature.interpolator.region_function)
159
+ self.builders[2].interpolator.set_region(gx_feature.interpolator.region_function)
160
+ if 'data_region' in kwargs:
161
+ kwargs.pop('data_region')
162
+ if 'region' in kwargs:
163
+ kwargs.pop('region')
164
+ if len(self.builders[2].data) > 0:
165
+ logger.info("Building %s coordinate 2"%self.name)
166
+ # if gy_feature is not None:
167
+ # self.builders[
168
+ # 2].interpolator.add_gradient_orthogonal_constraint(
169
+ # np.arange(0, self.support.n_elements),
170
+ # gy_feature.evaluate_gradient(self.support.barycentre),
171
+ # w=gyxgz)
172
+ if gx_feature is not None and gxxgz>0:
173
+ self.builders[2].add_orthogonal_feature(gx_feature, gxxgz,step=step)
174
+ gz_feature = self.builders[2].feature
175
+ kwargs['regularisation'] = regularisation[2]
176
+ self.builders[2].build_arguments = kwargs
177
+
178
+ if len(self.builders[1].data) > 0:
179
+ logger.info("Building %s coordinate 1"%self.name)
180
+ if gx_feature is not None and gxxgy>0:
181
+ self.builders[1].add_orthogonal_feature(gx_feature, gxxgy,step=step)
182
+ if gz_feature is not None and gyxgz>0:
183
+ self.builders[1].add_orthogonal_feature(gz_feature, gyxgz,step=step)
184
+ gy_feature = self.builders[1].feature
185
+ kwargs['regularisation'] = regularisation[1]
186
+ self.builders[1].build_arguments = kwargs
187
+
188
+
189
+ if gy_feature is None:
190
+ logger.warning(
191
+ "Not enough constraints for structural frame coordinate 1, \n"
192
+ "Add some more and try again.")
193
+
194
+ if len(self.builders[2].data) == 0:
195
+ if gy_feature is not None:
196
+ logger.debug(
197
+ "Creating analytical structural frame coordinate 2")
198
+ gz_feature = CrossProductGeologicalFeature(self.name + '_2',
199
+ gy_feature,
200
+ gx_feature)
201
+ if gy_feature is None or gx_feature is None:
202
+ logger.warning(
203
+ "Not enough constraints for fold frame coordinate 1, \n"
204
+ "Add some more and try again.")
205
+ # use the frame argument to build a structural frame
206
+ return frame(self.name, [gx_feature, gy_feature, gz_feature],fold=fold)
@@ -0,0 +1,74 @@
1
+ """
2
+
3
+ """
4
+ class UnconformityFeature:
5
+ """
6
+
7
+ """
8
+ def __init__(self, feature, value):
9
+ """
10
+
11
+ Parameters
12
+ ----------
13
+ feature
14
+ value
15
+ """
16
+ self.feature = feature
17
+ self.value = value
18
+ self.type = 'unconformity'
19
+ self.name = '{}_unconformity'.format(feature.name)
20
+ self.builder = self.feature.builder
21
+ def add_region(self, region):
22
+ # self.feature.add_region(region)
23
+ pass
24
+ def set_model(self, model):
25
+ self.model = model
26
+
27
+ def evaluate(self,pos):
28
+ """
29
+
30
+ Parameters
31
+ ----------
32
+ pos : numpy array
33
+ locations to evaluate whether below or above unconformity
34
+
35
+ Returns
36
+ -------
37
+ boolean
38
+ true if above the unconformity, false if below
39
+ """
40
+ return self.feature.evaluate_value(pos) < self.value
41
+
42
+ def evaluate_value(self,pos):
43
+ """
44
+
45
+ Parameters
46
+ ----------
47
+ pos : numpy array
48
+ locations to evaluate the value of the base geological feature
49
+
50
+ Returns
51
+ -------
52
+
53
+ """
54
+ return self.feature.evaluate_value(pos)
55
+
56
+ def evaluate_gradient(self,pos):
57
+ """
58
+
59
+ Parameters
60
+ ----------
61
+ pos : numpy array
62
+ location to evaluate the gradient of the base geological feature
63
+
64
+ Returns
65
+ -------
66
+
67
+ """
68
+ return self.feature.evaluate_gradient(pos)
69
+
70
+ def min(self):
71
+ return self.feature.min()
72
+
73
+ def max(self):
74
+ return self.feature.max()
@@ -0,0 +1,8 @@
1
+ """
2
+
3
+ """
4
+ from .fold import FoldEvent
5
+ from .svariogram import SVariogram
6
+ from .fold_rotation_angle_feature import FoldRotationAngleFeature, fourier_series
7
+ from .foldframe import FoldFrame
8
+ from .fold_rotation_angle import FoldRotationAngle
@@ -0,0 +1,143 @@
1
+ import logging
2
+
3
+ import numpy as np
4
+
5
+ from LoopStructural.utils import getLogger
6
+ logger = getLogger(__name__)
7
+
8
+
9
+ class FoldEvent:
10
+ """
11
+
12
+ """
13
+ def __init__(self, foldframe, fold_axis_rotation=None, fold_limb_rotation=None, fold_axis=None, name='Fold'):
14
+ """
15
+ A fold event describes the geometry of the fold using a fold frame
16
+ and two geometrical descriptors
17
+
18
+ Parameters
19
+ ----------
20
+ foldframe the fold frame object
21
+ fold_axis_rotation function for the fold axis rotation angle
22
+ fold_limb_rotation function for the fold limb rotation angle
23
+ """
24
+
25
+ self.foldframe = foldframe
26
+ self.fold_axis_rotation = fold_axis_rotation
27
+ self.fold_limb_rotation = fold_limb_rotation
28
+ self.fold_axis = fold_axis
29
+ self.name = name
30
+
31
+ def get_fold_axis_orientation(self, points):
32
+ """
33
+ gets the fold axis orientation for evaluation points
34
+
35
+ Parameters
36
+ ----------
37
+ points locations to calculate fold axis numpy array Nx3
38
+
39
+ Returns
40
+ -------
41
+
42
+ """
43
+ # evaluate fold axis from rotation angle
44
+ if self.fold_axis_rotation is not None:
45
+ logger.info("Using fold_axis_rotation function")
46
+ # get the gz direction
47
+ dgx = self.foldframe.features[0].evaluate_gradient(points)
48
+ dgy = self.foldframe.features[1].evaluate_gradient(points)
49
+ dgx /= np.linalg.norm(dgx, axis=1)[:, None]
50
+ dgy /= np.linalg.norm(dgy, axis=1)[:, None]
51
+ # get gy
52
+ gy = self.foldframe.features[1].evaluate_value(points)
53
+ R1 = self.rot_mat(-dgx, self.fold_axis_rotation(gy))
54
+ fold_axis = np.einsum('ijk,ki->kj', R1, dgy)
55
+ fold_axis /= np.linalg.norm(fold_axis, axis=1)[:, None]
56
+ return fold_axis
57
+
58
+ # use constant fold axis
59
+ if self.fold_axis is not None:
60
+ logger.info("Using constant fold axis")
61
+ return np.tile(self.fold_axis, (points.shape[0], 1))
62
+
63
+ def get_deformed_orientation(self, points):
64
+ """
65
+ Calculate the direction vectors of the fold
66
+
67
+ Parameters
68
+ ----------
69
+ points - np.array
70
+ location Nx3 array of x,y,z locations to evaluate fold
71
+
72
+ Returns
73
+ -------
74
+ fold_direction : np.array
75
+ a vector parallel to the fold
76
+ fold axis : np.array
77
+ the fold axis
78
+ dgz : np.array
79
+ the X direction of the finite strain ellipsoid, perpendicular to both
80
+ fold axis and fold direction
81
+
82
+ """
83
+ fold_axis = self.get_fold_axis_orientation(points)
84
+ gx = self.foldframe.features[0].evaluate_value(points)
85
+ dgx = self.foldframe.features[0].evaluate_gradient(points)
86
+ dgx /= np.linalg.norm(dgx, axis=1)[:, None]
87
+ dgz = np.cross(dgx,fold_axis,axisa=1,axisb=1)
88
+ # dgz = self.foldframe.features[2].evaluate_gradient(points)
89
+ dgz /= np.linalg.norm(dgz, axis=1)[:, None]
90
+
91
+ R2 = self.rot_mat(fold_axis, self.fold_limb_rotation(gx))
92
+ fold_direction = np.einsum('ijk,ki->kj', R2, dgx)
93
+ fold_direction /= np.sum(fold_direction, axis=1)[:, None]
94
+ # calculate dot product between fold_direction and axis
95
+ # if its less than 0 then inverse dgz
96
+ d = np.einsum('ij,ik->i', fold_direction, fold_axis)
97
+ dgz[d < 0] = -dgz[d < 0]
98
+ return fold_direction, fold_axis, dgz
99
+
100
+ # def get_regularisation_direction(self, points):
101
+ # self.foldframe.features[2].evaluate_gradient(points)
102
+
103
+ def rot_mat(self, axis, angle):
104
+ """
105
+ Create a rotation matrix for axis and angle
106
+
107
+ Parameters
108
+ ----------
109
+ axis Nx3 vector for axis
110
+ angle N array for angle in degrees
111
+
112
+ Returns 3,3,N rotation matrix
113
+ -------
114
+
115
+ """
116
+ c = np.cos(np.deg2rad(angle))
117
+ s = np.sin(np.deg2rad(angle))
118
+ C = 1.0 - c
119
+ x = axis[:, 0]
120
+ y = axis[:, 1]
121
+ z = axis[:, 2]
122
+ xs = x * s
123
+ ys = y * s
124
+ zs = z * s
125
+ xC = x * C
126
+ yC = y * C
127
+ zC = z * C
128
+ xyC = x * yC
129
+ yzC = y * zC
130
+ zxC = z * xC
131
+ rotation_mat = np.zeros((3, 3, len(angle)))
132
+ rotation_mat[0, 0, :] = x * xC + c
133
+ rotation_mat[0, 1, :] = xyC - zs
134
+ rotation_mat[0, 2, :] = zxC + ys
135
+
136
+ rotation_mat[1, 0, :] = xyC + zs
137
+ rotation_mat[1, 1, :] = y * yC + c
138
+ rotation_mat[1, 2, :] = yzC - xs
139
+
140
+ rotation_mat[2, 0, :] = zxC - ys
141
+ rotation_mat[2, 1, :] = yzC + xs
142
+ rotation_mat[2, 2, :] = z * zC + c
143
+ return rotation_mat
@@ -0,0 +1,133 @@
1
+ import logging
2
+
3
+ import numpy as np
4
+ from scipy.optimize import curve_fit
5
+
6
+ from LoopStructural.modelling.fold.fold_rotation_angle_feature import \
7
+ fourier_series
8
+ from LoopStructural.modelling.fold import SVariogram
9
+
10
+ from LoopStructural.utils import getLogger
11
+ logger = getLogger(__name__)
12
+
13
+
14
+ class FoldRotationAngle:
15
+ """
16
+
17
+ """
18
+ def __init__(self, rotation_angle, fold_frame_coordinate, svario=False):
19
+ """
20
+
21
+ Parameters
22
+ ----------
23
+ rotation_angle
24
+ fold_frame_coordinate
25
+ svario
26
+ """
27
+ self.rotation_angle = rotation_angle
28
+ self.fold_frame_coordinate = fold_frame_coordinate
29
+ self.fold_rotation_function = None
30
+ self.svario = None
31
+ if svario:
32
+ self.svario = SVariogram(self.fold_frame_coordinate, self.rotation_angle)
33
+ self.fitted_params = None
34
+
35
+ def fit_fourier_series(self, wl = None, lags = None, nlag = None, lag = None, skip_variogram=False,**kwargs):
36
+ """
37
+
38
+ Parameters
39
+ ----------
40
+ wl
41
+ lags
42
+ nlag
43
+ lag
44
+
45
+ Returns
46
+ -------
47
+
48
+ """
49
+ if self.svario is None:
50
+ self.svario = SVariogram(self.fold_frame_coordinate,
51
+ self.rotation_angle)
52
+ if skip_variogram == False:
53
+ self.svario.calc_semivariogram(lags=lags, nlag=nlag, lag=lag)
54
+ if wl is None:
55
+ wl = self.svario.find_wavelengths(lags=lags, nlag=nlag, lag=lag)
56
+ # for now only consider single fold wavelength
57
+ wl = wl[0]
58
+ guess = np.zeros(4)
59
+ guess[3] = wl # np.max(limb_wl)
60
+ logger.info(
61
+ 'Guess: %f %f %f %f' % (guess[0], guess[1], guess[2], guess[3]))
62
+ # mask nans
63
+ mask = np.logical_or(~np.isnan(self.fold_frame_coordinate), ~np.isnan(self.rotation_angle))
64
+ logger.info(
65
+ "There are %i nans for the fold limb rotation angle and "
66
+ "%i observations" % (np.sum(~mask), np.sum(mask)))
67
+ if np.sum(mask) < len(guess):
68
+ logger.error(
69
+ "Not enough data points to fit Fourier series setting "
70
+ "fold rotation angle"
71
+ "to 0")
72
+ self.fold_rotation_function = lambda x: np.zeros(x.shape)
73
+ else:
74
+ try:
75
+ # try fitting using wavelength guess
76
+ popt, pcov = curve_fit(fourier_series,
77
+ self.fold_frame_coordinate[mask],
78
+ np.tan(np.deg2rad(self.rotation_angle[mask])),
79
+ guess)
80
+ except RuntimeError:
81
+ try:
82
+ # if fitting failed, try with just 0s
83
+ logger.info("Running curve fit without initial guess")
84
+ popt, pcov = curve_fit(fourier_series,
85
+ self.fold_frame_coordinate[mask],
86
+ np.tan(np.deg2rad(self.rotation_angle[mask])))
87
+ except RuntimeError:
88
+ # otherwise set the fourier series parameters to 0
89
+ popt = guess
90
+ logger.error(
91
+ "Could not fit curve to S-Plot, check the wavelength")
92
+ logger.info(
93
+ 'Fitted: %f %f %f %f' % (popt[0], popt[1], popt[2], popt[3]))
94
+ self.fold_rotation_function = lambda x: np.rad2deg(
95
+ np.arctan(
96
+ fourier_series(x, popt[0], popt[1], popt[2], popt[3])))
97
+ self.fitted_params = popt
98
+
99
+ def __call__(self, fold_frame_coordinate):
100
+ """
101
+
102
+ Parameters
103
+ ----------
104
+ fold_frame_coordinate
105
+
106
+ Returns
107
+ -------
108
+
109
+ """
110
+ return self.fold_rotation_function(fold_frame_coordinate)
111
+
112
+ def calculate_misfit(self):
113
+ """
114
+
115
+ Returns
116
+ -------
117
+
118
+ """
119
+ return np.tan(np.deg2rad(self.rotation_angle)) - np.tan(np.deg2rad(
120
+ self.__call__(self.fold_frame_coordinate)))
121
+
122
+ def set_function(self, function):
123
+ """
124
+
125
+ Parameters
126
+ ----------
127
+ function
128
+
129
+ Returns
130
+ -------
131
+
132
+ """
133
+ self. fold_rotation_function = function
@@ -0,0 +1,58 @@
1
+ import logging
2
+
3
+ import numpy as np
4
+
5
+ from LoopStructural.utils import getLogger
6
+ logger = getLogger(__name__)
7
+
8
+
9
+ class FoldRotationAngleFeature:
10
+ """
11
+
12
+ """
13
+ def __init__(self, fold_frame, rotation):
14
+ """
15
+
16
+ Parameters
17
+ ----------
18
+ fold_frame
19
+ rotation
20
+ """
21
+ self.fold_frame = fold_frame
22
+ self.rotation = rotation
23
+
24
+ def evaluate_value(self, location):
25
+ """
26
+
27
+ Parameters
28
+ ----------
29
+ location
30
+
31
+ Returns
32
+ -------
33
+
34
+ """
35
+ s1 = self.fold_frame.features[0].evaluate_value(location)
36
+ r = self.rotation(s1)
37
+ return r
38
+
39
+
40
+ def fourier_series(x, c0, c1, c2, w):
41
+ """
42
+
43
+ Parameters
44
+ ----------
45
+ x
46
+ c0
47
+ c1
48
+ c2
49
+ w
50
+
51
+ Returns
52
+ -------
53
+
54
+ """
55
+ v = np.array(x.astype(float))
56
+ # v.fill(c0)
57
+ v = c0 + c1 * np.cos(2 * np.pi / w * x) + c2 * np.sin(2 * np.pi / w * x)
58
+ return np.rad2deg(np.arctan(v))