apsg 1.3.4__py3-none-any.whl → 1.3.6__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.
- apsg/__init__.py +91 -31
- apsg/config.py +0 -1
- apsg/database/_sdbread.py +1 -1
- apsg/feature/__init__.py +24 -20
- apsg/feature/_container.py +156 -101
- apsg/feature/_geodata.py +65 -11
- apsg/feature/_tensor3.py +24 -0
- apsg/math/_matrix.py +1 -5
- apsg/plotting/_roseplot.py +36 -35
- {apsg-1.3.4.dist-info → apsg-1.3.6.dist-info}/METADATA +2 -8
- {apsg-1.3.4.dist-info → apsg-1.3.6.dist-info}/RECORD +15 -15
- {apsg-1.3.4.dist-info → apsg-1.3.6.dist-info}/WHEEL +0 -0
- {apsg-1.3.4.dist-info → apsg-1.3.6.dist-info}/entry_points.txt +0 -0
- {apsg-1.3.4.dist-info → apsg-1.3.6.dist-info}/licenses/LICENSE +0 -0
- {apsg-1.3.4.dist-info → apsg-1.3.6.dist-info}/top_level.txt +0 -0
apsg/__init__.py
CHANGED
|
@@ -1,56 +1,114 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
|
|
3
|
-
from apsg.math import (
|
|
4
|
-
Vector3 as vec,
|
|
5
|
-
Vector2 as vec2,
|
|
6
|
-
Matrix2 as matrix2,
|
|
7
|
-
Matrix3 as matrix,
|
|
8
|
-
)
|
|
9
3
|
from apsg.config import apsg_conf
|
|
10
4
|
from apsg.feature import (
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
Fault as fault,
|
|
5
|
+
ClusterSet as cluster,
|
|
6
|
+
)
|
|
7
|
+
from apsg.feature import (
|
|
15
8
|
Cone as cone,
|
|
16
9
|
)
|
|
17
10
|
from apsg.feature import (
|
|
18
|
-
Vector3Set as vecset,
|
|
19
|
-
Vector2Set as vec2set,
|
|
20
|
-
LineationSet as linset,
|
|
21
|
-
FoliationSet as folset,
|
|
22
|
-
PairSet as pairset,
|
|
23
|
-
FaultSet as faultset,
|
|
24
11
|
ConeSet as coneset,
|
|
12
|
+
)
|
|
13
|
+
from apsg.feature import (
|
|
14
|
+
DeformationGradient2 as defgrad2,
|
|
15
|
+
)
|
|
16
|
+
from apsg.feature import (
|
|
17
|
+
DeformationGradient3 as defgrad,
|
|
18
|
+
)
|
|
19
|
+
from apsg.feature import (
|
|
20
|
+
Direction as dir2,
|
|
21
|
+
)
|
|
22
|
+
from apsg.feature import (
|
|
23
|
+
Direction2Set as dir2set,
|
|
24
|
+
)
|
|
25
|
+
from apsg.feature import (
|
|
26
|
+
Ellipse as ellipse,
|
|
27
|
+
)
|
|
28
|
+
from apsg.feature import (
|
|
25
29
|
EllipseSet as ellipseset,
|
|
30
|
+
)
|
|
31
|
+
from apsg.feature import (
|
|
32
|
+
Ellipsoid as ellipsoid,
|
|
33
|
+
)
|
|
34
|
+
from apsg.feature import (
|
|
26
35
|
EllipsoidSet as ellipsoidset,
|
|
36
|
+
)
|
|
37
|
+
from apsg.feature import (
|
|
38
|
+
Fault as fault,
|
|
39
|
+
)
|
|
40
|
+
from apsg.feature import (
|
|
41
|
+
FaultSet as faultset,
|
|
42
|
+
)
|
|
43
|
+
from apsg.feature import (
|
|
44
|
+
Foliation as fol,
|
|
45
|
+
)
|
|
46
|
+
from apsg.feature import (
|
|
47
|
+
FoliationSet as folset,
|
|
48
|
+
)
|
|
49
|
+
from apsg.feature import G
|
|
50
|
+
from apsg.feature import (
|
|
51
|
+
Lineation as lin,
|
|
52
|
+
)
|
|
53
|
+
from apsg.feature import (
|
|
54
|
+
LineationSet as linset,
|
|
55
|
+
)
|
|
56
|
+
from apsg.feature import (
|
|
57
|
+
OrientationTensor2 as ortensor2,
|
|
58
|
+
)
|
|
59
|
+
from apsg.feature import (
|
|
27
60
|
OrientationTensor2Set as ortensor2set,
|
|
61
|
+
)
|
|
62
|
+
from apsg.feature import (
|
|
63
|
+
OrientationTensor3 as ortensor,
|
|
64
|
+
)
|
|
65
|
+
from apsg.feature import (
|
|
28
66
|
OrientationTensor3Set as ortensorset,
|
|
29
|
-
ClusterSet as cluster,
|
|
30
67
|
)
|
|
31
68
|
from apsg.feature import (
|
|
32
|
-
|
|
33
|
-
|
|
69
|
+
Pair as pair,
|
|
70
|
+
)
|
|
71
|
+
from apsg.feature import (
|
|
72
|
+
PairSet as pairset,
|
|
73
|
+
)
|
|
74
|
+
from apsg.feature import (
|
|
75
|
+
Stress2 as stress2,
|
|
76
|
+
)
|
|
77
|
+
from apsg.feature import (
|
|
34
78
|
Stress3 as stress,
|
|
35
|
-
Ellipsoid as ellipsoid,
|
|
36
|
-
OrientationTensor3 as ortensor,
|
|
37
79
|
)
|
|
38
80
|
from apsg.feature import (
|
|
39
|
-
|
|
81
|
+
Vector2Set as vec2set,
|
|
82
|
+
)
|
|
83
|
+
from apsg.feature import (
|
|
84
|
+
Vector3Set as vecset,
|
|
85
|
+
)
|
|
86
|
+
from apsg.feature import (
|
|
40
87
|
VelocityGradient2 as velgrad2,
|
|
41
|
-
Stress2 as stress2,
|
|
42
|
-
Ellipse as ellipse,
|
|
43
|
-
OrientationTensor2 as ortensor2,
|
|
44
88
|
)
|
|
45
|
-
from apsg.feature import
|
|
89
|
+
from apsg.feature import (
|
|
90
|
+
VelocityGradient3 as velgrad,
|
|
91
|
+
)
|
|
92
|
+
from apsg.math import (
|
|
93
|
+
Matrix2 as matrix2,
|
|
94
|
+
)
|
|
95
|
+
from apsg.math import (
|
|
96
|
+
Matrix3 as matrix,
|
|
97
|
+
)
|
|
98
|
+
from apsg.math import (
|
|
99
|
+
Vector2 as vec2,
|
|
100
|
+
)
|
|
101
|
+
from apsg.math import (
|
|
102
|
+
Vector3 as vec,
|
|
103
|
+
)
|
|
46
104
|
from apsg.plotting import (
|
|
105
|
+
FlinnPlot,
|
|
106
|
+
HsuPlot,
|
|
107
|
+
RamsayPlot,
|
|
108
|
+
RosePlot,
|
|
47
109
|
StereoGrid,
|
|
48
110
|
StereoNet,
|
|
49
|
-
RosePlot,
|
|
50
111
|
VollmerPlot,
|
|
51
|
-
RamsayPlot,
|
|
52
|
-
FlinnPlot,
|
|
53
|
-
HsuPlot,
|
|
54
112
|
quicknet,
|
|
55
113
|
)
|
|
56
114
|
|
|
@@ -60,6 +118,7 @@ __all__ = (
|
|
|
60
118
|
"vec2",
|
|
61
119
|
"matrix",
|
|
62
120
|
"matrix2",
|
|
121
|
+
"dir2",
|
|
63
122
|
"lin",
|
|
64
123
|
"fol",
|
|
65
124
|
"pair",
|
|
@@ -67,6 +126,7 @@ __all__ = (
|
|
|
67
126
|
"cone",
|
|
68
127
|
"vecset",
|
|
69
128
|
"vec2set",
|
|
129
|
+
"dir2set",
|
|
70
130
|
"linset",
|
|
71
131
|
"folset",
|
|
72
132
|
"pairset",
|
|
@@ -98,6 +158,6 @@ __all__ = (
|
|
|
98
158
|
"quicknet",
|
|
99
159
|
)
|
|
100
160
|
|
|
101
|
-
__version__ = "1.3.
|
|
161
|
+
__version__ = "1.3.6"
|
|
102
162
|
__author__ = "Ondrej Lexa"
|
|
103
163
|
__email__ = "lexa.ondrej@gmail.com"
|
apsg/config.py
CHANGED
apsg/database/_sdbread.py
CHANGED
apsg/feature/__init__.py
CHANGED
|
@@ -1,39 +1,42 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
import sys
|
|
3
|
-
|
|
3
|
+
|
|
4
4
|
from apsg.feature._container import (
|
|
5
|
-
|
|
6
|
-
Vector2Set,
|
|
7
|
-
Vector3Set,
|
|
8
|
-
LineationSet,
|
|
9
|
-
FoliationSet,
|
|
10
|
-
PairSet,
|
|
11
|
-
FaultSet,
|
|
5
|
+
ClusterSet,
|
|
12
6
|
ConeSet,
|
|
7
|
+
Direction2Set,
|
|
13
8
|
EllipseSet,
|
|
14
9
|
EllipsoidSet,
|
|
10
|
+
FaultSet,
|
|
11
|
+
FeatureSet,
|
|
12
|
+
FoliationSet,
|
|
13
|
+
G,
|
|
14
|
+
LineationSet,
|
|
15
15
|
OrientationTensor2Set,
|
|
16
16
|
OrientationTensor3Set,
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
from apsg.feature._tensor3 import (
|
|
21
|
-
DeformationGradient3,
|
|
22
|
-
VelocityGradient3,
|
|
23
|
-
Stress3,
|
|
24
|
-
Ellipsoid,
|
|
25
|
-
OrientationTensor3,
|
|
17
|
+
PairSet,
|
|
18
|
+
Vector2Set,
|
|
19
|
+
Vector3Set,
|
|
26
20
|
)
|
|
21
|
+
from apsg.feature._geodata import Cone, Direction, Fault, Foliation, Lineation, Pair
|
|
22
|
+
from apsg.feature._paleomag import Core
|
|
27
23
|
from apsg.feature._tensor2 import (
|
|
28
24
|
DeformationGradient2,
|
|
29
|
-
VelocityGradient2,
|
|
30
|
-
Stress2,
|
|
31
25
|
Ellipse,
|
|
32
26
|
OrientationTensor2,
|
|
27
|
+
Stress2,
|
|
28
|
+
VelocityGradient2,
|
|
29
|
+
)
|
|
30
|
+
from apsg.feature._tensor3 import (
|
|
31
|
+
DeformationGradient3,
|
|
32
|
+
Ellipsoid,
|
|
33
|
+
OrientationTensor3,
|
|
34
|
+
Stress3,
|
|
35
|
+
VelocityGradient3,
|
|
33
36
|
)
|
|
34
|
-
from apsg.feature._paleomag import Core
|
|
35
37
|
|
|
36
38
|
__all__ = (
|
|
39
|
+
"Direction",
|
|
37
40
|
"Lineation",
|
|
38
41
|
"Foliation",
|
|
39
42
|
"Pair",
|
|
@@ -50,6 +53,7 @@ __all__ = (
|
|
|
50
53
|
"Ellipse",
|
|
51
54
|
"OrientationTensor2",
|
|
52
55
|
"Vector2Set",
|
|
56
|
+
"Direction2Set",
|
|
53
57
|
"FeatureSet",
|
|
54
58
|
"Vector3Set",
|
|
55
59
|
"LineationSet",
|
apsg/feature/_container.py
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
|
-
import
|
|
1
|
+
import csv
|
|
2
2
|
from itertools import combinations
|
|
3
|
-
|
|
3
|
+
from os.path import basename
|
|
4
|
+
|
|
4
5
|
import matplotlib.pyplot as plt
|
|
6
|
+
import numpy as np
|
|
7
|
+
from scipy.cluster.hierarchy import dendrogram, fcluster, linkage
|
|
5
8
|
from scipy.stats import vonmises
|
|
6
|
-
from scipy.cluster.hierarchy import linkage, fcluster, dendrogram
|
|
7
9
|
|
|
8
10
|
from apsg.config import apsg_conf
|
|
9
|
-
from apsg.
|
|
10
|
-
from apsg.helpers._math import acosd
|
|
11
|
-
from apsg.feature._geodata import Lineation, Foliation, Pair, Fault, Cone
|
|
12
|
-
from apsg.feature._tensor3 import OrientationTensor3, Ellipsoid, DeformationGradient3
|
|
13
|
-
from apsg.feature._tensor2 import OrientationTensor2, Ellipse
|
|
11
|
+
from apsg.feature._geodata import Cone, Direction, Fault, Foliation, Lineation, Pair
|
|
14
12
|
from apsg.feature._statistics import KentDistribution, vonMisesFisher
|
|
13
|
+
from apsg.feature._tensor2 import Ellipse, OrientationTensor2
|
|
14
|
+
from apsg.feature._tensor3 import DeformationGradient3, Ellipsoid, OrientationTensor3
|
|
15
|
+
from apsg.helpers._math import acosd
|
|
16
|
+
from apsg.math._vector import Axial2, Axial3, Vector2, Vector3
|
|
15
17
|
|
|
16
18
|
|
|
17
19
|
class FeatureSet:
|
|
@@ -22,12 +24,11 @@ class FeatureSet:
|
|
|
22
24
|
__slots__ = ("data", "name")
|
|
23
25
|
|
|
24
26
|
def __init__(self, data, name="Default"):
|
|
25
|
-
dtype_cls = getattr(sys.modules[__name__], type(self).__feature_type__)
|
|
26
27
|
assert all(
|
|
27
|
-
[isinstance(obj,
|
|
28
|
-
), f"Data must be instances of {
|
|
28
|
+
[isinstance(obj, self.__feature_class__) for obj in data]
|
|
29
|
+
), f"Data must be instances of {self.__feature_class__.__name__}"
|
|
29
30
|
# cast to correct instances
|
|
30
|
-
self.data = tuple([
|
|
31
|
+
self.data = tuple([self.__feature_class__(d) for d in data])
|
|
31
32
|
self.name = name
|
|
32
33
|
self._cache = {}
|
|
33
34
|
|
|
@@ -117,7 +118,7 @@ class Vector2Set(FeatureSet):
|
|
|
117
118
|
Class to store set of ``Vector2`` features
|
|
118
119
|
"""
|
|
119
120
|
|
|
120
|
-
|
|
121
|
+
__feature_class__ = Vector2
|
|
121
122
|
|
|
122
123
|
def __repr__(self):
|
|
123
124
|
return f"V2({len(self)}) {self.name}"
|
|
@@ -141,6 +142,14 @@ class Vector2Set(FeatureSet):
|
|
|
141
142
|
"""Return array of direction angles"""
|
|
142
143
|
return np.asarray([e.direction for e in self]).T
|
|
143
144
|
|
|
145
|
+
def to_vec2(self):
|
|
146
|
+
"""Return ``Vector2Set`` object with all data converted to ``Vector2``."""
|
|
147
|
+
return Vector2Set([Vector2(e) for e in self], name=self.name)
|
|
148
|
+
|
|
149
|
+
def to_dir2(self):
|
|
150
|
+
"""Return ``Direction2Set`` object with all data converted to ``Direction``."""
|
|
151
|
+
return Direction2Set([Direction(e) for e in self], name=self.name)
|
|
152
|
+
|
|
144
153
|
def proj(self, vec):
|
|
145
154
|
"""Return projections of all features in ``Vector2Set`` onto vector."""
|
|
146
155
|
return type(self)([e.project() for e in self], name=self.name)
|
|
@@ -283,7 +292,6 @@ class Vector2Set(FeatureSet):
|
|
|
283
292
|
resultant.
|
|
284
293
|
|
|
285
294
|
"""
|
|
286
|
-
dtype_cls = getattr(sys.modules[__name__], type(self).__feature_type__)
|
|
287
295
|
v = Vector3Set(self)
|
|
288
296
|
v_data = list(v)
|
|
289
297
|
alldone = np.all(v.angle(v.R()) <= 90)
|
|
@@ -294,10 +302,10 @@ class Vector2Set(FeatureSet):
|
|
|
294
302
|
v_data[ix] = -v_data[ix]
|
|
295
303
|
v = Vector3Set(v_data)
|
|
296
304
|
alldone = np.all(v.angle(v.R()) <= 90)
|
|
297
|
-
return type(self)([
|
|
305
|
+
return type(self)([self.__feature_class__(vec) for vec in v], name=self.name)
|
|
298
306
|
|
|
299
307
|
@classmethod
|
|
300
|
-
def
|
|
308
|
+
def from_directions(cls, angles, name="Default"):
|
|
301
309
|
"""Create ``Vector2Set`` object from arrays of direction angles
|
|
302
310
|
|
|
303
311
|
Args:
|
|
@@ -309,8 +317,7 @@ class Vector2Set(FeatureSet):
|
|
|
309
317
|
Example:
|
|
310
318
|
>>> f = vec2set.from_angles([120,130,140,125, 132. 131])
|
|
311
319
|
"""
|
|
312
|
-
|
|
313
|
-
return cls([dtype_cls(a) for a in angles], name=name)
|
|
320
|
+
return cls([cls.__feature_class__(a) for a in angles], name=name)
|
|
314
321
|
|
|
315
322
|
@classmethod
|
|
316
323
|
def from_xy(cls, x, y, name="Default"):
|
|
@@ -327,8 +334,7 @@ class Vector2Set(FeatureSet):
|
|
|
327
334
|
>>> v = vec2set.from_xy([-0.4330127, -0.4330127, -0.66793414],
|
|
328
335
|
[0.75, 0.25, 0.60141061])
|
|
329
336
|
"""
|
|
330
|
-
|
|
331
|
-
return cls([dtype_cls(xx, yy) for xx, yy in zip(x, y)], name=name)
|
|
337
|
+
return cls([cls.__feature_class__(xx, yy) for xx, yy in zip(x, y)], name=name)
|
|
332
338
|
|
|
333
339
|
@classmethod
|
|
334
340
|
def random(cls, n=100, name="Default"):
|
|
@@ -344,8 +350,7 @@ class Vector2Set(FeatureSet):
|
|
|
344
350
|
>>> l = vec2set.random(100)
|
|
345
351
|
|
|
346
352
|
"""
|
|
347
|
-
|
|
348
|
-
return cls([dtype_cls.random() for i in range(n)], name=name)
|
|
353
|
+
return cls([cls.__feature_class__.random() for i in range(n)], name=name)
|
|
349
354
|
|
|
350
355
|
@classmethod
|
|
351
356
|
def random_vonmises(cls, n=100, position=0, kappa=5, name="Default"):
|
|
@@ -361,9 +366,19 @@ class Vector2Set(FeatureSet):
|
|
|
361
366
|
Example:
|
|
362
367
|
>>> l = linset.random_fisher(position=lin(120,50))
|
|
363
368
|
"""
|
|
364
|
-
dtype_cls = getattr(sys.modules[__name__], cls.__feature_type__)
|
|
365
369
|
angles = np.degrees(vonmises.rvs(kappa, loc=np.radians(position), size=n))
|
|
366
|
-
return cls([
|
|
370
|
+
return cls([cls.__feature_class__(a) for a in angles], name=name)
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
class Direction2Set(Vector2Set):
|
|
374
|
+
"""
|
|
375
|
+
Class to store set of ``Direction`` features
|
|
376
|
+
"""
|
|
377
|
+
|
|
378
|
+
__feature_class__ = Direction
|
|
379
|
+
|
|
380
|
+
def __repr__(self):
|
|
381
|
+
return f"D2({len(self)}) {self.name}"
|
|
367
382
|
|
|
368
383
|
|
|
369
384
|
class Vector3Set(FeatureSet):
|
|
@@ -371,7 +386,7 @@ class Vector3Set(FeatureSet):
|
|
|
371
386
|
Class to store set of ``Vector3`` features
|
|
372
387
|
"""
|
|
373
388
|
|
|
374
|
-
|
|
389
|
+
__feature_class__ = Vector3
|
|
375
390
|
|
|
376
391
|
def __repr__(self):
|
|
377
392
|
return f"V3({len(self)}) {self.name}"
|
|
@@ -597,7 +612,6 @@ class Vector3Set(FeatureSet):
|
|
|
597
612
|
resultant.
|
|
598
613
|
|
|
599
614
|
"""
|
|
600
|
-
dtype_cls = getattr(sys.modules[__name__], type(self).__feature_type__)
|
|
601
615
|
v = Vector3Set(self)
|
|
602
616
|
v_data = list(v)
|
|
603
617
|
alldone = np.all(v.angle(v.R()) <= 90)
|
|
@@ -608,7 +622,7 @@ class Vector3Set(FeatureSet):
|
|
|
608
622
|
v_data[ix] = -v_data[ix]
|
|
609
623
|
v = Vector3Set(v_data)
|
|
610
624
|
alldone = np.all(v.angle(v.R()) <= 90)
|
|
611
|
-
return type(self)([
|
|
625
|
+
return type(self)([self.__feature_class__(vec) for vec in v], name=self.name)
|
|
612
626
|
|
|
613
627
|
@classmethod
|
|
614
628
|
def from_csv(cls, filename, acol=0, icol=1):
|
|
@@ -627,9 +641,6 @@ class Vector3Set(FeatureSet):
|
|
|
627
641
|
>>> gl = linset.from_csv('file2.csv', acol=1, icol=2) #doctest: +SKIP
|
|
628
642
|
|
|
629
643
|
"""
|
|
630
|
-
from os.path import basename
|
|
631
|
-
import csv
|
|
632
|
-
|
|
633
644
|
with open(filename) as csvfile:
|
|
634
645
|
has_header = csv.Sniffer().has_header(csvfile.read(1024))
|
|
635
646
|
csvfile.seek(0)
|
|
@@ -665,7 +676,6 @@ class Vector3Set(FeatureSet):
|
|
|
665
676
|
Note: Written values are rounded according to `ndigits` settings in apsg_conf
|
|
666
677
|
|
|
667
678
|
"""
|
|
668
|
-
import csv
|
|
669
679
|
|
|
670
680
|
n = apsg_conf["ndigits"]
|
|
671
681
|
|
|
@@ -692,8 +702,9 @@ class Vector3Set(FeatureSet):
|
|
|
692
702
|
>>> f = folset.from_array([120,130,140], [10,20,30])
|
|
693
703
|
>>> l = linset.from_array([120,130,140], [10,20,30])
|
|
694
704
|
"""
|
|
695
|
-
|
|
696
|
-
|
|
705
|
+
return cls(
|
|
706
|
+
[cls.__feature_class__(azi, inc) for azi, inc in zip(azis, incs)], name=name
|
|
707
|
+
)
|
|
697
708
|
|
|
698
709
|
@classmethod
|
|
699
710
|
def from_xyz(cls, x, y, z, name="Default"):
|
|
@@ -712,8 +723,10 @@ class Vector3Set(FeatureSet):
|
|
|
712
723
|
[0.75, 0.25, 0.60141061],
|
|
713
724
|
[0.5, 0.8660254, 0.43837115])
|
|
714
725
|
"""
|
|
715
|
-
|
|
716
|
-
|
|
726
|
+
return cls(
|
|
727
|
+
[cls.__feature_class__(xx, yy, zz) for xx, yy, zz in zip(x, y, z)],
|
|
728
|
+
name=name,
|
|
729
|
+
)
|
|
717
730
|
|
|
718
731
|
@classmethod
|
|
719
732
|
def random_normal(cls, n=100, position=Vector3(0, 0, 1), sigma=20, name="Default"):
|
|
@@ -733,7 +746,6 @@ class Vector3Set(FeatureSet):
|
|
|
733
746
|
|
|
734
747
|
"""
|
|
735
748
|
data = []
|
|
736
|
-
dtype_cls = getattr(sys.modules[__name__], cls.__feature_type__)
|
|
737
749
|
orig = Vector3(0, 0, 1)
|
|
738
750
|
ax = orig.cross(position)
|
|
739
751
|
ang = orig.angle(position)
|
|
@@ -742,7 +754,7 @@ class Vector3Set(FeatureSet):
|
|
|
742
754
|
np.random.normal(loc=0, scale=sigma, size=n),
|
|
743
755
|
):
|
|
744
756
|
v = orig.rotate(Vector3(s, 0), r).rotate(ax, ang)
|
|
745
|
-
data.append(
|
|
757
|
+
data.append(cls.__feature_class__(v))
|
|
746
758
|
return cls(data, name=name)
|
|
747
759
|
|
|
748
760
|
@classmethod
|
|
@@ -759,9 +771,8 @@ class Vector3Set(FeatureSet):
|
|
|
759
771
|
Example:
|
|
760
772
|
>>> l = linset.random_fisher(position=lin(120,50))
|
|
761
773
|
"""
|
|
762
|
-
dtype_cls = getattr(sys.modules[__name__], cls.__feature_type__)
|
|
763
774
|
dc = vonMisesFisher(position, kappa, n)
|
|
764
|
-
return cls([
|
|
775
|
+
return cls([cls.__feature_class__(d) for d in dc], name=name)
|
|
765
776
|
|
|
766
777
|
@classmethod
|
|
767
778
|
def random_fisher2(cls, n=100, position=Vector3(0, 0, 1), kappa=20, name="Default"):
|
|
@@ -807,11 +818,10 @@ class Vector3Set(FeatureSet):
|
|
|
807
818
|
>>> l = linset.random_kent(p, n=300, kappa=30)
|
|
808
819
|
"""
|
|
809
820
|
assert issubclass(type(p), Pair), "Argument must be Pair object."
|
|
810
|
-
dtype_cls = getattr(sys.modules[__name__], cls.__feature_type__)
|
|
811
821
|
if beta is None:
|
|
812
822
|
beta = kappa / 2
|
|
813
823
|
kd = KentDistribution(p.lvec, p.fvec.cross(p.lvec), p.fvec, kappa, beta)
|
|
814
|
-
return cls([
|
|
824
|
+
return cls([cls.__feature_class__(d) for d in kd.rvs(n)], name=name)
|
|
815
825
|
|
|
816
826
|
@classmethod
|
|
817
827
|
def uniform_sfs(cls, n=100, name="Default"):
|
|
@@ -830,14 +840,13 @@ class Vector3Set(FeatureSet):
|
|
|
830
840
|
>>> v.ortensor().eigenvalues()
|
|
831
841
|
(0.3334645347163635, 0.33333474915201167, 0.33320071613162483)
|
|
832
842
|
"""
|
|
833
|
-
dtype_cls = getattr(sys.modules[__name__], cls.__feature_type__)
|
|
834
843
|
phi = (1 + np.sqrt(5)) / 2
|
|
835
844
|
i2 = 2 * np.arange(n) - n + 1
|
|
836
845
|
theta = 2 * np.pi * i2 / phi
|
|
837
846
|
sp = i2 / n
|
|
838
847
|
cp = np.sqrt((n + i2) * (n - i2)) / n
|
|
839
848
|
dc = np.array([cp * np.sin(theta), cp * np.cos(theta), sp]).T
|
|
840
|
-
return cls([
|
|
849
|
+
return cls([cls.__feature_class__(d) for d in dc], name=name)
|
|
841
850
|
|
|
842
851
|
@classmethod
|
|
843
852
|
def uniform_gss(cls, n=100, name="Default"):
|
|
@@ -855,7 +864,6 @@ class Vector3Set(FeatureSet):
|
|
|
855
864
|
>>> v.ortensor().eigenvalues()
|
|
856
865
|
(0.33335688569571587, 0.33332315115436933, 0.33331996314991513)
|
|
857
866
|
"""
|
|
858
|
-
dtype_cls = getattr(sys.modules[__name__], cls.__feature_type__)
|
|
859
867
|
inc = np.pi * (3 - np.sqrt(5))
|
|
860
868
|
off = 2 / n
|
|
861
869
|
k = np.arange(n)
|
|
@@ -863,7 +871,7 @@ class Vector3Set(FeatureSet):
|
|
|
863
871
|
r = np.sqrt(1 - y * y)
|
|
864
872
|
phi = k * inc
|
|
865
873
|
dc = np.array([np.cos(phi) * r, y, np.sin(phi) * r]).T
|
|
866
|
-
return cls([
|
|
874
|
+
return cls([cls.__feature_class__(d) for d in dc], name=name)
|
|
867
875
|
|
|
868
876
|
|
|
869
877
|
class LineationSet(Vector3Set):
|
|
@@ -871,7 +879,7 @@ class LineationSet(Vector3Set):
|
|
|
871
879
|
Class to store set of ``Lineation`` features
|
|
872
880
|
"""
|
|
873
881
|
|
|
874
|
-
|
|
882
|
+
__feature_class__ = Lineation
|
|
875
883
|
|
|
876
884
|
def __repr__(self):
|
|
877
885
|
return f"L({len(self)}) {self.name}"
|
|
@@ -882,7 +890,7 @@ class FoliationSet(Vector3Set):
|
|
|
882
890
|
Class to store set of ``Foliation`` features
|
|
883
891
|
"""
|
|
884
892
|
|
|
885
|
-
|
|
893
|
+
__feature_class__ = Foliation
|
|
886
894
|
|
|
887
895
|
def __repr__(self):
|
|
888
896
|
return f"S({len(self)}) {self.name}"
|
|
@@ -897,7 +905,7 @@ class PairSet(FeatureSet):
|
|
|
897
905
|
Class to store set of ``Pair`` features
|
|
898
906
|
"""
|
|
899
907
|
|
|
900
|
-
|
|
908
|
+
__feature_class__ = Pair
|
|
901
909
|
|
|
902
910
|
def __repr__(self):
|
|
903
911
|
return f"P({len(self)}) {self.name}"
|
|
@@ -995,9 +1003,6 @@ class PairSet(FeatureSet):
|
|
|
995
1003
|
def from_csv(cls, filename, delimiter=",", facol=0, ficol=1, lacol=2, licol=3):
|
|
996
1004
|
"""Read ``PairSet`` from csv file"""
|
|
997
1005
|
|
|
998
|
-
from os.path import basename
|
|
999
|
-
import csv
|
|
1000
|
-
|
|
1001
1006
|
with open(filename) as csvfile:
|
|
1002
1007
|
has_header = csv.Sniffer().has_header(csvfile.read(1024))
|
|
1003
1008
|
csvfile.seek(0)
|
|
@@ -1063,7 +1068,6 @@ class PairSet(FeatureSet):
|
|
|
1063
1068
|
Note: Written values are rounded according to `ndigits` settings in apsg_conf
|
|
1064
1069
|
|
|
1065
1070
|
"""
|
|
1066
|
-
import csv
|
|
1067
1071
|
|
|
1068
1072
|
n = apsg_conf["ndigits"]
|
|
1069
1073
|
|
|
@@ -1095,10 +1099,9 @@ class PairSet(FeatureSet):
|
|
|
1095
1099
|
name: name of ``PairSet`` object. Default is 'Default'
|
|
1096
1100
|
"""
|
|
1097
1101
|
|
|
1098
|
-
dtype_cls = getattr(sys.modules[__name__], cls.__feature_type__)
|
|
1099
1102
|
return cls(
|
|
1100
1103
|
[
|
|
1101
|
-
|
|
1104
|
+
cls.__feature_class__(fazi, finc, lazi, linc)
|
|
1102
1105
|
for fazi, finc, lazi, linc in zip(fazis, fincs, lazis, lincs)
|
|
1103
1106
|
],
|
|
1104
1107
|
name=name,
|
|
@@ -1110,7 +1113,7 @@ class FaultSet(PairSet):
|
|
|
1110
1113
|
Class to store set of ``Fault`` features
|
|
1111
1114
|
"""
|
|
1112
1115
|
|
|
1113
|
-
|
|
1116
|
+
__feature_class__ = Fault
|
|
1114
1117
|
|
|
1115
1118
|
def __repr__(self):
|
|
1116
1119
|
return f"F({len(self)}) {self.name}"
|
|
@@ -1120,6 +1123,11 @@ class FaultSet(PairSet):
|
|
|
1120
1123
|
"""Return array of sense values"""
|
|
1121
1124
|
return np.array([f.sense for f in self])
|
|
1122
1125
|
|
|
1126
|
+
@property
|
|
1127
|
+
def sense_str(self):
|
|
1128
|
+
"""Return array of sense characters"""
|
|
1129
|
+
return np.array([f.sense_str for f in self])
|
|
1130
|
+
|
|
1123
1131
|
@property
|
|
1124
1132
|
def p_vector(self, ptangle=90):
|
|
1125
1133
|
"""Return p-axes of FaultSet as Vector3Set"""
|
|
@@ -1196,13 +1204,18 @@ class FaultSet(PairSet):
|
|
|
1196
1204
|
|
|
1197
1205
|
@classmethod
|
|
1198
1206
|
def from_csv(
|
|
1199
|
-
cls,
|
|
1207
|
+
cls,
|
|
1208
|
+
filename,
|
|
1209
|
+
delimiter=",",
|
|
1210
|
+
sense_str=False,
|
|
1211
|
+
facol=0,
|
|
1212
|
+
ficol=1,
|
|
1213
|
+
lacol=2,
|
|
1214
|
+
licol=3,
|
|
1215
|
+
scol=4,
|
|
1200
1216
|
):
|
|
1201
1217
|
"""Read ``FaultSet`` from csv file"""
|
|
1202
1218
|
|
|
1203
|
-
from os.path import basename
|
|
1204
|
-
import csv
|
|
1205
|
-
|
|
1206
1219
|
with open(filename) as csvfile:
|
|
1207
1220
|
has_header = csv.Sniffer().has_header(csvfile.read(1024))
|
|
1208
1221
|
csvfile.seek(0)
|
|
@@ -1220,48 +1233,73 @@ class FaultSet(PairSet):
|
|
|
1220
1233
|
faname, finame = reader.fieldnames[facol], reader.fieldnames[ficol]
|
|
1221
1234
|
laname, liname = reader.fieldnames[lacol], reader.fieldnames[licol]
|
|
1222
1235
|
sname = reader.fieldnames[scol]
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1236
|
+
if sense_str:
|
|
1237
|
+
r = [
|
|
1238
|
+
(
|
|
1239
|
+
float(row[faname]),
|
|
1240
|
+
float(row[finame]),
|
|
1241
|
+
float(row[laname]),
|
|
1242
|
+
float(row[liname]),
|
|
1243
|
+
row[sname],
|
|
1244
|
+
)
|
|
1245
|
+
for row in reader
|
|
1246
|
+
]
|
|
1247
|
+
else:
|
|
1248
|
+
r = [
|
|
1249
|
+
(
|
|
1250
|
+
float(row[faname]),
|
|
1251
|
+
float(row[finame]),
|
|
1252
|
+
float(row[laname]),
|
|
1253
|
+
float(row[liname]),
|
|
1254
|
+
int(row[sname]),
|
|
1255
|
+
)
|
|
1256
|
+
for row in reader
|
|
1257
|
+
]
|
|
1233
1258
|
else:
|
|
1234
1259
|
reader = csv.reader(csvfile, dialect=dialect)
|
|
1260
|
+
|
|
1235
1261
|
r = [
|
|
1236
1262
|
(
|
|
1237
1263
|
float(row[facol]),
|
|
1238
1264
|
float(row[ficol]),
|
|
1239
1265
|
float(row[lacol]),
|
|
1240
1266
|
float(row[licol]),
|
|
1241
|
-
|
|
1267
|
+
row[scol],
|
|
1242
1268
|
)
|
|
1243
1269
|
for row in reader
|
|
1244
1270
|
]
|
|
1245
1271
|
else:
|
|
1246
1272
|
if has_header:
|
|
1247
1273
|
reader = csv.DictReader(csvfile, dialect=dialect)
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1274
|
+
if sense_str:
|
|
1275
|
+
r = [
|
|
1276
|
+
(
|
|
1277
|
+
float(row[facol]),
|
|
1278
|
+
float(row[ficol]),
|
|
1279
|
+
float(row[lacol]),
|
|
1280
|
+
float(row[licol]),
|
|
1281
|
+
row[scol],
|
|
1282
|
+
)
|
|
1283
|
+
for row in reader
|
|
1284
|
+
]
|
|
1285
|
+
else:
|
|
1286
|
+
r = [
|
|
1287
|
+
(
|
|
1288
|
+
float(row[facol]),
|
|
1289
|
+
float(row[ficol]),
|
|
1290
|
+
float(row[lacol]),
|
|
1291
|
+
float(row[licol]),
|
|
1292
|
+
int(row[scol]),
|
|
1293
|
+
)
|
|
1294
|
+
for row in reader
|
|
1295
|
+
]
|
|
1258
1296
|
else:
|
|
1259
1297
|
raise ValueError("No header line in CSV file...")
|
|
1260
1298
|
|
|
1261
1299
|
fazi, finc, lazi, linc, sense = zip(*r)
|
|
1262
1300
|
return cls.from_array(fazi, finc, lazi, linc, sense, name=basename(filename))
|
|
1263
1301
|
|
|
1264
|
-
def to_csv(self, filename, delimiter=","):
|
|
1302
|
+
def to_csv(self, filename, delimiter=",", sense_str=False):
|
|
1265
1303
|
"""Save ``FaultSet`` object to csv file
|
|
1266
1304
|
|
|
1267
1305
|
Args:
|
|
@@ -1269,11 +1307,11 @@ class FaultSet(PairSet):
|
|
|
1269
1307
|
|
|
1270
1308
|
Keyword Args:
|
|
1271
1309
|
delimiter (str): values delimiter. Default ','
|
|
1310
|
+
sense_str (bool): save sense as N, R, S or D. Default False
|
|
1272
1311
|
|
|
1273
1312
|
Note: Written values are rounded according to `ndigits` settings in apsg_conf
|
|
1274
1313
|
|
|
1275
1314
|
"""
|
|
1276
|
-
import csv
|
|
1277
1315
|
|
|
1278
1316
|
n = apsg_conf["ndigits"]
|
|
1279
1317
|
|
|
@@ -1284,19 +1322,30 @@ class FaultSet(PairSet):
|
|
|
1284
1322
|
for dt in self:
|
|
1285
1323
|
fazi, finc = dt.fol.geo
|
|
1286
1324
|
lazi, linc = dt.lin.geo
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1325
|
+
if sense_str:
|
|
1326
|
+
writer.writerow(
|
|
1327
|
+
{
|
|
1328
|
+
"fazi": round(fazi, n),
|
|
1329
|
+
"finc": round(finc, n),
|
|
1330
|
+
"lazi": round(lazi, n),
|
|
1331
|
+
"linc": round(linc, n),
|
|
1332
|
+
"sense": dt.sense_str,
|
|
1333
|
+
}
|
|
1334
|
+
)
|
|
1335
|
+
else:
|
|
1336
|
+
writer.writerow(
|
|
1337
|
+
{
|
|
1338
|
+
"fazi": round(fazi, n),
|
|
1339
|
+
"finc": round(finc, n),
|
|
1340
|
+
"lazi": round(lazi, n),
|
|
1341
|
+
"linc": round(linc, n),
|
|
1342
|
+
"sense": dt.sense,
|
|
1343
|
+
}
|
|
1344
|
+
)
|
|
1296
1345
|
|
|
1297
1346
|
@classmethod
|
|
1298
1347
|
def from_array(cls, fazis, fincs, lazis, lincs, senses, name="Default"):
|
|
1299
|
-
"""Create ``
|
|
1348
|
+
"""Create ``FaultSet`` from arrays of azimuths, inclinations and senses
|
|
1300
1349
|
|
|
1301
1350
|
Args:
|
|
1302
1351
|
azis: list or array of azimuths
|
|
@@ -1306,10 +1355,9 @@ class FaultSet(PairSet):
|
|
|
1306
1355
|
name: name of ``PairSet`` object. Default is 'Default'
|
|
1307
1356
|
"""
|
|
1308
1357
|
|
|
1309
|
-
dtype_cls = getattr(sys.modules[__name__], cls.__feature_type__)
|
|
1310
1358
|
return cls(
|
|
1311
1359
|
[
|
|
1312
|
-
|
|
1360
|
+
cls.__feature_class__(fazi, finc, lazi, linc, sense)
|
|
1313
1361
|
for fazi, finc, lazi, linc, sense in zip(
|
|
1314
1362
|
fazis, fincs, lazis, lincs, senses
|
|
1315
1363
|
)
|
|
@@ -1323,7 +1371,7 @@ class ConeSet(FeatureSet):
|
|
|
1323
1371
|
Class to store set of ``Cone`` features
|
|
1324
1372
|
"""
|
|
1325
1373
|
|
|
1326
|
-
|
|
1374
|
+
__feature_class__ = Cone
|
|
1327
1375
|
|
|
1328
1376
|
def __repr__(self):
|
|
1329
1377
|
return f"C({len(self)}) {self.name}"
|
|
@@ -1334,7 +1382,7 @@ class EllipseSet(FeatureSet):
|
|
|
1334
1382
|
Class to store set of ``Ellipse`` features
|
|
1335
1383
|
"""
|
|
1336
1384
|
|
|
1337
|
-
|
|
1385
|
+
__feature_class__ = Ellipse
|
|
1338
1386
|
|
|
1339
1387
|
@property
|
|
1340
1388
|
def S1(self) -> np.ndarray:
|
|
@@ -1391,7 +1439,7 @@ class OrientationTensor2Set(EllipseSet):
|
|
|
1391
1439
|
Class to store set of ``OrientationTensor2`` features
|
|
1392
1440
|
"""
|
|
1393
1441
|
|
|
1394
|
-
|
|
1442
|
+
__feature_class__ = OrientationTensor2
|
|
1395
1443
|
|
|
1396
1444
|
|
|
1397
1445
|
class EllipsoidSet(FeatureSet):
|
|
@@ -1399,7 +1447,7 @@ class EllipsoidSet(FeatureSet):
|
|
|
1399
1447
|
Class to store set of ``Ellipsoid`` features
|
|
1400
1448
|
"""
|
|
1401
1449
|
|
|
1402
|
-
|
|
1450
|
+
__feature_class__ = Ellipsoid
|
|
1403
1451
|
|
|
1404
1452
|
@property
|
|
1405
1453
|
def strength(self) -> np.ndarray:
|
|
@@ -1633,7 +1681,7 @@ class OrientationTensor3Set(EllipsoidSet):
|
|
|
1633
1681
|
Class to store set of ``OrientationTensor3`` features
|
|
1634
1682
|
"""
|
|
1635
1683
|
|
|
1636
|
-
|
|
1684
|
+
__feature_class__ = OrientationTensor3
|
|
1637
1685
|
|
|
1638
1686
|
|
|
1639
1687
|
class ClusterSet(object):
|
|
@@ -1660,7 +1708,7 @@ class ClusterSet(object):
|
|
|
1660
1708
|
isinstance(d, Vector2Set)
|
|
1661
1709
|
or isinstance(d, Vector3Set)
|
|
1662
1710
|
or isinstance(d, PairSet)
|
|
1663
|
-
), "Only vec2set
|
|
1711
|
+
), "Only vec2set, vecset and pairset could be clustered"
|
|
1664
1712
|
self.data = d.copy()
|
|
1665
1713
|
self.maxclust = kwargs.get("maxclust", 2)
|
|
1666
1714
|
self.angle = kwargs.get("angle", None)
|
|
@@ -1712,7 +1760,10 @@ class ClusterSet(object):
|
|
|
1712
1760
|
"""
|
|
1713
1761
|
|
|
1714
1762
|
self.method = kwargs.get("method", self.method)
|
|
1715
|
-
|
|
1763
|
+
if issubclass(self.data.__feature_class__, (Axial2, Axial3)):
|
|
1764
|
+
self.Z = linkage(self.pdist, method=self.method, metric=angle_metric_axial)
|
|
1765
|
+
else:
|
|
1766
|
+
self.Z = linkage(self.pdist, method=self.method, metric=angle_metric)
|
|
1716
1767
|
|
|
1717
1768
|
def dendrogram(self, **kwargs):
|
|
1718
1769
|
"""Show dendrogram
|
|
@@ -1805,4 +1856,8 @@ def G(lst, name="Default"):
|
|
|
1805
1856
|
|
|
1806
1857
|
|
|
1807
1858
|
def angle_metric(u, v):
|
|
1859
|
+
return np.degrees(np.arccos(np.dot(u, v)))
|
|
1860
|
+
|
|
1861
|
+
|
|
1862
|
+
def angle_metric_axial(u, v):
|
|
1808
1863
|
return np.degrees(np.arccos(np.abs(np.dot(u, v))))
|
apsg/feature/_geodata.py
CHANGED
|
@@ -1,15 +1,50 @@
|
|
|
1
1
|
import warnings
|
|
2
|
+
|
|
2
3
|
import numpy as np
|
|
3
4
|
|
|
5
|
+
from apsg.decorator._decorator import ensure_arguments, ensure_first_arg_same
|
|
4
6
|
from apsg.helpers._notation import (
|
|
5
7
|
geo2vec_planar,
|
|
6
|
-
vec2geo_planar,
|
|
7
|
-
vec2geo_planar_signed,
|
|
8
8
|
vec2geo_linear,
|
|
9
9
|
vec2geo_linear_signed,
|
|
10
|
+
vec2geo_planar,
|
|
11
|
+
vec2geo_planar_signed,
|
|
10
12
|
)
|
|
11
|
-
from apsg.
|
|
12
|
-
|
|
13
|
+
from apsg.math._vector import Axial2, Axial3, Vector3
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Direction(Axial2):
|
|
17
|
+
"""
|
|
18
|
+
A class to represent axial (non-oriented) 2D linear feature (direction).
|
|
19
|
+
|
|
20
|
+
There are different way to create ``Direction`` object:
|
|
21
|
+
|
|
22
|
+
- without arguments create default ``Direction`` D:0
|
|
23
|
+
- with single argument `d`, where:
|
|
24
|
+
|
|
25
|
+
- `d` could be Vector2-like object
|
|
26
|
+
- `d` could be string 'x' or 'y' - principal axes of coordinate system
|
|
27
|
+
- `d` could be tuple of (x, y) - vector components
|
|
28
|
+
- with 1 argument direction
|
|
29
|
+
- with 2 numerical arguments defining vector components
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
direction (float): plunge direction of linear feature in degrees
|
|
33
|
+
|
|
34
|
+
Example:
|
|
35
|
+
>>> dir2()
|
|
36
|
+
>>> dir2('y')
|
|
37
|
+
>>> dir2(45)
|
|
38
|
+
>>> d = dir2(1, -1)
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
def __repr__(self):
|
|
42
|
+
return f"D:{self.direction:.0f}"
|
|
43
|
+
|
|
44
|
+
def to_json(self):
|
|
45
|
+
"""Return as JSON dict"""
|
|
46
|
+
azi, inc = vec2geo_linear_signed(self)
|
|
47
|
+
return {"datatype": type(self).__name__, "args": (azi, inc)}
|
|
13
48
|
|
|
14
49
|
|
|
15
50
|
class Lineation(Axial3):
|
|
@@ -446,15 +481,15 @@ class Fault(Pair):
|
|
|
446
481
|
elif isinstance(sense, str):
|
|
447
482
|
p = Pair(fvec, lvec)
|
|
448
483
|
if sense.lower() == "s":
|
|
449
|
-
if p.rax
|
|
450
|
-
res = -1
|
|
451
|
-
else:
|
|
452
|
-
res = 1
|
|
453
|
-
elif sense.lower() == "d":
|
|
454
|
-
if p.rax == p.rax.lower():
|
|
484
|
+
if p.rax.is_upper():
|
|
455
485
|
res = 1
|
|
456
486
|
else:
|
|
457
487
|
res = -1
|
|
488
|
+
elif sense.lower() == "d":
|
|
489
|
+
if p.rax.is_upper():
|
|
490
|
+
res = -1
|
|
491
|
+
else:
|
|
492
|
+
res = 1
|
|
458
493
|
elif sense.lower() == "n":
|
|
459
494
|
res = 1
|
|
460
495
|
elif sense.lower() == "r":
|
|
@@ -464,7 +499,8 @@ class Fault(Pair):
|
|
|
464
499
|
def __repr__(self):
|
|
465
500
|
fazi, finc = self.fol.geo
|
|
466
501
|
lazi, linc = self.lin.geo
|
|
467
|
-
schar =
|
|
502
|
+
schar = self.sense_str
|
|
503
|
+
# schar = [" ", "+", "-"][self.sense]
|
|
468
504
|
return f"F:{fazi:.0f}/{finc:.0f}-{lazi:.0f}/{linc:.0f} {schar}"
|
|
469
505
|
|
|
470
506
|
@ensure_first_arg_same
|
|
@@ -519,6 +555,24 @@ class Fault(Pair):
|
|
|
519
555
|
else:
|
|
520
556
|
return -1
|
|
521
557
|
|
|
558
|
+
@property
|
|
559
|
+
def sense_str(self):
|
|
560
|
+
if abs(self.rax.geo[1]) > 75:
|
|
561
|
+
if self.rax.z > 0:
|
|
562
|
+
schar = "D"
|
|
563
|
+
elif self.rax.z < 0:
|
|
564
|
+
schar = "S"
|
|
565
|
+
else:
|
|
566
|
+
schar = " "
|
|
567
|
+
else:
|
|
568
|
+
if self.sense < 0:
|
|
569
|
+
schar = "R"
|
|
570
|
+
elif self.sense > 0:
|
|
571
|
+
schar = "N"
|
|
572
|
+
else:
|
|
573
|
+
schar = " "
|
|
574
|
+
return schar
|
|
575
|
+
|
|
522
576
|
def p_vector(self, ptangle=90):
|
|
523
577
|
"""Return P axis as ``Vector3``"""
|
|
524
578
|
return self.fvec.rotate(self.lvec.cross(self.fvec), -ptangle / 2)
|
apsg/feature/_tensor3.py
CHANGED
|
@@ -440,6 +440,30 @@ class Stress3(Tensor3):
|
|
|
440
440
|
|
|
441
441
|
return cls([[xx, xy, xz], [xy, yy, yz], [xz, yz, zz]])
|
|
442
442
|
|
|
443
|
+
@classmethod
|
|
444
|
+
def from_ratio(cls, r=0.5, mag=1):
|
|
445
|
+
"""
|
|
446
|
+
Return ``Stress`` tensor with given shape ration.
|
|
447
|
+
|
|
448
|
+
Keyword Args:
|
|
449
|
+
r (float): shape ratio between 0 and 1. Default 0.5
|
|
450
|
+
mag (float): magnitude of differential stress. Default 1.
|
|
451
|
+
|
|
452
|
+
Example:
|
|
453
|
+
>>> S = stress.from_ratio(r=0.25, mag=10)
|
|
454
|
+
>>> S
|
|
455
|
+
Stress3
|
|
456
|
+
[[-5. 0. 0. ]
|
|
457
|
+
[ 0. -2.5 0. ]
|
|
458
|
+
[ 0. 0. 5. ]]
|
|
459
|
+
|
|
460
|
+
"""
|
|
461
|
+
|
|
462
|
+
xx = -mag / 2
|
|
463
|
+
yy = xx + r * mag
|
|
464
|
+
zz = mag / 2
|
|
465
|
+
return cls([[xx, 0, 0], [0, yy, 0], [0, 0, zz]])
|
|
466
|
+
|
|
443
467
|
@property
|
|
444
468
|
def mean_stress(self):
|
|
445
469
|
"""
|
apsg/math/_matrix.py
CHANGED
|
@@ -4,10 +4,6 @@ from apsg.config import apsg_conf
|
|
|
4
4
|
from apsg.decorator._decorator import ensure_first_arg_same
|
|
5
5
|
from apsg.math._vector import Vector3, Vector2
|
|
6
6
|
|
|
7
|
-
"""
|
|
8
|
-
TO BE ADDED
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
7
|
|
|
12
8
|
class Matrix:
|
|
13
9
|
"""Base class for Matrix2 and Matrix3"""
|
|
@@ -128,7 +124,7 @@ class Matrix:
|
|
|
128
124
|
return self._coefs[1][1]
|
|
129
125
|
|
|
130
126
|
@property
|
|
131
|
-
def I(self):
|
|
127
|
+
def I(self): # noqa: E743
|
|
132
128
|
return type(self)(np.linalg.inv(self))
|
|
133
129
|
|
|
134
130
|
@property
|
apsg/plotting/_roseplot.py
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import pickle
|
|
2
2
|
|
|
3
|
-
import numpy as np
|
|
4
3
|
import matplotlib.pyplot as plt
|
|
5
|
-
|
|
4
|
+
import numpy as np
|
|
5
|
+
from scipy.stats import circmean, vonmises
|
|
6
6
|
|
|
7
7
|
from apsg.config import apsg_conf
|
|
8
|
-
from apsg.plotting._plot_artists import RosePlotArtistFactory
|
|
9
8
|
from apsg.feature import feature_from_json
|
|
9
|
+
from apsg.math._vector import Axial2, Axial3
|
|
10
|
+
from apsg.plotting._plot_artists import RosePlotArtistFactory
|
|
10
11
|
|
|
11
12
|
__all__ = ["RosePlot"]
|
|
12
13
|
|
|
@@ -20,7 +21,6 @@ class RosePlot(object):
|
|
|
20
21
|
title_kws (dict): dictionary of keyword arguments passed to matplotlib suptitle
|
|
21
22
|
method.
|
|
22
23
|
bins (int): Number of bins. Default 36
|
|
23
|
-
axial (bool): Directional data are axial. Defaut True
|
|
24
24
|
density (bool): Use density instead of counts. Default False
|
|
25
25
|
pdf (bool): Plot Von Mises density function instead histogram. Default False
|
|
26
26
|
pdf_res (int): Resolution of pdf. Default 901
|
|
@@ -245,7 +245,7 @@ class RosePlot(object):
|
|
|
245
245
|
width = 2 * np.pi / self._kwargs["bins"]
|
|
246
246
|
legend = kwargs.pop("legend")
|
|
247
247
|
for arg in args:
|
|
248
|
-
if
|
|
248
|
+
if issubclass(arg.__feature_class__, (Axial2, Axial3)):
|
|
249
249
|
ang = np.concatenate((arg.direction % 360, (arg.direction + 180) % 360))
|
|
250
250
|
weights = np.concatenate((abs(arg), abs(arg)))
|
|
251
251
|
else:
|
|
@@ -279,7 +279,7 @@ class RosePlot(object):
|
|
|
279
279
|
ang = arg.direction % 360
|
|
280
280
|
# weights = abs(arg)
|
|
281
281
|
radii = np.zeros_like(theta)
|
|
282
|
-
if
|
|
282
|
+
if issubclass(arg.__feature_class__, (Axial2, Axial3)):
|
|
283
283
|
for a in ang:
|
|
284
284
|
radii += (
|
|
285
285
|
vonmises.pdf(theta, self._kwargs["kappa"], loc=np.radians(a))
|
|
@@ -308,32 +308,21 @@ class RosePlot(object):
|
|
|
308
308
|
bottom = bottom + radii
|
|
309
309
|
|
|
310
310
|
def _muci(self, *args, **kwargs):
|
|
311
|
-
ang = np.radians(np.concatenate([arg.direction for arg in args]))
|
|
312
311
|
conflevel = kwargs.pop("confidence_level")
|
|
313
312
|
n_resamples = kwargs.pop("n_resamples")
|
|
314
|
-
# calculate mean and CI
|
|
315
|
-
if self._kwargs["axial"]:
|
|
316
|
-
mu = circmean(2 * ang) / 2
|
|
317
|
-
ang_shift = ang + np.pi / 2 - mu
|
|
318
|
-
bsmu = [
|
|
319
|
-
circmean(np.random.choice(2 * ang_shift, size=len(ang_shift)))
|
|
320
|
-
for i in range(n_resamples)
|
|
321
|
-
]
|
|
322
|
-
low = np.percentile(bsmu, 100 - conflevel) / 2 + mu - np.pi / 2
|
|
323
|
-
high = np.percentile(bsmu, conflevel) / 2 + mu - np.pi / 2
|
|
324
|
-
else:
|
|
325
|
-
mu = circmean(ang)
|
|
326
|
-
ang_shift = ang + np.pi - mu
|
|
327
|
-
bsmu = [
|
|
328
|
-
circmean(np.random.choice(ang_shift, size=len(ang_shift)))
|
|
329
|
-
for i in range(n_resamples)
|
|
330
|
-
]
|
|
331
|
-
low = np.percentile(bsmu, (100 - conflevel) / 2) + mu - np.pi
|
|
332
|
-
high = np.percentile(bsmu, 100 - (100 - conflevel) / 2) + mu - np.pi
|
|
333
|
-
radii = []
|
|
334
313
|
for arg in args:
|
|
314
|
+
radii = []
|
|
335
315
|
p = 0
|
|
336
|
-
|
|
316
|
+
ang = np.radians(arg.direction)
|
|
317
|
+
if issubclass(arg.__feature_class__, (Axial2, Axial3)):
|
|
318
|
+
mu = circmean(2 * ang) / 2
|
|
319
|
+
ang_shift = ang + np.pi / 2 - mu
|
|
320
|
+
bsmu = [
|
|
321
|
+
circmean(np.random.choice(2 * ang_shift, size=len(ang_shift)))
|
|
322
|
+
for i in range(n_resamples)
|
|
323
|
+
]
|
|
324
|
+
low = np.percentile(bsmu, 100 - conflevel) / 2 + mu - np.pi / 2
|
|
325
|
+
high = np.percentile(bsmu, conflevel) / 2 + mu - np.pi / 2
|
|
337
326
|
for a in arg.direction:
|
|
338
327
|
p += vonmises.pdf(mu, self._kwargs["kappa"], loc=np.radians(a)) / 2
|
|
339
328
|
p += (
|
|
@@ -341,16 +330,28 @@ class RosePlot(object):
|
|
|
341
330
|
/ 2
|
|
342
331
|
)
|
|
343
332
|
else:
|
|
333
|
+
mu = circmean(ang)
|
|
334
|
+
ang_shift = ang + np.pi - mu
|
|
335
|
+
bsmu = [
|
|
336
|
+
circmean(np.random.choice(ang_shift, size=len(ang_shift)))
|
|
337
|
+
for i in range(n_resamples)
|
|
338
|
+
]
|
|
339
|
+
low = np.percentile(bsmu, (100 - conflevel) / 2) + mu - np.pi
|
|
340
|
+
high = np.percentile(bsmu, 100 - (100 - conflevel) / 2) + mu - np.pi
|
|
344
341
|
for a in arg.direction:
|
|
345
342
|
p += vonmises.pdf(mu, self._kwargs["kappa"], loc=np.radians(a))
|
|
346
343
|
radii.append(p / len(arg))
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
344
|
+
if self._kwargs["scaled"]:
|
|
345
|
+
radii = np.sqrt(radii)
|
|
346
|
+
mur = 1.1 * sum(radii)
|
|
347
|
+
ci_angles = np.linspace(low, high, int(5 * np.degrees(high - low)))
|
|
348
|
+
if issubclass(arg.__feature_class__, (Axial2, Axial3)):
|
|
349
|
+
self.ax.plot([mu, mu + np.pi], [mur, mur], **kwargs)
|
|
350
|
+
self.ax.plot(ci_angles, mur * np.ones_like(ci_angles), **kwargs)
|
|
351
|
+
self.ax.plot(ci_angles + np.pi, mur * np.ones_like(ci_angles), **kwargs)
|
|
352
|
+
else:
|
|
353
|
+
self.ax.plot([0, mu], [0, mur], **kwargs)
|
|
354
|
+
self.ax.plot(ci_angles, mur * np.ones_like(ci_angles), **kwargs)
|
|
354
355
|
|
|
355
356
|
|
|
356
357
|
def roseartist_from_json(obj_json):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: apsg
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.6
|
|
4
4
|
Summary: APSG - The package for structural geologists
|
|
5
5
|
Author-email: Ondrej Lexa <lexa.ondrej@gmail.com>
|
|
6
6
|
Maintainer-email: Ondrej Lexa <lexa.ondrej@gmail.com>
|
|
@@ -59,14 +59,8 @@ Requires-Dist: ipykernel; extra == "docs"
|
|
|
59
59
|
Requires-Dist: nbsphinx; extra == "docs"
|
|
60
60
|
Requires-Dist: autodocsumm; extra == "docs"
|
|
61
61
|
Provides-Extra: dev
|
|
62
|
-
Requires-Dist:
|
|
62
|
+
Requires-Dist: apsg[docs,extra,tests]; extra == "dev"
|
|
63
63
|
Requires-Dist: black; extra == "dev"
|
|
64
|
-
Requires-Dist: sphinx; extra == "dev"
|
|
65
|
-
Requires-Dist: sphinx_rtd_theme; extra == "dev"
|
|
66
|
-
Requires-Dist: readthedocs-sphinx-search; extra == "dev"
|
|
67
|
-
Requires-Dist: ipykernel; extra == "dev"
|
|
68
|
-
Requires-Dist: nbsphinx; extra == "dev"
|
|
69
|
-
Requires-Dist: autodocsumm; extra == "dev"
|
|
70
64
|
Dynamic: license-file
|
|
71
65
|
|
|
72
66
|
<img src="https://ondrolexa.github.io/apsg/apsg_banner.svg" alt="APSG logo" width="300px"/>
|
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
apsg/__init__.py,sha256
|
|
2
|
-
apsg/config.py,sha256=
|
|
1
|
+
apsg/__init__.py,sha256=er5PTmzLPoYoorvyKGhTjeyE6lVsLZr0nB5ariut94o,2849
|
|
2
|
+
apsg/config.py,sha256=vwJZVqWQ2bXe4TNW3hzse-dIam3QBwNeFx5VJUhNjU8,4549
|
|
3
3
|
apsg/shell.py,sha256=1D0PeB7qXzlpiOf2QYGo6OJlEVN1KJPYld1GEREBiFg,707
|
|
4
4
|
apsg/database/__init__.py,sha256=7Rvcf1KBBBNhoM28ZlvQ01CkScQTroFkoS4d1kD55Ws,315
|
|
5
5
|
apsg/database/_alchemy.py,sha256=geV3Q6ZLdGvjzxry7GTHHIQq6t_ccsUxZvuv13CLYFQ,19467
|
|
6
|
-
apsg/database/_sdbread.py,sha256=
|
|
6
|
+
apsg/database/_sdbread.py,sha256=lKvImHCFaxXr0wx5FnogVRp6bAPeaP01MDpUn_rH3Ek,11009
|
|
7
7
|
apsg/decorator/__init__.py,sha256=fZ-dxpldQIk6-2JhVnCj-Tsl8bz2nvoGOyG7uXKvBfg,160
|
|
8
8
|
apsg/decorator/_decorator.py,sha256=8TMSrcVvhU5UCbNMrnyrW3-65qo20_6N2ShtXd3bP-k,1194
|
|
9
|
-
apsg/feature/__init__.py,sha256=
|
|
10
|
-
apsg/feature/_container.py,sha256=
|
|
11
|
-
apsg/feature/_geodata.py,sha256=
|
|
9
|
+
apsg/feature/__init__.py,sha256=XkyS-X8lUaXCVaXgoK0GETmTCCGqB1BmSwZRZG3blZQ,1733
|
|
10
|
+
apsg/feature/_container.py,sha256=7RLkTnEwDDhm6c4jErQOTIPg5KBM46SLpcFlrtyZHvg,60812
|
|
11
|
+
apsg/feature/_geodata.py,sha256=tjgPSKXyEOXiAN3iPeHpm8kpj__jI4ahtTpDuWhQNBE,24008
|
|
12
12
|
apsg/feature/_paleomag.py,sha256=WIICUOEJGGFHbCDF0gbW7lMt10jI0el0UVhkbMH7XAs,14911
|
|
13
13
|
apsg/feature/_statistics.py,sha256=WwBU2D7SyIHMpWnO7WFqbIpSkz6KUCT9xkG8oVzgskQ,13916
|
|
14
14
|
apsg/feature/_tensor2.py,sha256=XzGuSU46RkeVHQu3pqKzgzf0cYZCgbs9eP_yfYa82SU,13451
|
|
15
|
-
apsg/feature/_tensor3.py,sha256=
|
|
15
|
+
apsg/feature/_tensor3.py,sha256=uRC-Vi3HFNwOM33wg5r5N8JUwOeKC64PyRV5J9QbSTk,30329
|
|
16
16
|
apsg/helpers/__init__.py,sha256=6SF_Srq6fS-uomvpwdW0JSQs-tmWnzUoTk4a1K_J1aE,532
|
|
17
17
|
apsg/helpers/_helper.py,sha256=1Xf1yiNYIEoUJqXH4C0390osGWk6AERr_LrCSTnsRVw,146
|
|
18
18
|
apsg/helpers/_math.py,sha256=NLHw9UGiSlNggwZB-o0ORpG2sY00qIcbMbDJftRWFE8,896
|
|
19
19
|
apsg/helpers/_notation.py,sha256=oSxvZdv06eJ5GotS2IwbAJ-8UTZ49z8slqdhUDQJ9e8,2486
|
|
20
20
|
apsg/math/__init__.py,sha256=qJa4JP79nXn-6Xb7aaZUPWmz0qadmC4F0tGORTOZDVI,211
|
|
21
|
-
apsg/math/_matrix.py,sha256=
|
|
21
|
+
apsg/math/_matrix.py,sha256=4LcafIEdpnJ0yoeoD1bypfeyyVPeDDzSbQKKlF5nerg,10411
|
|
22
22
|
apsg/math/_vector.py,sha256=mD8kYggfGys-XWtnE90X2ZcTGBtDN49wEAUXQYXj3dI,16587
|
|
23
23
|
apsg/pandas/__init__.py,sha256=jmlsulHmH9IbErJgSWlJx1J33-v--O5zxSE4kdt6fUI,456
|
|
24
24
|
apsg/pandas/_pandas_api.py,sha256=MKV7MIhPIeSMH8ryjC858F3MjyB47cA_bAKtlKbFlNc,13576
|
|
@@ -27,12 +27,12 @@ apsg/plotting/_fabricplot.py,sha256=yjy3DEhIZfq448FYKnQb3EhqLm9-f-EZHJEamG98k9Q,
|
|
|
27
27
|
apsg/plotting/_paleomagplots.py,sha256=Gw-fqYJVjNxTNXLwAiUKnFUBoOTZv2MEd3XACLmQ6AM,2325
|
|
28
28
|
apsg/plotting/_plot_artists.py,sha256=6S0EKCqYU6rlBxcxcXALTk9PaUK6QL-BgUKmZH8tkMc,21059
|
|
29
29
|
apsg/plotting/_projection.py,sha256=ix67PwOU2WGjryEcsHlVIMpcVC9yxy45ycOV9k5x_Q8,11805
|
|
30
|
-
apsg/plotting/_roseplot.py,sha256=
|
|
30
|
+
apsg/plotting/_roseplot.py,sha256=Wq5NBCDZMUQWEioIC6hYAZzjDKZsiDIJtjk_vQzzCd8,13104
|
|
31
31
|
apsg/plotting/_stereogrid.py,sha256=awh7MwN1WgszhOlr6UgR20wHQJ8u778-Tf_w1uflrV4,11869
|
|
32
32
|
apsg/plotting/_stereonet.py,sha256=uHJXluFMkeaI4yzD9pGc4DIlgjZA01INySLKtUHLAlU,36624
|
|
33
|
-
apsg-1.3.
|
|
34
|
-
apsg-1.3.
|
|
35
|
-
apsg-1.3.
|
|
36
|
-
apsg-1.3.
|
|
37
|
-
apsg-1.3.
|
|
38
|
-
apsg-1.3.
|
|
33
|
+
apsg-1.3.6.dist-info/licenses/LICENSE,sha256=lY0kfpVRrzcgVZq7pI6rLK5WYiUMWe0bdKpDelN6hk8,1120
|
|
34
|
+
apsg-1.3.6.dist-info/METADATA,sha256=tD60lfw5Bi1DY0NlsQG6FEnKxv87Bukfz5a-_-jVdks,8047
|
|
35
|
+
apsg-1.3.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
36
|
+
apsg-1.3.6.dist-info/entry_points.txt,sha256=SowP7_uRI0NJuzznKBXyM9BJcSwBxbXo6Iz5LUo9mEQ,42
|
|
37
|
+
apsg-1.3.6.dist-info/top_level.txt,sha256=xWxwi0nqqOyKdmpsszfR-bmqnNpgVbhnLRuIKGJnaUM,5
|
|
38
|
+
apsg-1.3.6.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|