470 lines
12 KiB
C
470 lines
12 KiB
C
|
/*
|
|||
|
Functions that calculate the gravitational potential and its first and second
|
|||
|
derivatives for the rectangular prism using the formulas in Nagy et al. (2000).
|
|||
|
|
|||
|
The coordinate system used is that of the article, ie:
|
|||
|
|
|||
|
x -> North y -> East z -> Down
|
|||
|
|
|||
|
References
|
|||
|
----------
|
|||
|
|
|||
|
* Nagy, D., Papp, G., Benedek, J. (2000): The gravitational potential and its
|
|||
|
derivatives for the prism. Journal of Geodesy, 74, 552–560.
|
|||
|
*/
|
|||
|
|
|||
|
|
|||
|
#include <math.h>
|
|||
|
#include <stdlib.h>
|
|||
|
#include "geometry.h"
|
|||
|
#include "constants.h"
|
|||
|
#include "grav_prism.h"
|
|||
|
|
|||
|
double safe_atan2(double y, double x)
|
|||
|
{
|
|||
|
if(y == 0)
|
|||
|
{
|
|||
|
return 0;
|
|||
|
}
|
|||
|
if((y > 0) && (x < 0))
|
|||
|
{
|
|||
|
return atan2(y, x) - PI;
|
|||
|
}
|
|||
|
if((y < 0) && (x < 0))
|
|||
|
{
|
|||
|
return atan2(y, x) + PI;
|
|||
|
}
|
|||
|
return atan2(y, x);
|
|||
|
}
|
|||
|
|
|||
|
double safe_log(double x)
|
|||
|
{
|
|||
|
if(x == 0)
|
|||
|
{
|
|||
|
return 0;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return log(x);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Calculates the potential cause by a prism. */
|
|||
|
double prism_pot(PRISM prism, double xp, double yp, double zp)
|
|||
|
{
|
|||
|
double x[2], y[2], z[2], kernel, res, r;
|
|||
|
register int i, j, k;
|
|||
|
|
|||
|
/* First thing to do is make P the origin of the coordinate system */
|
|||
|
x[0] = prism.x2 - xp;
|
|||
|
x[1] = prism.x1 - xp;
|
|||
|
y[0] = prism.y2 - yp;
|
|||
|
y[1] = prism.y1 - yp;
|
|||
|
z[0] = prism.z2 - zp;
|
|||
|
z[1] = prism.z1 - zp;
|
|||
|
|
|||
|
res = 0;
|
|||
|
|
|||
|
/* Evaluate the integration limits */
|
|||
|
for(k=0; k<=1; k++)
|
|||
|
{
|
|||
|
for(j=0; j<=1; j++)
|
|||
|
{
|
|||
|
for(i=0; i<=1; i++)
|
|||
|
{
|
|||
|
r = sqrt(x[i]*x[i] + y[j]*y[j] + z[k]*z[k]);
|
|||
|
kernel = (x[i]*y[j]*safe_log(z[k] + r)
|
|||
|
+ y[j]*z[k]*safe_log(x[i] + r)
|
|||
|
+ x[i]*z[k]*safe_log(y[j] + r)
|
|||
|
- 0.5*x[i]*x[i]*safe_atan2(z[k]*y[j], x[i]*r)
|
|||
|
- 0.5*y[j]*y[j]*safe_atan2(z[k]*x[i], y[j]*r)
|
|||
|
- 0.5*z[k]*z[k]*safe_atan2(x[i]*y[j], z[k]*r));
|
|||
|
res += pow(-1, i + j + k)*kernel;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Now all that is left is to multiply res by the gravitational constant and
|
|||
|
density */
|
|||
|
res *= G*prism.density;
|
|||
|
|
|||
|
return res;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* Calculates the x component of gravitational attraction cause by a prism. */
|
|||
|
double prism_gx(PRISM prism, double xp, double yp, double zp)
|
|||
|
{
|
|||
|
double x[2], y[2], z[2], kernel, res, r;
|
|||
|
register int i, j, k;
|
|||
|
|
|||
|
/* First thing to do is make P the origin of the coordinate system */
|
|||
|
x[0] = prism.x2 - xp;
|
|||
|
x[1] = prism.x1 - xp;
|
|||
|
y[0] = prism.y2 - yp;
|
|||
|
y[1] = prism.y1 - yp;
|
|||
|
z[0] = prism.z2 - zp;
|
|||
|
z[1] = prism.z1 - zp;
|
|||
|
|
|||
|
res = 0;
|
|||
|
|
|||
|
/* Evaluate the integration limits */
|
|||
|
for(k=0; k<=1; k++)
|
|||
|
{
|
|||
|
for(j=0; j<=1; j++)
|
|||
|
{
|
|||
|
for(i=0; i<=1; i++)
|
|||
|
{
|
|||
|
r = sqrt(x[i]*x[i] + y[j]*y[j] + z[k]*z[k]);
|
|||
|
|
|||
|
kernel = -(y[j]*safe_log(z[k] + r) + z[k]*safe_log(y[j] + r)
|
|||
|
- x[i]*safe_atan2(z[k]*y[j], x[i]*r));
|
|||
|
|
|||
|
res += pow(-1, i + j + k)*kernel;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Now all that is left is to multiply res by the gravitational constant and
|
|||
|
density and convert it to mGal units */
|
|||
|
res *= G*SI2MGAL*prism.density;
|
|||
|
|
|||
|
return res;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* Calculates the y component of gravitational attraction cause by a prism. */
|
|||
|
double prism_gy(PRISM prism, double xp, double yp, double zp)
|
|||
|
{
|
|||
|
double x[2], y[2], z[2], kernel, res, r;
|
|||
|
register int i, j, k;
|
|||
|
|
|||
|
/* First thing to do is make P the origin of the coordinate system */
|
|||
|
x[0] = prism.x2 - xp;
|
|||
|
x[1] = prism.x1 - xp;
|
|||
|
y[0] = prism.y2 - yp;
|
|||
|
y[1] = prism.y1 - yp;
|
|||
|
z[0] = prism.z2 - zp;
|
|||
|
z[1] = prism.z1 - zp;
|
|||
|
|
|||
|
res = 0;
|
|||
|
|
|||
|
/* Evaluate the integration limits */
|
|||
|
for(k=0; k<=1; k++)
|
|||
|
{
|
|||
|
for(j=0; j<=1; j++)
|
|||
|
{
|
|||
|
for(i=0; i<=1; i++)
|
|||
|
{
|
|||
|
r = sqrt(x[i]*x[i] + y[j]*y[j] + z[k]*z[k]);
|
|||
|
|
|||
|
kernel = -(z[k]*safe_log(x[i] + r) + x[i]*safe_log(z[k] + r)
|
|||
|
- y[j]*safe_atan2(z[k]*x[i], y[j]*r));
|
|||
|
|
|||
|
res += pow(-1, i + j + k)*kernel;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Now all that is left is to multiply res by the gravitational constant and
|
|||
|
density and convert it to mGal units */
|
|||
|
res *= G*SI2MGAL*prism.density;
|
|||
|
|
|||
|
return res;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* Calculates the z component of gravitational attraction cause by a prism. */
|
|||
|
double prism_gz(PRISM prism, double xp, double yp, double zp)
|
|||
|
{
|
|||
|
double x[2], y[2], z[2], kernel, res, r;
|
|||
|
register int i, j, k;
|
|||
|
|
|||
|
/* First thing to do is make P the origin of the coordinate system */
|
|||
|
x[0] = prism.x2 - xp;
|
|||
|
x[1] = prism.x1 - xp;
|
|||
|
y[0] = prism.y2 - yp;
|
|||
|
y[1] = prism.y1 - yp;
|
|||
|
z[0] = prism.z2 - zp;
|
|||
|
z[1] = prism.z1 - zp;
|
|||
|
|
|||
|
res = 0;
|
|||
|
|
|||
|
/* Evaluate the integration limits */
|
|||
|
for(k=0; k<=1; k++)
|
|||
|
{
|
|||
|
for(j=0; j<=1; j++)
|
|||
|
{
|
|||
|
for(i=0; i<=1; i++)
|
|||
|
{
|
|||
|
r = sqrt(x[i]*x[i] + y[j]*y[j] + z[k]*z[k]);
|
|||
|
|
|||
|
kernel = -(x[i]*safe_log(y[j] + r) + y[j]*safe_log(x[i] + r)
|
|||
|
- z[k]*safe_atan2(x[i]*y[j], z[k]*r));
|
|||
|
|
|||
|
res += pow(-1, i + j + k)*kernel;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Now all that is left is to multiply res by the gravitational constant and
|
|||
|
density and convert it to mGal units */
|
|||
|
res *= G*SI2MGAL*prism.density;
|
|||
|
|
|||
|
return res;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* Calculates the gxx gravity gradient tensor component cause by a prism. */
|
|||
|
double prism_gxx(PRISM prism, double xp, double yp, double zp)
|
|||
|
{
|
|||
|
double x[2], y[2], z[2], kernel, res, r;
|
|||
|
register int i, j, k;
|
|||
|
|
|||
|
/* First thing to do is make P the origin of the coordinate system */
|
|||
|
x[0] = prism.x2 - xp;
|
|||
|
x[1] = prism.x1 - xp;
|
|||
|
y[0] = prism.y2 - yp;
|
|||
|
y[1] = prism.y1 - yp;
|
|||
|
z[0] = prism.z2 - zp;
|
|||
|
z[1] = prism.z1 - zp;
|
|||
|
|
|||
|
res = 0;
|
|||
|
|
|||
|
/* Evaluate the integration limits */
|
|||
|
for(k=0; k<=1; k++)
|
|||
|
{
|
|||
|
for(j=0; j<=1; j++)
|
|||
|
{
|
|||
|
for(i=0; i<=1; i++)
|
|||
|
{
|
|||
|
r = sqrt(x[i]*x[i] + y[j]*y[j] + z[k]*z[k]);
|
|||
|
kernel = -safe_atan2(z[k]*y[j], x[i]*r);
|
|||
|
res += pow(-1, i + j + k)*kernel;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Now all that is left is to multiply res by the gravitational constant and
|
|||
|
density and convert it to Eotvos units */
|
|||
|
res *= G*SI2EOTVOS*prism.density;
|
|||
|
|
|||
|
return res;
|
|||
|
}
|
|||
|
|
|||
|
/* Calculates the gxy gravity gradient tensor component cause by a prism. */
|
|||
|
double prism_gxy(PRISM prism, double xp, double yp, double zp)
|
|||
|
{
|
|||
|
double x[2], y[2], z[2], kernel, res, r, xtmp, ytmp;
|
|||
|
register int i, j, k;
|
|||
|
|
|||
|
/* First thing to do is make P the origin of the coordinate system */
|
|||
|
x[0] = prism.x2 - xp;
|
|||
|
x[1] = prism.x1 - xp;
|
|||
|
y[0] = prism.y2 - yp;
|
|||
|
y[1] = prism.y1 - yp;
|
|||
|
z[0] = prism.z2 - zp;
|
|||
|
z[1] = prism.z1 - zp;
|
|||
|
|
|||
|
res = 0;
|
|||
|
|
|||
|
/* Evaluate the integration limits */
|
|||
|
for(k=0; k<=1; k++)
|
|||
|
{
|
|||
|
for(j=0; j<=1; j++)
|
|||
|
{
|
|||
|
for(i=0; i<=1; i++)
|
|||
|
{
|
|||
|
if(x[i] == 0 && y[j] == 0 && z[k] < 0)
|
|||
|
{
|
|||
|
xtmp = 0.0001*(prism.x2 - prism.x1);
|
|||
|
ytmp = 0.0001*(prism.y2 - prism.y1);
|
|||
|
r = sqrt(xtmp*xtmp + ytmp*ytmp + z[k]*z[k]);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
r = sqrt(x[i]*x[i] + y[j]*y[j] + z[k]*z[k]);
|
|||
|
}
|
|||
|
kernel = safe_log(z[k] + r);
|
|||
|
res += pow(-1, i + j + k)*kernel;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Now all that is left is to multiply res by the gravitational constant and
|
|||
|
density and convert it to Eotvos units */
|
|||
|
res *= G*SI2EOTVOS*prism.density;
|
|||
|
|
|||
|
return res;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* Calculates the gxz gravity gradient tensor component cause by a prism. */
|
|||
|
double prism_gxz(PRISM prism, double xp, double yp, double zp)
|
|||
|
{
|
|||
|
double x[2], y[2], z[2], kernel, res, r, xtmp, ztmp;
|
|||
|
register int i, j, k;
|
|||
|
|
|||
|
/* First thing to do is make P the origin of the coordinate system */
|
|||
|
x[0] = prism.x2 - xp;
|
|||
|
x[1] = prism.x1 - xp;
|
|||
|
y[0] = prism.y2 - yp;
|
|||
|
y[1] = prism.y1 - yp;
|
|||
|
z[0] = prism.z2 - zp;
|
|||
|
z[1] = prism.z1 - zp;
|
|||
|
|
|||
|
res = 0;
|
|||
|
|
|||
|
/* Evaluate the integration limits */
|
|||
|
for(k=0; k<=1; k++)
|
|||
|
{
|
|||
|
for(j=0; j<=1; j++)
|
|||
|
{
|
|||
|
for(i=0; i<=1; i++)
|
|||
|
{
|
|||
|
if(x[i] == 0 && z[k] == 0 && y[j] < 0)
|
|||
|
{
|
|||
|
xtmp = 0.0001*(prism.x2 - prism.x1);
|
|||
|
ztmp = 0.0001*(prism.z2 - prism.z1);
|
|||
|
r = sqrt(xtmp*xtmp + ztmp*ztmp + y[j]*y[j]);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
r = sqrt(x[i]*x[i] + y[j]*y[j] + z[k]*z[k]);
|
|||
|
}
|
|||
|
kernel = safe_log(y[j] + r);
|
|||
|
res += pow(-1, i + j + k)*kernel;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Now all that is left is to multiply res by the gravitational constant and
|
|||
|
density and convert it to Eotvos units */
|
|||
|
res *= G*SI2EOTVOS*prism.density;
|
|||
|
|
|||
|
return res;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* Calculates the gyy gravity gradient tensor component cause by a prism. */
|
|||
|
double prism_gyy(PRISM prism, double xp, double yp, double zp)
|
|||
|
{
|
|||
|
double x[2], y[2], z[2], kernel, res, r;
|
|||
|
register int i, j, k;
|
|||
|
|
|||
|
/* First thing to do is make P the origin of the coordinate system */
|
|||
|
x[0] = prism.x2 - xp;
|
|||
|
x[1] = prism.x1 - xp;
|
|||
|
y[0] = prism.y2 - yp;
|
|||
|
y[1] = prism.y1 - yp;
|
|||
|
z[0] = prism.z2 - zp;
|
|||
|
z[1] = prism.z1 - zp;
|
|||
|
|
|||
|
res = 0;
|
|||
|
|
|||
|
/* Evaluate the integration limits */
|
|||
|
for(k=0; k<=1; k++)
|
|||
|
{
|
|||
|
for(j=0; j<=1; j++)
|
|||
|
{
|
|||
|
for(i=0; i<=1; i++)
|
|||
|
{
|
|||
|
r = sqrt(x[i]*x[i] + y[j]*y[j] + z[k]*z[k]);
|
|||
|
kernel = -safe_atan2(z[k]*x[i], y[j]*r);
|
|||
|
res += pow(-1, i + j + k)*kernel;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Now all that is left is to multiply res by the gravitational constant and
|
|||
|
density and convert it to Eotvos units */
|
|||
|
res *= G*SI2EOTVOS*prism.density;
|
|||
|
|
|||
|
return res;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* Calculates the gyz gravity gradient tensor component cause by a prism. */
|
|||
|
double prism_gyz(PRISM prism, double xp, double yp, double zp)
|
|||
|
{
|
|||
|
double x[2], y[2], z[2], kernel, res, r, ytmp, ztmp;
|
|||
|
register int i, j, k;
|
|||
|
|
|||
|
/* First thing to do is make P the origin of the coordinate system */
|
|||
|
x[0] = prism.x2 - xp;
|
|||
|
x[1] = prism.x1 - xp;
|
|||
|
y[0] = prism.y2 - yp;
|
|||
|
y[1] = prism.y1 - yp;
|
|||
|
z[0] = prism.z2 - zp;
|
|||
|
z[1] = prism.z1 - zp;
|
|||
|
|
|||
|
res = 0;
|
|||
|
|
|||
|
/* Evaluate the integration limits */
|
|||
|
for(k=0; k<=1; k++)
|
|||
|
{
|
|||
|
for(j=0; j<=1; j++)
|
|||
|
{
|
|||
|
for(i=0; i<=1; i++)
|
|||
|
{
|
|||
|
if(z[k] == 0 && y[j] == 0 && x[i] < 0)
|
|||
|
{
|
|||
|
ytmp = 0.0001*(prism.y2 - prism.y1);
|
|||
|
ztmp = 0.0001*(prism.z2 - prism.z1);
|
|||
|
r = sqrt(ztmp*ztmp + ytmp*ytmp + x[i]*x[i]);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
r = sqrt(x[i]*x[i] + y[j]*y[j] + z[k]*z[k]);
|
|||
|
}
|
|||
|
kernel = safe_log(x[i] + r);
|
|||
|
res += pow(-1, i + j + k)*kernel;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Now all that is left is to multiply res by the gravitational constant and
|
|||
|
density and convert it to Eotvos units */
|
|||
|
res *= G*SI2EOTVOS*prism.density;
|
|||
|
|
|||
|
return res;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* Calculates the gzz gravity gradient tensor component cause by a prism. */
|
|||
|
double prism_gzz(PRISM prism, double xp, double yp, double zp)
|
|||
|
{
|
|||
|
double x[2], y[2], z[2], kernel, res, r;
|
|||
|
register int i, j, k;
|
|||
|
|
|||
|
/* First thing to do is make P the origin of the coordinate system */
|
|||
|
x[0] = prism.x2 - xp;
|
|||
|
x[1] = prism.x1 - xp;
|
|||
|
y[0] = prism.y2 - yp;
|
|||
|
y[1] = prism.y1 - yp;
|
|||
|
z[0] = prism.z2 - zp;
|
|||
|
z[1] = prism.z1 - zp;
|
|||
|
|
|||
|
res = 0;
|
|||
|
|
|||
|
/* Evaluate the integration limits */
|
|||
|
for(k=0; k<=1; k++)
|
|||
|
{
|
|||
|
for(j=0; j<=1; j++)
|
|||
|
{
|
|||
|
for(i=0; i<=1; i++)
|
|||
|
{
|
|||
|
r = sqrt(x[i]*x[i] + y[j]*y[j] + z[k]*z[k]);
|
|||
|
kernel = -safe_atan2(x[i]*y[j], z[k]*r);
|
|||
|
res += pow(-1, i + j + k)*kernel;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Now all that is left is to multiply res by the gravitational constant and
|
|||
|
density and convert it to Eotvos units */
|
|||
|
res *= G*SI2EOTVOS*prism.density;
|
|||
|
|
|||
|
return res;
|
|||
|
}
|