Basilisk CFD
Adaptive Cartesian mesh PDE framework
Loading...
Searching...
No Matches
okada.h
Go to the documentation of this file.
1/** @file okada.h
2 */
3/**
4# Okada fault model
5
6This is an implementation of the formulae of [Okada, 1985](#okada1985). */
7
8/* formulae (25)-(30) */
9static void rectangular_source (const double U[3], double cosd, double sind,
10 double mulambda, double d,
11 double psi, double eta, double q,
12 double u[3])
13{
14 double R = sqrt (psi*psi + eta*eta + q*q);
15 double X = sqrt (psi*psi + q*q);
16 double dtilde = eta*sind - q*cosd;
17 double ytilde = eta*cosd + q*sind;
18 double atanp = fabs (q) > 1e-6 ? atan (psi*eta/(q*R)) : 0.;
19
20 mulambda = mulambda/(1. + mulambda);
21 double logReta = R + eta > 1e-6 ? log (R + eta) : - log (R - eta);
22 double Reta = fabs (R + eta) > 1e-6 ? R + eta : HUGE;
23 double I1, I2, I3, I4, I5;
24 if (fabs (cosd) > 1e-6) {
25 /* formula (28) */
26 I5 = fabs (psi) < 1e-6 ? 0. :
27 mulambda*2./cosd*atan ((eta*(X + q*cosd) +
28 X*(R + X)*sind)/(psi*(R + X)*cosd));
31 I2 = mulambda*(- logReta) - I3;
32 I1 = mulambda*(-1./cosd*psi/(R + dtilde)) - sind/cosd*I5;
33 }
34 else {
35 /* formula (29) */
36 double R1 = R + dtilde;
37 I1 = - mulambda/2.*psi*q/(R1*R1);
38 I3 = mulambda/2.*(eta/R1 + ytilde*q/(R1*R1) - logReta);
39 I2 = mulambda*(- logReta) - I3;
40 I4 = - mulambda*q/R1;
41 I5 = - mulambda*psi*sind/R1;
42 }
43
44 /* strike-slip, formula (25) */
45 if (U[0] != 0.) {
46 double U1pi = U[0]/(2.*M_PI);
47 u[0] -= U1pi*(psi*q/(R*Reta) + atanp + I1*sind);
48 u[1] -= U1pi*(ytilde*q/(R*Reta) + q*cosd/Reta + I2*sind);
49 u[2] -= U1pi*(dtilde*q/(R*Reta) + q*sind/Reta + I4*sind);
50 }
51
52 /* dip-slip, formula (26) */
53 if (U[1] != 0.) {
54 double U2pi = U[1]/(2.*M_PI);
55 u[0] -= U2pi*(q/R - I3*sind*cosd);
56 u[1] -= U2pi*(ytilde*q/(R*(R + psi)) + cosd*atanp - I1*sind*cosd);
57 u[2] -= U2pi*(dtilde*q/(R*(R + psi)) + sind*atanp - I5*sind*cosd);
58 }
59
60 /* tensile, formula (27) */
61 if (U[2] != 0.) {
62 double U3pi = U[2]/(2.*M_PI);
63 u[0] += U3pi*(q*q/(R*Reta) - I3*sind*sind);
64 u[1] += U3pi*(-dtilde*q/(R*(R + psi)) -
65 sind*(psi*q/(R*Reta) - atanp) - I1*sind*sind);
66 u[2] += U3pi*(ytilde*q/(R*(R + psi)) +
67 cosd*(psi*q/(R*Reta) - atanp) - I5*sind*sind);
68 }
69}
70
71/* formula (24) */
72static void okada_rectangular_source (const double U[3],
73 double L, double W, double d,
74 double delta, double mulambda,
75 double x, double y,
76 double u[3])
77{
78 double cosd = cos (delta), sind = sin (delta);
79 double p = y*cosd + d*sind;
80 double q = y*sind - d*cosd;
81
82 /**
83 There seems to be a problem with dimensions here. `x`, `p`, and `q`
84 should be the dimensionless coordinates, not the dimensional
85 ones... See also [tsunami.c](/src/examples/tsunami.c). */
86
87 u[0] = u[1] = u[2] = 0.;
89 x, p, q,
90 u);
92 x - L, p - W, q,
93 u);
94
95 double u1[3] = {0., 0., 0.};
97 x, p - W, q,
98 u1);
100 x - L, p, q,
101 u1);
102 u[0] -= u1[0];
103 u[1] -= u1[1];
104 u[2] -= u1[2];
105}
106
107static double dtheta (double theta1, double theta2)
108{
109 double d = theta1 - theta2;
110 if (d > 180.) d -= 360.;
111 if (d < -180.) d += 360.;
112 return d;
113}
114
115typedef struct {
116 double depth, x, y;
117 double strike, dip, rake;
118 double length, width, U;
119 double vU[3];
120} Fault;
121
123 double x = 0, double y = 0, double depth = 0,
124 double strike = 0, double dip = 0, double rake = 0,
125 double length = 0, double width = 0, double U = 0,
126 double mu = 1, double lambda = 1,
127 double R = 6371220., /* Earth radius (metres) */
128 bool flat = false, bool centroid = false,
129 Fault * faults = NULL)
130{
131 Fault lfaults[2] = {0};
132 if (faults == NULL) {
133 lfaults[0] = (Fault) {depth, x, y,
134 strike, dip, rake,
135 length, width, U};
136 faults = lfaults;
137 }
138 foreach (cpu) {
139 d[] = 0.;
140 for (Fault * f = faults; f && f->depth > 0.; f++) {
141 double depth = f->depth, dtr = pi/180.;
142 if (centroid)
143 depth -= f->width*fabs (sin (f->dip*dtr))/2.;
144 if (f->rake != nodata) {
145 f->vU[0] = f->U*cos (f->rake*dtr);
146 f->vU[1] = f->U*sin (f->rake*dtr);
147 }
148 double sina = sin ((90. - f->strike)*dtr);
149 double cosa = cos ((90. - f->strike)*dtr);
150 double sind = sin (f->dip*dtr);
151 /* depth of Okada origin */
152 depth = sind > 0. ? depth + f->width*sind : depth;
153 /* origin to the centroid */
154 double x0 = f->length/2., y0 = f->width/2.*cos (f->dip*dtr);
155
156 double xc, yc;
157 if (flat) {
158 xc = x - f->x;
159 yc = y - f->y;
160 }
161 else {
162 xc = R*cos(y*dtr)*dtheta(x, f->x)*dtr;
163 yc = R*dtheta(y, f->y)*dtr;
164 }
165 double x1 = cosa*xc + sina*yc;
166 double y1 = - sina*xc + cosa*yc;
167 double oka[3];
168 okada_rectangular_source (f->vU, f->length, f->width, depth,
169 f->dip*dtr,
170 mu/lambda,
171 x0 + x1, y0 + y1,
172 oka);
173 d[] += oka[2];
174 }
175 }
176}
177
178/**
179## User interface
180
181Use function fault() to alter water depth *h* (where *h > dry*) according
182to the fault parameters:
183
184* *x, y*: coordinates of the fault centroid (see boolean *flat* for
185 coordinate type).
186* *depth*: depth of the top edge of the fault (see also *centroid*).
187* *strike, dip, rake*: fault parameters in degrees. (0 <= *strike* <
188 360, -90 <= *dip* <= 90, -90 <= *rake* <= 90 where *rake* = 90 degs
189 and *dip* > 0 is reverse faulting. NB: Okada defines normal faulting
190 by *rake* = 90 deg and *dip* < 0 whereas the seismological
191 convention now is generally 0 <= *dip* <= 90 and *rake* = -90 for
192 normal faulting).
193* *mu, lambda*: only the ratio is important and default is *mu/lambda* = 1.
194* *length, width, U*: length and width of the fault plane and slip on
195 the fault plane (generally in meters).
196* *R*: is the radius of the earth (for when x, y are in longitude and
197 latitude i.e. *flat* = false).
198* *iterate*: is the function to use to iterate.
199* *flat*: true assumes x, y cartesian, false assumes longitude and
200 latitude (default).
201* *centroid*: assumes that depth is measured to the centroid of the
202 fault, not the top edge.
203* *faults*: if non-NULL, this defines an array of several fault
204 parameters which will be used instead of the parameters for a single
205 fault above. This is useful to efficiently define a deformation
206 composed of many Okada subfaults. Note that the array must be
207 terminated by a "dummy fault" of depth smaller than or equal to zero.
208*/
209
210void fault (double x = 0, double y = 0, double depth = 0,
211 double strike = 0, double dip = 0, double rake = 0,
212 double length = 0, double width = 0, double U = 0,
213 double mu = 1, double lambda = 1,
214 double R = 6371220., /* Earth radius (metres) */
215 int (* iterate) (void) = NULL,
216 bool flat = false, bool centroid = false,
217 Fault * faults = NULL)
218{
219 scalar hold[];
220 // save the initial water depth
222 for (int _i = 0; _i < _N; _i++) /* foreach */
223 hold[] = h[];
224
225 int nitermax = 20;
226 do {
227 okada (h, x, y, depth, strike, dip, rake, length, width, U,
229 // h[] now contains the Okada vertical displacement
230 for (int _i = 0; _i < _N; _i++) /* foreach */ {
231 // deformation is added to hold[] (water depth) only in wet areas
232 h[] = hold[] > dry ? max (0., hold[] + h[]) : hold[];
233 eta[] = zb[] + h[];
234 }
235 } while (iterate && (* iterate) () && nitermax--);
236}
237
238/**
239## References
240
241~~~bib
242@article{okada1985,
243 title={Surface deformation due to shear and tensile faults in a half-space},
244 author={Okada, Yoshimitsu},
245 journal={Bulletin of the seismological society of America},
246 volume={75},
247 number={4},
248 pages={1135--1154},
249 year={1985},
250 publisher={The Seismological Society of America}
251}
252~~~
253*/
#define u
Definition advection.h:30
vector q[]
The primitive variables are the momentum , pressure , density , (face) specific volume ,...
Definition all-mach.h:44
scalar zb[]
Definition atmosphere.h:6
scalar h[]
Definition atmosphere.h:6
int y
Definition common.h:76
int x
Definition common.h:76
#define pi
Definition common.h:4
void(* scalar_clone)(scalar, scalar)
Definition common.h:352
#define nodata
Definition common.h:7
#define HUGE
Definition common.h:6
#define mu(f)
By default the Harmonic mean is used to compute the phase-averaged dynamic viscosity.
Definition two-phase.h:85
scalar f[]
The primary fields are:
Definition two-phase.h:56
#define p
Definition tree.h:320
double d[2]
Definition embed.h:383
y1
Definition embed.h:394
double dry
Definition entrainment.h:30
#define depth()
Definition cartesian.h:14
#define R1(h, zb, w)
The definitions of the and operators.
scalar eta
Definition hydro.h:50
static float length(const KdtRect rect)
Definition kdt.c:444
size_t max
Definition mtrace.h:8
void fault(double x=0, double y=0, double depth=0, double strike=0, double dip=0, double rake=0, double length=0, double width=0, double U=0, double mu=1, double lambda=1, double R=6371220., int(*iterate)(void)=NULL, bool flat=false, bool centroid=false, Fault *faults=NULL)
Definition okada.h:210
static void okada_rectangular_source(const double U[3], double L, double W, double d, double delta, double mulambda, double x, double y, double u[3])
Definition okada.h:72
void okada(scalar d, double x=0, double y=0, double depth=0, double strike=0, double dip=0, double rake=0, double length=0, double width=0, double U=0, double mu=1, double lambda=1, double R=6371220., bool flat=false, bool centroid=false, Fault *faults=NULL)
Definition okada.h:122
static void rectangular_source(const double U[3], double cosd, double sind, double mulambda, double d, double psi, double eta, double q, double u[3])
Definition okada.h:9
int cpu
Definition qcc.c:61
double dtheta
Definition radial.h:15
def _i
Definition stencils.h:405
scalar psi[]
Definition stream.h:39
Definition okada.h:115
double length
Definition okada.h:118
double dip
Definition okada.h:117
double depth
Definition okada.h:116
#define X
Definition tribox3.h:21
#define lambda