tesseroids/lib/grav_prism.c
2021-05-05 10:58:03 +08:00

470 lines
12 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
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, 552560.
*/
#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;
}