LoopStructural 1.6.1__py3-none-any.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.

Potentially problematic release.


This version of LoopStructural might be problematic. Click here for more details.

Files changed (129) hide show
  1. LoopStructural/__init__.py +52 -0
  2. LoopStructural/datasets/__init__.py +23 -0
  3. LoopStructural/datasets/_base.py +301 -0
  4. LoopStructural/datasets/_example_models.py +10 -0
  5. LoopStructural/datasets/data/claudius.csv +21049 -0
  6. LoopStructural/datasets/data/claudiusbb.txt +2 -0
  7. LoopStructural/datasets/data/duplex.csv +126 -0
  8. LoopStructural/datasets/data/duplexbb.txt +2 -0
  9. LoopStructural/datasets/data/fault_trace/fault_trace.cpg +1 -0
  10. LoopStructural/datasets/data/fault_trace/fault_trace.dbf +0 -0
  11. LoopStructural/datasets/data/fault_trace/fault_trace.prj +1 -0
  12. LoopStructural/datasets/data/fault_trace/fault_trace.shp +0 -0
  13. LoopStructural/datasets/data/fault_trace/fault_trace.shx +0 -0
  14. LoopStructural/datasets/data/geological_map_data/bbox.csv +2 -0
  15. LoopStructural/datasets/data/geological_map_data/contacts.csv +657 -0
  16. LoopStructural/datasets/data/geological_map_data/fault_displacement.csv +7 -0
  17. LoopStructural/datasets/data/geological_map_data/fault_edges.txt +2 -0
  18. LoopStructural/datasets/data/geological_map_data/fault_locations.csv +79 -0
  19. LoopStructural/datasets/data/geological_map_data/fault_orientations.csv +19 -0
  20. LoopStructural/datasets/data/geological_map_data/stratigraphic_order.csv +13 -0
  21. LoopStructural/datasets/data/geological_map_data/stratigraphic_orientations.csv +207 -0
  22. LoopStructural/datasets/data/geological_map_data/stratigraphic_thickness.csv +13 -0
  23. LoopStructural/datasets/data/intrusion.csv +1017 -0
  24. LoopStructural/datasets/data/intrusionbb.txt +2 -0
  25. LoopStructural/datasets/data/onefoldbb.txt +2 -0
  26. LoopStructural/datasets/data/onefolddata.csv +2226 -0
  27. LoopStructural/datasets/data/refolded_bb.txt +2 -0
  28. LoopStructural/datasets/data/refolded_fold.csv +205 -0
  29. LoopStructural/datasets/data/tabular_intrusion.csv +23 -0
  30. LoopStructural/datatypes/__init__.py +4 -0
  31. LoopStructural/datatypes/_bounding_box.py +422 -0
  32. LoopStructural/datatypes/_point.py +166 -0
  33. LoopStructural/datatypes/_structured_grid.py +94 -0
  34. LoopStructural/datatypes/_surface.py +184 -0
  35. LoopStructural/export/exporters.py +554 -0
  36. LoopStructural/export/file_formats.py +15 -0
  37. LoopStructural/export/geoh5.py +100 -0
  38. LoopStructural/export/gocad.py +126 -0
  39. LoopStructural/export/omf_wrapper.py +88 -0
  40. LoopStructural/interpolators/__init__.py +105 -0
  41. LoopStructural/interpolators/_api.py +143 -0
  42. LoopStructural/interpolators/_builders.py +149 -0
  43. LoopStructural/interpolators/_cython/__init__.py +0 -0
  44. LoopStructural/interpolators/_discrete_fold_interpolator.py +183 -0
  45. LoopStructural/interpolators/_discrete_interpolator.py +692 -0
  46. LoopStructural/interpolators/_finite_difference_interpolator.py +470 -0
  47. LoopStructural/interpolators/_geological_interpolator.py +380 -0
  48. LoopStructural/interpolators/_interpolator_factory.py +89 -0
  49. LoopStructural/interpolators/_non_linear_discrete_interpolator.py +0 -0
  50. LoopStructural/interpolators/_operator.py +38 -0
  51. LoopStructural/interpolators/_p1interpolator.py +228 -0
  52. LoopStructural/interpolators/_p2interpolator.py +277 -0
  53. LoopStructural/interpolators/_surfe_wrapper.py +174 -0
  54. LoopStructural/interpolators/supports/_2d_base_unstructured.py +340 -0
  55. LoopStructural/interpolators/supports/_2d_p1_unstructured.py +68 -0
  56. LoopStructural/interpolators/supports/_2d_p2_unstructured.py +288 -0
  57. LoopStructural/interpolators/supports/_2d_structured_grid.py +462 -0
  58. LoopStructural/interpolators/supports/_2d_structured_tetra.py +0 -0
  59. LoopStructural/interpolators/supports/_3d_base_structured.py +467 -0
  60. LoopStructural/interpolators/supports/_3d_p2_tetra.py +331 -0
  61. LoopStructural/interpolators/supports/_3d_structured_grid.py +470 -0
  62. LoopStructural/interpolators/supports/_3d_structured_tetra.py +746 -0
  63. LoopStructural/interpolators/supports/_3d_unstructured_tetra.py +637 -0
  64. LoopStructural/interpolators/supports/__init__.py +55 -0
  65. LoopStructural/interpolators/supports/_aabb.py +77 -0
  66. LoopStructural/interpolators/supports/_base_support.py +114 -0
  67. LoopStructural/interpolators/supports/_face_table.py +70 -0
  68. LoopStructural/interpolators/supports/_support_factory.py +32 -0
  69. LoopStructural/modelling/__init__.py +29 -0
  70. LoopStructural/modelling/core/__init__.py +0 -0
  71. LoopStructural/modelling/core/geological_model.py +1867 -0
  72. LoopStructural/modelling/features/__init__.py +32 -0
  73. LoopStructural/modelling/features/_analytical_feature.py +79 -0
  74. LoopStructural/modelling/features/_base_geological_feature.py +364 -0
  75. LoopStructural/modelling/features/_cross_product_geological_feature.py +100 -0
  76. LoopStructural/modelling/features/_geological_feature.py +288 -0
  77. LoopStructural/modelling/features/_lambda_geological_feature.py +93 -0
  78. LoopStructural/modelling/features/_region.py +18 -0
  79. LoopStructural/modelling/features/_structural_frame.py +186 -0
  80. LoopStructural/modelling/features/_unconformity_feature.py +83 -0
  81. LoopStructural/modelling/features/builders/__init__.py +5 -0
  82. LoopStructural/modelling/features/builders/_base_builder.py +111 -0
  83. LoopStructural/modelling/features/builders/_fault_builder.py +590 -0
  84. LoopStructural/modelling/features/builders/_folded_feature_builder.py +129 -0
  85. LoopStructural/modelling/features/builders/_geological_feature_builder.py +543 -0
  86. LoopStructural/modelling/features/builders/_structural_frame_builder.py +237 -0
  87. LoopStructural/modelling/features/fault/__init__.py +3 -0
  88. LoopStructural/modelling/features/fault/_fault_function.py +444 -0
  89. LoopStructural/modelling/features/fault/_fault_function_feature.py +82 -0
  90. LoopStructural/modelling/features/fault/_fault_segment.py +505 -0
  91. LoopStructural/modelling/features/fold/__init__.py +9 -0
  92. LoopStructural/modelling/features/fold/_fold.py +167 -0
  93. LoopStructural/modelling/features/fold/_fold_rotation_angle.py +149 -0
  94. LoopStructural/modelling/features/fold/_fold_rotation_angle_feature.py +67 -0
  95. LoopStructural/modelling/features/fold/_foldframe.py +194 -0
  96. LoopStructural/modelling/features/fold/_svariogram.py +188 -0
  97. LoopStructural/modelling/input/__init__.py +2 -0
  98. LoopStructural/modelling/input/fault_network.py +80 -0
  99. LoopStructural/modelling/input/map2loop_processor.py +165 -0
  100. LoopStructural/modelling/input/process_data.py +650 -0
  101. LoopStructural/modelling/input/project_file.py +84 -0
  102. LoopStructural/modelling/intrusions/__init__.py +25 -0
  103. LoopStructural/modelling/intrusions/geom_conceptual_models.py +142 -0
  104. LoopStructural/modelling/intrusions/geometric_scaling_functions.py +123 -0
  105. LoopStructural/modelling/intrusions/intrusion_builder.py +672 -0
  106. LoopStructural/modelling/intrusions/intrusion_feature.py +410 -0
  107. LoopStructural/modelling/intrusions/intrusion_frame_builder.py +971 -0
  108. LoopStructural/modelling/intrusions/intrusion_support_functions.py +460 -0
  109. LoopStructural/utils/__init__.py +38 -0
  110. LoopStructural/utils/_surface.py +143 -0
  111. LoopStructural/utils/_transformation.py +76 -0
  112. LoopStructural/utils/config.py +18 -0
  113. LoopStructural/utils/dtm_creator.py +17 -0
  114. LoopStructural/utils/exceptions.py +31 -0
  115. LoopStructural/utils/helper.py +292 -0
  116. LoopStructural/utils/json_encoder.py +18 -0
  117. LoopStructural/utils/linalg.py +8 -0
  118. LoopStructural/utils/logging.py +79 -0
  119. LoopStructural/utils/maths.py +245 -0
  120. LoopStructural/utils/regions.py +103 -0
  121. LoopStructural/utils/typing.py +7 -0
  122. LoopStructural/utils/utils.py +68 -0
  123. LoopStructural/version.py +1 -0
  124. LoopStructural/visualisation/__init__.py +11 -0
  125. LoopStructural-1.6.1.dist-info/LICENSE +21 -0
  126. LoopStructural-1.6.1.dist-info/METADATA +81 -0
  127. LoopStructural-1.6.1.dist-info/RECORD +129 -0
  128. LoopStructural-1.6.1.dist-info/WHEEL +5 -0
  129. LoopStructural-1.6.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,76 @@
