initial upload

This commit is contained in:
2021-05-05 15:31:06 +08:00
parent cdb06fb087
commit 95e17fce02
29 changed files with 4989 additions and 0 deletions

49
lib/CMakeLists.txt Normal file
View File

@@ -0,0 +1,49 @@
if(${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Windows")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2")
endif()
if(${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Linux")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -lopenblas -lm -O2")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -lopenblas -lm -O2")
endif()
if(${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Darwin")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -framework Accelerate -O2")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -framework Accelerate -O2")
endif()
# 设置库文件的输出地址
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
# 设定库源文件
aux_source_directory(. LIBMAGTESS_SRC)
# 以下部分为库的编译
# 注意目标名必须唯一 所以不能直接生成相同名称的动态库与静态库
# 注意此处不必为目标名称添加lib前缀和相应后缀cmake会自行添加
add_library(magtess SHARED ${LIBMAGTESS_SRC})
# 首先添加静态库的生成命令
add_library(magtess_static STATIC ${LIBMAGTESS_SRC})
# 设置静态库的输出名称从而获得与动态库名称相同的静态库
set_target_properties(magtess_static PROPERTIES OUTPUT_NAME "magtess")
# 设置输出目标属性以同时输出动态库与静态库
set_target_properties(magtess PROPERTIES CLEAN_DIRECT_OUTPUT 1)
set_target_properties(magtess_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
# 设置动态库的版本号
set_target_properties(magtess PROPERTIES VERSION 1.0 SOVERSION 1.0)
# 库的安装命令
if(WIN32)
install(TARGETS magtess DESTINATION lib)
install(TARGETS magtess_static DESTINATION lib)
else()
install(TARGETS magtess magtess_static
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)
endif()
# 头文件安装命令
file(GLOB LIBMEGTESS_HEAD *.h)
install(FILES ${LIBMEGTESS_HEAD} DESTINATION include/magtess)

60
lib/constants.h Executable file
View File

@@ -0,0 +1,60 @@
/*
Define constants used, like the gravitational constant and unit conversions.
Values are assigned in file constants.c
All values are in SI units!
*/
#ifndef _TESSEROIDS_CONSTANTS_H_
#define _TESSEROIDS_CONSTANTS_H_
/* Mean Earth radius [\f$ m \f$] */
const double MEAN_EARTH_RADIUS = 6378137.0;
const double EARTH_RADIUS_IGRF_KM = 6371.2;
/* The gravitational constant [\f$ m^3*kg^{-1}*s^{-1} \f$] */
const double G = 0.00000000006673;
/* Conversion factor from SI units to Eotvos
[\f$ \frac{1}{s^2} = 10^9\ Eotvos \f$] */
const double SI2EOTVOS = 1000000000.0;
const double EOTVOS2SI = 0.000000001;
/* Conversion factor from SI units to mGal
[\f$ 1 \frac{m}{s^2} = 10^5\ mGal \f$] */
const double SI2MGAL = 100000.0;
/* Pi */
#ifdef __cplusplus
const double PI = 3.1415926535897932384626433832795;
#else
#define PI 3.1415926535897932384626433832795
#endif
/* minimum distance-to-size ratio for potential computations to be accurate */
const double TESSEROID_POT_SIZE_RATIO = 1.5;
/* Minimum distance-to-size ratio for gravity computations to be accurate */
const double TESSEROID_GX_SIZE_RATIO = 3;
const double TESSEROID_GY_SIZE_RATIO = 3;
const double TESSEROID_GZ_SIZE_RATIO = 2;
/* Minimum distance-to-size ratio for gravity gradient computations to be
accurate */
const double TESSEROID_GXX_SIZE_RATIO = 3;
const double TESSEROID_GXY_SIZE_RATIO = 4.5;
const double TESSEROID_GXZ_SIZE_RATIO = 4;
const double TESSEROID_GYY_SIZE_RATIO = 3;
const double TESSEROID_GYZ_SIZE_RATIO = 4;
const double TESSEROID_GZZ_SIZE_RATIO = 3;
const double M_0 = 4 * (PI) * 0.0000001;
const double DEG2RAD = (PI)/180.0;
#define FALSE 0
#define TRUE 1
#endif

48
lib/geometry.cpp Executable file
View File

@@ -0,0 +1,48 @@
/*
Data structures for geometric elements and functions that operate on them.
Defines the TESSEROID, SPHERE, and PRISM structures.
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include "constants.h"
#include "logger.h"
#include "geometry.h"
/* Split a tesseroid into 8. */
void split_tess(TESSEROID tess, TESSEROID *split)
{
double dlon = 0.5*(tess.e - tess.w),
dlat = 0.5*(tess.n - tess.s),
dr = 0.5*(tess.r2 - tess.r1),
ws[2], ss[2], r1s[2];
int i, j, k, t = 0;
ws[0] = tess.w;
ws[1] = tess.w + dlon;
ss[0] = tess.s;
ss[1] = tess.s + dlat;
r1s[0] = tess.r1;
r1s[1] = tess.r1 + dr;
for(k = 0; k < 2; k++)
{
for(j = 0; j < 2; j++)
{
for(i = 0; i < 2; i++)
{
split[t].w = ws[i];
split[t].e = ws[i] + dlon;
split[t].s = ss[j];
split[t].n = ss[j] + dlat;
split[t].r1 = r1s[k];
split[t].r2 = r1s[k] + dr;
split[t].density = tess.density;
t++;
}
}
}
}

37
lib/geometry.h Executable file
View File

@@ -0,0 +1,37 @@
/*
Data structures for geometric elements and functions that operate on them.
Defines the TESSEROID, SPHERE, and PRISM structures.
*/
#ifndef _TESSEROIDS_GEOMETRY_H_
#define _TESSEROIDS_GEOMETRY_H_
/* Store information on a tesseroid */
typedef struct tess_struct {
/* s, n, w, e in degrees. r1 and r2 are the smaller and larger radius */
double density; /* in SI units */
double w; /* western longitude border in degrees */
double e; /* eastern longitude border in degrees */
double s; /* southern latitude border in degrees */
double n; /* northern latitude border in degrees */
double r1; /* smallest radius border in SI units */
double r2; /* largest radius border in SI units */
double suscept; /* magnetic susceptibility */
double Bx; /* x-component of ambient magnetic field */
double By; /* y-component of ambient magnetic field */
double Bz; /* z-component of ambient magnetic field */
double cos_a1;
double sin_a1;
double cos_b1;
double sin_b1;
//double Rx;
//double Ry;
//double Rz;
} TESSEROID;
void split_tess(TESSEROID tess, TESSEROID *split);
#endif

265
lib/glq.cpp Executable file
View File

@@ -0,0 +1,265 @@
/*
Functions for implementing a Gauss-Legendre Quadrature numerical integration.
*/
#include <stdlib.h>
#include <math.h>
#include "constants.h"
#include "logger.h"
#include "glq.h"
/* Make a new GLQ structure and set all the parameters needed */
GLQ * glq_new(int order, double lower, double upper)
{
GLQ *glq;
int rc;
glq = (GLQ *)malloc(sizeof(GLQ));
if(glq == NULL)
{
return NULL;
}
glq->order = order;
glq->nodes = (double *)malloc(sizeof(double)*order);
if(glq->nodes == NULL)
{
free(glq);
return NULL;
}
glq->nodes_unscaled = (double *)malloc(sizeof(double)*order);
if(glq->nodes_unscaled == NULL)
{
free(glq);
free(glq->nodes);
return NULL;
}
glq->weights = (double *)malloc(sizeof(double)*order);
if(glq->weights == NULL)
{
free(glq);
free(glq->nodes);
free(glq->nodes_unscaled);
return NULL;
}
rc = glq_nodes(order, glq->nodes_unscaled);
if(rc != 0 && rc != 3)
{
switch(rc)
{
case 1:
log_error("glq_nodes invalid GLQ order %d. Should be >= 2.",
order);
break;
case 2:
log_error("glq_nodes NULL pointer for nodes");
break;
default:
log_error("glq_nodes unknown error code %g", rc);
break;
}
glq_free(glq);
return NULL;
}
else if(rc == 3)
{
log_warning("glq_nodes max iterations reached in root finder");
log_warning("nodes might not have desired accuracy %g", GLQ_MAXERROR);
}
rc = glq_weights(order, glq->nodes_unscaled, glq->weights);
if(rc != 0)
{
switch(rc)
{
case 1:
log_error("glq_weights invalid GLQ order %d. Should be >= 2.",
order);
break;
case 2:
log_error("glq_weights NULL pointer for nodes");
break;
case 3:
log_error("glq_weights NULL pointer for weights");
break;
default:
log_error("glq_weights unknown error code %d\n", rc);
break;
}
glq_free(glq);
return NULL;
}
if(glq_set_limits(lower, upper, glq) != 0)
{
glq_free(glq);
return NULL;
}
return glq;
}
/* Free the memory allocated to make a GLQ structure */
void glq_free(GLQ *glq)
{
free(glq->nodes);
free(glq->nodes_unscaled);
free(glq->weights);
free(glq);
}
/* Calculates the GLQ nodes using glq_next_root. */
int glq_nodes(int order, double *nodes)
{
register int i;
int rc = 0;
double initial;
if(order < 2)
{
return 1;
}
if(nodes == NULL)
{
return 2;
}
for(i = 0; i < order; i++)
{
initial = cos(PI*(order - i - 0.25)/(order + 0.5));
if(glq_next_root(initial, i, order, nodes) == 3)
{
rc = 3;
}
}
return rc;
}
/* Put the GLQ nodes to the integration limits IN PLACE. */
int glq_set_limits(double lower, double upper, GLQ *glq)
{
/* Only calculate once to optimize the code */
double tmpplus = 0.5*(upper + lower), tmpminus = 0.5*(upper - lower);
register int i;
if(glq->order < 2)
{
return 1;
}
if(glq->nodes == NULL)
{
return 2;
}
if(glq->nodes_unscaled == NULL)
{
return 2;
}
for(i = 0; i < glq->order; i++)
{
glq->nodes[i] = tmpminus*glq->nodes_unscaled[i] + tmpplus;
}
return 0;
}
/* Calculate the next Legendre polynomial root given the previous root found. */
int glq_next_root(double initial, int root_index, int order, double *roots)
{
double x1, x0, pn, pn_2, pn_1, pn_line, sum;
int it = 0;
register int n;
if(order < 2)
{
return 1;
}
if(root_index < 0 || root_index >= order)
{
return 2;
}
x1 = initial;
do
{
x0 = x1;
/* Calculate Pn(x0) */
/* Starting from P0(x) and P1(x), */
/* find the others using the recursive relation: */
/* Pn(x)=(2n-1)xPn_1(x)/n - (n-1)Pn_2(x)/n */
pn_1 = 1.; /* This is Po(x) */
pn = x0; /* and this P1(x) */
for(n = 2; n <= order; n++)
{
pn_2 = pn_1;
pn_1 = pn;
pn = ( ((2*n - 1)*x0*pn_1) - ((n - 1)*pn_2) )/n;
}
/* Now calculate Pn'(x0) using another recursive relation: */
/* Pn'(x)=n(xPn(x)-Pn_1(x))/(x*x-1) */
pn_line = order*(x0*pn - pn_1)/(x0*x0 - 1);
/* Sum the roots found so far */
for(n = 0, sum = 0; n < root_index; n++)
{
sum += 1./(x0 - roots[n]);
}
/* Update the estimate for the root */
x1 = x0 - (double)pn/(pn_line - pn*sum);
/** Compute the absolute value of x */
#define GLQ_ABS(x) ((x) < 0 ? -1*(x) : (x))
} while(GLQ_ABS(x1 - x0) > GLQ_MAXERROR && ++it <= GLQ_MAXIT);
#undef GLQ_ABS
roots[root_index] = x1;
/* Tell the user if stagnation occurred */
if(it > GLQ_MAXIT)
{
return 3;
}
return 0;
}
/* Calculates the weighting coefficients for the GLQ integration. */
int glq_weights(int order, double *nodes, double *weights)
{
register int i, n;
double xi, pn, pn_2, pn_1, pn_line;
if(order < 2)
{
return 1;
}
if(nodes == NULL)
{
return 2;
}
if(weights == NULL)
{
return 3;
}
for(i = 0; i < order; i++){
xi = nodes[i];
/* Find Pn'(xi) with the recursive relation to find Pn and Pn-1: */
/* Pn(x)=(2n-1)xPn_1(x)/n - (n-1)Pn_2(x)/n */
/* Then use: Pn'(x)=n(xPn(x)-Pn_1(x))/(x*x-1) */
/* Find Pn and Pn-1 stating from P0 and P1 */
pn_1 = 1; /* This is Po(x) */
pn = xi; /* and this P1(x) */
for(n = 2; n <= order; n++)
{
pn_2 = pn_1;
pn_1 = pn;
pn = ((2*n - 1)*xi*pn_1 - (n - 1)*pn_2)/n;
}
pn_line = order*(xi*pn - pn_1)/(xi*xi - 1.);
/* ith weight is: wi = 2/(1 - xi^2)(Pn'(xi)^2) */
weights[i] = 2./((1 - xi*xi)*pn_line*pn_line);
}
return 0;
}

182
lib/glq.h Executable file
View File

@@ -0,0 +1,182 @@
/*
Functions for implementing a Gauss-Legendre Quadrature numerical integration
(Hildebrand, 1987).
Usage example
-------------
To integrate the cossine function from 0 to 90 degrees:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "src/c/glq.h"
int main(){
// Create a new glq structure
GLQ *glq;
double result = 0, a = 0, b = 0.5*3.14;
int i;
glq = glq_new(5, a, b);
if(glq == NULL){
printf("malloc error");
return 1;
}
// Calculate the integral
for(i = 0; i < glq->order; i++)
result += glq->weights[i]*cos(glq->nodes[i]);
// Need to multiply by a scale factor of the integration limits
result *= 0.5*(b - a);
printf("Integral of cossine from 0 to 90 degrees = %lf\n", result);
// Free allocated memory
glq_free(glq);
return 0;
}
References
----------
* Hildebrand, F.B (1987): Introduction to numerical analysis.
Courier Dover Publications, 2. ed.
*/
#ifndef _TESSEROIDS_GLQ_H_
#define _TESSEROIDS_GLQ_H_
/** \var GLQ_MAXIT
Max iterations of the root-finder algorithm */
const int GLQ_MAXIT = 1000;
/** \var GLQ_MAXERROR
Max error allowed for the root-finder algorithm */
const double GLQ_MAXERROR = 0.000000000000001;
/** Store the nodes and weights needed for a GLQ integration */
typedef struct glq_struct
{
int order; /**< order of the quadrature, ie number of nodes */
double *nodes; /**< abscissas or discretization points of the quadrature */
double *weights; /**< weighting coefficients of the quadrature */
double *nodes_unscaled; /**< nodes in [-1,1] interval */
} GLQ;
/** Make a new GLQ structure and set all the parameters needed
<b>WARNING</b>: Don't forget to free the memory malloced by this function using
glq_free()!
Prints error and warning messages using the logging.h module.
@param order order of the quadrature, ie number of nodes
@param lower lower integration limit
@param upper upper integration limit
@return GLQ data structure with the nodes and weights calculated. NULL if there
was an error with allocation.
*/
GLQ * glq_new(int order, double lower, double upper);
/** Free the memory allocated to make a GLQ structure
@param glq pointer to the allocated memory
*/
void glq_free(GLQ *glq);
/** Put the GLQ nodes to the integration limits <b>IN PLACE</b>.
Will replace the values of glq.nodes with ones in the specified integration
limits.
In case the GLQ structure was created with glq_new(), the integration limits can
be reset using this function.
@param lower lower integration limit
@param upper upper integration limit
@param glq pointer to a GLQ structure created with glq_new() and with all
necessary memory allocated
@return Return code:
- 0: if everything went OK
- 1: if invalid order
- 2: if NULL pointer for nodes or nodes_unscaled
*/
int glq_set_limits(double lower, double upper, GLQ *glq);
/** Calculates the GLQ nodes using glq_next_root.
Nodes will be in the [-1,1] interval. To convert them to the integration limits
use glq_scale_nodes
@param order order of the quadrature, ie how many nodes. Must be >= 2.
@param nodes pre-allocated array to return the nodes.
@return Return code:
- 0: if everything went OK
- 1: if invalid order
- 2: if NULL pointer for nodes
- 3: if number of maximum iterations was reached when calculating the root.
This usually means that the desired accuracy was not achieved. Default
desired accuracy is GLQ_MAXERROR. Default maximum iterations is
GLQ_MAXIT.
*/
int glq_nodes(int order, double *nodes);
/** Calculate the next Legendre polynomial root given the previous root found.
Uses the root-finder algorithm of:
Barrera-Figueroa, V., Sosa-Pedroza, J. and López-Bonilla, J., 2006,
"Multiple root finder algorithm for Legendre and Chebyshev polynomials via
Newton's method", 2006, Annales mathematicae et Informaticae, 33, pp 3-13
@param initial initial estimate of the next root. I recommend the use of
\f$ \cos\left(\pi\frac{(N - i - 0.25)}{N + 0.5}\right) \f$,
where \f$ i \f$ is the index of the desired root
@param root_index index of the desired root, starting from 0
@param order order of the Legendre polynomial, ie number of roots.
@param roots array with the roots found so far. Will return the next root in
roots[root_index], so make sure to malloc enough space.
@return Return code:
- 0: if everything went OK
- 1: if order is not valid
- 2: if root_index is not valid (negative)
- 3: if number of maximum iterations was reached when calculating the root.
This usually means that the desired accuracy was not achieved. Default
desired accuracy is GLQ_MAXERROR. Default maximum iterations is
GLQ_MAXIT.
*/
int glq_next_root(double initial, int root_index, int order,
double *roots);
/** Calculates the weighting coefficients for the GLQ integration.
@param order order of the quadrature, ie number of nodes and weights.
@param nodes array containing the GLQ nodes calculated by glq_nodes.
<b>IMPORTANT</b>: needs the nodes in [-1,1] interval! Scaled nodes
will result in wrong weights!
@param weights pre-allocated array to return the weights
@return Return code:
- 0: if everything went OK
- 1: if order is not valid
- 2: if nodes is a NULL pointer
- 3: if weights is a NULL pointer
*/
int glq_weights(int order, double *nodes, double *weights);
#endif

628
lib/grav_tess.cpp Executable file
View File

@@ -0,0 +1,628 @@
/*
Functions that calculate the gravitational potential and its first and second
derivatives for the tesseroid.
References
----------
* Grombein, T.; Seitz, K.; Heck, B. (2010): Untersuchungen zur effizienten
Berechnung topographischer Effekte auf den Gradiententensor am Fallbeispiel der
Satellitengradiometriemission GOCE.
KIT Scientific Reports 7547, ISBN 978-3-86644-510-9, KIT Scientific Publishing,
Karlsruhe, Germany.
*/
#include <math.h>
#include "logger.h"
#include "geometry.h"
#include "glq.h"
#include "constants.h"
#include "grav_tess.h"
/* Calculates the field of a tesseroid model at a given point. */
double calc_tess_model(TESSEROID *model, int size, double lonp, double latp, double rp, GLQ *glq_lon, GLQ *glq_lat, GLQ *glq_r, double (*field)(TESSEROID, double, double, double, GLQ, GLQ, GLQ))
{
double res;
int tess;
res = 0;
for(tess = 0; tess < size; tess++)
{
if(lonp >= model[tess].w && lonp <= model[tess].e &&
latp >= model[tess].s && latp <= model[tess].n &&
rp >= model[tess].r1 && rp <= model[tess].r2)
{
log_warning("Point (%g %g %g) is on tesseroid %d: %g %g %g %g %g %g %g. Can't guarantee accuracy.",
lonp, latp, rp - MEAN_EARTH_RADIUS, tess,
model[tess].w, model[tess].e, model[tess].s,
model[tess].n, model[tess].r2 - MEAN_EARTH_RADIUS,
model[tess].r1 - MEAN_EARTH_RADIUS,
model[tess].density);
}
glq_set_limits(model[tess].w, model[tess].e, glq_lon);
glq_set_limits(model[tess].s, model[tess].n, glq_lat);
glq_set_limits(model[tess].r1, model[tess].r2, glq_r);
res += field(model[tess], lonp, latp, rp, *glq_lon, *glq_lat, *glq_r);
}
return res;
}
void calc_tess_model_triple(TESSEROID *model, int size, double lonp, double latp, double rp, GLQ *glq_lon, GLQ *glq_lat, GLQ *glq_r, void (*field_triple)(TESSEROID, double, double, double, GLQ, GLQ, GLQ, double*), double *res)
{
double r1, r2, r3, ri[3];
int tess;
res[0] = 0;
res[1] = 0;
res[2] = 0;
for(tess = 0; tess < size; tess++)
{
ri[0] = 0;
ri[1] = 0;
ri[2] = 0;
if(lonp >= model[tess].w && lonp <= model[tess].e &&
latp >= model[tess].s && latp <= model[tess].n &&
rp >= model[tess].r1 && rp <= model[tess].r2)
{
log_warning("Point (%g %g %g) is on tesseroid %d: %g %g %g %g %g %g %g. Can't guarantee accuracy.",
lonp, latp, rp - MEAN_EARTH_RADIUS, tess,
model[tess].w, model[tess].e, model[tess].s,
model[tess].n, model[tess].r2 - MEAN_EARTH_RADIUS,
model[tess].r1 - MEAN_EARTH_RADIUS,
model[tess].density);
}
glq_set_limits(model[tess].w, model[tess].e, glq_lon);
glq_set_limits(model[tess].s, model[tess].n, glq_lat);
glq_set_limits(model[tess].r1, model[tess].r2, glq_r);
field_triple(model[tess], lonp, latp, rp, *glq_lon, *glq_lat, *glq_r, ri);
res[0] += ri[0];
res[1] += ri[1];
res[2] += ri[2];
}
return;
}
/* Adaptatively calculate the field of a tesseroid model at a given point */
double calc_tess_model_adapt(TESSEROID *model, int size, double lonp, double latp, double rp, GLQ *glq_lon, GLQ *glq_lat, GLQ *glq_r, double (*field)(TESSEROID, double, double, double, GLQ, GLQ, GLQ), double ratio)
{
double res, dist, lont, latt, rt, d2r = PI/180.;
int tess;
TESSEROID split[8];
res = 0;
for(tess = 0; tess < size; tess++)
{
rt = model[tess].r2;
lont = 0.5*(model[tess].w + model[tess].e);
latt = 0.5*(model[tess].s + model[tess].n);
dist = sqrt(rp*rp + rt*rt - 2*rp*rt*(sin(d2r*latp)*sin(d2r*latt) +
cos(d2r*latp)*cos(d2r*latt)*cos(d2r*(lonp - lont))));
/* Would get stuck in infinite loop if dist = 0 and get wrong results if
inside de tesseroid. Still do the calculation but warn user that it's
probably wrong. */
if(lonp >= model[tess].w && lonp <= model[tess].e &&
latp >= model[tess].s && latp <= model[tess].n &&
rp >= model[tess].r1 && rp <= model[tess].r2)
{
log_warning("Point (%g %g %g) is on top of tesseroid %d: %g %g %g %g %g %g %g. Can't guarantee accuracy.",
lonp, latp, rp - MEAN_EARTH_RADIUS, tess,
model[tess].w, model[tess].e, model[tess].s,
model[tess].n, model[tess].r2 - MEAN_EARTH_RADIUS,
model[tess].r1 - MEAN_EARTH_RADIUS,
model[tess].density);
glq_set_limits(model[tess].w, model[tess].e, glq_lon);
glq_set_limits(model[tess].s, model[tess].n, glq_lat);
glq_set_limits(model[tess].r1, model[tess].r2, glq_r);
res += field(model[tess], lonp, latp, rp, *glq_lon, *glq_lat,
*glq_r);
}
/* Check if the computation point is at an acceptable distance. If not
split the tesseroid using the given ratio */
else if(
dist < ratio*MEAN_EARTH_RADIUS*d2r*(model[tess].e - model[tess].w) ||
dist < ratio*MEAN_EARTH_RADIUS*d2r*(model[tess].n - model[tess].s) ||
dist < ratio*(model[tess].r2 - model[tess].r1))
{
log_debug("Splitting tesseroid %d (%g %g %g %g %g %g %g) at point (%g %g %g) using ratio %g",
tess, model[tess].w, model[tess].e, model[tess].s,
model[tess].n, model[tess].r2 - MEAN_EARTH_RADIUS,
model[tess].r1 - MEAN_EARTH_RADIUS, model[tess].density,
lonp, latp, rp - MEAN_EARTH_RADIUS, ratio);
/* Do it recursively until ratio*size is smaller than distance */
split_tess(model[tess], split);
res += calc_tess_model_adapt(split, 8, lonp, latp, rp, glq_lon,
glq_lat, glq_r, field, ratio);
}
else
{
glq_set_limits(model[tess].w, model[tess].e, glq_lon);
glq_set_limits(model[tess].s, model[tess].n, glq_lat);
glq_set_limits(model[tess].r1, model[tess].r2, glq_r);
res += field(model[tess], lonp, latp, rp, *glq_lon, *glq_lat,
*glq_r);
}
}
return res;
}
/* Calculates gxx caused by a tesseroid. */
double tess_gxx(TESSEROID tess, double lonp, double latp, double rp, GLQ glq_lon,
GLQ glq_lat, GLQ glq_r)
{
double d2r = PI/180., l_sqr, kphi, coslatp, coslatc, sinlatp, sinlatc,
coslon, rc, kappa, res;
register int i, j, k;
coslatp = cos(d2r*latp);
sinlatp = sin(d2r*latp);
res = 0;
for(k = 0; k < glq_lon.order; k++)
{
for(j = 0; j < glq_lat.order; j++)
{
for(i = 0; i < glq_r.order; i++)
{
rc = glq_r.nodes[i];
sinlatc = sin(d2r*glq_lat.nodes[j]);
coslatc = cos(d2r*glq_lat.nodes[j]);
coslon = cos(d2r*(lonp - glq_lon.nodes[k]));
l_sqr = rp*rp + rc*rc - 2*rp*rc*(sinlatp*sinlatc +
coslatp*coslatc*coslon);
kphi = coslatp*sinlatc - sinlatp*coslatc*coslon;
kappa = rc*rc*coslatc;
res += glq_lon.weights[k]*glq_lat.weights[j]*glq_r.weights[i]*
kappa*(3*rc*kphi*rc*kphi - l_sqr)/pow(l_sqr, 2.5);
}
}
}
res *= SI2EOTVOS*G*tess.density*d2r*(tess.e - tess.w)*d2r*(tess.n - tess.s)*
(tess.r2 - tess.r1)*0.125;
return res;
}
/* Calculates gxy caused by a tesseroid. */
double tess_gxy(TESSEROID tess, double lonp, double latp, double rp, GLQ glq_lon,
GLQ glq_lat, GLQ glq_r)
{
double d2r = PI/180., l_sqr, kphi, coslatp, coslatc, sinlatp, sinlatc,
coslon, sinlon, rc, kappa, deltax, deltay, res;
register int i, j, k;
coslatp = cos(d2r*latp);
sinlatp = sin(d2r*latp);
res = 0;
for(k = 0; k < glq_lon.order; k++)
{
for(j = 0; j < glq_lat.order; j++)
{
for(i = 0; i < glq_r.order; i++)
{
rc = glq_r.nodes[i];
sinlatc = sin(d2r*glq_lat.nodes[j]);
coslatc = cos(d2r*glq_lat.nodes[j]);
coslon = cos(d2r*(lonp - glq_lon.nodes[k]));
sinlon = sin(d2r*(glq_lon.nodes[k] - lonp));
l_sqr = rp*rp + rc*rc - 2*rp*rc*(sinlatp*sinlatc +
coslatp*coslatc*coslon);
kphi = coslatp*sinlatc - sinlatp*coslatc*coslon;
kappa = rc*rc*coslatc;
deltax = rc*kphi;
deltay = rc*coslatc*sinlon;
res += glq_lon.weights[k]*glq_lat.weights[j]*glq_r.weights[i]*
kappa*(3*deltax*deltay)/pow(l_sqr, 2.5);
}
}
}
res *= SI2EOTVOS*G*tess.density*d2r*(tess.e - tess.w)*d2r*(tess.n - tess.s)*
(tess.r2 - tess.r1)*0.125;
return res;
}
/* Calculates gxz caused by a tesseroid. */
double tess_gxz(TESSEROID tess, double lonp, double latp, double rp, GLQ glq_lon,
GLQ glq_lat, GLQ glq_r)
{
double d2r = PI/180., l_sqr, kphi, coslatp, coslatc, sinlatp, sinlatc,
coslon, cospsi, rc, kappa, deltax, deltaz, res;
register int i, j, k;
coslatp = cos(d2r*latp);
sinlatp = sin(d2r*latp);
res = 0;
for(k = 0; k < glq_lon.order; k++)
{
for(j = 0; j < glq_lat.order; j++)
{
for(i = 0; i < glq_r.order; i++)
{
rc = glq_r.nodes[i];
sinlatc = sin(d2r*glq_lat.nodes[j]);
coslatc = cos(d2r*glq_lat.nodes[j]);
coslon = cos(d2r*(lonp - glq_lon.nodes[k]));
cospsi = sinlatp*sinlatc + coslatp*coslatc*coslon;
l_sqr = rp*rp + rc*rc - 2*rp*rc*cospsi;
kphi = coslatp*sinlatc - sinlatp*coslatc*coslon;
kappa = rc*rc*coslatc;
deltax = rc*kphi;
deltaz = rc*cospsi - rp;
res += glq_lon.weights[k]*glq_lat.weights[j]*glq_r.weights[i]*
kappa*(3*deltax*deltaz)/pow(l_sqr, 2.5);
}
}
}
res *= SI2EOTVOS*G*tess.density*d2r*(tess.e - tess.w)*d2r*(tess.n - tess.s)*
(tess.r2 - tess.r1)*0.125;
return res;
}
/* Calculates gyy caused by a tesseroid. */
double tess_gyy(TESSEROID tess, double lonp, double latp, double rp, GLQ glq_lon,
GLQ glq_lat, GLQ glq_r)
{
double d2r = PI/180., l_sqr, coslatp, coslatc, sinlatp, sinlatc,
coslon, sinlon, rc, kappa, deltay, res;
register int i, j, k;
coslatp = cos(d2r*latp);
sinlatp = sin(d2r*latp);
res = 0;
for(k = 0; k < glq_lon.order; k++)
{
for(j = 0; j < glq_lat.order; j++)
{
for(i = 0; i < glq_r.order; i++)
{
rc = glq_r.nodes[i];
sinlatc = sin(d2r*glq_lat.nodes[j]);
coslatc = cos(d2r*glq_lat.nodes[j]);
coslon = cos(d2r*(lonp - glq_lon.nodes[k]));
sinlon = sin(d2r*(glq_lon.nodes[k] - lonp));
l_sqr = rp*rp + rc*rc - 2*rp*rc*(sinlatp*sinlatc +
coslatp*coslatc*coslon);
kappa = rc*rc*coslatc;
deltay = rc*coslatc*sinlon;
res += glq_lon.weights[k]*glq_lat.weights[j]*glq_r.weights[i]*
kappa*(3*deltay*deltay - l_sqr)/pow(l_sqr, 2.5);
}
}
}
res *= SI2EOTVOS*G*tess.density*d2r*(tess.e - tess.w)*d2r*(tess.n - tess.s)*
(tess.r2 - tess.r1)*0.125;
return res;
}
/* Calculates gyz caused by a tesseroid. */
double tess_gyz(TESSEROID tess, double lonp, double latp, double rp, GLQ glq_lon,
GLQ glq_lat, GLQ glq_r)
{
double d2r = PI/180., l_sqr, coslatp, coslatc, sinlatp, sinlatc,
coslon, sinlon, cospsi, rc, kappa, deltay, deltaz, res;
register int i, j, k;
coslatp = cos(d2r*latp);
sinlatp = sin(d2r*latp);
res = 0;
for(k = 0; k < glq_lon.order; k++)
{
for(j = 0; j < glq_lat.order; j++)
{
for(i = 0; i < glq_r.order; i++)
{
rc = glq_r.nodes[i];
sinlatc = sin(d2r*glq_lat.nodes[j]);
coslatc = cos(d2r*glq_lat.nodes[j]);
coslon = cos(d2r*(lonp - glq_lon.nodes[k]));
sinlon = sin(d2r*(glq_lon.nodes[k] - lonp));
cospsi = sinlatp*sinlatc + coslatp*coslatc*coslon;
l_sqr = rp*rp + rc*rc - 2*rp*rc*cospsi;
kappa = rc*rc*coslatc;
deltay = rc*coslatc*sinlon;
deltaz = rc*cospsi - rp;
res += glq_lon.weights[k]*glq_lat.weights[j]*glq_r.weights[i]*
kappa*(3*deltay*deltaz)/pow(l_sqr, 2.5);
}
}
}
res *= SI2EOTVOS*G*tess.density*d2r*(tess.e - tess.w)*d2r*(tess.n - tess.s)*
(tess.r2 - tess.r1)*0.125;
return res;
}
/* Calculates gzz caused by a tesseroid. */
double tess_gzz(TESSEROID tess, double lonp, double latp, double rp, GLQ glq_lon,
GLQ glq_lat, GLQ glq_r)
{
double d2r = PI/180., l_sqr, coslatp, coslatc, sinlatp, sinlatc,
coslon, cospsi, rc, kappa, deltaz, res;
register int i, j, k;
coslatp = cos(d2r*latp);
sinlatp = sin(d2r*latp);
res = 0;
for(k = 0; k < glq_lon.order; k++)
{
for(j = 0; j < glq_lat.order; j++)
{
for(i = 0; i < glq_r.order; i++)
{
rc = glq_r.nodes[i];
sinlatc = sin(d2r*glq_lat.nodes[j]);
coslatc = cos(d2r*glq_lat.nodes[j]);
coslon = cos(d2r*(lonp - glq_lon.nodes[k]));
cospsi = sinlatp*sinlatc + coslatp*coslatc*coslon;
l_sqr = rp*rp + rc*rc - 2*rp*rc*cospsi;
kappa = rc*rc*coslatc;
deltaz = rc*cospsi - rp;
res += glq_lon.weights[k]*glq_lat.weights[j]*glq_r.weights[i]*
kappa*(3*deltaz*deltaz - l_sqr)/pow(l_sqr, 2.5);
}
}
}
res *= SI2EOTVOS*G*tess.density*d2r*(tess.e - tess.w)*d2r*(tess.n - tess.s)*
(tess.r2 - tess.r1)*0.125;
return res;
}
/*Calculate three gravity gradient components simultaneously*/
void tess_gxz_gyz_gzz(TESSEROID tess, double lonp, double latp, double rp, GLQ glq_lon,
GLQ glq_lat, GLQ glq_r, double *res)
{
double d2r = PI/180., l_sqr, coslatp, coslatc, sinlatp, sinlatc, sinlon,
coslon, cospsi, rc, kappa, deltaz, deltax, deltay, kphi,
res_gxz, res_gyz, res_gzz;
register int i, j, k;
coslatp = cos(d2r*latp);
sinlatp = sin(d2r*latp);
res_gxz = 0;
res_gyz = 0;
res_gzz = 0;
for(k = 0; k < glq_lon.order; k++)
{
for(j = 0; j < glq_lat.order; j++)
{
for(i = 0; i < glq_r.order; i++)
{
rc = glq_r.nodes[i];
sinlatc = sin(d2r*glq_lat.nodes[j]);
coslatc = cos(d2r*glq_lat.nodes[j]);
coslon = cos(d2r*(lonp - glq_lon.nodes[k]));
sinlon = sin(d2r*(glq_lon.nodes[k] - lonp));
cospsi = sinlatp*sinlatc + coslatp*coslatc*coslon;
l_sqr = rp*rp + rc*rc - 2*rp*rc*cospsi;
kphi = coslatp*sinlatc - sinlatp*coslatc*coslon;
kappa = rc*rc*coslatc;
deltax = rc*kphi;
deltay = rc*coslatc*sinlon;
deltaz = rc*cospsi - rp;
res_gxz += glq_lon.weights[k]*glq_lat.weights[j]*glq_r.weights[i]*
kappa*(3*deltax*deltaz)/pow(l_sqr, 2.5);
res_gyz += glq_lon.weights[k]*glq_lat.weights[j]*glq_r.weights[i]*
kappa*(3*deltay*deltaz)/pow(l_sqr, 2.5);
res_gzz += glq_lon.weights[k]*glq_lat.weights[j]*glq_r.weights[i]*
kappa*(3*deltaz*deltaz - l_sqr)/pow(l_sqr, 2.5);
}
}
}
res_gxz *= SI2EOTVOS*G*tess.density*d2r*(tess.e - tess.w)*d2r*(tess.n - tess.s)*
(tess.r2 - tess.r1)*0.125;
res_gyz *= SI2EOTVOS*G*tess.density*d2r*(tess.e - tess.w)*d2r*(tess.n - tess.s)*
(tess.r2 - tess.r1)*0.125;
res_gzz *= SI2EOTVOS*G*tess.density*d2r*(tess.e - tess.w)*d2r*(tess.n - tess.s)*
(tess.r2 - tess.r1)*0.125;
res[0] = res_gxz;
res[1] = res_gyz;
res[2] = res_gzz;
return;
}
void tess_gxx_gxy_gxz(TESSEROID tess, double lonp, double latp, double rp, GLQ glq_lon,
GLQ glq_lat, GLQ glq_r, double *res)
{
double d2r = PI/180., l_sqr, coslatp, coslatc, sinlatp, sinlatc, sinlon,
coslon, cospsi, rc, kappa, deltaz, deltax, deltay, kphi,
res_gxx, res_gxy, res_gxz;
register int i, j, k;
coslatp = cos(d2r*latp);
sinlatp = sin(d2r*latp);
res_gxx = 0;
res_gxy = 0;
res_gxz = 0;
for(k = 0; k < glq_lon.order; k++)
{
for(j = 0; j < glq_lat.order; j++)
{
for(i = 0; i < glq_r.order; i++)
{
rc = glq_r.nodes[i];
sinlatc = sin(d2r*glq_lat.nodes[j]);
coslatc = cos(d2r*glq_lat.nodes[j]);
coslon = cos(d2r*(lonp - glq_lon.nodes[k]));
sinlon = sin(d2r*(glq_lon.nodes[k] - lonp));
cospsi = sinlatp*sinlatc + coslatp*coslatc*coslon;
l_sqr = rp*rp + rc*rc - 2*rp*rc*cospsi;
kphi = coslatp*sinlatc - sinlatp*coslatc*coslon;
kappa = rc*rc*coslatc;
deltax = rc*kphi;
deltay = rc*coslatc*sinlon;
deltaz = rc*cospsi - rp;
res_gxx += glq_lon.weights[k]*glq_lat.weights[j]*glq_r.weights[i]*
kappa*(3*rc*kphi*rc*kphi - l_sqr)/pow(l_sqr, 2.5);
res_gxy += glq_lon.weights[k]*glq_lat.weights[j]*glq_r.weights[i]*
kappa*(3*deltax*deltay)/pow(l_sqr, 2.5);
res_gxz += glq_lon.weights[k]*glq_lat.weights[j]*glq_r.weights[i]*
kappa*(3*deltax*deltaz)/pow(l_sqr, 2.5);
}
}
}
res_gxx *= SI2EOTVOS*G*tess.density*d2r*(tess.e - tess.w)*d2r*(tess.n - tess.s)*
(tess.r2 - tess.r1)*0.125;
res_gxy *= SI2EOTVOS*G*tess.density*d2r*(tess.e - tess.w)*d2r*(tess.n - tess.s)*
(tess.r2 - tess.r1)*0.125;
res_gxz *= SI2EOTVOS*G*tess.density*d2r*(tess.e - tess.w)*d2r*(tess.n - tess.s)*
(tess.r2 - tess.r1)*0.125;
res[0] = res_gxx;
res[1] = res_gxy;
res[2] = res_gxz;
return;
}
void tess_gxy_gyy_gyz(TESSEROID tess, double lonp, double latp, double rp, GLQ glq_lon,
GLQ glq_lat, GLQ glq_r, double *res)
{
double d2r = PI/180., l_sqr, coslatp, coslatc, sinlatp, sinlatc, sinlon,
coslon, cospsi, rc, kappa, deltaz, deltax, deltay, kphi,
res_gxy, res_gyy, res_gyz;
register int i, j, k;
coslatp = cos(d2r*latp);
sinlatp = sin(d2r*latp);
res_gxy = 0;
res_gyy = 0;
res_gyz = 0;
for(k = 0; k < glq_lon.order; k++)
{
for(j = 0; j < glq_lat.order; j++)
{
for(i = 0; i < glq_r.order; i++)
{
rc = glq_r.nodes[i];
sinlatc = sin(d2r*glq_lat.nodes[j]);
coslatc = cos(d2r*glq_lat.nodes[j]);
coslon = cos(d2r*(lonp - glq_lon.nodes[k]));
sinlon = sin(d2r*(glq_lon.nodes[k] - lonp));
cospsi = sinlatp*sinlatc + coslatp*coslatc*coslon;
l_sqr = rp*rp + rc*rc - 2*rp*rc*cospsi;
kphi = coslatp*sinlatc - sinlatp*coslatc*coslon;
kappa = rc*rc*coslatc;
deltax = rc*kphi;
deltay = rc*coslatc*sinlon;
deltaz = rc*cospsi - rp;
res_gxy += glq_lon.weights[k]*glq_lat.weights[j]*glq_r.weights[i]*
kappa*(3*deltax*deltay)/pow(l_sqr, 2.5);
res_gyy += glq_lon.weights[k]*glq_lat.weights[j]*glq_r.weights[i]*
kappa*(3*deltay*deltay - l_sqr)/pow(l_sqr, 2.5);
res_gyz += glq_lon.weights[k]*glq_lat.weights[j]*glq_r.weights[i]*
kappa*(3*deltay*deltaz)/pow(l_sqr, 2.5);
}
}
}
res_gxy *= SI2EOTVOS*G*tess.density*d2r*(tess.e - tess.w)*d2r*(tess.n - tess.s)*
(tess.r2 - tess.r1)*0.125;
res_gyy *= SI2EOTVOS*G*tess.density*d2r*(tess.e - tess.w)*d2r*(tess.n - tess.s)*
(tess.r2 - tess.r1)*0.125;
res_gyz *= SI2EOTVOS*G*tess.density*d2r*(tess.e - tess.w)*d2r*(tess.n - tess.s)*
(tess.r2 - tess.r1)*0.125;
res[0] = res_gxy;
res[1] = res_gyy;
res[2] = res_gyz;
return;
}

93
lib/grav_tess.h Executable file
View File

@@ -0,0 +1,93 @@
/*
Functions that calculate the gravitational potential and its first and second
derivatives for the tesseroid.
The gravity gradients can be calculated using the general formula of
Grombein et al. (2010).
The integrals are solved using the Gauss-Legendre Quadrature rule
(Asgharzadeh et al., 2007).
The derivatives of the potential are made with respect to the local coordinate
system x->North, y->East, z->Up (away from center of the Earth).
To maintain the standard convention, only for component gz the z axis is
inverted, so a positive density results in positive gz.
Example
-------
To calculate the gzz component due to a tesseroid on a regular grid:
#include <stdio.h>
#include "glq.h"r
#include "constants.h"
#include "grav_tess.h"
int main()
{
TESSEROID tess = {1000, 44, 46, -1, 1, MEAN_EARTH_RADIUS - 100000,
MEAN_EARTH_RADIUS};
GLQ *glqlon, *glqlat, *glqr;
double lon, lat, r = MEAN_EARTH_RADIUS + 1500000, res;
int order = 8;
glqlon = glq_new(order, tess.w, tess.e);
glqlat = glq_new(order, tess.s, tess.n);
glqr = glq_new(order, tess.r1, tess.r2);
for(lat = 20; lat <= 70; lat += 0.5)
{
for(lon = -25; lon <= 25; lon += 0.5)
{
res = tess_gzz(tess, lon, lat, r, *glqlon, *glqlat, *glqr);
printf("%g %g %g\n", lon, lat, res);
}
}
glq_free(glqlon);
glq_free(glqlat);
glq_free(glqr);
return 0;
}
References
----------
Asgharzadeh, M.F., von Frese, R.R.B., Kim, H.R., Leftwich, T.E. & Kim, J.W.
(2007): Spherical prism gravity effects by Gauss-Legendre quadrature integration.
Geophysical Journal International, 169, 1-11.
Grombein, T.; Seitz, K.; Heck, B. (2010): Untersuchungen zur effizienten
Berechnung topographischer Effekte auf den Gradiententensor am Fallbeispiel der
Satellitengradiometriemission GOCE.
KIT Scientific Reports 7547, ISBN 978-3-86644-510-9, KIT Scientific Publishing,
Karlsruhe, Germany.
*/
#ifndef _TESSEROIDS_GRAV_TESS_H_
#define _TESSEROIDS_GRAV_TESS_H_
/* Needed for definition of TESSEROID */
#include "geometry.h"
/* Needed for definition of GLQ */
#include "glq.h"
double calc_tess_model(TESSEROID *model, int size, double lonp, double latp, double rp, GLQ *glq_lon, GLQ *glq_lat, GLQ *glq_r, double (*field)(TESSEROID, double, double, double, GLQ, GLQ, GLQ));
void calc_tess_model_triple(TESSEROID *model, int size, double lonp, double latp, double rp, GLQ *glq_lon, GLQ *glq_lat, GLQ *glq_r,
void (*field_triple)(TESSEROID, double, double, double, GLQ, GLQ, GLQ, double*), double *res);
double calc_tess_model_adapt(TESSEROID *model, int size, double lonp, double latp, double rp, GLQ *glq_lon, GLQ *glq_lat, GLQ *glq_r, double (*field)(TESSEROID, double, double, double, GLQ, GLQ, GLQ), double ratio);
double tess_gxx(TESSEROID tess, double lonp, double latp, double rp, GLQ glq_lon, GLQ glq_lat, GLQ glq_r);
double tess_gxy(TESSEROID tess, double lonp, double latp, double rp, GLQ glq_lon, GLQ glq_lat, GLQ glq_r);
double tess_gxz(TESSEROID tess, double lonp, double latp, double rp, GLQ glq_lon, GLQ glq_lat, GLQ glq_r);
double tess_gyy(TESSEROID tess, double lonp, double latp, double rp, GLQ glq_lon, GLQ glq_lat, GLQ glq_r);
double tess_gyz(TESSEROID tess, double lonp, double latp, double rp, GLQ glq_lon, GLQ glq_lat, GLQ glq_r);
double tess_gzz(TESSEROID tess, double lonp, double latp, double rp, GLQ glq_lon, GLQ glq_lat, GLQ glq_r);
void tess_gxz_gyz_gzz(TESSEROID tess, double lonp, double latp, double rp, GLQ glq_lon, GLQ glq_lat, GLQ glq_r, double *res);
void tess_gxx_gxy_gxz(TESSEROID tess, double lonp, double latp, double rp, GLQ glq_lon, GLQ glq_lat, GLQ glq_r, double *res);
void tess_gxy_gyy_gyz(TESSEROID tess, double lonp, double latp, double rp, GLQ glq_lon, GLQ glq_lat, GLQ glq_r, double *res);
#endif

142
lib/linalg.cpp Executable file
View File

@@ -0,0 +1,142 @@
/*
Functions matrix and vector multiplications.
*/
#include "linalg.h"
#include "constants.h"
#include <math.h>
//macOS only!
//#include <Accelerate/Accelerate.h>
#ifdef __linux__ // Debian, Ubuntu, Gentoo, Fedora, openSUSE, RedHat, Centos and other
#include <cblas.h>
#elif defined(__APPLE__) && defined(__MACH__)
#include <Accelerate/Accelerate.h>
#else
//
#endif
/* Calculate magnetization vector in a coordinate system of a given point */
void conv_vect_cblas(double *vect, double lon1, double lat1, double lon2, double lat2, double *res)
{
double a1 = DEG2RAD*lat1;
double b1 = DEG2RAD*lon1;
double a2 = DEG2RAD*lat2;
double b2 = DEG2RAD*lon2;
double cos_a1 = cos(PI/2.0-a1);
double sin_a1 = sin(PI/2.0-a1);
double cos_a2 = cos(PI/2.0-a2);
double sin_a2 = sin(PI/2.0-a2);
double cos_b1 = cos(b1);
double sin_b1 = sin(b1);
double cos_b2 = cos(b2);
double sin_b2 = sin(b2);
double Z1Y1[9] = {cos_a1*cos_b1, -sin_b1, cos_b1*sin_a1, cos_a1*sin_b1, cos_b1, sin_a1*sin_b1, -sin_a1, 0, cos_a1};
double Z2Y2t[9] = {-cos_a2*cos_b2, -cos_a2*sin_b2, sin_a2, -sin_b2, cos_b2, 0, cos_b2*sin_a2, sin_a2*sin_b2, cos_a2};
double R[9];
cblas_dgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, Z1Y1, 3, Z2Y2t, 3, 0.0, R, 3);
R[0] = -R[0];
R[3] = -R[3];
R[6] = -R[6];
cblas_dgemv(CblasRowMajor, CblasNoTrans, 3, 3, 1.0, R, 3, vect, 1, 0.0, res, 1);
return;
}
void conv_vect_cblas_precalc(double *vect, double cos_a1, double sin_a1, double cos_b1, double sin_b1, double cos_a2, double sin_a2, double cos_b2, double sin_b2, double *res)
{
// double a1 = DEG2RAD*lat1;
// double b1 = DEG2RAD*lon1;
// double a2 = DEG2RAD*lat2;
// double b2 = DEG2RAD*lon2;
// double cos_a1 = cos(PI/2.0-a1);
// double sin_a1 = sin(PI/2.0-a1);
// double cos_a2 = cos(PI/2.0-a2);
// double sin_a2 = sin(PI/2.0-a2);
// double cos_b1 = cos(b1);
// double sin_b1 = sin(b1);
// double cos_b2 = cos(b2);
// double sin_b2 = sin(b2);
double Z1Y1[9] = {cos_a1*cos_b1, -sin_b1, cos_b1*sin_a1, cos_a1*sin_b1, cos_b1, sin_a1*sin_b1, -sin_a1, 0, cos_a1};
double Z2Y2t[9] = {-cos_a2*cos_b2, -cos_a2*sin_b2, sin_a2, -sin_b2, cos_b2, 0, cos_b2*sin_a2, sin_a2*sin_b2, cos_a2};
double R[9];
cblas_dgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, Z1Y1, 3, Z2Y2t, 3, 0.0, R, 3);
R[0] = -R[0];
R[3] = -R[3];
R[6] = -R[6];
cblas_dgemv(CblasRowMajor, CblasNoTrans, 3, 3, 1.0, R, 3, vect, 1, 0.0, res, 1);
return;
}
void from_loc_sphr_to_cart(double* columnvect_xyzloc, double colatitude, double longitude, double* columnvect_res)
{
/*IMPORTANT: this subroutine is in the coordinate system NED*/
double phi = colatitude*DEG2RAD;
double lambda = longitude*DEG2RAD;
double cos_phi = cos(phi);
double sin_phi = sin(phi);
double cos_lambda = cos(lambda);
double sin_lambda = sin(lambda);
double columnvect_phi_unit[3] = {-sin_phi*cos_lambda, -sin_phi*sin_lambda, cos_phi};
double columnvect_lambda_unit[3] = {-sin_lambda, cos_lambda, 0};
double columnvect_r_unit[3] = {cos_phi*cos_lambda, cos_phi*sin_lambda, sin_phi};
columnvect_res[0] = columnvect_phi_unit[0]*columnvect_xyzloc[0]+columnvect_lambda_unit[0]*columnvect_xyzloc[1]+columnvect_r_unit[0]*columnvect_xyzloc[2];
columnvect_res[1] = columnvect_phi_unit[1]*columnvect_xyzloc[0]+columnvect_lambda_unit[1]*columnvect_xyzloc[1]+columnvect_r_unit[1]*columnvect_xyzloc[2];
columnvect_res[2] = columnvect_phi_unit[2]*columnvect_xyzloc[0]+columnvect_lambda_unit[2]*columnvect_xyzloc[1]+columnvect_r_unit[2]*columnvect_xyzloc[2];
return;
}
void from_cart_to_loc_sphr(double* columnvect_xyzglob, double colatitude, double longitude, double* columnvect_res)
{
/*IMPORTANT: this subroutine is in the coordinate system NED*/
double phi = colatitude*DEG2RAD;
double lambda = longitude*DEG2RAD;
double cos_phi = cos(phi);
double sin_phi = sin(phi);
double cos_lambda = cos(lambda);
double sin_lambda = sin(lambda);
double rowvect_phi_unit[3] = {-sin_phi*cos_lambda, -sin_phi*sin_lambda, cos_phi};
double rowvect_lambda_unit[3] = {-sin_lambda, cos_lambda, 0};
double rowvect_r_unit[3] = {cos_phi*cos_lambda, cos_phi*sin_lambda, sin_phi};
columnvect_res[0] = rowvect_phi_unit[0]*columnvect_xyzglob[0]+rowvect_phi_unit[1]*columnvect_xyzglob[1]+rowvect_phi_unit[2]*columnvect_xyzglob[2];
columnvect_res[1] = rowvect_lambda_unit[0]*columnvect_xyzglob[0]+rowvect_lambda_unit[1]*columnvect_xyzglob[1]+rowvect_lambda_unit[2]*columnvect_xyzglob[2];
columnvect_res[2] = rowvect_r_unit[0]*columnvect_xyzglob[0]+rowvect_r_unit[1]*columnvect_xyzglob[1]+rowvect_r_unit[2]*columnvect_xyzglob[2];
return;
}
void from_loc_sphr_to_loc_sphr(double* columnvect_xyzloc, double colatitude1, double longitude1, double colatitude2, double longitude2, double* columnvect_res)
{
double columnvect_xyzglob[3];
from_loc_sphr_to_cart(columnvect_xyzloc, colatitude1, longitude1, columnvect_xyzglob);
from_cart_to_loc_sphr(columnvect_xyzglob, colatitude2, longitude2, columnvect_res);
return;
}

11
lib/linalg.h Executable file
View File

@@ -0,0 +1,11 @@
#ifndef _LINALG_H_
#define _LINALG_H_
void conv_vect_cblas(double *vect, double lon1, double lat1, double lon2, double lat2, double *res);
void conv_vect_cblas_precalc(double *vect, double cos_a1, double sin_a1, double cos_b1, double sin_b1, double cos_a2, double sin_a2, double cos_b2, double sin_b2, double *res);
void from_loc_sphr_to_cart(double* columnvect_xyzloc, double colatitude, double longitude, double* columnvect_res);
void from_cart_to_loc_sphr(double* columnvect_xyzglob, double colatitude, double longitude, double* columnvect_res);
void from_loc_sphr_to_loc_sphr(double* columnvect_xyzloc, double colatitude1, double longitude1, double colatitude2, double longitude2, double* columnvect_res);
#endif

112
lib/logger.cpp Executable file
View File

@@ -0,0 +1,112 @@
/*
Functions to set up logging.
*/
#include <stdio.h>
#include <stdarg.h>
#include <time.h>
#include "logger.h"
/* Initialize the logger so that it doesn't print by default */
LOGGER logger = {100, 0, 100, NULL};
/* Setup logging to stderr.*/
void log_init(int level)
{
logger.level = level;
}
/* Set logging to a file. */
void log_tofile(FILE *logfile, int level)
{
logger.filelogging = 1;
logger.logfile = logfile;
logger.file_level = level;
}
/* Log a message at debug level */
void log_debug(const char *fmt, ...)
{
char msg[10000];
va_list args;
va_start(args, fmt);
vsprintf(msg, fmt, args);
va_end(args);
if(logger.level <= LOG_DEBUG)
{
fprintf(stderr, "DEBUG: %s\n", msg);
}
if(logger.filelogging && (logger.file_level <= LOG_DEBUG))
{
fprintf(logger.logfile, "DEBUG: %s\n", msg);
}
}
/* Log a message at info level */
void log_info(const char *fmt, ...)
{
char msg[10000];
va_list args;
va_start(args, fmt);
vsprintf(msg, fmt, args);
va_end(args);
if(logger.level <= LOG_INFO)
{
fprintf(stderr, "%s\n", msg);
}
if(logger.filelogging && logger.file_level <= LOG_INFO)
{
fprintf(logger.logfile, "%s\n", msg);
}
}
/* Log a message at warning level */
void log_warning(const char *fmt, ...)
{
char msg[10000];
va_list args;
va_start(args, fmt);
vsprintf(msg, fmt, args);
va_end(args);
if(logger.level <= LOG_WARNING)
{
fprintf(stderr, "WARNING: %s\n", msg);
}
if(logger.filelogging && logger.file_level <= LOG_WARNING)
{
fprintf(logger.logfile, "WARNING: %s\n", msg);
}
}
/* Log a message at error level */
void log_error(const char *fmt, ...)
{
char msg[10000];
va_list args;
va_start(args, fmt);
vsprintf(msg, fmt, args);
va_end(args);
if(logger.level <= LOG_ERROR)
{
fprintf(stderr, "ERROR: %s\n", msg);
}
if(logger.filelogging && logger.file_level <= LOG_ERROR)
{
fprintf(logger.logfile, "ERROR: %s\n", msg);
}
}

166
lib/logger.h Executable file
View File

@@ -0,0 +1,166 @@
/*
Functions to set up logging.
Examples
--------
Logging to stderr:
#include "logger.h"
void my_func(){
log_info("From my_func!\n");
}
int main(){
// Enable logging to stderr in debug level
// will only print messages of level DEBUG or higher
log_init(LOG_DEBUG);
log_debug("debug line. The code is %d", LOG_DEBUG);
log_info("info line. The code is %d", LOG_INFO);
log_warning("warning line. The code is %d", LOG_WARNING);
log_error("error line. The code is %d", LOG_ERROR);
my_func();
return 0;
}
will print:
DEBUG: debug line. The code is 0
info line. The code is 1
WARNING: warning line. The code is 2
ERROR: error line. The code is 3
From my_func!
If function log_init() is not called than logging to stderr is disabled and no
messages will be printed.
Logging to a file:
#include <stdio.h>
#include "logger.h"
void my_func(){
log_info("From my_func!\n");
log_debug("Should not appear in log file\n");
}
int main(){
// Enable logging to file "log.txt" in info level
// will not print DEBUG level messages
// since log_init was not called, there is no logging to stderr
FILE *logfile = fopen("log.txt", "w");
log_tofile(logfile, LOG_INFO);
log_debug("debug line. The code is %d", LOG_DEBUG);
log_info("info line. The code is %d", LOG_INFO);
log_warning("warning line. The code is %d", LOG_WARNING);
log_error("error line. The code is %d", LOG_ERROR);
my_func();
return 0;
}
File log.txt will look like:
info line. The code is 1
WARNING: warning line. The code is 2
ERROR: error line. The code is 3
From my_func!
Note that you can combine loggin to stderr and to a file with different
levels in the same program.
*/
#ifndef _TESSEROIDS_LOGGER_H_
#define _TESSEROIDS_LOGGER_H_
/* Needed for definition of FILE */
#include <stdio.h>
/** Logging level for debug messages */
#define LOG_DEBUG 1
/** Logging level for general information */
#define LOG_INFO 2
/** Logging level for warning messages */
#define LOG_WARNING 3
/** Logging level for error messages */
#define LOG_ERROR 4
/** Keep the information on the global logger */
typedef struct logger_struct
{
int level; /**< level of logging */
int filelogging; /**< flag to know wether loggint to a file is enabled */
int file_level; /**< logging level for the file */
FILE *logfile; /**< file to log to */
} LOGGER;
/** Global logger struct. Only declare in the main program! */
//LOGGER logger;
/** Setup logging to stderr.
@param level level of logging to be made. Can be one of:
- LOG_DEBUG
- LOG_INFO
- LOG_WARNING
- LOG_ERROR
*/
void log_init(int level);
/** Set logging to a file.
@param logfile FILE pointer to the already open file to log to.
@param level level of logging to be made to the file. Can be one of:
- LOG_DEBUG
- LOG_INFO
- LOG_WARNING
- LOG_ERROR
*/
void log_tofile(FILE *logfile, int level);
/** Log a message at debug level.
Pass parameters in the same format as printf()
Prints a newline at the end.
*/
void log_debug(const char *fmt, ...);
/** Log a message at info level.
Pass parameters in the same format as printf()
Does not print "INFO: " in front of the message when logging
Prints a newline at the end.
*/
void log_info(const char *fmt, ...);
/** Log a message at warning level.
Pass parameters in the same format as printf()
Prints a newline at the end.
*/
void log_warning(const char *fmt, ...);
/** Log a message at error level.
Pass parameters in the same format as printf()
Prints a newline at the end.
*/
void log_error(const char *fmt, ...);
#endif

678
lib/parsers.cpp Executable file
View File

@@ -0,0 +1,678 @@
/*
Input and output parsing tools.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "logger.h"
#include "version.h"
#include "parsers.h"
#include "constants.h"
#include "geometry.h"
#include <math.h>
/* Parse basic command line arguments for programs */
int parse_basic_args(int argc, char **argv, const char *progname,
BASIC_ARGS *args, void (*print_help)(void))
{
int bad_args = 0, parsed_args = 0, total_args = 1, i;
char *params;
/* Default values for options */
args->verbose = 0;
args->logtofile = 0;
/* Parse arguments */
for(i = 1; i < argc; i++)
{
if(argv[i][0] == '-')
{
switch(argv[i][1])
{
case 'h':
if(argv[i][2] != '\0')
{
log_error("invalid argument '%s'", argv[i]);
bad_args++;
break;
}
print_help();
return 2;
case 'v':
if(argv[i][2] != '\0')
{
log_error("invalid argument '%s'", argv[i]);
bad_args++;
break;
}
if(args->verbose)
{
log_error("repeated option -v");
bad_args++;
break;
}
args->verbose = 1;
break;
case 'l':
{
if(args->logtofile)
{
log_error("repeated option -l");
bad_args++;
break;
}
params = &argv[i][2];
if(strlen(params) == 0)
{
log_error("bad input argument -l. Missing filename.");
bad_args++;
}
else
{
args->logtofile = 1;
args->logfname = params;
}
break;
}
case '-':
{
params = &argv[i][2];
if(strcmp(params, "version"))
{
log_error("invalid argument '%s'", argv[i]);
bad_args++;
}
else
{
print_version(progname);
return 2;
}
break;
}
default:
log_error("invalid argument '%s'", argv[i]);
bad_args++;
break;
}
}
else
{
if(parsed_args == 0)
{
args->inputfname = argv[i];
parsed_args++;
}
else
{
log_error("invalid argument '%s'. Already given model file %s",
argv[i], args->inputfname);
bad_args++;
}
}
}
/* Check if parsing went well */
if(parsed_args > total_args)
{
log_error("%s: too many input arguments. given %d, max %d.",
progname, parsed_args, total_args);
}
if(bad_args > 0)
{
log_error("%d bad input argument(s)", bad_args);
return 1;
}
if(parsed_args < total_args)
{
return 3;
}
return 0;
}
/* Parse command line arguments for tessh* programs */
int parse_tessb_args(int argc, char **argv, const char *progname,
TESSB_ARGS *args, void (*print_help)(const char *))
{
int bad_args = 0, parsed_args = 0, total_args = 1, parsed_order = 0,
parsed_ratio1 = 0, parsed_ratio2 = 0, parsed_ratio3 = 0, i, nchar, nread;
char *params;
/* Default values for options */
args->verbose = 0;
args->logtofile = 0;
args->lon_order = 2;
args->lat_order = 2;
args->r_order = 2;
args->adaptative = 1;
args->ratio1 = 0; /* zero means use the default for the program */
args->ratio2 = 0;
args->ratio3 = 0;
/* Parse arguments */
for(i = 1; i < argc; i++)
{
if(argv[i][0] == '-')
{
switch(argv[i][1])
{
case 'h':
if(argv[i][2] != '\0')
{
log_error("invalid argument '%s'", argv[i]);
bad_args++;
break;
}
print_help(progname);
return 2;
case 'v':
if(argv[i][2] != '\0')
{
log_error("invalid argument '%s'", argv[i]);
bad_args++;
break;
}
if(args->verbose)
{
log_error("repeated option -v");
bad_args++;
break;
}
args->verbose = 1;
break;
case 'l':
{
if(args->logtofile)
{
log_error("repeated option -l");
bad_args++;
break;
}
params = &argv[i][2];
if(strlen(params) == 0)
{
log_error("bad input argument -l. Missing filename.");
bad_args++;
}
else
{
args->logtofile = 1;
args->logfname = params;
}
break;
}
case '-':
{
params = &argv[i][2];
if(strcmp(params, "version"))
{
log_error("invalid argument '%s'", argv[i]);
bad_args++;
}
else
{
print_version(progname);
return 2;
}
break;
}
case 'a':
if(argv[i][2] != '\0')
{
log_error("invalid argument '%s'", argv[i]);
bad_args++;
break;
}
if(!args->adaptative)
{
log_error("repeated option -a");
bad_args++;
break;
}
args->adaptative = 0;
break;
case 'o':
{
if(parsed_order)
{
log_error("repeated option -o");
bad_args++;
break;
}
params = &argv[i][2];
nchar = 0;
nread = sscanf(params, "%d/%d/%d%n", &(args->lon_order),
&(args->lat_order), &(args->r_order), &nchar);
if(nread != 3 || *(params + nchar) != '\0')
{
log_error("bad input argument '%s'", argv[i]);
bad_args++;
}
parsed_order = 1;
break;
}
case 't':
{
//ELDAR BAYKIEV///////////////////////////////////////////////////////////////////
switch(argv[i][2])
{
case '1':
{
if(parsed_ratio1)
{
log_error("repeated option -t1");
bad_args++;
break;
}
params = &argv[i][3];
nchar = 0;
nread = sscanf(params, "%lf%n", &(args->ratio1), &nchar);
if(nread != 1 || *(params + nchar) != '\0')
{
log_error("bad input argument '%s'", argv[i]);
bad_args++;
}
parsed_ratio1 = 1;
break;
}
case '2':
{
if(parsed_ratio2)
{
log_error("repeated option -t2");
bad_args++;
break;
}
params = &argv[i][3];
nchar = 0;
nread = sscanf(params, "%lf%n", &(args->ratio2), &nchar);
if(nread != 1 || *(params + nchar) != '\0')
{
log_error("bad input argument '%s'", argv[i]);
bad_args++;
}
parsed_ratio2 = 1;
break;
}
case '3':
{
if(parsed_ratio3)
{
log_error("repeated option -t3");
bad_args++;
break;
}
params = &argv[i][3];
nchar = 0;
nread = sscanf(params, "%lf%n", &(args->ratio3), &nchar);
if(nread != 1 || *(params + nchar) != '\0')
{
log_error("bad input argument '%s'", argv[i]);
bad_args++;
}
parsed_ratio3 = 1;
break;
}
}
//ELDAR BAYKIEV///////////////////////////////////////////////////////////////////
}
default:
log_error("invalid argument '%s'", argv[i]);
bad_args++;
break;
}
}
else
{
if(parsed_args == 0)
{
args->modelfname = argv[i];
parsed_args++;
}
else
{
log_error("invalid argument '%s'. Already given model file %s",
argv[i], args->modelfname);
bad_args++;
}
}
}
/* Check if parsing went well */
if(bad_args > 0 || parsed_args != total_args)
{
if(parsed_args < total_args)
{
log_error("%s: missing input file.",
progname, parsed_args, total_args);
}
if(parsed_args > total_args)
{
log_error("%s: too many input arguments. given %d, max %d.",
progname, parsed_args, total_args);
}
if(bad_args > 0)
{
log_error("%d bad input argument(s)", bad_args);
}
return 1;
}
return 0;
}
//parse arguments for gradient calculator
int parse_gradcalc_args(int argc, char **argv, const char *progname, GRADCALC_ARGS *args, void (*print_help)(const char *))
{
int bad_args = 0, parsed_args = 0, total_args = 5, i;
char *params;
/* Default values for options */
args->verbose = 0;
args->logtofile = 0;
args->gridbx_set = FALSE;
args->gridby_set = FALSE;
args->gridbz_set = FALSE;
args->out_set = -1;
args->bz_NEU_NED = -1;
args->bz_NEU_NED_set = FALSE;
/* Parse arguments */
for(i = 1; i < argc; i++)
{
if(argv[i][0] == '-')
{
switch(argv[i][1])
{
case 'h':
if(argv[i][2] != '\0')
{
//log_error("invalid argument '%s'", argv[i]);
printf("invalid argument '%s'\n", argv[i]);
bad_args++;
break;
}
print_help(progname);
return 2;
case '-':
{
params = &argv[i][2];
if(strcmp(params, "version"))
{
printf("invalid argument '%s'\n", argv[i]);
bad_args++;
}
else
{
print_version(progname);
return 2;
}
break;
}
case 'b':
params = &argv[i][2];
if(strlen(params) <= 1)
{
printf("bad input argument -b. Missing component and filename\n");
bad_args++;
break;
}
else
{
switch(argv[i][2])
{
case 'x':
if(args->gridbx_set)
{
printf("invalid argument '%s', gridfile bx already set\n", argv[i]);
bad_args++;
break;
}
else
{
args->gridbx_set = 1;
args->gridbx_fn = &argv[i][3];
}
break;
case 'y':
if(args->gridby_set)
{
printf("invalid argument '%s', gridfile by already set\n", argv[i]);
bad_args++;
break;
}
else
{
args->gridby_set = 1;
args->gridby_fn = &argv[i][3];
}
break;
case 'z':
if(args->gridbz_set)
{
printf("invalid argument '%s', gridfile by already set\n", argv[i]);
bad_args++;
break;
}
else
{
args->gridbz_set = 1;
args->gridbz_fn = &argv[i][3];
}
break;
default:
printf("invalid argument '%s', wrong component\n", argv[i]);
bad_args++;
break;
}
}
break;
case 'c':
params = &argv[i][2];
if(args->bz_NEU_NED_set)
{
printf("invalid argument '%s', coordinate system is already set\n", argv[i]);
bad_args++;
break;
}
if(strlen(params) > 1)
{
printf("invalid argument '%s', specify coordinate system in the input grids\n", argv[i]);
bad_args++;
break;
}
if(argv[i][2] == '1')
{
args->bz_NEU_NED_set = 1;
args->bz_NEU_NED = 1;
break;
}
else if(argv[i][2] == '2')
{
args->bz_NEU_NED_set = 1;
args->bz_NEU_NED = -1;
break;
}
else
{
printf("invalid argument '%s', there are only NED (1) and NEU (2, default) coordinate systems\n", argv[i]);
bad_args++;
break;
}
break;
case 'o':
params = &argv[i][2];
if(args->out_set>=0)
{
printf("invalid argument '%s', output format is already set\n", argv[i]);
bad_args++;
break;
}
if(strlen(params) != 1)
{
printf("invalid argument '%s', specify output format\n", argv[i]);
bad_args++;
break;
}
//TODO Add check if it is integer
args->out_set = atoi(params);
break;
default:
printf("invalid argument '%s'\n", argv[i]);
bad_args++;
break;
}
}
}
if(parsed_args > total_args)
{
//log_error("%s: too many input arguments. given %d, max %d.", progname, parsed_args, total_args);
}
if(bad_args > 0)
{
//log_error("%d bad input argument(s)", bad_args);
return 1;
}
if(parsed_args < total_args)
{
return 3;
}
return 0;
}
/* Strip trailing spaces and newlines from the end of a string */
void strstrip(char *str)
{
int i;
for(i = strlen(str) - 1; i >= 0; i--)
{
if(str[i] != ' ' && str[i] != '\n' && str[i] != '\r' && str[i] != '\0')
break;
}
str[i + 1] = '\0';
}
/* Read a single tesseroid from a string */
int gets_mag_tess(const char *str, TESSEROID *tess)
{
double w, e, s, n, top, bot, dens, suscept, Bx, By, Bz, Rx, Ry, Rz;
int nread, nchars;
nread = sscanf(str, "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf%n", &w, &e, &s,
&n, &top, &bot, &dens, &suscept, &Bx, &By, &Bz, &nchars);
if(nread != 11 || str[nchars] != '\0')
{
return 1;
}
tess->w = w;
tess->e = e;
tess->s = s;
tess->n = n;
tess->r1 = MEAN_EARTH_RADIUS + bot;
tess->r2 = MEAN_EARTH_RADIUS + top;
tess->density = dens;
tess->suscept = suscept;
tess->Bx = Bx;
tess->By = By;
tess->Bz = Bz;
tess->cos_a1 = cos(PI/2.0-DEG2RAD*(w+e)*0.5);
tess->sin_a1 = sin(PI/2.0-DEG2RAD*(w+e)*0.5);
tess->cos_b1 = cos(DEG2RAD*(s+n)*0.5);
tess->sin_b1 = sin(DEG2RAD*(s+n)*0.5);
return 0;
}
//ELDAR BAYKIEV////////////////////////////////
TESSEROID * read_mag_tess_model(FILE *modelfile, int *size)
{
TESSEROID *model, *tmp;
int buffsize = 300, line, badinput = 0, error_exit = 0;
char sbuff[10000];
/* Start with a single buffer allocation and expand later if necessary */
model = (TESSEROID *)malloc(buffsize*sizeof(TESSEROID));
if(model == NULL)
{
log_error("problem allocating initial memory to load tesseroid model.");
return NULL;
}
*size = 0;
for(line = 1; !feof(modelfile); line++)
{
if(fgets(sbuff, 10000, modelfile) == NULL)
{
if(ferror(modelfile))
{
log_error("problem encountered reading line %d.", line);
error_exit = 1;
break;
}
}
else
{
/* Check for comments and blank lines */
if(sbuff[0] == '#' || sbuff[0] == '\r' || sbuff[0] == '\n')
{
continue;
}
if(*size == buffsize)
{
buffsize += buffsize;
tmp = (TESSEROID *)realloc(model, buffsize*sizeof(TESSEROID));
if(tmp == NULL)
{
/* Need to free because realloc leaves unchanged in case of
error */
free(model);
log_error("problem expanding memory for tesseroid model.\nModel is too big.");
return NULL;
}
model = tmp;
}
/* Remove any trailing spaces or newlines */
strstrip(sbuff);
if(gets_mag_tess(sbuff, &model[*size]))
{
log_warning("bad/invalid tesseroid at line %d.", line);
badinput = 1;
continue;
}
(*size)++;
}
}
if(badinput || error_exit)
{
free(model);
return NULL;
}
/* Adjust the size of the model */
if(*size != 0)
{
tmp = (TESSEROID *)realloc(model, (*size)*sizeof(TESSEROID));
if(tmp == NULL)
{
/* Need to free because realloc leaves unchanged in case of
error */
free(model);
log_error("problem freeing excess memory for tesseroid model.");
return NULL;
}
model = tmp;
}
return model;
}
/* Read a single rectangular prism from a string */

75
lib/parsers.h Executable file
View File

@@ -0,0 +1,75 @@
/*
Input and output parsing tools.
*/
#ifndef _TESSEROIDS_PARSERS_H_
#define _TESSEROIDS_PARSERS_H_
/* Needed for definition of TESSEROID and PRISM */
#include "geometry.h"
/* Need for the definition of FILE */
#include <stdio.h>
/** Store basic input arguments and option flags */
typedef struct basic_args
{
char *inputfname; /**< name of the input file */
int verbose; /**< flag to indicate if verbose printing is enabled */
int logtofile; /**< flag to indicate if logging to a file is enabled */
char *logfname; /**< name of the log file */
} BASIC_ARGS;
typedef struct tessh_args
{
int lon_order; /**< glq order in longitude integration */
int lat_order; /**< glq order in latitude integration */
int r_order; /**< glq order in radial integration */
char *modelfname; /**< name of the file with the tesseroid model */
int verbose; /**< flag to indicate if verbose printing is enabled */
int logtofile; /**< flag to indicate if logging to a file is enabled */
char *logfname; /**< name of the log file */
int adaptative; /**< flat to indicate wether to use the adaptative size
of tesseroid algorithm */
double ratio1; /**< distance-size ratio used for recusive division */
double ratio2; /**< distance-size ratio used for recusive division */
double ratio3; /**< distance-size ratio used for recusive division */
} TESSB_ARGS;
typedef struct gradcalc_args
{
int gridbx_set;
int gridby_set;
int gridbz_set;
char* gridbx_fn;
char* gridby_fn;
char* gridbz_fn;
int out_set;
int bz_NEU_NED;
int bz_NEU_NED_set;
int verbose; /**< flag to indicate if verbose printing is enabled */
int logtofile; /**< flag to indicate if logging to a file is enabled */
} GRADCALC_ARGS;
int parse_basic_args(int argc, char **argv, const char *progname, BASIC_ARGS *args, void (*print_help)(void));
int parse_tessb_args(int argc, char **argv, const char *progname, TESSB_ARGS *args, void (*print_help)(const char *));
int parse_gradcalc_args(int argc, char **argv, const char *progname, GRADCALC_ARGS *args, void (*print_help)(const char *));
void strstrip(char *str);
int gets_mag_tess(const char *str, TESSEROID *tess);
TESSEROID * read_mag_tess_model(FILE *modelfile, int *size);
#endif

385
lib/tessb_main.cpp Executable file
View File

@@ -0,0 +1,385 @@
/*
Generic main function for the tessb* programs.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "logger.h"
#include "version.h"
#include "grav_tess.h"
#include "glq.h"
#include "constants.h"
#include "geometry.h"
#include "parsers.h"
#include "tessb_main.h"
#include "linalg.h"
#include <math.h>
/* Print the help message for tessh* programs */
void print_tessb_help(const char *progname)
{
printf("MAGNETIC TESSEROIDS\n");
printf("Usage: %s MODELFILE [OPTIONS]\n\n", progname);
if(strcmp(progname + 4, "pot") == 0)
{
printf("Calculate the potential due to a tesseroid model on\n");
}
else
{
printf("Calculate the %s component due to a tesseroid model on\n",
progname + 4);
}
printf("TODO\n");
}
/* Run the main for a generic tessh* program */
int run_tessb_main(int argc, char **argv, const char *progname,
double (*field)(TESSEROID, double, double, double, GLQ, GLQ, GLQ),
double ratio1, double ratio2, double ratio3)
{
TESSB_ARGS args;
GLQ *glq_lon, *glq_lat, *glq_r;
TESSEROID *model;
int modelsize, rc, line, points = 0, error_exit = 0, bad_input = 0;
char buff[10000];
double lon, lat, height, res;
/*variables for precalculation of trigonometrical functions for tesseroid centers*/
double cos_a2, sin_a2, cos_b2, sin_b2;
/*variables for precalculation of trigonometrical functions for grid points*/
double lon_prev, lat_prev;
double cos_a2_prev, sin_a2_prev, cos_b2_prev, sin_b2_prev;
FILE *logfile = NULL, *modelfile = NULL;
time_t rawtime;
clock_t tstart;
struct tm * timeinfo;
double (*field1)(TESSEROID, double, double, double, GLQ, GLQ, GLQ);
double (*field2)(TESSEROID, double, double, double, GLQ, GLQ, GLQ);
double (*field3)(TESSEROID, double, double, double, GLQ, GLQ, GLQ);
void (*field_triple)(TESSEROID, double, double, double, GLQ, GLQ, GLQ, double*);
double ggt_1, ggt_2, ggt_3;
double gtt_v[3];
int n_tesseroid;
log_init(LOG_INFO);
rc = parse_tessb_args(argc, argv, progname, &args, &print_tessb_help);
if(rc == 2)
{
return 0;
}
if(rc == 1)
{
log_warning("Terminating due to bad input");
log_warning("Try '%s -h' for instructions", progname);
return 1;
}
/* Set the appropriate logging level and log to file if necessary */
if(!args.verbose)
{
log_init(LOG_WARNING);
}
if(args.logtofile)
{
logfile = fopen(args.logfname, "w");
if(logfile == NULL)
{
log_error("unable to create log file %s", args.logfname);
log_warning("Terminating due to bad input");
log_warning("Try '%s -h' for instructions", progname);
return 1;
}
log_tofile(logfile, LOG_DEBUG);
}
/* Check if a custom distance-size ratio is given */
if(args.ratio1 != 0)
{
ratio1 = args.ratio1;
}
if(args.ratio2 != 0)
{
ratio2 = args.ratio2;
}
if(args.ratio3 != 0)
{
ratio3 = args.ratio3;
}
/* Print standard verbose */
log_info("%s (Tesseroids project) %s", progname, tesseroids_version);
time(&rawtime);
timeinfo = localtime(&rawtime);
log_info("(local time) %s", asctime(timeinfo));
log_info("Use recursive division of tesseroids: %s",
args.adaptative ? "True" : "False");
log_info("Distance-size ratio1 for recusive division: %g", ratio1);
log_info("Distance-size ratio2 for recusive division: %g", ratio2);
log_info("Distance-size ratio3 for recusive division: %g", ratio3);
/* Make the necessary GLQ structures */
log_info("Using GLQ orders: %d lon / %d lat / %d r", args.lon_order,
args.lat_order, args.r_order);
glq_lon = glq_new(args.lon_order, -1, 1);
glq_lat = glq_new(args.lat_order, -1, 1);
glq_r = glq_new(args.r_order, -1, 1);
if(glq_lon == NULL || glq_lat == NULL || glq_r == NULL)
{
log_error("failed to create required GLQ structures");
log_warning("Terminating due to bad input");
log_warning("Try '%s -h' for instructions", progname);
if(args.logtofile)
fclose(logfile);
return 1;
}
/* Read the tesseroid model file */
log_info("Reading magnetic tesseroid model from file %s", args.modelfname);
modelfile = fopen(args.modelfname, "r");
if(modelfile == NULL)
{
log_error("failed to open model file %s", args.modelfname);
log_warning("Terminating due to bad input");
log_warning("Try '%s -h' for instructions", progname);
if(args.logtofile)
fclose(logfile);
return 1;
}
model = read_mag_tess_model(modelfile, &modelsize);
fclose(modelfile);
if(modelsize == 0)
{
log_error("tesseroid file %s is empty", args.modelfname);
log_warning("Terminating due to bad input");
log_warning("Try '%s -h' for instructions", progname);
if(args.logtofile)
fclose(logfile);
return 1;
}
if(model == NULL)
{
log_error("failed to read model from file %s", args.modelfname);
log_warning("Terminating due to bad input");
log_warning("Try '%s -h' for instructions", progname);
if(args.logtofile)
fclose(logfile);
return 1;
}
log_info("Total of %d tesseroid(s) read", modelsize);
/* Print a header on the output with provenance information */
if(strcmp(progname + 4, "pot") == 0)
{
printf("# Potential calculated with %s %s:\n", progname,
tesseroids_version);
}
else
{
printf("# %s component calculated with %s %s:\n", progname+4, progname,
tesseroids_version);
}
printf("# local time: %s", asctime(timeinfo));
printf("# model file: %s (%d tesseroids)\n", args.modelfname, modelsize);
printf("# GLQ order: %d lon / %d lat / %d r\n", args.lon_order,
args.lat_order, args.r_order);
printf("# Use recursive division of tesseroids: %s\n",
args.adaptative ? "True" : "False");
printf("# Distance-size ratio1 for recusive division: %g\n", ratio1);
printf("# Distance-size ratio2 for recusive division: %g\n", ratio2);
printf("# Distance-size ratio3 for recusive division: %g\n", ratio3);
/////////////ELDAR BAYKIEV//////////////
/* Assign pointers to functions that calculate gravity gradient tensor components */
if (!strcmp("tessbx", progname))
{
field1 = &tess_gxx;
field2 = &tess_gxy;
field3 = &tess_gxz;
field_triple = &tess_gxx_gxy_gxz;
}
if (!strcmp("tessby", progname))
{
field1 = &tess_gxy;
field2 = &tess_gyy;
field3 = &tess_gyz;
field_triple = &tess_gxy_gyy_gyz;
}
if (!strcmp("tessbz", progname))
{
field1 = &tess_gxz;
field2 = &tess_gyz;
field3 = &tess_gzz;
field_triple = &tess_gxz_gyz_gzz;
}
/////////////ELDAR BAYKIEV//////////////
/* Read each computation point from stdin and calculate */
log_info("Calculating (this may take a while)...");
tstart = clock();
///////////////
lon_prev = 0;
lat_prev = 0;
for(line = 1; !feof(stdin); line++)
{
if(fgets(buff, 10000, stdin) == NULL)
{
if(ferror(stdin))
{
log_error("problem encountered reading line %d", line);
error_exit = 1;
break;
}
}
else
{
/* Check for comments and blank lines */
if(buff[0] == '#' || buff[0] == '\r' || buff[0] == '\n')
{
printf("%s", buff);
continue;
}
if(sscanf(buff, "%lf %lf %lf", &lon, &lat, &height) != 3)
{
log_warning("bad/invalid computation point at line %d", line);
log_warning("skipping this line and continuing");
bad_input++;
continue;
}
/* Need to remove \n and \r from end of buff first to print the
result in the end */
strstrip(buff);
/////////////ELDAR BAYKIEV//////////////
res = 0;
if(args.adaptative)
{
for(n_tesseroid = 0; n_tesseroid < modelsize; n_tesseroid++)
{
gtt_v[0] = 0;
gtt_v[1] = 0;
gtt_v[2] = 0;
double B_to_H = model[n_tesseroid].suscept/(M_0);//IMPORTANT
double M_vect[3] = {model[n_tesseroid].Bx * B_to_H, model[n_tesseroid].By * B_to_H, model[n_tesseroid].Bz * B_to_H};
double M_vect_p[3] = {0, 0, 0};
conv_vect_cblas(M_vect, (model[n_tesseroid].w + model[n_tesseroid].e)*0.5, (model[n_tesseroid].s + model[n_tesseroid].n)*0.5, lon, lat, M_vect_p);
ggt_1 = calc_tess_model_adapt(&model[n_tesseroid], 1, lon, lat, height + MEAN_EARTH_RADIUS, glq_lon, glq_lat, glq_r, field1, ratio1);
ggt_2 = calc_tess_model_adapt(&model[n_tesseroid], 1, lon, lat, height + MEAN_EARTH_RADIUS, glq_lon, glq_lat, glq_r, field2, ratio2);
ggt_3 = calc_tess_model_adapt(&model[n_tesseroid], 1, lon, lat, height + MEAN_EARTH_RADIUS, glq_lon, glq_lat, glq_r, field3, ratio3);
res = res + M_0*EOTVOS2SI*(ggt_1 * M_vect_p[0] + ggt_2 * M_vect_p[1] + ggt_3 * M_vect_p[2]) /(G*model[n_tesseroid].density*4*PI);
//printf("res %g\n", res);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
}
else
{
//precalculate trigonometrical functions
if(lon == lon_prev)
{
cos_b2 = cos_b2_prev;
sin_b2 = sin_b2_prev;
}
else
{
cos_b2 = cos(DEG2RAD*lon);
sin_b2 = sin(DEG2RAD*lon);
}
if(lat == lat_prev)
{
cos_a2 = cos_a2_prev;
sin_a2 = sin_a2_prev;
}
else
{
cos_a2 = cos(PI/2.0-DEG2RAD*lat);
sin_a2 = sin(PI/2.0-DEG2RAD*lat);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
for(n_tesseroid = 0; n_tesseroid < modelsize; n_tesseroid++)
{
gtt_v[0] = 0;
gtt_v[1] = 0;
gtt_v[2] = 0;
//ELDAR: TODO: PRECALCULATE SIC COSINE TABLES
double B_to_H = model[n_tesseroid].suscept/(M_0);//IMPORTANT
double M_vect[3] = {model[n_tesseroid].Bx * B_to_H, model[n_tesseroid].By * B_to_H, model[n_tesseroid].Bz * B_to_H};
double M_vect_p[3] = {0, 0, 0};
//conv_vect_cblas(M_vect, (model[n_tesseroid].w + model[n_tesseroid].e)*0.5, (model[n_tesseroid].s + model[n_tesseroid].n)*0.5, lon, lat, M_vect_p);
conv_vect_cblas_precalc(M_vect, model[n_tesseroid].cos_a1, model[n_tesseroid].sin_a1, model[n_tesseroid].cos_b1, model[n_tesseroid].sin_b1, cos_a2, sin_a2, cos_b2, sin_b2, M_vect_p);
calc_tess_model_triple(&model[n_tesseroid], 1, lon, lat, height + MEAN_EARTH_RADIUS, glq_lon, glq_lat, glq_r, field_triple, gtt_v);
res = res + M_0*EOTVOS2SI*(gtt_v[0] * M_vect_p[0] + gtt_v[1] * M_vect_p[1] + gtt_v[2] * M_vect_p[2]) /(G*model[n_tesseroid].density*4*PI);
}
lon_prev = lon;
lat_prev = lat;
cos_a2_prev = cos_a2;
sin_a2_prev = sin_a2;
cos_b2_prev = cos_b2;
sin_b2_prev = sin_b2;
/////////////////////////////////////////////////////////////////////////////////////////////////////////
}
printf("%s %.15g\n", buff, res);
points++;
}
}
if(bad_input)
{
log_warning("Encountered %d bad computation points which were skipped",
bad_input);
}
if(error_exit)
{
log_warning("Terminating due to error in input");
log_warning("Try '%s -h' for instructions", progname);
}
else
{
log_info("Calculated on %d points in %.5g seconds", points,
(double)(clock() - tstart)/CLOCKS_PER_SEC);
}
/* Clean up */
free(model);
glq_free(glq_lon);
glq_free(glq_lat);
glq_free(glq_r);
log_info("Done");
if(args.logtofile)
fclose(logfile);
return 0;
}

14
lib/tessb_main.h Executable file
View File

@@ -0,0 +1,14 @@
/*
Generic main function for the tessb* programs.
*/
#ifndef _TESSEROIDS_TESSH_MAIN_H_
#define _TESSEROIDS_TESSH_MAIN_H_
#include "glq.h"
#include "geometry.h"
void print_tessb_help(const char *progname);
int run_tessb_main(int argc, char **argv, const char *progname, double (*field)(TESSEROID, double, double, double, GLQ, GLQ, GLQ), double ratio1, double ratio2, double ratio3);
#endif

17
lib/version.cpp Executable file
View File

@@ -0,0 +1,17 @@
/*
Hold the version number of the project.
*/
#include <stdio.h>
#include "version.h"
/* Print version and license information */
void print_version(const char *progname)
{
printf("%s (Magnetic Tesseroids) %s\n\n", progname, tesseroids_version);
printf("Copyright (C) 2015, Eldar Baykiev.\n");
printf("This program is based on the code of Leonardo Uieda.\n");
printf("<http://tesseroids.readthedocs.org/>\n");
printf("Developed by Eldar Baykiev.\n");
}

18
lib/version.h Executable file
View File

@@ -0,0 +1,18 @@
/*
Hold the version number of the project.
*/
#ifndef _TESSEROIDS_VERSION_H_
#define _TESSEROIDS_VERSION_H_
/** Current project version number */
const char tesseroids_version[] = "1.1";
/** Print version and license information
@param progname name of the program
*/
void print_version(const char *progname);
#endif