1 |
|
2 |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
3 |
% Copyright (c) 2003-2018 by The University of Queensland |
4 |
% http://www.uq.edu.au |
5 |
% |
6 |
% Primary Business: Queensland, Australia |
7 |
% Licensed under the Apache License, version 2.0 |
8 |
% http://www.apache.org/licenses/LICENSE-2.0 |
9 |
% |
10 |
% Development until 2012 by Earth Systems Science Computational Center (ESSCC) |
11 |
% Development 2012-2013 by School of Earth Sciences |
12 |
% Development from 2014 by Centre for Geoscience Computing (GeoComp) |
13 |
% |
14 |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
15 |
|
16 |
\section{Fault System} |
17 |
\label{Fault System} |
18 |
The \class{FaultSystem} class provides an easy-to-use interface to handle 2D |
19 |
and 3D fault systems\index{faults} as used for instance in simulating fault |
20 |
ruptures. The main purpose of the class is to provide a parameterization of |
21 |
an individual fault in the system of faults. |
22 |
In case of a 2D fault the fault is parameterized by a single value $w_{0}$ and |
23 |
in the case of a 3D fault two parameters $w_{0}$ and $w_{1}$ are used. |
24 |
This parameterization can be used to impose data (e.g. a slip distribution) |
25 |
onto the fault. It can also be a useful tool to visualize or analyze the |
26 |
results on the fault if the fault is not straight. |
27 |
|
28 |
\begin{figure} |
29 |
\centering |
30 |
\includegraphics{FaultSystem2D} |
31 |
\caption{\label{FAULTSYSTEM2D}Two dimensional fault system with one fault |
32 |
named `t` in the $(x_{0},x_{1})$ space and its parameterization in the |
33 |
$w_{0}$ space. The fault has three segments.} |
34 |
\end{figure} |
35 |
|
36 |
A fault $t$ in the fault system is represented by a starting point $V^{t0}$ |
37 |
and series of directions, called strikes\index{strike}, and the lengths $(l^{ti})$. |
38 |
The strike of segment $i$ is defined by the angle $\sigma^{ti}$ between the |
39 |
$x_{0}$-axis and the direction of the fault, see Figure~\ref{FAULTSYSTEM2D}. |
40 |
The length and strike defines the polyline $(V^{ti})$ of the fault by |
41 |
\begin{equation} |
42 |
V^{ti} = V^{t(i-1)} + |
43 |
l^{ti} \cdot S^{ti} |
44 |
\mbox{ with } |
45 |
S^{ti} = |
46 |
\left[ |
47 |
\begin{array}{c} |
48 |
cos(\sigma^{ti}) \\ |
49 |
sin(\sigma^{ti}) \\ |
50 |
0 |
51 |
\end{array} |
52 |
\right] |
53 |
\label{eq:fault 00} |
54 |
\end{equation} |
55 |
In the 3D case each fault segment $i$ has an additional dip\index{dip} |
56 |
$\theta^{ti}$ and at each vertex $i$ a depth $\delta^{ti}$ is given. |
57 |
The fault segment normal $n^{ti}$ is given by |
58 |
\begin{equation} |
59 |
n^{ti} = |
60 |
\left[ |
61 |
\begin{array}{c} |
62 |
-sin(\theta^{ti}) \cdot S^{ti}_{1} \\ |
63 |
sin(\theta^{ti}) \cdot S^{ti}_{0} \\ |
64 |
cos(\theta^{ti}) |
65 |
\end{array} |
66 |
\right] |
67 |
\label{eq:fault 0} |
68 |
\end{equation} |
69 |
At each vertex we define a depth vector $d^{ti}$ defined as the intersect of |
70 |
the fault planes of segment $(i-1)$ and $i$ where for the first segment and |
71 |
last segment the vector orthogonal to strike vector $S^{ti}$\index{strike} |
72 |
and the segment normal $n^{ti}$ is used. The direction $\tilde{d}^{ti}$ of the |
73 |
depth vector is given as |
74 |
\begin{equation} |
75 |
\tilde{d}^{ti} = n^{ti} \times n^{t(i-1)} |
76 |
\label{eq:fault b} |
77 |
\end{equation} |
78 |
If $\tilde{d}^{ti}$ is zero the strike vectors $L^{t(i-1)}$ and $L^{ti}$ are |
79 |
collinear and we can set $\tilde{d}^{ti} = l^{ti} \times n^{ti}$. |
80 |
If the two fault segments are almost orthogonal $\tilde{d}^{ti}$ is pointing |
81 |
in the direction of $L^{t(i-1)}$ and $L^{ti}$. In this case no depth can be |
82 |
defined. So we will reject a fault system if |
83 |
\begin{equation} |
84 |
min(\| \tilde{d}^{ti} \times L^{t(i-1)} \|,\| \tilde{d}^{ti} \times L^{ti} \|) |
85 |
\le 0.1 \cdot \| \tilde{d}^{ti} | |
86 |
\label{eq:fault c} |
87 |
\end{equation} |
88 |
which corresponds to an angle of less than $10^o$ between the depth vector and |
89 |
the strike. We then set |
90 |
\begin{equation} |
91 |
d^{ti}=\delta^{ti} \cdot \frac{\tilde{d}^{ti}}{\|\tilde{d}^{ti}\|} |
92 |
\label{eq:fault d} |
93 |
\end{equation} |
94 |
We can then define the polyline $(v^{ti})$ for the bottom of the fault as |
95 |
\begin{equation} |
96 |
v^{ti}= V^{ti}+d^{ti} |
97 |
\label{eq:fault e} |
98 |
\end{equation} |
99 |
In order to simplify working on a fault $t$ in a fault system a |
100 |
parameterization $P^t: (w_{0},w_{1}) \rightarrow (x_{0},x_{1},x_{2})$ over a |
101 |
rectangular domain is introduced such that |
102 |
\begin{equation} |
103 |
0\le w_{0} \le w^t_{0 max} \mbox{ and } -w^t_{1max}\le w_{1} \le 0 |
104 |
\label{eq:fault 1} |
105 |
\end{equation} |
106 |
with positive numbers $w^t_{0 max}$ and $w^t_{1 max}$. Typically one chooses |
107 |
$w^t_{0 max}$ to be the unrolled length of the fault and $w^t_{1 max}$ to be |
108 |
the mean value of segment depth. Moreover we have |
109 |
\begin{equation} |
110 |
P^t(W^{ti})=V^{ti}\mbox{ and } P^t(w^{ti})=v^{ti}\ |
111 |
\label{eq:fault 2} |
112 |
\end{equation} |
113 |
where |
114 |
\begin{equation} |
115 |
W^{ti}=(\Omega^{ti},0) \mbox{ and } w^{ti}=(\Omega^{ti},-w^t_{1 max}) |
116 |
\label{eq:fault 3} |
117 |
\end{equation} |
118 |
and $\Omega^{ti}$ is the unrolled distance of $W^{ti}$ from $W^{t0}$, i.e. |
119 |
$l^{ti}=\Omega^{t(i+1)}-\Omega^{ti}$. In the 2D case $w^t_{1 max}$ is set to |
120 |
zero and therefore the second component is dropped, see Figure~\ref{FAULTSYSTEM2D}. |
121 |
|
122 |
In the 2D case the parameterization $P^t$ is constructed as follows: |
123 |
The line connecting $V^{t(i-1)}$ and $V^{ti}$ is given by |
124 |
\begin{equation} |
125 |
x=V^{ti} + s \cdot ( V^{t(i+1)}- V^{ti} ) |
126 |
\label{eq:2D line 1} |
127 |
\end{equation} |
128 |
where $s$ is between $0$ and $1$. The point $x$ is on $i$-th fault segment if |
129 |
and only if such an $s$ exists. Assuming $x$ is on the fault it can be |
130 |
calculated as |
131 |
\begin{equation} |
132 |
s = \frac{ (x- V^{ti})^t \cdot (V^{t(i+1)}- V^{ti}) }{ \|V^{t(i+1)}- V^{ti}\|^2} |
133 |
\label{eq:2D line 1b} |
134 |
\end{equation} |
135 |
We then can set |
136 |
\begin{equation} |
137 |
w_{0}=\Omega^{ti}+s \cdot (\Omega^{ti}-\Omega^{t(i-1)}) |
138 |
\label{eq:2D line 2} |
139 |
\end{equation} |
140 |
to get $P^t(w_{0})=x$. |
141 |
It remains the question if the given $x$ is actually on the segment $i$ of |
142 |
fault $t$. To test this $s$ is restricted between $0$ and $1$ (so if $s<0$, $s$ |
143 |
is set to $0$ and if $s>1$, $s$ is set to $1$) and then we check the residual |
144 |
of \eqn{eq:2D line 1}, i.e. $x$ has been accepted to be in the segment if |
145 |
\begin{equation} |
146 |
\|x-V^{ti} - s \cdot (V^{t(i+1)}- V^{ti}) \| \le tol \cdot |
147 |
max(l^{ti}, \|x-V^{ti} \|) |
148 |
\label{eq:2D line 3} |
149 |
\end{equation} |
150 |
where $tol$ is a given tolerance. |
151 |
|
152 |
In the 3D case the situation is a bit more complicated: we split the fault |
153 |
segment across the diagonal $V^{ti}$-$v^{t(i+1)}$ to produce two triangles. |
154 |
In the upper triangle we use the parameterization |
155 |
\begin{equation} |
156 |
x= V^{ti} + s \cdot (V^{t(i+1)}-V^{ti}) + r \cdot (v^{t(i+1)}-V^{t(i+1)}) |
157 |
\mbox{ with } r \le s; |
158 |
\label{eq:2D line 4} |
159 |
\end{equation} |
160 |
while in the lower triangle we use |
161 |
\begin{equation} |
162 |
x= V^{ti} + s \cdot (v^{t(i+1)}-v^{ti}) + r \cdot (v^{ti}-V^{ti}) |
163 |
\mbox{ with } s \le r; |
164 |
\label{eq:2D line 4b} |
165 |
\end{equation} |
166 |
where $0\le s,r \le 1$. Both equations are solved in the least-squares sense |
167 |
e.g. using the Moore-Penrose pseudo-inverse for the coefficient matrices. |
168 |
The resulting $s$ and $r$ are then restricted to the unit square. Similar to |
169 |
the 2D case (see \eqn{eq:2D line 3}) we identify $x$ to be in the upper |
170 |
triangle of the segment if |
171 |
\begin{equation} |
172 |
\|x- V^{ti} - s \cdot (V^{t(i+1)}-V^{ti}) - r \cdot (v^{t(i+1)}-V^{t(i+1)}) \| |
173 |
\le tol \cdot max(\|x-V^{ti} \|,\|v^{t(i+1)}-V^{t(i)})\|) |
174 |
\label{eq:2D line 4c} |
175 |
\end{equation} |
176 |
and in the lower part |
177 |
\begin{equation} |
178 |
\|x-V^{ti} - s \cdot (v^{t(i+1)}-v^{ti}) - r \cdot (v^{ti}-V^{ti}) \| |
179 |
\le tol \cdot max(\|x-V^{ti} \|,\|v^{t(i+1)}-V^{t(i)})\|) |
180 |
\label{eq:2D line 4d} |
181 |
\end{equation} |
182 |
after the restriction of $(s,t)$ to the unit square. |
183 |
Note that $\|v^{t(i+1)}-V^{t(i)})\|$ is the length of the diagonal of the |
184 |
fault segment. For those $x$ which have been located in the $i$-th segment we |
185 |
then set |
186 |
\begin{equation} |
187 |
w_{0}=\Omega^{ti}+s \cdot (\Omega^{ti}-\Omega^{t(i-1)}) |
188 |
\mbox{ and } |
189 |
w_{1}=w^t_{1max} (r-1) |
190 |
\label{eq:2D line 5} |
191 |
\end{equation} |
192 |
|
193 |
\subsection{Functions} |
194 |
|
195 |
\begin{classdesc}{FaultSystem}{\optional{dim =3}} |
196 |
creates a fault system in the \var{dim} dimensional space. |
197 |
\end{classdesc} |
198 |
|
199 |
\begin{methoddesc}[FaultSystem]{getMediumDepth}{tag} |
200 |
returns the medium depth of fault \var{tag}. |
201 |
\end{methoddesc} |
202 |
|
203 |
\begin{methoddesc}[FaultSystem]{getTags}{} |
204 |
returns a list of the tags used by the fault system. |
205 |
\end{methoddesc} |
206 |
|
207 |
\begin{methoddesc}[FaultSystem]{getStart}{tag} |
208 |
returns the starting point of fault \var{tag} as a \numpyNDA object. |
209 |
\end{methoddesc} |
210 |
|
211 |
\begin{methoddesc}[FaultSystem]{getDim}{} |
212 |
returns the spatial dimension. |
213 |
\end{methoddesc} |
214 |
|
215 |
\begin{methoddesc}[FaultSystem]{getDepths}{tag} |
216 |
returns the list of the depths of the segments in fault \var{tag}. |
217 |
\end{methoddesc} |
218 |
|
219 |
\begin{methoddesc}[FaultSystem]{getTopPolyline}{tag} |
220 |
returns the polyline used to describe the fault tagged by \var{tag}. |
221 |
\end{methoddesc} |
222 |
|
223 |
\begin{methoddesc}[FaultSystem]{getStrikes}{tag} |
224 |
returns the list of strikes $\sigma^{ti}$ of the segments in fault |
225 |
$t=$\var{tag}. |
226 |
\end{methoddesc} |
227 |
|
228 |
\begin{methoddesc}[FaultSystem]{getStrikeVectors}{tag} |
229 |
returns the strike vectors $S^{ti}$ of fault $t=$\var{tag}. |
230 |
\end{methoddesc} |
231 |
|
232 |
\begin{methoddesc}[FaultSystem]{getLengths}{tag} |
233 |
returns the lengths $l^{ti}$ of the segments in fault $t=$\var{tag}. |
234 |
\end{methoddesc} |
235 |
|
236 |
\begin{methoddesc}[FaultSystem]{getTotalLength}{tag} |
237 |
returns the total unrolled length of fault \var{tag}. |
238 |
\end{methoddesc} |
239 |
|
240 |
\begin{methoddesc}[FaultSystem]{getDips}{tag} |
241 |
returns the list of the dips of the segments in fault \var{tag}. |
242 |
\end{methoddesc} |
243 |
|
244 |
\begin{methoddesc}[FaultSystem]{getBottomPolyline}{tag} |
245 |
returns the list of the vertices defining the bottom of the fault \var{tag}. |
246 |
\end{methoddesc} |
247 |
|
248 |
\begin{methoddesc}[FaultSystem]{getSegmentNormals}{tag} |
249 |
returns the list of the normals of the segments in fault \var{tag}. |
250 |
\end{methoddesc} |
251 |
|
252 |
\begin{methoddesc}[FaultSystem]{getDepthVectors}{tag} |
253 |
returns the list of the depth vectors $d^{ti}$ for fault $t=$\var{tag}. |
254 |
\end{methoddesc} |
255 |
|
256 |
\begin{methoddesc}[FaultSystem]{getDepths}{tag} |
257 |
returns the list of the depths of the segments in fault \var{tag}. |
258 |
\end{methoddesc} |
259 |
|
260 |
\begin{methoddesc}[FaultSystem]{getW0Range}{tag} |
261 |
returns the range of the parameterization in $w_{0}$. |
262 |
For tag $t$ this is the pair $(\Omega^{t0},\Omega^{tn})$ where $n$ is the |
263 |
number of segments in the fault. |
264 |
In most cases one has $(\Omega^{t0},\Omega^{tn})=(0,w^t_{0 max})$. |
265 |
\end{methoddesc} |
266 |
|
267 |
\begin{methoddesc}[FaultSystem]{getW1Range}{tag} |
268 |
returns the range of the parameterization in $w_{1}$. |
269 |
For tag $t$ this is the pair $(-w^t_{1max},0)$. |
270 |
\end{methoddesc} |
271 |
|
272 |
\begin{methoddesc}[FaultSystem]{getW0Offsets}{tag} |
273 |
returns the offsets for the parameterization of fault \var{tag}. |
274 |
For tag \var{tag}=$t$ this is the list $[\Omega^{ti}]$. |
275 |
\end{methoddesc} |
276 |
|
277 |
\begin{methoddesc}[FaultSystem]{getCenterOnSurface}{} |
278 |
returns the center point of the fault system at the surfaces. |
279 |
In 3D the calculation of the center is considering the top edge of the faults |
280 |
and projects the edge to the surface (the $x_{2}$ component is assumed to be |
281 |
0). An \numpyNDA object is returned. |
282 |
\end{methoddesc} |
283 |
|
284 |
\begin{methoddesc}[FaultSystem]{getOrientationOnSurface}{} |
285 |
returns the orientation of the fault system in RAD on the surface |
286 |
($x_{2}=0$ plane) around the fault system center. |
287 |
\end{methoddesc} |
288 |
|
289 |
\begin{methoddesc}[FaultSystem]{transform}{\optional{rot=0, \optional{shift=numpy.zeros((3,)}}} |
290 |
applies a shift \var{shift} and a consecutive rotation in the $x_{2}=0$ plane. |
291 |
\var{rot} is a float number and \var{shift} an \numpyNDA object. |
292 |
\end{methoddesc} |
293 |
|
294 |
\begin{methoddesc}[FaultSystem]{getMaxValue}{f\optional{, tol=1.e-8}} |
295 |
returns the tag of the fault where \var{f} takes the maximum value and a |
296 |
\class{Locator} object which can be used to collect values from \Data objects |
297 |
at the location where the maximum is taken, e.g. |
298 |
\begin{python} |
299 |
fs=FaultSystem() |
300 |
f=Scalar(..) |
301 |
t, loc=fs.getMaxValue(f) |
302 |
print("maximum value of f on the fault %s is %s at location %s."%(t, \ |
303 |
loc(f), loc.getX())) |
304 |
\end{python} |
305 |
\var{f} must be a \Scalar. When the maximum is calculated only |
306 |
\DataSamplePoints are considered which are on a fault in the fault system in |
307 |
the sense of condition~\ref{eq:2D line 3} or \ref{eq:2D line 4d}, respectively. |
308 |
In the case no \DataSamplePoints are found the returned tag is \var{None} and |
309 |
the maximum value as well as the location of the maximum value are undefined. |
310 |
\end{methoddesc} |
311 |
|
312 |
\begin{methoddesc}[FaultSystem]{getMinValue}{f\optional{, tol=1.e-8}} |
313 |
returns the tag of the fault where \var{f} takes the minimum value and a |
314 |
\class{Locator} object which can be used to collect values from \Data objects |
315 |
at the location where the minimum is taken, e.g. |
316 |
\begin{python} |
317 |
fs=FaultSystem() |
318 |
f=Scalar(..) |
319 |
t, loc=fs.getMinValue(f) |
320 |
print("minimum value of f on the fault %s is %s at location."%\ |
321 |
(t,loc(f),loc.getX())) |
322 |
\end{python} |
323 |
\var{f} must be a \Scalar. When the minimum is calculated only |
324 |
\DataSamplePoints are considered which are on a fault in the fault system in |
325 |
the sense of condition~\ref{eq:2D line 3} or \ref{eq:2D line 4d}, respectively. |
326 |
In the case no \DataSamplePoints are found the returned tag is \var{None} and |
327 |
the minimum value as well as the location of the minimum value are undefined. |
328 |
\end{methoddesc} |
329 |
|
330 |
\begin{methoddesc}[FaultSystem]{getParametrization}{x,tag \optional{\optional{, tol=1.e-8}, outsider=None}} |
331 |
returns the argument $w$ of the parameterization $P^t$ for \var{tag}=$t$ to |
332 |
provide \var{x} together with a mask indicating where the given location if on |
333 |
a fault in the fault system by the value $1$ (otherwise the value is set to $0$). |
334 |
\var{x} needs to be a \Vector or \numpyNDA object. |
335 |
\var{tol} defines the tolerance to decide if given \DataSamplePoints are on |
336 |
fault \var{tag}. The value \var{outside} is the value used as a replacement |
337 |
value for $w$ where the corresponding value in \var{x} is not on a fault. |
338 |
If \var{outside} is not present an appropriate value is used. |
339 |
\end{methoddesc} |
340 |
|
341 |
\begin{methoddesc}[FaultSystem]{getSideAndDistance}{x,tag} |
342 |
returns the side and the distance at locations \var{x} from the fault \var{tag}. |
343 |
\var{x} needs to be a \Vector or \numpyNDA object. |
344 |
Positive values for side means that the corresponding location is to the right |
345 |
of the fault, a negative value means that the corresponding location is |
346 |
to the left of the fault. The value zero means that the side is undefined. |
347 |
\end{methoddesc} |
348 |
|
349 |
\begin{methoddesc}[FaultSystem]{getFaultSegments}{tag} |
350 |
returns the polylines used to describe fault \var{tag}. For \var{tag}=$t$ this |
351 |
is the list of the vertices $[V^{ti}]$ for the 2D and the pair of lists of the |
352 |
top vertices $[V^{ti}]$ and the bottom vertices $[v^{ti}]$ in 3D. |
353 |
Note that the coordinates are represented as \numpyNDA objects. |
354 |
\end{methoddesc} |
355 |
|
356 |
\begin{methoddesc}[FaultSystem]{addFault}{ |
357 |
strikes\optional{, |
358 |
ls\optional{, |
359 |
V0=[0.,0.,0.]\optional{, |
360 |
tag=None\optional{, |
361 |
dips=None\optional{, |
362 |
depths= None\optional{, |
363 |
w0_offsets=None\optional{, |
364 |
w1_max=None}}}}}}}} |
365 |
adds the fault \var{tag} to the fault system. |
366 |
\var{V0} defines the start point of fault named $t=$\var{tag}. |
367 |
The polyline defining the fault segments on the surface are set by the strike |
368 |
angles \var{strikes} (=$\sigma^{ti}$, north = $\pi/2$, the orientation is |
369 |
counterclockwise.) and the length \var{ls} (=$l^{ti}$). |
370 |
In the 3D case one also needs to define the dip angles \var{dips} |
371 |
(=$\delta^{ti}$, vertical=$0$, right-hand rule applies.) and the depth |
372 |
\var{depths} for each segment. |
373 |
\var{w1_max} defines the range of $w_{1}$. |
374 |
If not present the mean value over the depth of all segment edges in the fault |
375 |
is used. |
376 |
\var{w0_offsets} sets the offsets $\Omega^{ti}$. If not present it is chosen |
377 |
such that $\Omega^{ti}-\Omega^{t(i-1)}$ is the length of the $i$-th segment. |
378 |
In some cases, e.g. when kinks in the fault are relevant, it can be useful |
379 |
to explicitly specify the offsets in order to simplify the assignment of values. |
380 |
\end{methoddesc} |
381 |
|
382 |
\subsection{Example} |
383 |
See \Sec{Slip CHAP}. |
384 |
|