1
+ import numpy as np
2
+ from sklearn import decomposition
3
+
4
+
5
+ class EuclideanTransformation:
6
+ def __init__(self, dimensions=2):
7
+ """Transforms points into a new coordinate
8
+ system where the main eigenvector is aligned with x
9
+
10
+ Parameters
11
+ ----------
12
+ dimensions : int, optional
13
+ Do transformation in map view or on 3d volume, by default 2
14
+ """
15
+ self.rotation = None
16
+ self.translation = None
17
+ self.dimensions = dimensions
18
+ self.angle = 0
19
+
20
+ def fit(self, points: np.ndarray):
21
+ """Fit the transformation to a point cloud
22
+ This function will find the main eigenvector of the point cloud
23
+ and rotate the point cloud so that this is aligned with x
24
+
25
+
26
+ Parameters
27
+ ----------
28
+ points : np.ndarray
29
+ xyz points as as numpy array
30
+ """
31
+ points = np.array(points)
32
+ if points.shape[1] < self.dimensions:
33
+ raise ValueError("Points must have at least {} dimensions".format(self.dimensions))
34
+ # standardise the points so that centre is 0
35
+ self.translation = np.mean(points, axis=0)
36
+ # find main eigenvector and and calculate the angle of this with x
37
+ pca = decomposition.PCA(n_components=self.dimensions).fit(
38
+ points[:, : self.dimensions] - self.translation[None, : self.dimensions]
39
+ )
40
+ coeffs = pca.components_
41
+ self.angle = -np.arccos(np.dot(coeffs[0, :], [1, 0]))
42
+ self.rotation = self._rotation(self.angle)
43
+
44
+ def _rotation(self, angle):
45
+ return np.array(
46
+ [
47
+ [np.cos(angle), -np.sin(angle), 0],
48
+ [np.sin(angle), np.cos(angle), 0],
49
+ [0, 0, 1],
50
+ ]
51
+ )
52
+
53
+ def fit_transform(self, points: np.ndarray) -> np.ndarray:
54
+ self.fit(points)
55
+ return self.transform(points)
56
+
57
+ def transform(self, points: np.ndarray) -> np.ndarray:
58
+ """_summary_
59
+
60
+ Parameters
61
+ ----------
62
+ points : _type_
63
+ _description_
64
+
65
+ Returns
66
+ -------
67
+ _type_
68
+ _description_
69
+ """
70
+ return np.dot(points - self.translation, self.rotation)
71
+
72
+ def inverse_transform(self, points: np.ndarray) -> np.ndarray:
73
+ return np.dot(points, self._rotation(-self.angle)) + self.translation
74
+
75
+ def __call__(self, points: np.ndarray) -> np.ndarray:
76
+ return self.transform(points)
@@ -0,0 +1,18 @@
1
+ class LoopStructuralConfig:
2
+ """
3
+ Class to store configuration settings.
4
+ """
5
+
6
+ __splay_fault_threshold = 30
7
+ __experimental = False
8
+ __default_interpolator = "FDI"
9
+ __default_nelements = 1e4
10
+ __default_solver = "cg"
11
+
12
+ # @property
13
+ # def experimental():
14
+ # return __experimental
15
+
16
+ # @experimental.setter
17
+ # def experimental(self, value):
18
+ # __experimental = value
@@ -0,0 +1,17 @@
1
+ from ctypes import Union
2
+ from pathlib import Path
3
+
4
+
5
+ def create_dtm_with_rasterio(dtm_path: Union[str, Path]):
6
+ try:
7
+ import rasterio
8
+ except ImportError:
9
+ print("rasterio not installed. Please install it and try again.")
10
+ return
11
+ try:
12
+ from map2loop.map import MapUtil
13
+
14
+ dtm_map = MapUtil(None, dtm=rasterio.open(dtm_path))
15
+ return lambda xyz: dtm_map.evaluate_dtm_at_points(xyz[:, :2])
16
+ except ImportError:
17
+ print("map2loop not installed. Please install it and try again")
@@ -0,0 +1,31 @@
1
+ from ..utils import getLogger
2
+
3
+ logger = getLogger(__name__)
4
+
5
+
6
+ class LoopException(Exception):
7
+ """
8
+ Base loop exception
9
+ """
10
+
11
+
12
+ class LoopImportError(LoopException):
13
+ """ """
14
+
15
+ def __init__(self, message, additional_information=None):
16
+ super().__init__(message)
17
+ self.additional_information = additional_information
18
+
19
+ pass
20
+
21
+
22
+ class InterpolatorError(LoopException):
23
+ pass
24
+
25
+
26
+ class LoopTypeError(LoopException):
27
+ pass
28
+
29
+
30
+ class LoopValueError(LoopException):
31
+ pass
@@ -0,0 +1,292 @@
1
+ import numpy as np
2
+ import pandas as pd
3
+ from sklearn.decomposition import PCA
4
+
5
+ from LoopStructural.utils import getLogger
6
+
7
+ logger = getLogger(__name__)
8
+
9
+
10
+ def get_data_bounding_box_map(xyz, buffer):
11
+ """
12
+
13
+ Parameters
14
+ ----------
15
+ xyz
16
+ buffer
17
+
18
+ Returns
19
+ -------
20
+
21
+ """
22
+ # find the aligned coordinates box using pca
23
+ modelpca = PCA(n_components=3)
24
+ modelpca.fit(xyz)
25
+ # transform the data to this new coordinate then find extents
26
+ # transformed_xyz = modelpca.transform(xyz)
27
+ minx = np.min(xyz[:, 0])
28
+ maxx = np.max(xyz[:, 0])
29
+ miny = np.min(xyz[:, 1])
30
+ maxy = np.max(xyz[:, 1])
31
+ minz = np.min(xyz[:, 2])
32
+ maxz = np.max(xyz[:, 2])
33
+
34
+ # length = np.max([xlen, ylen, zlen])
35
+ minx -= buffer
36
+ maxx += buffer
37
+
38
+ miny -= buffer
39
+ maxy += buffer
40
+
41
+ minz -= buffer
42
+ maxz += buffer
43
+
44
+ bb = np.array([[minx, miny, minz], [maxx, maxy, maxz]])
45
+
46
+ def region(xyz):
47
+ b = np.ones(xyz.shape[0]).astype(bool)
48
+ b = np.logical_and(b, xyz[:, 0] > minx)
49
+ b = np.logical_and(b, xyz[:, 0] < maxx)
50
+ b = np.logical_and(b, xyz[:, 1] > miny)
51
+ b = np.logical_and(b, xyz[:, 1] < maxy)
52
+
53
+ return b
54
+
55
+ return bb, region
56
+
57
+
58
+ def get_data_bounding_box(xyz, buffer):
59
+ """
60
+
61
+ Parameters
62
+ ----------
63
+ xyz
64
+ buffer
65
+
66
+ Returns
67
+ -------
68
+
69
+ """
70
+ # find the aligned coordinates box using pca
71
+ modelpca = PCA(n_components=3)
72
+ modelpca.fit(xyz)
73
+ # transform the data to this new coordinate then find extents
74
+ # transformed_xyz = modelpca.transform(xyz)
75
+ minx = np.min(xyz[:, 0])
76
+ maxx = np.max(xyz[:, 0])
77
+ miny = np.min(xyz[:, 1])
78
+ maxy = np.max(xyz[:, 1])
79
+ minz = np.min(xyz[:, 2])
80
+ maxz = np.max(xyz[:, 2])
81
+
82
+ xlen = maxx - minx
83
+ ylen = maxy - miny
84
+ zlen = maxz - minz
85
+ length = np.max([xlen, ylen, zlen])
86
+ minx -= length * buffer
87
+ maxx += length * buffer
88
+
89
+ miny -= length * buffer
90
+ maxy += length * buffer
91
+
92
+ minz -= length * buffer
93
+ maxz += length * buffer
94
+
95
+ bb = np.array([[minx, miny, minz], [maxx, maxy, maxz]])
96
+
97
+ def region(xyz):
98
+ b = np.ones(xyz.shape[0]).astype(bool)
99
+ b = np.logical_and(b, xyz[:, 0] > minx)
100
+ b = np.logical_and(b, xyz[:, 0] < maxx)
101
+ b = np.logical_and(b, xyz[:, 1] > miny)
102
+ b = np.logical_and(b, xyz[:, 1] < maxy)
103
+ b = np.logical_and(b, xyz[:, 2] > minz)
104
+ b = np.logical_and(b, xyz[:, 2] < maxz)
105
+ return b
106
+
107
+ return bb, region
108
+
109
+
110
+ # def azimuthplunge2vector(
111
+ # plunge: Union[np.ndarray, list], plunge_dir: Union[np.ndarray, list]
112
+ # ) -> np.ndarray:
113
+ # """Convert plunge and plunge direction to a vector
114
+
115
+ # Parameters
116
+ # ----------
117
+ # plunge : Union[np.ndarray, list]
118
+ # array or array like of plunge values
119
+ # plunge_dir : Union[np.ndarray, list]
120
+ # array or array like of plunge direction values
121
+
122
+ # Returns
123
+ # -------
124
+ # np.array
125
+ # nx3 vector
126
+ # """
127
+ # plunge = np.deg2rad(plunge)
128
+ # plunge_dir = np.deg2rad(plunge_dir)
129
+ # vec = np.zeros(3)
130
+ # vec[0] = np.sin(plunge_dir) * np.cos(plunge)
131
+ # vec[1] = np.cos(plunge_dir) * np.cos(plunge)
132
+ # vec[2] = -np.sin(plunge)
133
+ # return vec
134
+
135
+
136
+ def create_surface(bounding_box, nstep):
137
+ x = np.linspace(bounding_box[0, 0], bounding_box[1, 0], nstep[0]) #
138
+ y = np.linspace(bounding_box[0, 1], bounding_box[1, 1], nstep[1])
139
+ xx, yy = np.meshgrid(x, y, indexing="xy")
140
+
141
+ def gi(i, j):
142
+ return i + j * nstep[0]
143
+
144
+ corners = np.array([[0, 1, 0, 1], [0, 0, 1, 1]])
145
+ i = np.arange(0, nstep[0] - 1)
146
+
147
+ j = np.arange(0, nstep[1] - 1)
148
+ ii, jj = np.meshgrid(i, j, indexing="ij")
149
+ corner_gi = gi(
150
+ ii[:, :, None]
151
+ + corners[
152
+ None,
153
+ None,
154
+ 0,
155
+ :,
156
+ ],
157
+ jj[:, :, None]
158
+ + corners[
159
+ None,
160
+ None,
161
+ 1,
162
+ :,
163
+ ],
164
+ )
165
+ corner_gi = corner_gi.reshape((nstep[0] - 1) * (nstep[1] - 1), 4)
166
+ tri = np.vstack([corner_gi[:, :3], corner_gi[:, 1:]])
167
+ return tri, xx.flatten(), yy.flatten()
168
+
169
+
170
+ def create_box(bounding_box, nsteps):
171
+ from LoopStructural.datatypes import BoundingBox
172
+
173
+ if isinstance(bounding_box, BoundingBox):
174
+ bounding_box = bounding_box.bb
175
+
176
+ tri, xx, yy = create_surface(bounding_box[0:2, :], nsteps[0:2])
177
+
178
+ zz = np.zeros(xx.shape)
179
+ zz[:] = bounding_box[1, 2]
180
+
181
+ tri = np.vstack([tri, tri + np.max(tri) + 1])
182
+ xx = np.hstack([xx, xx])
183
+ yy = np.hstack([yy, yy])
184
+
185
+ z = np.zeros(zz.shape)
186
+ z[:] = bounding_box[0, 2]
187
+ zz = np.hstack([zz, z])
188
+ # y faces
189
+ t, x, z = create_surface(bounding_box[:, [0, 2]], nsteps[[0, 2]])
190
+ tri = np.vstack([tri, t + np.max(tri) + 1])
191
+
192
+ y = np.zeros(x.shape)
193
+ y[:] = bounding_box[0, 1]
194
+ xx = np.hstack([xx, x])
195
+ zz = np.hstack([zz, z])
196
+ yy = np.hstack([yy, y])
197
+
198
+ tri = np.vstack([tri, t + np.max(tri) + 1])
199
+ y[:] = bounding_box[1, 1]
200
+ xx = np.hstack([xx, x])
201
+ zz = np.hstack([zz, z])
202
+ yy = np.hstack([yy, y])
203
+
204
+ # x faces
205
+ t, y, z = create_surface(bounding_box[:, [1, 2]], nsteps[[1, 2]])
206
+ tri = np.vstack([tri, t + np.max(tri) + 1])
207
+ x = np.zeros(y.shape)
208
+ x[:] = bounding_box[0, 0]
209
+ xx = np.hstack([xx, x])
210
+ zz = np.hstack([zz, z])
211
+ yy = np.hstack([yy, y])
212
+
213
+ tri = np.vstack([tri, t + np.max(tri) + 1])
214
+ x[:] = bounding_box[1, 0]
215
+ xx = np.hstack([xx, x])
216
+ zz = np.hstack([zz, z])
217
+ yy = np.hstack([yy, y])
218
+
219
+ points = np.zeros((len(xx), 3)) #
220
+ points[:, 0] = xx
221
+ points[:, 1] = yy
222
+ points[:, 2] = zz
223
+ return points, tri
224
+
225
+
226
+ def xyz_names():
227
+ return ["X", "Y", "Z"]
228
+
229
+
230
+ def normal_vec_names():
231
+ return ["nx", "ny", "nz"]
232
+
233
+
234
+ def tangent_vec_names():
235
+ return ["tx", "ty", "tz"]
236
+
237
+
238
+ def gradient_vec_names():
239
+ return ["gx", "gy", "gz"]
240
+
241
+
242
+ def weight_name():
243
+ return ["w"]
244
+
245
+
246
+ def val_name():
247
+ return ["val"]
248
+
249
+
250
+ def coord_name():
251
+ return ["coord"]
252
+
253
+
254
+ def interface_name():
255
+ return ["interface"]
256
+
257
+
258
+ def inequality_name():
259
+ return ["l", "u"]
260
+
261
+
262
+ def feature_name():
263
+ return ["feature_name"]
264
+
265
+
266
+ def polarity_name():
267
+ return ["polarity"]
268
+
269
+
270
+ def pairs_name():
271
+ return ["pair_id"]
272
+
273
+
274
+ def all_heading():
275
+ return (
276
+ xyz_names()
277
+ + normal_vec_names()
278
+ + tangent_vec_names()
279
+ + gradient_vec_names()
280
+ + weight_name()
281
+ + val_name()
282
+ + coord_name()
283
+ + feature_name()
284
+ + interface_name()
285
+ + polarity_name()
286
+ + inequality_name()
287
+ + pairs_name()
288
+ )
289
+
290
+
291
+ def empty_dataframe():
292
+ return pd.DataFrame(columns=[all_heading()])
@@ -0,0 +1,18 @@
1
+ import json
2
+
3
+
4
+ class LoopJSONEncoder(json.JSONEncoder):
5
+ def default(self, obj):
6
+ """All jsonable loop objects should have a tojson method
7
+
8
+ Parameters
9
+ ----------
10
+ obj : LoopStructuralObject
11
+ An object from loopstructural
12
+
13
+ Returns
14
+ -------
15
+ str
16
+ string representing the json encoding
17
+ """
18
+ return obj.__tojson__()
@@ -0,0 +1,8 @@
1
+ import numpy as np
2
+
3
+
4
+ def normalise(v):
5
+ v = np.array(v)
6
+
7
+ np.linalg.norm(v, axis=1)
8
+ return v / np.linalg.norm(v)
@@ -0,0 +1,79 @@
1
+ import logging
2
+ import LoopStructural
3
+ import os
4
+
5
+
6
+ def get_levels():
7
+ """dict for converting to logger levels from string
8
+
9
+
10
+ Returns
11
+ -------
12
+ dict
13
+ contains all strings with corresponding logging levels.
14
+ """
15
+ return {
16
+ "info": logging.INFO,
17
+ "warning": logging.WARNING,
18
+ "error": logging.ERROR,
19
+ "debug": logging.DEBUG,
20
+ }
21
+
22
+
23
+ def getLogger(name):
24
+ logger = logging.getLogger(name)
25
+ logger.addHandler(LoopStructural.ch)
26
+ # don't pass message back up the chain, what an odd default behavior
27
+ logger.propagate = False
28
+ # store the loopstructural loggers so we can change values
29
+ LoopStructural.loggers[name] = logger
30
+ return logger
31
+
32
+
33
+ def log_to_file(filename, overwrite=True, level="info"):
34
+ """Set the logging parameters for log file
35
+
36
+
37
+ Parameters
38
+ ----------
39
+ filename : string
40
+ name of file or path to file
41
+ level : str, optional
42
+ 'info', 'warning', 'error', 'debug' mapped to logging levels, by default 'info'
43
+ """
44
+ logger = getLogger(__name__)
45
+ if os.path.isfile(filename):
46
+ logger.warning("Overwriting existing logfile. To avoid this, set overwrite=False")
47
+ os.remove(filename)
48
+ levels = get_levels()
49
+ level = levels.get(level, logging.WARNING)
50
+ fh = logging.FileHandler(filename)
51
+ fh.setFormatter(LoopStructural.formatter)
52
+ fh.setLevel(level)
53
+ for logger in LoopStructural.loggers.values():
54
+ for hdlr in logger.handlers[:]: # remove the existing file handlers
55
+ if isinstance(hdlr, logging.FileHandler): # fixed two typos here
56
+ logger.removeHandler(hdlr)
57
+ logger.addHandler(fh)
58
+ logger.setLevel(level)
59
+
60
+
61
+ def log_to_console(level="warning"):
62
+ """Set the level of logging to the console
63
+
64
+
65
+ Parameters
66
+ ----------
67
+ level : str, optional
68
+ 'info', 'warning', 'error', 'debug' mapped to logging levels, by default 'info'
69
+ """
70
+ levels = get_levels()
71
+ level = levels.get(level, logging.WARNING)
72
+ for logger in LoopStructural.loggers.values():
73
+ for hdlr in logger.handlers:
74
+ # both stream and file are base stream, so check if not a filehandler
75
+ if not isinstance(hdlr, logging.FileHandler):
76
+ logger.removeHandler(hdlr)
77
+ hdlr = LoopStructural.ch
78
+ hdlr.setLevel(level)
79
+ logger.addHandler(hdlr)