3
3
"""
4
4
5
5
from collections .abc import Sequence
6
+ from enum import StrEnum
6
7
from pathlib import Path
7
8
from typing import Any , ClassVar , Literal
8
9
@@ -43,29 +44,31 @@ def _data_geometry_is_point(data: Any, kind: str) -> bool:
43
44
return False
44
45
45
46
46
- class _FocalMechanismConvention :
47
+ class _ConventionCode (StrEnum ):
48
+ """
49
+ Enum to handle focal mechanism convention codes.
47
50
"""
48
- Class to handle focal mechanism convention, code, and associated parameters.
49
-
50
- Parameters
51
- ----------
52
- convention
53
- The focal mechanism convention. Valid values are:
54
51
55
- - ``"aki"``: Aki and Richards convention.
56
- - ``"gcmt"``: Global CMT (Centroid Moment Tensor) convention.
57
- - ``"partial"``: Partial focal mechanism convention.
58
- - ``"mt"``: Moment Tensor convention.
59
- - ``"principal_axis"``: Principal axis convention.
60
- component
61
- The component of the seismic moment tensor to plot. Valid values are:
52
+ AKI_DC = "a"
53
+ AKI_DEVIATORIC = "a"
54
+ AKI_FULL = "a"
55
+ GCMT_DC = "c"
56
+ GCMT_DEVIATORIC = "c"
57
+ GCMT_FULL = "c"
58
+ PARTIAL_DC = "p"
59
+ PARTIAL_DEVIATORIC = "p"
60
+ PARTIAL_FULL = "p"
61
+ MT_DC = "d"
62
+ MT_DEVIATORIC = "z"
63
+ MT_FULL = "m"
64
+ PRINCIPAL_AXIS_DC = "y"
65
+ PRINCIPAL_AXIS_DEVIATORIC = "t"
66
+ PRINCIPAL_AXIS_FULL = "x"
62
67
63
- - ``"full"``: the full tensor seismic moment tensor
64
- - ``"dc"``: the closest double coupe defined from the moment tensor (zero trace
65
- and zero determinant)
66
- - ``"deviatoric"``: deviatoric part of the moment tensor (zero trace)
67
68
68
- Only valid for conventions ``"mt"`` and ``"principal_axis"``.
69
+ class _FocalMechanismConvention :
70
+ """
71
+ Class to handle focal mechanism convention, code, and associated parameters.
69
72
70
73
Attributes
71
74
----------
@@ -81,81 +84,51 @@ class _FocalMechanismConvention:
81
84
>>> from pygmt.src._common import _FocalMechanismConvention
82
85
83
86
>>> conv = _FocalMechanismConvention("aki")
84
- >>> conv.convention, conv. code
85
- ('aki', 'a')
87
+ >>> conv.code
88
+ <_ConventionCode.AKI_DC: 'a'>
86
89
>>> conv.params
87
90
['strike', 'dip', 'rake', 'magnitude']
88
91
89
- >>> conv = _FocalMechanismConvention("gcmt")
90
- >>> conv.convention, conv.code
91
- ('gcmt', 'c')
92
- >>> conv.params
93
- ['strike1', 'dip1', 'rake1', 'strike2', 'dip2', 'rake2', 'mantissa', 'exponent']
94
-
95
- >>> conv = _FocalMechanismConvention("partial")
96
- >>> conv.convention, conv.code
97
- ('partial', 'p')
92
+ >>> conv = _FocalMechanismConvention("mt")
93
+ >>> conv.code
94
+ <_ConventionCode.MT_FULL: 'm'>
98
95
>>> conv.params
99
- ['strike1 ', 'dip1 ', 'strike2 ', 'fault_type ', 'magnitude ']
96
+ ['mrr ', 'mtt ', 'mff ', 'mrt ', 'mrf', 'mtf', 'exponent ']
100
97
101
98
>>> conv = _FocalMechanismConvention("mt", component="dc")
102
- >>> conv.convention, conv. code
103
- ('mt', 'd')
99
+ >>> conv.code
100
+ <_ConventionCode.MT_DC: 'd'>
104
101
>>> conv.params
105
102
['mrr', 'mtt', 'mff', 'mrt', 'mrf', 'mtf', 'exponent']
106
103
107
- >>> conv = _FocalMechanismConvention("principal_axis", component="deviatoric")
108
- >>> conv.convention, conv.code
109
- ('principal_axis', 't')
110
-
111
104
>>> conv = _FocalMechanismConvention("a")
112
- >>> conv.convention, conv.code
113
- ('aki', 'a')
105
+ >>> conv.code
106
+ <_ConventionCode.AKI_DC: 'a'>
107
+ >>> conv.params
108
+ ['strike', 'dip', 'rake', 'magnitude']
114
109
115
110
>>> conv = _FocalMechanismConvention.from_params(
116
111
... ["strike", "dip", "rake", "magnitude"]
117
112
... )
118
- >>> conv.convention, conv. code
119
- ('aki', 'a')
113
+ >>> conv.code
114
+ <_ConventionCode.AKI_DC: 'a'>
120
115
121
116
>>> conv = _FocalMechanismConvention(convention="invalid")
122
117
Traceback (most recent call last):
123
118
...
124
- pygmt.exceptions.GMTInvalidInput: Invalid focal mechanism convention 'invalid '.
119
+ pygmt.exceptions.GMTInvalidInput: Invalid focal mechanism ... '.
125
120
126
121
>>> conv = _FocalMechanismConvention("mt", component="invalid")
127
122
Traceback (most recent call last):
128
123
...
129
- pygmt.exceptions.GMTInvalidInput: Invalid component 'invalid' for ... 'mt '.
124
+ pygmt.exceptions.GMTInvalidInput: Invalid focal mechanism ...'.
130
125
131
126
>>> _FocalMechanismConvention.from_params(["strike", "dip", "rake"])
132
127
Traceback (most recent call last):
133
128
...
134
- pygmt.exceptions.GMTInvalidInput: Fail to determine ...
129
+ pygmt.exceptions.GMTInvalidInput: Fail to determine focal mechanism convention ...
135
130
"""
136
131
137
- # Mapping of focal mechanism conventions to their single-letter codes.
138
- _conventions : ClassVar = {
139
- "aki" : "a" ,
140
- "gcmt" : "c" ,
141
- "partial" : "p" ,
142
- "mt" : {"full" : "m" , "deviatoric" : "z" , "dc" : "d" },
143
- "principal_axis" : {"full" : "x" , "deviatoric" : "t" , "dc" : "y" },
144
- }
145
-
146
- # Mapping of single-letter codes to focal mechanism convention names
147
- _codes : ClassVar = {
148
- "a" : "aki" ,
149
- "c" : "gcmt" ,
150
- "p" : "partial" ,
151
- "m" : "mt" ,
152
- "z" : "mt" ,
153
- "d" : "mt" ,
154
- "x" : "principal_axis" ,
155
- "t" : "principal_axis" ,
156
- "y" : "principal_axis" ,
157
- }
158
-
159
132
# Mapping of focal mechanism conventions to their parameters.
160
133
_params : ClassVar = {
161
134
"aki" : ["strike" , "dip" , "rake" , "magnitude" ],
@@ -191,36 +164,63 @@ def __init__(
191
164
component : Literal ["full" , "deviatoric" , "dc" ] = "full" ,
192
165
):
193
166
"""
194
- Initialize the FocalMechanismConvention object.
167
+ Initialize the FocalMechanismConvention object from convention and component.
168
+
169
+ If the convention is specified via a single-letter code, the convention and
170
+ component are determined from the code.
171
+
172
+ Parameters
173
+ ----------
174
+ convention
175
+ The focal mechanism convention. Valid values are:
176
+
177
+ - ``"aki"``: Aki and Richards convention.
178
+ - ``"gcmt"``: Global CMT (Centroid Moment Tensor) convention.
179
+ - ``"partial"``: Partial focal mechanism convention.
180
+ - ``"mt"``: Moment Tensor convention.
181
+ - ``"principal_axis"``: Principal axis convention.
182
+ component
183
+ The component of the seismic moment tensor to plot. Valid values are:
184
+
185
+ - ``"full"``: the full tensor seismic moment tensor
186
+ - ``"dc"``: the closest double coupe defined from the moment tensor (zero
187
+ trace and zero determinant)
188
+ - ``"deviatoric"``: deviatoric part of the moment tensor (zero trace)
189
+
190
+ Doesn't apply to conventions ``"aki"``, ``"gcmt"``, and ``"partial"``.
195
191
"""
196
- if convention in self ._conventions :
197
- # Convention is given via 'convention' and 'component' parameters.
198
- if component not in {"full" , "deviatoric" , "dc" }:
192
+ if convention in _ConventionCode .__members__ .values ():
193
+ # 'convention' is specified via the actual single-letter convention code.
194
+ self .code = _ConventionCode (convention )
195
+ # Parse the convention from the convention code name.
196
+ self ._convention = "_" .join (self .code .name .split ("_" )[:- 1 ]).lower ()
197
+ else :
198
+ # Convention is specified via 'convention' and 'component'.
199
+ name = f"{ convention .upper ()} _{ component .upper ()} " # e.g., "AKI_DC"
200
+ if name not in _ConventionCode .__members__ :
199
201
msg = (
200
- f "Invalid component ' { component } ' for focal mechanism convention "
201
- f"'{ convention } '."
202
+ "Invalid focal mechanism convention with "
203
+ f"convention= '{ convention } ' and component=' { component } '."
202
204
)
203
205
raise GMTInvalidInput (msg )
206
+ self .code = _ConventionCode [name ]
207
+ self ._convention = convention
204
208
205
- self .convention = convention
206
- self .code = self ._conventions [convention ]
207
- if isinstance (self .code , dict ):
208
- self .code = self .code [component ]
209
- elif convention in self ._codes :
210
- # Convention is given as a single-letter code.
211
- self .code = convention
212
- self .convention = self ._codes [convention ]
213
- else :
214
- msg = f"Invalid focal mechanism convention '{ convention } '."
215
- raise GMTInvalidInput (msg )
216
- self .params = self ._params [self .convention ]
209
+ @property
210
+ def params (self ):
211
+ """
212
+ The parameters associated with the focal mechanism convention.
213
+ """
214
+ return self ._params [self ._convention ]
217
215
218
- @staticmethod
216
+ @classmethod
219
217
def from_params (
220
- params : Sequence [str ], component : Literal ["full" , "deviatoric" , "dc" ] = "full"
218
+ cls ,
219
+ params : Sequence [str ],
220
+ component : Literal ["full" , "deviatoric" , "dc" ] = "full" ,
221
221
) -> "_FocalMechanismConvention" :
222
222
"""
223
- Create a FocalMechanismConvention object from a sequence of parameters.
223
+ Create a _FocalMechanismConvention object from a sequence of parameters.
224
224
225
225
The method checks if the given parameters are a superset of a known focal
226
226
mechanism convention to determine the convention. If the parameters are not
@@ -235,16 +235,19 @@ def from_params(
235
235
Returns
236
236
-------
237
237
_FocalMechanismConvention
238
- The FocalMechanismConvention object.
238
+ The _FocalMechanismConvention object.
239
239
240
240
Raises
241
241
------
242
242
GMTInvalidInput
243
243
If the focal mechanism convention cannot be determined from the given
244
- parameters
244
+ parameters.
245
245
"""
246
- for convention , param_list in _FocalMechanismConvention ._params .items ():
246
+ for convention , param_list in cls ._params .items ():
247
247
if set (param_list ).issubset (set (params )):
248
- return _FocalMechanismConvention (convention , component = component )
249
- msg = "Fail to determine focal mechanism convention from the data column names."
248
+ return cls (convention , component = component )
249
+ msg = (
250
+ "Fail to determine focal mechanism convention from the given parameters: "
251
+ f"{ ', ' .join (params )} ."
252
+ )
250
253
raise GMTInvalidInput (msg )
0 commit comments