/* Implementation of the formulae of Okada, 1985, "Surface deformation due to shear and tensile faults in a half-space", Bulletin of the Seismological Society of America, 75:4, 1135-1154, */ /* formulae (25)-(30) */ 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]) { double R = sqrt (psi*psi + eta*eta + q*q); double X = sqrt (psi*psi + q*q); double dtilde = eta*sind - q*cosd; double ytilde = eta*cosd + q*sind; double atanp = fabs (q) > 1e-6 ? atan (psi*eta/(q*R)) : 0.; mulambda = mulambda/(1. + mulambda); double logReta = R + eta > 1e-6 ? log (R + eta) : - log (R - eta); double Reta = fabs (R + eta) > 1e-6 ? R + eta : 1e30; double I1, I2, I3, I4, I5; if (fabs (cosd) > 1e-6) { /* formula (28) */ I5 = fabs (psi) < 1e-6 ? 0. : mulambda*2./cosd*atan ((eta*(X + q*cosd) + X*(R + X)*sind)/(psi*(R + X)*cosd)); I4 = mulambda/cosd*(log (R + dtilde) - sind*logReta); I3 = mulambda*(1./cosd*ytilde/(R + dtilde) - logReta) + sind/cosd*I4; I2 = mulambda*(- logReta) - I3; I1 = mulambda*(-1./cosd*psi/(R + dtilde)) - sind/cosd*I5; } else { /* formula (29) */ double R1 = R + dtilde; I1 = - mulambda/2.*psi*q/(R1*R1); I3 = mulambda/2.*(eta/R1 + ytilde*q/(R1*R1) - logReta); I2 = mulambda*(- logReta) - I3; I4 = - mulambda*q/R1; I5 = - mulambda*psi*sind/R1; } /* strike-slip, formula (25) */ if (U[0] != 0.) { double U1pi = U[0]/(2.*M_PI); u[0] -= U1pi*(psi*q/(R*Reta) + atanp + I1*sind); u[1] -= U1pi*(ytilde*q/(R*Reta) + q*cosd/Reta + I2*sind); u[2] -= U1pi*(dtilde*q/(R*Reta) + q*sind/Reta + I4*sind); } /* dip-slip, formula (26) */ if (U[1] != 0.) { double U2pi = U[1]/(2.*M_PI); u[0] -= U2pi*(q/R - I3*sind*cosd); u[1] -= U2pi*(ytilde*q/(R*(R + psi)) + cosd*atanp - I1*sind*cosd); u[2] -= U2pi*(dtilde*q/(R*(R + psi)) + sind*atanp - I5*sind*cosd); } /* tensile, formula (27) */ if (U[2] != 0.) { double U3pi = U[2]/(2.*M_PI); u[0] += U3pi*(q*q/(R*Reta) - I3*sind*sind); u[1] += U3pi*(-dtilde*q/(R*(R + psi)) - sind*(psi*q/(R*Reta) - atanp) - I1*sind*sind); u[2] += U3pi*(ytilde*q/(R*(R + psi)) + cosd*(psi*q/(R*Reta) - atanp) - I5*sind*sind); } } /* formula (24) */ 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]) { double cosd = cos (delta), sind = sin (delta); double p = y*cosd + d*sind; double q = y*sind - d*cosd; u[0] = u[1] = u[2] = 0.; rectangular_source (U, cosd, sind, mulambda, d, x, p, q, u); rectangular_source (U, cosd, sind, mulambda, d, x - L, p - W, q, u); double u1[3] = {0., 0., 0.}; rectangular_source (U, cosd, sind, mulambda, d, x, p - W, q, u1); rectangular_source (U, cosd, sind, mulambda, d, x - L, p, q, u1); u[0] -= u1[0]; u[1] -= u1[1]; u[2] -= u1[2]; } static double dtheta (double theta1, double theta2) { double d = theta1 - theta2; if (d > 180.) d -= 360.; if (d < -180.) d += 360.; return d; } struct Okada { scalar d; double x, y, depth; double strike, dip, rake; double mu, lambda; double length, width, vU[3], U; double R; int (* iterate) (void); bool flat; }; void okada (struct Okada p) { // default settings if (p.mu == 0.) p.mu = 1.; if (p.lambda == 0.) p.lambda = 1.; if (p.R == 0.) p.R = 6371220.; /* Earth radius (metres) */ double dtr = pi/180.; if (p.rake != nodata) { p.vU[0] = p.U*cos (p.rake*dtr); p.vU[1] = p.U*sin (p.rake*dtr); } double sina = sin ((90. - p.strike)*dtr); double cosa = cos ((90. - p.strike)*dtr); double sind = sin (p.dip*dtr); /* depth of the bottom edge */ double depth = sind > 0. ? p.depth + p.width*sind : p.depth; /* origin to the centroid */ double x0 = p.length/2., y0 = p.width/2.*cos (p.dip*dtr); foreach() { if ( p.flat ) { x -= p.x; y -= p.y; } else { x = p.R*cos(y*dtr)*dtheta(x, p.x)*dtr; y = p.R*dtheta(y, p.y)*dtr; } double x1 = cosa*x + sina*y; double y1 = - sina*x + cosa*y; double oka[3]; okada_rectangular_source (p.vU, p.length, p.width, depth, p.dip*dtr, p.mu/p.lambda, x0 + x1, y0 + y1, oka); val(p.d,0,0) = oka[2]; } } void fault (struct Okada p) { scalar hold[]; // save the initial water depth scalar_clone (hold, h); foreach() hold[] = h[]; boundary ({hold}); p.d = h; do { okada (p); // h[] now contains the Okada vertical displacement foreach() { // deformation is added to hold[] (water depth) only in wet areas h[] = hold[] > dry ? max (0., hold[] + h[]) : hold[]; eta[] = zb[] + h[]; } } while (p.iterate && p.iterate()); }