initial upload

This commit is contained in:
张壹 2021-05-05 10:58:03 +08:00
parent d6ffc7f33c
commit f1cf25db22
114 changed files with 83953 additions and 0 deletions

4
.gitignore vendored
View File

@ -50,3 +50,7 @@ modules.order
Module.symvers
Mkfile.old
dkms.conf
build/
.vscode/
.DS_Store

70
CITATION.txt Executable file
View File

@ -0,0 +1,70 @@
Citing
======
Geophysics paper
----------------
To cite *Tesseroids* in publications, please use our paper published in
*Geophysics*:
Uieda, L., V. Barbosa, and C. Braitenberg (2016), Tesseroids:
Forward-modeling gravitational fields in spherical coordinates, GEOPHYSICS,
F41-F48,
doi:`10.1190/geo2015-0204.1 <http://dx.doi.org/10.1190/geo2015-0204.1>`__.
You can download a copy of the `paper PDF
<http://www.leouieda.com/papers/paper-tesseroids-2016.html>`__ and see all
source code used in the paper at
`the Github repository <https://github.com/pinga-lab/paper-tesseroids>`__.
Please note that **citing the paper is prefered** over citing the previous
conference proceedings.
If you're a BibTeX user::
@article{uieda2016,
title = {Tesseroids: {{Forward}}-modeling gravitational fields in spherical coordinates},
author = {Uieda, L. and Barbosa, V. and Braitenberg, C.},
issn = {0016-8033},
doi = {10.1190/geo2015-0204.1},
url = {http://library.seg.org/doi/abs/10.1190/geo2015-0204.1},
journal = {GEOPHYSICS},
month = jul,
year = {2016},
pages = {F41--F48},
}
Source code
-----------
You can refer to individual versions of Tesseroids through their DOIs.
However, please **also cite the Geophysics paper**.
For example. if you want to mention that you used the 1.1.1 version,
you can go to :ref:`the Releases page <releases>` of the documentation
and get the DOI link for that version.
This link will not be broken, even if I move the site somewhere else.
You can also cite the specific version instead of just providing the link.
If you click of the DOI link for 1.1.1, the Zenodo page will
recommend that you cite it as:
Uieda, Leonardo. (2015). Tesseroids v1.1.1: Forward modeling of
gravitational fields in spherical coordinates. Zenodo. 10.5281/zenodo.15800
Conference proceeding
---------------------
The previous way citation for Tesseroids was a conference proceeding from the
2011 GOCE User Workshop:
Uieda, L., E. P. Bomfim, C. Braitenberg, and E. Molina (2011),
Optimal forward calculation method of the Marussi tensor
due to a geologic structure at GOCE height,
Proceedings of the 4th International GOCE User Workshop.
Download a `PDF version of the proceedings
<http://www.leouieda.com/pdf/goce-2011.pdf>`__.
You can also see the poster and source code at
the `Github repository <https://github.com/leouieda/goce2011>`__.

26
CMakeLists.txt Normal file
View File

@ -0,0 +1,26 @@
cmake_minimum_required(VERSION 3.15.2)
#
project(LIBTESS VERSION 1.6)
#
if(${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Linux")
message(STATUS "Platform: " ${CMAKE_HOST_SYSTEM_NAME})
set(CMAKE_INSTALL_PREFIX /usr/local)
elseif (${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Darwin")
message(STATUS "Platform: " ${CMAKE_HOST_SYSTEM_NAME})
set(CMAKE_INSTALL_PREFIX /usr/local)
elseif (${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Windows")
message(STATUS "Platform: " ${CMAKE_HOST_SYSTEM_NAME})
# 使MinGW GCC
#set(CMAKE_C_COMPILER gcc)
#set(CMAKE_CXX_COMPILER g++)
set(CMAKE_INSTALL_PREFIX D:/Library)
else()
message(STATUS "Platform: " ${CMAKE_HOST_SYSTEM_NAME})
set(CMAKE_INSTALL_PREFIX /usr/local)
endif()
message(STATUS "Install prefix: " ${CMAKE_INSTALL_PREFIX})
#
add_subdirectory(lib)
add_subdirectory(toolkits)
add_subdirectory(test)

25
LICENSE.txt Executable file
View File

@ -0,0 +1,25 @@
Copyright (c) 2012-2017, Leonardo Uieda
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of Leonardo Uieda nor the names of any contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

210
README.md Executable file
View File

@ -0,0 +1,210 @@
# ![Tesseroids](https://raw.githubusercontent.com/leouieda/tesseroids/master/doc/_static/banner.png)
[Documentation](http://tesseroids.leouieda.com) |
[Download](https://github.com/leouieda/tesseroids/releases)
[![Version number](http://img.shields.io/github/release/leouieda/tesseroids.svg?style=flat)](https://github.com/leouieda/tesseroids/releases)
[![Travis CI build status](http://img.shields.io/travis/leouieda/tesseroids/master.svg?style=flat)](https://travis-ci.org/leouieda/tesseroids)
[![BSD license](http://img.shields.io/badge/license-BSD-lightgrey.svg?style=flat)](https://github.com/leouieda/tesseroids/blob/master/LICENSE.txt)
[![DOI](https://zenodo.org/badge/doi/10.5281/zenodo.582366.svg)](http://dx.doi.org/10.5281/zenodo.582366)
*Forward modeling of gravitational fields in spherical coordinates.*
Developed by [Leonardo Uieda](http://www.leouieda.com)
in cooperation with [Carla Braitenberg](http://lithoflex.org/).
## About
*Tesseroids* is a collection of **command-line tools**
for modeling the gravitational potential, acceleration, and
gradient (Marussi) tensor.
The mass models can be made of right rectangular prisms or tesseroids
(spherical prisms).
Computation for rectangular prisms can be made in Cartesian or spherical
(geocentric) coordinates.
[![This is a tesseroid.](https://raw.githubusercontent.com/leouieda/tesseroids/master/doc/_static/tesseroid.png)](http://tesseroids.leouieda.com/en/latest/theory.html#what-is-a-tesseroid-anyway)
## License
*Tesseroids* is [free software](http://www.fsf.org/about/what-is-free-software)
made available under the terms of the
BSD 3-clause license.
See [LICENSE.txt](https://github.com/leouieda/tesseroids/blob/master/LICENSE.txt).
## Citing
*Tesseroids* is research software made by scientists.
If you use it in your research,
please **cite** our *Geophysics* paper in your publications:
> Uieda, L., V. Barbosa, and C. Braitenberg (2016), Tesseroids: Forward-modeling gravitational fields in spherical coordinates, GEOPHYSICS, F41-F48, doi:[10.1190/geo2015-0204.1](http://dx.doi.org/10.1190/geo2015-0204.1).
You can download a copy of the paper PDF at
[leouieda.com/papers/paper-tesseroids-2016.html](http://www.leouieda.com/papers/paper-tesseroids-2016.html)
and see all source code used in the paper at the Github repository
[pinga-lab/paper-tesseroids](https://github.com/pinga-lab/paper-tesseroids).
See [CITATION.txt](https://github.com/leouieda/tesseroids/blob/master/CITATION.txt)
or the [Citing](http://tesseroids.leouieda.com/en/latest/citation.html)
page of the documentation for more information.
## Installing
The easiest way to install is to download the latest compiled binary
distribution from:
https://github.com/leouieda/tesseroids/releases/latest
We offer binaries for Windows (32 and 64 bit)
and GNU/Linux (32 and 64 bit).
Once downloaded, simply unpack the archive in the desired directory.
The executables will be in the `bin` folder.
For easier access to the programs, consider
[adding the bin folder to your PATH environment
variable](http://www.computerhope.com/issues/ch000549.htm).
## Getting started
Take a look at the examples in the
[Cookbook](http://tesseroids.leouieda.com/en/latest/cookbook.html).
They contain scripts that run *Tesseroids* and some Python code to plot the
results.
The documentation contains sections on
[the theory and equations](http://tesseroids.leouieda.com/en/latest/theory.html)
and [usage instructions](http://tesseroids.leouieda.com/en/latest/usage.html).
Also, all programs accept the `-h` flag to print the instructions for using
that particular program. For example:
$ tessgrd -h
Usage: tessgrd [PARAMS] [OPTIONS]
Make a regular grid of points.
All units either SI or degrees!
Output:
Printed to standard output (stdout) in the format:
lon1 lat1 height
lon2 lat1 height
... ... ...
lonNLON lat1 height
lon1 lat2 height
... ... ...
... ... ...
lonNLON latNLAT height
* Comments about the provenance of the data are inserted into
the top of the output
Parameters:
-r W/E/S/N: Bounding region of the grid.
-b NLON/NLAT: Number of grid points in the
longitudinal and latitudinal directions.
-z HEIGHT: Height of the grid with respect to the
mean Earth radius.
-h Print instructions.
--version Print version and license information.
Options:
-v Enable verbose printing to stderr.
-lFILENAME Print log messages to file FILENAME.
Part of the Tesseroids package.
Project site: <http://fatiando.org/software/tesseroids>
Report bugs at: <http://code.google.com/p/tesseroids/issues/list>
## Getting help
Write an e-mail to [Leonardo Uieda](http://www.leouieda.com/),
or [tweet](https://twitter.com/leouieda),
or [Google Hangout](https://plus.google.com/+LeonardoUieda).
**Even better**, submit a bug report/feature request/question to the
[Github issue tracker](https://github.com/leouieda/tesseroids/issues).
## Compiling from source
If you want to build *Tesseroids* from source, you'll need:
* A C compiler (preferably [GCC](http://gcc.gnu.org))
* The build tool [SCons](http://www.scons.org/)
### Setting up SCons
Tesseroids uses the build tool SCons.
A `SConstruct` file (`Makefile` equivalent)
is used to define the compilation rules.
The advantage of SCons over Make is that it automatically detects your system
settings.
You will have to download and install SCons
in order to easily compile Tesseroids.
SCons is available for both GNU/Linux and Windows
so compiling should work the same on both platforms.
SCons requires that you have [Python](http://www.python.org) installed.
Follow the instructions in the [SCons website](http://www.scons.org/)
to install it.
Python is usually installed by default on most GNU/Linux systems.
Under Windows you will have to put SCons on
your `PATH` environment variable
in order to use it from the command line.
It is usually located in the `Scripts` directory of your Python installation.
On GNU/Linux, SCons will generally use
the GCC compiler to compile sources.
On Windows it will search for an existing compiler.
We recommend that you install GCC on Windows using
[MinGW](http://mingw.org/).
### Compiling
Download a source distribution and
unpack the archive anywhere you want
(e.g., `~/tesseroids` or `C:\tesseroids` or whatever).
To compile,
open a terminal (or `cmd.exe` on Windows)
and go to the directory where you unpacked (use the `cd` command).
Then, type the following and hit `Enter`:
scons
If everything goes well, the compiled executables will be placed on a `bin`
folder.
To clean up the build (delete all generated files), run:
scons -c
If you get any strange errors or the code doesn't compile for some reason,
please [submit a bug report](https://github.com/leouieda/tesseroids/issues).
Don't forget to copy the output of running `scons`.
### Testing the build
After the compilation,
a program called `tesstest`
will be placed in the directory where you unpacked the source.
This program runs the [unit tests](https://en.wikipedia.org/wiki/Unit_testing)
for *Tesseroids* (sources in the `test` directory).
To run the test suite, simply execute `tesstest` with no arguments:
tesstest
or on GNU/Linux:
./tesstest
A summary of all tests (pass or fail) will be printed on the screen.
If all tests pass,
the compilation probably went well.
If any test fail,
please [submit a bug report](https://github.com/leouieda/tesseroids/issues)
with the output of running `tesstest`.

View File

@ -0,0 +1,10 @@
:: Calculate effect of the model at a low height using difference distance-size
:: ratios for the recursive division of tesseroids.
:: WARNING: This is only an example. You should not use the -t option in
:: practice
tessgrd -r-3/3/-3/3 -b50/50 -z4e03 | ^
tessgzz model.txt -t0.0001 -lratio1.log | ^
tessgzz model.txt -t0.5 -lratio2.log | ^
tessgzz model.txt -t1 -lratio3.log | ^
tessgzz model.txt -v -lratio-default.log > output.txt

View File

@ -0,0 +1,11 @@
#!/bin/bash
# Calculate effect of the model at a low height using difference distance-size
# ratios for the recursive division of tesseroids.
# WARNING: This is only an example. You should not use the -t option in practice
tessgrd -r-3/3/-3/3 -b50/50 -z4e03 | \
tessgzz model.txt -t0.0001 -lratio1.log | \
tessgzz model.txt -t0.5 -lratio2.log | \
tessgzz model.txt -t1 -lratio3.log | \
tessgzz model.txt -v -lratio-default.log > output.txt

View File

@ -0,0 +1,2 @@
# Test tesseroid model file
-1.5 1.5 -1.5 1.5 0 -5000 200

18
cookbook/custom_ratio/plot.py Executable file
View File

@ -0,0 +1,18 @@
"""
Plot the columns of the output files
"""
import sys
from matplotlib import pyplot as plt
import numpy as np
data = np.loadtxt(sys.argv[1], unpack=True)
shape = (int(sys.argv[2]), int(sys.argv[3]))
lon = np.reshape(data[0], shape)
lat = np.reshape(data[1], shape)
for i, value in enumerate(data[3:]):
value = np.reshape(value, shape)
plt.figure(figsize=(4, 3))
plt.title("Column %d" % (i + 4))
plt.contourf(lon, lat, value, 50)
plt.colorbar()
plt.savefig('column%d.png' % (i + 4))

22805
cookbook/dem_brasil/dem.xyz Executable file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,22 @@
:: First, insert the density information into
:: the DEM file using the Python script.
python dem_density.py dem.xyz > dem-dens.txt
:: Next, use the modified DEM with tessmodgen
:: to create a tesseroid model
tessmodgen -s0.166667/0.166667 -z0 -v < dem-dens.txt ^
> dem-tess.txt
:: Calculate the GGT on a regular grid at 250km
:: use the -l option to log the processes to files
:: (usefull to diagnose when things go wrong)
:: The output is dumped to dem-ggt.txt
tessgrd -r-60/-45/-30/-15 -b50/50 -z250e03 | ^
tessgxx dem-tess.txt -lgxx.log | ^
tessgxy dem-tess.txt -lgxy.log | ^
tessgxz dem-tess.txt -lgxz.log | ^
tessgyy dem-tess.txt -lgyy.log | ^
tessgyz dem-tess.txt -lgyz.log | ^
tessgzz dem-tess.txt -lgzz.log -v > dem-ggt.txt

View File

@ -0,0 +1,22 @@
#!/bin/bash
# First, insert the density information into
# the DEM file using the Python script.
python dem_density.py dem.xyz > dem-dens.txt
# Next, use the modified DEM with tessmodgen
# to create a tesseroid model
tessmodgen -s0.166667/0.166667 -z0 -v < dem-dens.txt \
> dem-tess.txt
# Calculate the GGT on a regular grid at 250km
# use the -l option to log the processes to files
# (usefull to diagnose when things go wrong)
# The output is dumped to dem-ggt.txt
tessgrd -r-60/-45/-30/-15 -b50/50 -z250e03 | \
tessgxx dem-tess.txt -lgxx.log | \
tessgxy dem-tess.txt -lgxy.log | \
tessgxz dem-tess.txt -lgxz.log | \
tessgyy dem-tess.txt -lgyy.log | \
tessgyz dem-tess.txt -lgyz.log | \
tessgzz dem-tess.txt -lgzz.log -v > dem-ggt.txt

View File

@ -0,0 +1,13 @@
"""
Assign density values for the DEM points.
"""
import sys
import numpy
lons, lats, heights = numpy.loadtxt(sys.argv[1], unpack=True)
for i in xrange(len(heights)):
if heights[i] >=0:
print "%lf %lf %lf %lf" % (lons[i], lats[i], heights[i], 2670.0)
else:
print "%lf %lf %lf %lf" % (lons[i], lats[i], heights[i], 1670.0)

117
cookbook/dem_brasil/plot.py Executable file
View File

@ -0,0 +1,117 @@
# Make some nice plots of the DEM, the densities used and the calculated GGT
import numpy
from matplotlib import pyplot as plt
from mpl_toolkits.basemap import Basemap
# Plot the DEM and density maps
################################################################################
lons, lats, heights, dens = numpy.loadtxt('dem-dens.txt', unpack=True)
nlons = 151 # Number of points in the longitude direction
nlats = len(lats)/nlons
# Convert the lists to 2D grids
glons = numpy.reshape(lons, (nlats, nlons))
glats = numpy.reshape(lats, (nlats, nlons))
gheights = numpy.reshape(heights, (nlats, nlons))
gdens = numpy.reshape(dens, (nlats, nlons))
# Set up a Mercator projection
bm = Basemap(projection='merc',
llcrnrlon=lons[0], llcrnrlat=lats[-1],
urcrnrlon=lons[-1], urcrnrlat=lats[0],
lon_0=lons[nlons//2], lat_0=lats[len(lats)//2],
resolution='l',
area_thresh=10000)
glons, glats = bm(glons, glats)
# Plot the DEM first
print "Plotting DEM"
plt.figure()
bm.drawmeridians(numpy.arange(lons[0]+5., lons[-1], 5.),
labels=[0,0,0,1], fontsize=12, linewidth=0.5)
bm.drawparallels(numpy.arange(lats[-1]+5., lats[0], 5.),
labels=[1,0,0,0], fontsize=12, linewidth=0.5)
bm.drawcoastlines(linewidth=1)
bm.drawmapboundary()
bm.drawcountries(linewidth=0.8)
# Do the pseudocolor plot
cf = bm.pcolor(glons, glats, gheights, cmap=plt.cm.gist_earth, \
vmin=-1000, vmax=1000)
cb = plt.colorbar()
cb.set_label("Height [m]")
# Plot the calculation area used later
w = -60
e = -45
s = -30
n = -15
areax, areay = bm([w, w, e, e, w], \
[n, s, s, n, n])
bm.plot(areax, areay, '-r', label="Computation grid", linewidth=1.8)
plt.legend(shadow=True, loc='lower right', prop={'size':10})
# Save a png figure
plt.savefig('dem.png')
# Now plot the densities
print "Plotting density model"
plt.figure()
bm.drawmeridians(numpy.arange(lons[0]+5., lons[-1], 5.),
labels=[0,0,0,1], fontsize=12, linewidth=0.5)
bm.drawparallels(numpy.arange(lats[-1]+5., lats[0], 5.),
labels=[1,0,0,0], fontsize=12, linewidth=0.5)
bm.drawcoastlines(linewidth=1)
bm.drawmapboundary()
bm.drawcountries(linewidth=0.8)
# Do the pseudocolor plot
cf = bm.pcolor(glons, glats, gdens, cmap=plt.cm.jet)
cb = plt.colorbar()
cb.set_label(r"Density [$g.cm^{-3}$]")
# Save a png figure
plt.savefig('dem-dens.png')
# Plot the GGT
################################################################################
print "Plotting GGT"
data = numpy.loadtxt('dem-ggt.txt')
lons, lats, heights, gxx, gxy, gxz, gyy, gyz, gzz = data.T
nlons = 50 # Number of points in the longitude direction
nlats = len(lats)/nlons
# Convert the lists to 2D grids
glons = numpy.reshape(lons, (nlats, nlons))
glats = numpy.reshape(lats, (nlats, nlons))
# Set up a Mercator projection
bm = Basemap(projection='merc', \
llcrnrlon=lons[0], llcrnrlat=lats[0], \
urcrnrlon=lons[-1], urcrnrlat=lats[-1], \
lon_0=lons[nlons//2], lat_0=lats[len(lats)//2],
resolution='l', area_thresh=10000)
glons, glats = bm(glons, glats)
# Plot each component
fig = plt.figure(figsize=(14,9))
plt.subplots_adjust(wspace=0.35)
titles = [r"$g_{xx}$", r"$g_{xy}$", r"$g_{xz}$", r"$g_{yy}$", r"$g_{yz}$",
r"$g_{zz}$"]
fields = [gxx, gxy, gxz, gyy, gyz, gzz]
for i, args in enumerate(zip(fields, titles)):
field, title = args
ax = plt.subplot(2, 3, i + 1, aspect='equal')
plt.title(title, fontsize=18)
# Make it a 2D grid
gfield = numpy.reshape(field, (nlats, nlons))
# Plot the coastlines and etc
mer = bm.drawmeridians(numpy.arange(lons[0]+3, lons[-1]-3, 3),
labels=[0,0,0,1], fontsize=9, linewidth=0.5)
bm.drawparallels(numpy.arange(lats[0]+3, lats[-1]-3, 3),
labels=[1,0,0,0], fontsize=9, linewidth=0.5)
bm.drawcoastlines(linewidth=1)
bm.drawmapboundary()
bm.drawcountries(linewidth=1)
bm.drawstates(linewidth=0.2)
# Make a pseudocolor plot
cf = bm.pcolor(glons, glats, gfield, cmap=plt.cm.jet)
cb = plt.colorbar(orientation='vertical', format='%.2f', shrink=0.8)
cb.set_label(r"$E\"otv\"os$")
# Save a png figure
plt.savefig('dem-ggt.png')

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 372 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 KiB

View File

@ -0,0 +1,3 @@
# Test prism model file
2000 5000 2000 15000 0 5000 1000
10000 18000 10000 18000 0 5000 -1000

25
cookbook/simple_prism/plot.py Executable file
View File

@ -0,0 +1,25 @@
"""
Plot the columns of the output files
"""
import sys
import pylab
data = pylab.loadtxt(sys.argv[1], unpack=True)
shape = (int(sys.argv[2]), int(sys.argv[3]))
lon = pylab.reshape(data[0], shape)
lat = pylab.reshape(data[1], shape)
xmin, xmax = lon.min(), lon.max()
ymin, ymax = lat.min(), lat.max()
for i, value in enumerate(data[3:]):
value = pylab.reshape(value, shape)
pylab.figure(figsize=(4, 3))
pylab.title("Column %d" % (i + 4))
pylab.axis('scaled')
pylab.pcolor(lon, lat, value)
pylab.colorbar()
pylab.contour(lon, lat, value, 12, color='k')
#pylab.xlabel("Longitude")
#pylab.ylabel("Latitude")
pylab.xlim(xmin, xmax)
pylab.ylim(ymin, ymax)
pylab.savefig('column%d.png' % (i + 4))

View File

@ -0,0 +1,11 @@
:: Generate a regular grid, pipe it to all the computation programs,
:: and write the result to output.txt
tessgrd -r0/20000/0/20000 -b50/50 -z1000 | ^
prismpot model.txt | ^
prismgx model.txt | prismgy model.txt | prismgz model.txt | ^
prismgxx model.txt | prismgxy model.txt | ^
prismgxz model.txt | prismgyy model.txt | ^
prismgyz model.txt | prismgzz model.txt > output.txt

Binary file not shown.

After

Width:  |  Height:  |  Size: 585 KiB

View File

@ -0,0 +1,11 @@
#!/bin/bash
# Generate a regular grid, pipe it to all the computation programs,
# and write the result to output.txt
tessgrd -r0/20000/0/20000 -b50/50 -z1000 | \
prismpot model.txt | \
prismgx model.txt | prismgy model.txt | prismgz model.txt | \
prismgxx model.txt | prismgxy model.txt | \
prismgxz model.txt | prismgyy model.txt | \
prismgyz model.txt | prismgzz model.txt > output.txt

3
cookbook/simple_tess/model.txt Executable file
View File

@ -0,0 +1,3 @@
# Test tesseroid model file
10 20 10 20 0 -50000 200
-20 -10 -20 -10 0 -30000 -500

29
cookbook/simple_tess/plot.py Executable file
View File

@ -0,0 +1,29 @@
"""
Plot the columns of the output files
"""
import sys
from matplotlib import pyplot as plt
from mpl_toolkits.basemap import Basemap
import numpy as np
# Set up a projection
bm = Basemap(projection='ortho', lon_0=0, lat_0=0,
resolution='l', area_thresh=10000)
# Load the data and make them into matrices
data = np.loadtxt(sys.argv[1], unpack=True)
shape = (int(sys.argv[2]), int(sys.argv[3]))
lon = data[0].reshape(shape)
lat = data[1].reshape(shape)
glon, glat = bm(lon, lat)
plt.figure(figsize=(14, 12))
for i, value in enumerate(data[3:]):
plt.subplot(3, 4, i + 1)
plt.title("Column %d" % (i + 4))
bm.drawcoastlines()
bm.drawmapboundary()
bm.contourf(glon, glat, value.reshape(shape), 15, cmap=plt.cm.RdBu_r)
plt.colorbar(orientation="horizontal", pad=0, aspect=30)
plt.tight_layout()
plt.savefig('output.png')

View File

@ -0,0 +1,12 @@
:: Generate a regular grid, pipe it to all the computation programs,
:: and write the result to output.txt
tessgrd -r-45/45/-45/45 -b101/101 -z260e03 | ^
tesspot model.txt | ^
tessgx model.txt | tessgy model.txt | tessgz model.txt | ^
tessgxx model.txt | tessgxy model.txt | ^
tessgxz model.txt | tessgyy model.txt | ^
tessgyz model.txt | tessgzz model.txt -v -llog.txt > output.txt
:: Make a plot with the columns of output.txt
python plot.py output.txt 101 101

Binary file not shown.

After

Width:  |  Height:  |  Size: 389 KiB

View File

@ -0,0 +1,14 @@
#!/bin/bash
# Generate a regular grid, pipe it to all the computation programs,
# and write the result to output.txt
tessgrd -r-45/45/-45/45 -b101/101 -z260e03 | \
tesspot model.txt | \
tessgx model.txt | tessgy model.txt | tessgz model.txt | \
tessgxx model.txt | tessgxy model.txt | \
tessgxz model.txt | tessgyy model.txt | \
tessgyz model.txt | tessgzz model.txt -v -llog.txt > output.txt
# Make a plot with the columns of output.txt
python plot.py output.txt 101 101

32
cookbook/tess2prism/plot.py Executable file
View File

@ -0,0 +1,32 @@
"""
Plot the columns of the output files
"""
import sys
import pylab
from mpl_toolkits.basemap import Basemap
# Set up a projection
bm = Basemap(projection='ortho', lon_0=-80, lat_0=-40,
resolution='l', area_thresh=10000)
data = pylab.loadtxt(sys.argv[1], unpack=True)
shape = (int(sys.argv[2]), int(sys.argv[3]))
lon = pylab.reshape(data[0], shape)
lat = pylab.reshape(data[1], shape)
glon, glat = bm(lon, lat)
for i, value in enumerate(data[3:]):
value = pylab.reshape(value, shape)
pylab.figure(figsize=(4, 3))
pylab.title("Column %d" % (i + 4))
bm.drawcoastlines()
#bm.fillcontinents(color='coral',lake_color='aqua')
#bm.drawmapboundary(fill_color='aqua')
bm.drawmapboundary()
bm.drawparallels(pylab.arange(-90.,120.,30.))
bm.drawmeridians(pylab.arange(0.,420.,60.))
#bm.bluemarble()
bm.pcolor(glon, glat, value)
pylab.colorbar()
#bm.contour(glon, glat, value, 12, linewidth=3)
pylab.savefig('column%d.png' % (i + 4))

134
cookbook/tess2prism/result.svg Executable file
View File

@ -0,0 +1,134 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="1088.5714"
height="1122.8572"
id="svg2"
version="1.1"
inkscape:version="0.48.2 r9819"
sodipodi:docname="result.svg"
inkscape:export-filename="/home/leo/src/tesseroids/dev/cookbook/tess2prism/tess2prism.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="1"
inkscape:pageshadow="2"
inkscape:zoom="0.35"
inkscape:cx="182.14285"
inkscape:cy="492.85716"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1680"
inkscape:window-height="1003"
inkscape:window-x="0"
inkscape:window-y="25"
inkscape:window-maximized="1"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(165.71428,783.35211)">
<image
y="-509.06641"
x="522.85712"
id="image3026"
xlink:href="file:///home/leo/src/tesseroids/dev/cookbook/tess2prism/column7.png"
height="300"
width="400" />
<image
y="-234.78065"
x="522.85712"
id="image3059"
xlink:href="file:///home/leo/src/tesseroids/dev/cookbook/tess2prism/column10.png"
height="300"
width="400" />
<image
y="39.505058"
x="522.85712"
id="image3092"
xlink:href="file:///home/leo/src/tesseroids/dev/cookbook/tess2prism/column13.png"
height="300"
width="400" />
<image
y="-783.35211"
x="179.99997"
id="image2993"
xlink:href="file:///home/leo/src/tesseroids/dev/cookbook/tess2prism/column4.png"
height="300"
width="400" />
<image
y="-509.06641"
x="179.99997"
id="image3015"
xlink:href="file:///home/leo/src/tesseroids/dev/cookbook/tess2prism/column6.png"
height="300"
width="400" />
<image
y="-234.78065"
x="179.99997"
id="image3048"
xlink:href="file:///home/leo/src/tesseroids/dev/cookbook/tess2prism/column9.png"
height="300"
width="400" />
<image
y="39.505058"
x="179.99997"
id="image3081"
xlink:href="file:///home/leo/src/tesseroids/dev/cookbook/tess2prism/column12.png"
height="300"
width="400" />
<image
y="-509.06641"
x="-165.71428"
id="image3004"
xlink:href="file:///home/leo/src/tesseroids/dev/cookbook/tess2prism/column5.png"
height="300"
width="400" />
<image
y="-234.78065"
x="-165.71428"
id="image3037"
xlink:href="file:///home/leo/src/tesseroids/dev/cookbook/tess2prism/column8.png"
height="300"
width="400" />
<image
y="39.505058"
x="-165.71428"
id="image3070"
xlink:href="file:///home/leo/src/tesseroids/dev/cookbook/tess2prism/column11.png"
height="300"
width="400" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -0,0 +1,11 @@
# Prisms converted from tesseroid model with tess2prism 1.1dev
# local time: Wed May 16 14:34:47 2012
# tesseroids file: stdin
# conversion type: equal mass|spherical coordinates
# format: dx dy dz density lon lat r
# Test tesseroid model file
221766.31696055 169882.854778591 50000 499.977196258595 -76 -40 6378137
221766.31696055 169882.854778591 50000 499.977196258595 -78 -40 6378137
221766.31696055 169882.854778591 50000 499.977196258595 -80 -40 6378137
221766.31696055 169882.854778591 50000 499.977196258595 -82 -40 6378137
221766.31696055 169882.854778591 50000 499.977196258595 -84 -40 6378137

View File

@ -0,0 +1,6 @@
# Test tesseroid model file
-77 -75 -41 -39 0 -50000 500
-79 -77 -41 -39 0 -50000 500
-81 -79 -41 -39 0 -50000 500
-83 -81 -41 -39 0 -50000 500
-85 -83 -41 -39 0 -50000 500

View File

@ -0,0 +1,21 @@
:: Generate a prism model from a tesseroid model.
:: Prisms will have the same mass as the tesseroids and
:: associated spherical coordinates of the center of
:: the top of the tesseroid.
tess2prism.exe < tess-model.txt > prism-model.txt
:: Generate a regular grid in spherical coordinates,
:: pipe the grid to the computation programs,
:: and dump the result on output.txt
:: prismpots calculates the potential in spherical
:: coordinates, prismgs calculates the full
:: gravity vector, and prismggts calculates the full
:: gravity gradient tensor.
tessgrd -r-160/0/-80/0 -b100/100 -z250e03 | ^
prismpots prism-model.txt | ^
prismgs prism-model.txt | ^
prismggts prism-model.txt -v > output.txt

Binary file not shown.

After

Width:  |  Height:  |  Size: 888 KiB

View File

@ -0,0 +1,21 @@
#!/bin/bash
# Generate a prism model from a tesseroid model.
# Prisms will have the same mass as the tesseroids and
# associated spherical coordinates of the center of
# the top of the tesseroid.
tess2prism < tess-model.txt > prism-model.txt
# Generate a regular grid in spherical coordinates,
# pipe the grid to the computation programs,
# and dump the result on output.txt
# prismpots calculates the potential in spherical
# coordinates, prismgs calculates the full
# gravity vector, and prismggts calculates the full
# gravity gradient tensor.
tessgrd -r-160/0/-80/0 -b100/100 -z250e03 | \
prismpots prism-model.txt | \
prismgs prism-model.txt | \
prismggts prism-model.txt -v > output.txt

View File

@ -0,0 +1,25 @@
"""
Plot the columns of the output files
"""
import sys
import pylab
data = pylab.loadtxt(sys.argv[1], unpack=True)
shape = (int(sys.argv[2]), int(sys.argv[3]))
lon = pylab.reshape(data[0], shape)*0.001
lat = pylab.reshape(data[1], shape)*0.001
xmin, xmax = lon.min(), lon.max()
ymin, ymax = lat.min(), lat.max()
for i, value in enumerate(data[3:]):
value = pylab.reshape(value, shape)
pylab.figure(figsize=(4, 3))
pylab.title("Column %d" % (i + 4))
pylab.axis('scaled')
pylab.pcolor(lon, lat, value)
pylab.colorbar()
pylab.contour(lon, lat, value, 12, color='k')
#pylab.xlabel("Longitude")
#pylab.ylabel("Latitude")
pylab.xlim(xmin, xmax)
pylab.ylim(ymin, ymax)
pylab.savefig('column%d.png' % (i + 4))

View File

@ -0,0 +1,9 @@
# Prisms converted from tesseroid model with tess2prism 1.1dev
# local time: Tue May 8 14:55:02 2012
# tesseroids file: stdin
# conversion type: flatten
# format: x1 x2 y1 y2 z1 z2 density
# Test tesseroid model file
1111100 1666650 1111100 1666650 0 30000 487.534658568521
-1111100 1111100 -1666650 -1111100 0 50000 198.175508383774
-1777760 -1111100 -1666650 555550 0 30000 -291.9029748328

View File

@ -0,0 +1,4 @@
# Test tesseroid model file
10 15 10 15 0 -30000 500
-15 -10 -10 10 0 -50000 200
-15 5 -16 -10 0 -30000 -300

View File

@ -0,0 +1,21 @@
:: Generate a prism model from a tesseroid model by
:: flattening the tesseroids (1 degree = 111.11 km).
:: This way the converted prisms can be used
:: with the prism* programs in Cartesian coordinates.
tess2prism --flatten < tess-model.txt > prism-model.txt
:: Generate a regular grid in Cartesian coordinates,
:: pipe the grid to the computation programs,
:: and dump the result on output.txt
tessgrd -r-3e06/3e06/-3e06/3e06 -b50/50 -z250e03 | ^
prismpot prism-model.txt | ^
prismgx prism-model.txt | ^
prismgy prism-model.txt | ^
prismgz prism-model.txt | ^
prismgxx prism-model.txt | prismgxy prism-model.txt | ^
prismgxz prism-model.txt | prismgyy prism-model.txt | ^
prismgyz prism-model.txt | prismgzz prism-model.txt > output.txt

Binary file not shown.

After

Width:  |  Height:  |  Size: 575 KiB

View File

@ -0,0 +1,21 @@
#!/bin/bash
# Generate a prism model from a tesseroid model by
# flattening the tesseroids (1 degree = 111.11 km).
# This way the converted prisms can be used
# with the prism* programs in Cartesian coordinates.
tess2prism --flatten < tess-model.txt > prism-model.txt
# Generate a regular grid in Cartesian coordinates,
# pipe the grid to the computation programs,
# and dump the result on output.txt
tessgrd -r-3e06/3e06/-3e06/3e06 -b50/50 -z250e03 | \
prismpot prism-model.txt | \
prismgx prism-model.txt | \
prismgy prism-model.txt | \
prismgz prism-model.txt | \
prismgxx prism-model.txt | prismgxy prism-model.txt | \
prismgxz prism-model.txt | prismgyy prism-model.txt | \
prismgyz prism-model.txt | prismgzz prism-model.txt > output.txt

BIN
cookbook/tesslayers/layers.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

1683
cookbook/tesslayers/layers.txt Executable file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,34 @@
import numpy as np
import fatiando as ft
shape = (41, 41)
x, y = ft.grd.regular((-10, 10, 30, 50), shape)
height = 800 - 1000*ft.utils.gaussian2d(x, y, 3, 1, x0=0, y0=37)
rel = -7000*ft.utils.gaussian2d(x, y, 3, 5, x0=0, y0=40)
thick = height - rel
dens = 1900*np.ones_like(thick)
data = np.transpose([x, y, height, thick, dens])
with open('layers.txt', 'w') as f:
f.write("# Synthetic layer model of sediments and topography\n")
f.write("# Columns are:\n")
f.write("# lon lat height thickness density\n")
np.savetxt(f, data, fmt='%g')
ft.vis.figure(figsize=(4, 3))
ft.vis.title('Depth of sediments [m]')
ft.vis.axis('scaled')
ft.vis.pcolor(x, y, rel, shape)
ft.vis.colorbar()
ft.vis.savefig('depth.png')
ft.vis.figure(figsize=(4, 3))
ft.vis.title('Topography [m]')
ft.vis.axis('scaled')
ft.vis.pcolor(x, y, height, shape)
ft.vis.colorbar()
ft.vis.savefig('topography.png')
ft.vis.figure(figsize=(4, 3))
ft.vis.title('Thickness of sediment layer [m]')
ft.vis.axis('scaled')
ft.vis.pcolor(x, y, thick, shape)
ft.vis.colorbar()
ft.vis.savefig('thickness.png')
ft.vis.show()

20
cookbook/tesslayers/plot.py Executable file
View File

@ -0,0 +1,20 @@
"""
Plot the columns of the output files
"""
import sys
import pylab
data = pylab.loadtxt(sys.argv[1], unpack=True)
shape = (int(sys.argv[2]), int(sys.argv[3]))
lon = pylab.reshape(data[0], shape)
lat = pylab.reshape(data[1], shape)
for i, value in enumerate(data[3:]):
value = pylab.reshape(value, shape)
pylab.figure(figsize=(4, 3))
pylab.axis('scaled')
pylab.title("Column %d" % (i + 4))
pylab.pcolor(lon, lat, value)
pylab.colorbar()
pylab.xlim(lon.min(), lon.max())
pylab.ylim(lat.min(), lat.max())
pylab.savefig('column%d.png' % (i + 4))

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,13 @@
:: Convert the layer grids in layers.txt to tesseroids.
:: The grid spacing passed to -s is used as the size of the tesseroids,
:: so be careful!
tesslayers.exe -s0.5/0.5 -v < layers.txt > tessmodel.txt
:: Now calculate the gz and tensor effect of this model at 100km height
tessgrd -r-8/8/32/48 -b50/50 -z100000 | ^
tessgz tessmodel.txt | ^
tessgxx tessmodel.txt | tessgxy tessmodel.txt | ^
tessgxz tessmodel.txt | tessgyy tessmodel.txt | ^
tessgyz tessmodel.txt | tessgzz tessmodel.txt -v > output.txt

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

View File

@ -0,0 +1,13 @@
#!/bin/bash
# Convert the layer grids in layers.txt to tesseroids.
# The grid spacing passed to -s is used as the size of the tesseroids,
# so be careful!
tesslayers -s0.5/0.5 -v < layers.txt > tessmodel.txt
# Now calculate the gz and tensor effect of this model at 100km height
tessgrd -r-8/8/32/48 -b50/50 -z100000 | \
tessgz tessmodel.txt | \
tessgxx tessmodel.txt | tessgxy tessmodel.txt | \
tessgxz tessmodel.txt | tessgyy tessmodel.txt | \
tessgyz tessmodel.txt | tessgzz tessmodel.txt -v > output.txt

41
lib/CMakeLists.txt Normal file
View File

@ -0,0 +1,41 @@
#
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2")
if(WIN32)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --std=c++11 -O2")
endif()
#
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
#
aux_source_directory(. LIBTESS_SRC)
#
#
# libcmake
add_library(tesseroids SHARED ${LIBTESS_SRC})
#
add_library(tesseroids_static STATIC ${LIBTESS_SRC})
#
set_target_properties(tesseroids_static PROPERTIES OUTPUT_NAME "tesseroids")
#
set_target_properties(tesseroids PROPERTIES CLEAN_DIRECT_OUTPUT 1)
set_target_properties(tesseroids_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
#
set_target_properties(tesseroids PROPERTIES VERSION 1.6 SOVERSION 1.6)
#
if(WIN32)
install(TARGETS tesseroids DESTINATION lib)
install(TARGETS tesseroids_static DESTINATION lib)
else()
install(TARGETS tesseroids tesseroids_static
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)
endif()
#
file(GLOB LIBTESS_HEAD *.h)
install(FILES ${LIBTESS_HEAD} DESTINATION include/tesseroids)

39
lib/constants.c Normal file
View File

@ -0,0 +1,39 @@
/*
Define constants used, like the gravitational constant and unit conversions.
All values are in SI units!
*/
#include "constants.h"
/* Mean Earth radius [\f$ m \f$] */
const double MEAN_EARTH_RADIUS = 6378137.0;
/* 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;
/* Conversion factor from SI units to mGal
[\f$ 1 \frac{m}{s^2} = 10^5\ mGal \f$] */
const double SI2MGAL = 100000.0;
/* Pi */
const double PI = 3.1415926535897932384626433832795;
/* minimum distance-to-size ratio for potential computations to be accurate */
const double TESSEROID_POT_SIZE_RATIO = 1;
/* Minimum distance-to-size ratio for gravity computations to be accurate */
const double TESSEROID_GX_SIZE_RATIO = 1.5;
const double TESSEROID_GY_SIZE_RATIO = 1.5;
const double TESSEROID_GZ_SIZE_RATIO = 1.5;
/* Minimum distance-to-size ratio for gravity gradient computations to be
accurate */
const double TESSEROID_GXX_SIZE_RATIO = 8;
const double TESSEROID_GXY_SIZE_RATIO = 8;
const double TESSEROID_GXZ_SIZE_RATIO = 8;
const double TESSEROID_GYY_SIZE_RATIO = 8;
const double TESSEROID_GYZ_SIZE_RATIO = 8;
const double TESSEROID_GZZ_SIZE_RATIO = 8;

44
lib/constants.h Normal file
View File

@ -0,0 +1,44 @@
/*
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$] */
extern const double MEAN_EARTH_RADIUS;
/* The gravitational constant [\f$ m^3*kg^{-1}*s^{-1} \f$] */
extern const double G;
/* Conversion factor from SI units to Eotvos
[\f$ \frac{1}{s^2} = 10^9\ Eotvos \f$] */
extern const double SI2EOTVOS;
/* Conversion factor from SI units to mGal
[\f$ 1 \frac{m}{s^2} = 10^5\ mGal \f$] */
extern const double SI2MGAL;
/* Pi */
extern const double PI;
/* Minimum distance-to-size ratio for potential computations to be accurate */
extern const double TESSEROID_POT_SIZE_RATIO;
/* Minimum distance-to-size ratio for gravity computations to be accurate */
extern const double TESSEROID_GX_SIZE_RATIO;
extern const double TESSEROID_GY_SIZE_RATIO;
extern const double TESSEROID_GZ_SIZE_RATIO;
/* Minimum distance-to-size ratio for gravity gradient computations to be
accurate */
extern const double TESSEROID_GXX_SIZE_RATIO;
extern const double TESSEROID_GXY_SIZE_RATIO;
extern const double TESSEROID_GXZ_SIZE_RATIO;
extern const double TESSEROID_GYY_SIZE_RATIO;
extern const double TESSEROID_GYZ_SIZE_RATIO;
extern const double TESSEROID_GZZ_SIZE_RATIO;
#endif

175
lib/geometry.c Normal file
View File

@ -0,0 +1,175 @@
/*
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. */
int split_tess(TESSEROID tess, int nlon, int nlat, int nr, TESSEROID *split)
{
double dlon, dlat, dr, w, s, r1;
int i, j, k, t = 0;
dlon = (double)(tess.e - tess.w)/nlon;
dlat = (double)(tess.n - tess.s)/nlat;
dr = (double)(tess.r2 - tess.r1)/nr;
for(r1=tess.r1, k=0; r1 + dr <= tess.r2 || k < nr; r1 += dr, k++)
{
for(s=tess.s, j=0; s + dlat <= tess.n || j < nlat; s += dlat, j++)
{
for(w=tess.w, i=0; w + dlon <= tess.e || i < nlon; w += dlon, i++)
{
split[t].w = w;
split[t].e = w + dlon;
split[t].s = s;
split[t].n = s + dlat;
split[t].r1 = r1;
split[t].r2 = r1 + dr;
split[t].density = tess.density;
t++;
}
}
}
return t;
}
/* Calculate the total mass of a tesseroid model. */
double tess_total_mass(TESSEROID *model, int size)
{
double mass;
int i;
for(mass = 0, i = 0; i < size; i++)
{
mass += model[i].density*tess_volume(model[i]);
}
return mass;
}
/* Calculate the mass of a tesseroid model within a density range. */
double tess_range_mass(TESSEROID *model, int size, double low_dens,
double high_dens)
{
double mass;
int i;
for(mass = 0, i = 0; i < size; i++)
{
if(model[i].density >= low_dens && model[i].density <= high_dens)
{
mass += model[i].density*tess_volume(model[i]);
}
}
return mass;
}
/* Convert a tesseroid to a rectangular prism of equal volume and append
* the spherical coordinates of the center top surface (needed to calculate
* the effect in spherical coordinates). */
void tess2prism(TESSEROID tess, PRISM *prism)
{
double deg2rad = PI/180., r0, dx, dy;
r0 = 0.5*(tess.r1 + tess.r2);
dx = r0*deg2rad*(tess.n - tess.s);
dy = r0*cos(deg2rad*0.5*(tess.n + tess.s))*deg2rad*(tess.e - tess.w);
prism->x1 = -0.5*dx;
prism->x2 = 0.5*dx;
prism->y1 = -0.5*dy;
prism->y2 = 0.5*dy;
/* z1 = 0 because the center of the top face of the prism is the origin of
the coordiante system */
prism->z1 = 0.;
prism->z2 = tess.r2 - tess.r1;
/* Calculate the density of the prism so that they will have exactly
the same mass */
prism->density = (double)tess.density*
tess_volume(tess)/prism_volume(*prism);
/* Set the coordinates of the center of the prisms top face */
prism->lon = 0.5*(tess.e + tess.w);
prism->lat = 0.5*(tess.n + tess.s);
prism->r = tess.r2; /* The top face */
}
/* Convert a tesseroid to a rectangular prism of equal volume by approximating
* 1 degree by 111.11 km. */
void tess2prism_flatten(TESSEROID tess, PRISM *prism)
{
prism->x1 = tess.s*111110.;
prism->x2 = tess.n*111110.;
prism->y1 = tess.w*111110.;
prism->y2 = tess.e*111110.;
/* r1 is not z1 because r1 is the bottom face (because Nagy et al., 2000,
use z->Down) */
prism->z1 = MEAN_EARTH_RADIUS - tess.r2;
prism->z2 = MEAN_EARTH_RADIUS - tess.r1;
/* Calculate the density of the prism so that they will have exactly
the same mass */
prism->density = (double)tess.density*
tess_volume(tess)/prism_volume(*prism);
}
/* Convert a tesseroid to a sphere of equal volume. */
void tess2sphere(TESSEROID tess, SPHERE *sphere)
{
sphere->density = tess.density;
sphere->lonc = 0.5*(tess.e + tess.w);
sphere->latc = 0.5*(tess.n + tess.s);
sphere->rc = 0.5*(tess.r1 + tess.r2);
sphere->r = pow(3*tess_volume(tess)/(4.*PI), (double)1./3.);
}
/* Convert a rectangular prism into a sphere of equal volume. */
void prism2sphere(PRISM prism, double lonc, double latc, double rc,
SPHERE *sphere)
{
sphere->density = prism.density;
sphere->lonc = lonc;
sphere->latc = latc;
sphere->rc = rc;
sphere->r = pow(3*prism_volume(prism)/(4.*PI), (double)1./3.);
}
/* Calculate the volume of a tesseroid */
double tess_volume(TESSEROID tess)
{
double d2r = PI/180., vol;
vol = d2r*(tess.e - tess.w)*(pow(tess.r2, 3) - pow(tess.r1, 3))*
(sin(d2r*tess.n) - sin(d2r*tess.s))/3.;
return vol;
}
/* Calculate the volume of a sphere */
double sphere_volume(SPHERE sphere)
{
return 4.*PI*pow(sphere.r, 3)/3.;
}
/* Calculate the volume of a prism */
double prism_volume(PRISM prism)
{
return (prism.x2 - prism.x1)*(prism.y2 - prism.y1)*(prism.z2 - prism.z1);
}

168
lib/geometry.h Normal file
View File

@ -0,0 +1,168 @@
/*
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 */
} TESSEROID;
/* Store information on a rectangular prism */
typedef struct prism_struct {
double density; /* in SI units */
double x1; /* in SI units */
double x2; /* in SI units */
double y1; /* in SI units */
double y2; /* in SI units */
double z1; /* in SI units */
double z2; /* in SI units */
/* Geodetic coordinates of the center of the top face of the prism */
double lon, lat, r;
} PRISM;
/* Store information on a sphere */
typedef struct sphere_struct {
double density; /* in SI units */
double r; /* radius of the sphere in SI units */
double lonc; /* longitude of the center of the sphere in degrees */
double latc; /* latitude of the center of the sphere in degrees */
double rc; /* radial coordinate of the center of the sphere in SI units */
} SPHERE;
/* Split a tesseroid.
@param tess tesseroid that will be split
@param split array of nlon*nlat*nr tesseroids with memory allocated.
Returns:
Number of tesseroids in split.
*/
extern int split_tess(TESSEROID tess, int nlon, int nlat, int nr,
TESSEROID *split);
/* Calculate the total mass of a tesseroid model.
Give all in SI units and degrees!
@param model array of tesseroids
@param size size of the model
@return The calculated mass
*/
extern double tess_total_mass(TESSEROID *model, int size);
/* Calculate the mass of a tesseroid model within a density range.
Give all in SI units and degrees!
@param model array of tesseroids
@param size size of the model
@param low_dens lower bound of the density range
@param high_dens upper bound of the density range
@return The calculated mass
*/
extern double tess_range_mass(TESSEROID *model, int size, double low_dens,
double high_dens);
/* Convert a tesseroid into a rectangular prism of equal volume (Wild-Pfeiffer, 2008).
\f[
\Delta x = \frac{r_1 + r_2}{2} \Delta \phi,
\f]
\f[
\Delta y = \frac{r_1 + r_2}{2} \cos\left(\frac{\phi_1 + \phi_2}{2}\right) \Delta\lambda,
\f]
\f[
\Delta z = \Delta r,
\f]
<b>References</b>
- Wild-Pfeiffer, F. (2008). A comparison of different mass elements for use in
gravity gradiometry. Journal of Geodesy, 82(10), 637-653.
@param tess tesseroid to convert
@param prism prism with equal volume of the tesseroid (used to return)
*/
extern void tess2prism(TESSEROID tess, PRISM *prism);
/* Convert a tesseroid into a rectangular prism of equal volume by
approximating 1 degree by 111.11 km.
@param tess tesseroid to convert
@param prism prism with equal volume of the tesseroid (used to return)
*/
extern void tess2prism_flatten(TESSEROID tess, PRISM *prism);
/* Convert a tesseroid into a sphere of equal volume.
Parameters:
@param tess tesseroid to convert
@param sphere sphere with equal volume of the tesseroid (used to return)
*/
extern void tess2sphere(TESSEROID tess, SPHERE *sphere);
/* Convert a rectangular prism into a sphere of equal volume.
Parameters:
@param prism prism to convert
@param lonc longitude of the desired center of the sphere, in degrees
@param latc latitude of the desired center of the sphere, in degrees
@param rc radial coordinate of the desired center of the sphere, in SI units
@param sphere sphere with equal volume of the prism (used to return)
*/
extern void prism2sphere(PRISM prism, double lonc, double latc, double rc,
SPHERE *sphere);
/* Calculate the volume of a tesseroid.
@param tess the tesseroid whose volume will be calculated
@return the volume in the respective units
*/
extern double tess_volume(TESSEROID tess);
/* Calculate the volume of a sphere.
@param sphere the sphere whose volume will be calculated
@return the volume in the respective units
*/
extern double sphere_volume(SPHERE sphere);
/* Calculate the volume of a prism
@param prism the prism whose volume will be calculated
@return the volume in the respective units
*/
extern double prism_volume(PRISM prism);
#endif

308
lib/glq.c Normal file
View File

@ -0,0 +1,308 @@
/*
Functions for implementing a Gauss-Legendre Quadrature numerical integration.
*/
#include <stdlib.h>
#include <math.h>
#include "constants.h"
#include "logger.h"
#include "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;
/* 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;
}
glq->nodes_sin = (double *)malloc(sizeof(double)*order);
if(glq->nodes_sin == NULL)
{
free(glq);
free(glq->nodes);
free(glq->nodes_unscaled);
free(glq->weights);
return NULL;
}
glq->nodes_cos = (double *)malloc(sizeof(double)*order);
if(glq->nodes_cos == NULL)
{
free(glq);
free(glq->nodes);
free(glq->nodes_unscaled);
free(glq->weights);
free(glq->nodes_sin);
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->nodes_sin);
free(glq->nodes_cos);
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.
* Uses the method of Barrera-Figueroa et al. (2006). */
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;
}
void glq_precompute_sincos(GLQ *glq)
{
double d2r = PI/180.;
register int i;
for(i = 0; i < glq->order; i++)
{
glq->nodes_sin[i] = sin(d2r*glq->nodes[i]);
glq->nodes_cos[i] = cos(d2r*glq->nodes[i]);
}
}

192
lib/glq.h Normal file
View File

@ -0,0 +1,192 @@
/*
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 */
extern const int GLQ_MAXIT;
/** \var GLQ_MAXERROR
Max error allowed for the root-finder algorithm */
extern const double GLQ_MAXERROR;
/** 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 */
/* Used to store the pre-computed sine and cossine of the nodes, if needed.
* Can be useful for the latitude, which is always used as sin and cos */
double *nodes_sin;
double *nodes_cos;
} 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.
*/
extern 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
*/
extern 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
*/
extern 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.
*/
extern 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.
*/
extern 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
*/
extern int glq_weights(int order, double *nodes, double *weights);
/* Precompute the sine and cossine of the GLQ nodes and store them in the
* structure */
extern void glq_precompute_sincos(GLQ *glq);
#endif

469
lib/grav_prism.c Normal file
View File

@ -0,0 +1,469 @@
/*
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;
}

36
lib/grav_prism.h Normal file
View File

@ -0,0 +1,36 @@
/*
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.
*/
#ifndef _TESSEROIDS_GRAV_PRISM_H_
#define _TESSEROIDS_GRAV_PRISM_H_
/* Needed for definition of PRISM */
#include "geometry.h"
extern double safe_atan2(double y, double x);
extern double prism_pot(PRISM prism, double xp, double yp, double zp);
extern double prism_gx(PRISM prism, double xp, double yp, double zp);
extern double prism_gy(PRISM prism, double xp, double yp, double zp);
extern double prism_gz(PRISM prism, double xp, double yp, double zp);
extern double prism_gxx(PRISM prism, double xp, double yp, double zp);
extern double prism_gxy(PRISM prism, double xp, double yp, double zp);
extern double prism_gxz(PRISM prism, double xp, double yp, double zp);
extern double prism_gyy(PRISM prism, double xp, double yp, double zp);
extern double prism_gyz(PRISM prism, double xp, double yp, double zp);
extern double prism_gzz(PRISM prism, double xp, double yp, double zp);
#endif

219
lib/grav_prism_sph.c Normal file
View File

@ -0,0 +1,219 @@
/*
Functions that calculate the gravitational potential and its first and second
derivatives for the rectangular prism in spherical coordinates.
Uses the formulas in Nagy et al. (2000).
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 "geometry.h"
#include "constants.h"
#include "grav_prism_sph.h"
#include "grav_prism.h"
/* Transform spherical coordinates to local Cartesian coordinates of the prism*/
int global2local(double lon, double lat, double r, PRISM prism, double *x,
double *y, double *z)
{
double cosa, cosb, sina, sinb, d2r, X, Y, Z;
/* degrees to radians */
d2r = PI/180.;
X = r*cos(d2r*lat)*cos(d2r*lon) -
prism.r*cos(d2r*prism.lat)*cos(d2r*prism.lon);
Y = r*cos(d2r*lat)*sin(d2r*lon) -
prism.r*cos(d2r*prism.lat)*sin(d2r*prism.lon);
Z = r*sin(d2r*lat) - prism.r*sin(d2r*prism.lat);
cosa = cos(d2r*(90 - prism.lat));
sina = sin(d2r*(90 - prism.lat));
cosb = cos(d2r*(180 - prism.lon));
sinb = sin(d2r*(180 - prism.lon));
*x = X*cosa*cosb - Y*cosa*sinb + Z*sina;
*y = -X*sinb - Y*cosb;
/* -1 because Nagy et al. (2000) use z->down */
*z = -1*(-X*sina*cosb + Y*sina*sinb + Z*cosa);
return 0;
}
/* Rotate the gravity vector from the prisms coordinate system to the local
system of the computation point. */
int g_prism2point(double *atprism, PRISM prism, double lon, double lat,
double r, double *atpoint)
{
#define POS(x, y, cols) (((x)*(cols))+(y))
register int i, k;
double R[9], d2r, cosbeta, sinbeta, cosphi, sinphi, cosphil, sinphil;
/* degrees to radians */
d2r = PI/180.;
cosbeta = cos(d2r*(prism.lon - lon));
sinbeta = sin(d2r*(prism.lon - lon));
cosphi = cos(d2r*lat);
sinphi = sin(d2r*lat);
cosphil = cos(d2r*prism.lat);
sinphil = sin(d2r*prism.lat);
/* The transformation matrix */
R[0] = cosbeta*sinphi*sinphil + cosphi*cosphil;
R[1] = sinbeta*sinphi;
R[2] = -cosbeta*sinphi*cosphil + cosphi*sinphil;
R[3] = -sinbeta*sinphil;
R[4] = cosbeta;
R[5] = sinbeta*cosphil;
R[6] = -cosbeta*cosphi*sinphil + sinphi*cosphil;
R[7] = -sinbeta*cosphi;
R[8] = cosbeta*cosphi*cosphil + sinphi*sinphil;
/* Matrix-vector multiplication */
for(i = 0; i < 3; i++)
{
atpoint[i] = 0;
for(k = 0; k < 3; k++)
{
atpoint[i] += R[POS(i, k, 3)]*atprism[k];
}
}
#undef POS
return 0;
}
/* Rotate the gravity tensor from the prisms coordinate system to the local
system of the computation point. */
int ggt_prism2point(double *atprism, PRISM prism, double lon, double lat,
double r, double *atpoint)
{
#define POS(x, y, cols) (((x)*(cols))+(y))
register int i, j, k;
double R[9], tmp[9], d2r, cosbeta, sinbeta, cosphi, sinphi, cosphil, sinphil;
/* degrees to radians */
d2r = PI/180.;
cosbeta = cos(d2r*(prism.lon - lon));
sinbeta = sin(d2r*(prism.lon - lon));
cosphi = cos(d2r*lat);
sinphi = sin(d2r*lat);
cosphil = cos(d2r*prism.lat);
sinphil = sin(d2r*prism.lat);
/* The transformation matrix */
R[0] = cosbeta*sinphi*sinphil + cosphi*cosphil;
R[1] = sinbeta*sinphi;
R[2] = -cosbeta*sinphi*cosphil + cosphi*sinphil;
R[3] = -sinbeta*sinphil;
R[4] = cosbeta;
R[5] = sinbeta*cosphil;
R[6] = -cosbeta*cosphi*sinphil + sinphi*cosphil;
R[7] = -sinbeta*cosphi;
R[8] = cosbeta*cosphi*cosphil + sinphi*sinphil;
/* Multiply tmp = R*Tensor */
for(i = 0; i < 3; i++)
{
for(j = 0; j < 3; j++)
{
tmp[POS(i, j, 3)] = 0;
for(k = 0; k < 3; k++)
{
tmp[POS(i, j, 3)] += R[POS(i, k, 3)]*atprism[POS(k, j, 3)];
}
}
}
/* Multiply tmp*R^T */
for(i = 0; i < 3; i++)
{
for(j = 0; j < 3; j++)
{
atpoint[POS(i, j, 3)] = 0;
for(k = 0; k < 3; k++)
{
atpoint[POS(i, j, 3)] += tmp[POS(i, k, 3)]*R[POS(j, k, 3)];
}
}
}
#undef POS
return 0;
}
/* Calculates the gravity gradient tensor caused by a prism. */
int prism_ggt_sph(PRISM prism, double lonp, double latp, double rp, double *ggt)
{
double x = 0, y = 0, z = 0, ggtprism[9], ggtpoint[9];
global2local(lonp, latp, rp, prism, &x, &y, &z);
ggtprism[0] = prism_gxx(prism, x, y, z);
ggtprism[1] = prism_gxy(prism, x, y, z);
/* -1 because the prisms z is Down, but transformation assumes z is Up */
/* z -> Up is the system of the tesseroid */
ggtprism[2] = -1*prism_gxz(prism, x, y, z);
ggtprism[3] = ggtprism[1];
ggtprism[4] = prism_gyy(prism, x, y, z);
/* Same as xz */
ggtprism[5] = -1*prism_gyz(prism, x, y, z);
ggtprism[6] = ggtprism[2];
ggtprism[7] = ggtprism[5];
ggtprism[8] = -(ggtprism[0] + ggtprism[4]);
ggt_prism2point(ggtprism, prism, lonp, latp, rp, ggtpoint);
ggt[0] = ggtpoint[0];
ggt[1] = ggtpoint[1];
ggt[2] = ggtpoint[2];
ggt[3] = ggtpoint[4];
ggt[4] = ggtpoint[5];
ggt[5] = ggtpoint[8];
return 0;
}
/* Calculates the gravitational attraction caused by a prism. */
int prism_g_sph(PRISM prism, double lonp, double latp, double rp, double *gx,
double *gy, double *gz)
{
double x = 0, y = 0, z = 0, gprism[3], gpoint[3];
global2local(lonp, latp, rp, prism, &x, &y, &z);
gprism[0] = prism_gx(prism, x, y, z);
gprism[1] = prism_gy(prism, x, y, z);
/* Nagy wants z down, but the transformation assumes z up */
gprism[2] = -prism_gz(prism, x, y, z);
g_prism2point(gprism, prism, lonp, latp, rp, gpoint);
*gx = gpoint[0];
*gy = gpoint[1];
/* Put z back down again to maintain the normal convention for gz */
*gz = -gpoint[2];
return 0;
}
/* Calculates the potential caused by a prism. */
double prism_pot_sph(PRISM prism, double lonp, double latp, double rp)
{
double x = 0, y = 0, z = 0, res;
global2local(lonp, latp, rp, prism, &x, &y, &z);
res = prism_pot(prism, x, y, z);
return res;
}

100
lib/grav_prism_sph.h Normal file
View File

@ -0,0 +1,100 @@
/*
Functions that calculate the gravitational potential and its first and second
derivatives for the rectangular prism in spherical coordinates.
Uses the formulas in Nagy et al. (2000).
References
----------
* Nagy, D., Papp, G., Benedek, J. (2000): The gravitational potential and its
derivatives for the prism. Journal of Geodesy, 74, 552560.
*/
#ifndef _TESSEROIDS_GRAV_PRISM_SPH_H_
#define _TESSEROIDS_GRAV_PRISM_SPH_H_
/* Needed for definition of PRISM */
#include "geometry.h"
/* Transform spherical coordinates to local Cartesian coordinates of the prism
Parameters:
* lon, lat, r: spherical coordinates of the point.
* prism: a prism whose lon, lat, r values will be used as the origin of the
local coordinate system.
* x, y, z: used to return the x, y, z Cartesian coordinates of the point.
*/
extern int global2local(double lon, double lat, double r, PRISM prism,
double *x, double *y, double *z);
/* Rotate the g vector from the prisms coordinate system to the local
system of the computation point.
Parameters:
* atprism: the 3 component gravity vector in the coordinates of the prism.
* prism: the prism used to calculate atprism.
* lon, lat, r: coordinates of the computation point.
* atpoint: used to return the 3 component gravity vector in the coordinates of
the computation point.
*/
extern int g_prism2point(double *atprism, PRISM prism, double lon, double lat,
double r, double *atpoint);
/* Rotate the g vector from the prisms coordinate system to the local
system of the computation point.
Parameters:
* atprism: the 9 component gravity tensor in the coordinates of the prism.
The order is: gxx, gxy, gxz, gyx, gyy, gyz, gzx, gzy, gzz
* prism: the prism used to calculate atprism.
* lon, lat, r: coordinates of the computation point.
* atpoint: used to return the 9 component gravity tensor in the coordinates of
the computation point.
*/
extern int ggt_prism2point(double *atprism, PRISM prism, double lon, double lat,
double r, double *atpoint);
/* Calculates the gravity gradient tensor caused by a prism.
Parameters:
* prism: the prism whose effect will be calculated.
* lonp, latp, rp: coordinates of the computation point.
* ggt: 6 element array used to return the gradient tensor. The order is:
gxx, gxy, gxz, gyy, gyz, gzz
*/
extern int prism_ggt_sph(PRISM prism, double lonp, double latp, double rp,
double *ggt);
/* Calculates the gravitational attraction caused by a prism.
Parameters:
* prism: the prism whose effect will be calculated.
* lonp, latp, rp: coordinates of the computation point.
* gx, gy, gz: used to return the 3 components of the gravity vector
*/
extern int prism_g_sph(PRISM prism, double lonp, double latp, double rp,
double *gx, double *gy, double *gz);
/* Calculates the potential caused by a prism.
Parameters:
* prism: the prism whose effect will be calculated.
* lonp, latp, rp: coordinates of the computation point.
Returns:
* the calculated potential
*/
extern double prism_pot_sph(PRISM prism, double lonp, double latp, double rp);
#endif

252
lib/grav_sphere.c Normal file
View File

@ -0,0 +1,252 @@
/*
This module contains a set of functions that calculate the gravitational
potential and its first and second derivatives for the sphere in spherical
coordinates.
The position of the sphere and computation point are in spherical coordinates.
The derivatives of the potential are made with respect to the local coordinate
system x->North, y->East, z->out. So it would be normal for a sphere of positive
density to have negative gz
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 "geometry.h"
#include "constants.h"
#include "grav_sphere.h"
/* Calculates the potential caused by a sphere */
double sphere_pot(SPHERE sphere, double lonp, double latp, double rp)
{
double mass, l_sqr, d2r = PI/180., coslatp, coslatc, sinlatp, sinlatc,
coslon;
mass = (double)(sphere.density*4.*PI*sphere.r*sphere.r*sphere.r)/3.;
coslatp = cos(d2r*latp);
coslatc = cos(d2r*sphere.latc);
sinlatp = sin(d2r*latp);
sinlatc = sin(d2r*sphere.latc);
coslon = cos(d2r*(lonp - sphere.lonc));
l_sqr = rp*rp + sphere.rc*sphere.rc - 2*rp*sphere.rc*(
sinlatp*sinlatc + coslatp*coslatc*coslon);
return G*mass/sqrt(l_sqr);
}
/* Calculates the gx component of gravitational attraction caused by a sphere */
double sphere_gx(SPHERE sphere, double lonp, double latp, double rp)
{
double mass, l_sqr, d2r = PI/180., kphi, coslatp, coslatc, sinlatp, sinlatc,
coslon;
mass = (double)(sphere.density*4.*PI*sphere.r*sphere.r*sphere.r)/3.;
coslatp = cos(d2r*latp);
coslatc = cos(d2r*sphere.latc);
sinlatp = sin(d2r*latp);
sinlatc = sin(d2r*sphere.latc);
coslon = cos(d2r*(lonp - sphere.lonc));
l_sqr = rp*rp + sphere.rc*sphere.rc - 2*rp*sphere.rc*(
sinlatp*sinlatc + coslatp*coslatc*coslon);
kphi = coslatp*sinlatc - sinlatp*coslatc*coslon;
return G*SI2MGAL*mass*(sphere.rc*kphi)/pow(l_sqr, 1.5);
}
/* Calculates the gy component of gravitational attraction caused by a sphere */
double sphere_gy(SPHERE sphere, double lonp, double latp, double rp)
{
double mass, l_sqr, d2r = PI/180., cospsi, coslatc, kern;
mass = (double)(sphere.density*4.*PI*sphere.r*sphere.r*sphere.r)/3.;
coslatc = cos(d2r*sphere.latc);
cospsi = sin(d2r*latp)*sin(d2r*sphere.latc) + cos(d2r*latp)*coslatc*
cos(d2r*(lonp - sphere.lonc));
l_sqr = rp*rp + sphere.rc*sphere.rc - 2*rp*sphere.rc*cospsi;
kern = (sphere.rc*coslatc*sin(d2r*(sphere.lonc - lonp)))/pow(l_sqr, 1.5);
return G*SI2MGAL*mass*kern;
}
/* Calculates the gz component of gravitational attraction caused by a sphere */
double sphere_gz(SPHERE sphere, double lonp, double latp, double rp)
{
double mass, l_sqr, d2r = PI/180., cospsi;
mass = (double)(sphere.density*4.*PI*sphere.r*sphere.r*sphere.r)/3.;
cospsi = sin(d2r*latp)*sin(d2r*sphere.latc) + cos(d2r*latp)*
cos(d2r*sphere.latc)*cos(d2r*(lonp - sphere.lonc));
l_sqr = rp*rp + sphere.rc*sphere.rc - 2*rp*sphere.rc*cospsi;
return G*SI2MGAL*mass*(sphere.rc*cospsi - rp)/pow(l_sqr, 1.5);
}
/* Calculate the xx component of gravity gradient tensor cause by a sphere */
double sphere_gxx(SPHERE sphere, double lonp, double latp, double rp)
{
double mass, l_sqr, d2r = PI/180., kphi, coslatp, coslatc, sinlatp, sinlatc,
coslon, kern;
mass = (double)(sphere.density*4.*PI*sphere.r*sphere.r*sphere.r)/3.;
coslatp = cos(d2r*latp);
coslatc = cos(d2r*sphere.latc);
sinlatp = sin(d2r*latp);
sinlatc = sin(d2r*sphere.latc);
coslon = cos(d2r*(lonp - sphere.lonc));
l_sqr = rp*rp + sphere.rc*sphere.rc - 2*rp*sphere.rc*(sinlatp*sinlatc +
coslatp*coslatc*coslon);
kphi = coslatp*sinlatc - sinlatp*coslatc*coslon;
kern = (3*sphere.rc*kphi*sphere.rc*kphi - l_sqr)/pow(l_sqr, 2.5);
return G*SI2EOTVOS*mass*kern;
}
/* Calculate the xy component of gravity gradient tensor cause by a sphere */
double sphere_gxy(SPHERE sphere, double lonp, double latp, double rp)
{
double mass, l_sqr, d2r = PI/180., kphi, coslatp, coslatc, sinlatp, sinlatc,
coslon, kern;
mass = (double)(sphere.density*4.*PI*sphere.r*sphere.r*sphere.r)/3.;
coslatp = cos(d2r*latp);
coslatc = cos(d2r*sphere.latc);
sinlatp = sin(d2r*latp);
sinlatc = sin(d2r*sphere.latc);
coslon = cos(d2r*(lonp - sphere.lonc));
l_sqr = rp*rp + sphere.rc*sphere.rc - 2*rp*sphere.rc*(sinlatp*sinlatc +
coslatp*coslatc*coslon);
kphi = coslatp*sinlatc - sinlatp*coslatc*coslon;
kern = (3*sphere.rc*sphere.rc*kphi*coslatp*sin(d2r*(sphere.lonc - lonp)))/
pow(l_sqr, 2.5);
return G*SI2EOTVOS*mass*kern;
}
/* Calculate the xz component of gravity gradient tensor cause by a sphere */
double sphere_gxz(SPHERE sphere, double lonp, double latp, double rp)
{
double mass, l_sqr, d2r = PI/180., kphi, coslatp, coslatc, sinlatp, sinlatc,
coslon, kern, cospsi;
mass = (double)(sphere.density*4.*PI*sphere.r*sphere.r*sphere.r)/3.;
coslatp = cos(d2r*latp);
coslatc = cos(d2r*sphere.latc);
sinlatp = sin(d2r*latp);
sinlatc = sin(d2r*sphere.latc);
coslon = cos(d2r*(lonp - sphere.lonc));
cospsi = sinlatp*sinlatc + coslatp*coslatc*coslon;
l_sqr = rp*rp + sphere.rc*sphere.rc - 2*rp*sphere.rc*cospsi;
kphi = coslatp*sinlatc - sinlatp*coslatc*coslon;
kern = 3*sphere.rc*kphi*(sphere.rc*cospsi - rp)/pow(l_sqr, 2.5);
return G*SI2EOTVOS*mass*kern;
}
/* Calculate the yy component of gravity gradient tensor cause by a sphere */
double sphere_gyy(SPHERE sphere, double lonp, double latp, double rp)
{
double mass, l_sqr, d2r = PI/180., coslatp, coslatc, sinlatp, sinlatc,
coslon, sinlon, kern, cospsi;
mass = (double)(sphere.density*4.*PI*sphere.r*sphere.r*sphere.r)/3.;
coslatp = cos(d2r*latp);
coslatc = cos(d2r*sphere.latc);
sinlatp = sin(d2r*latp);
sinlatc = sin(d2r*sphere.latc);
coslon = cos(d2r*(lonp - sphere.lonc));
sinlon = sin(d2r*(sphere.lonc - lonp));
cospsi = sinlatp*sinlatc + coslatp*coslatc*coslon;
l_sqr = rp*rp + sphere.rc*sphere.rc - 2*rp*sphere.rc*cospsi;
kern = (3*sphere.rc*sphere.rc*coslatc*coslatc*sinlon*sinlon - l_sqr)/
pow(l_sqr, 2.5);
return G*SI2EOTVOS*mass*kern;
}
/* Calculate the yz component of gravity gradient tensor cause by a sphere */
double sphere_gyz(SPHERE sphere, double lonp, double latp, double rp)
{
double mass, l_sqr, d2r = PI/180., coslatp, coslatc, sinlatp, sinlatc,
coslon, sinlon, kern, cospsi;
mass = (double)(sphere.density*4.*PI*sphere.r*sphere.r*sphere.r)/3.;
coslatp = cos(d2r*latp);
coslatc = cos(d2r*sphere.latc);
sinlatp = sin(d2r*latp);
sinlatc = sin(d2r*sphere.latc);
coslon = cos(d2r*(lonp - sphere.lonc));
sinlon = sin(d2r*(sphere.lonc - lonp));
cospsi = sinlatp*sinlatc + coslatp*coslatc*coslon;
l_sqr = rp*rp + sphere.rc*sphere.rc - 2*rp*sphere.rc*cospsi;
kern = 3*sphere.rc*coslatc*sinlon*(sphere.rc*cospsi - rp)/pow(l_sqr, 2.5);
return G*SI2EOTVOS*mass*kern;
}
/* Calculate the zz component of gravity gradient tensor cause by a sphere */
double sphere_gzz(SPHERE sphere, double lonp, double latp, double rp)
{
double mass, l_sqr, d2r = PI/180., deltaz, cospsi;
mass = (double)(sphere.density*4.*PI*sphere.r*sphere.r*sphere.r)/3.;
cospsi = sin(d2r*latp)*sin(d2r*sphere.latc) + cos(d2r*latp)*
cos(d2r*sphere.latc)*cos(d2r*(lonp - sphere.lonc));
l_sqr = rp*rp + sphere.rc*sphere.rc - 2*rp*sphere.rc*cospsi;
deltaz = sphere.rc*cospsi - rp;
return G*SI2EOTVOS*mass*(3*deltaz*deltaz - l_sqr)/pow(l_sqr, 2.5);
}

267
lib/grav_sphere.h Normal file
View File

@ -0,0 +1,267 @@
/*
Functions that calculate the gravitational potential and its first and second
derivatives for the sphere in spherical coordinates.
The position of the sphere and computation point are in spherical coordinates.
The derivatives of the potential are made with respect to the local coordinate
system x->North, y->East, z->out. So it would be normal for a sphere of
positive density to have negative gz.
Used the generic formula for gravity gradient computation of tesseroids by
Grombein et al. (2010).
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.
*/
#ifndef _TESSEROIDS_GRAV_SPHERE_H_
#define _TESSEROIDS_GRAV_SPHERE_H_
/* Needed for definition of SPHERE */
#include "geometry.h"
/** Calculates potential caused by a sphere.
\f[
V(r_p,\phi_p,\lambda_p) = \frac{G M}{\ell}
\f]
The position of the sphere and computation point should be in spherical
coordinates.
<b>Input and output values in SI units and degrees</b>
@param sphere data structure describing the sphere
@param lonp longitude of the computation point P
@param latp latitude of the computation point P
@param rp radial coordinate of the computation point P
@return field calculated at P
*/
extern double sphere_pot(SPHERE sphere, double lonp, double latp, double rp);
/** Calculates gx caused by a sphere (Grombein et al., 2010).
\f[
g_x(r_p,\phi_p,\lambda_p) = G M \frac{r_c K_{\phi}}{\ell^3}
\f]
The position of the sphere and computation point should be in spherical
coordinates.
The derivatives of the potential are made with respect to the local coordinate
system <b>x->North, y->East, z->out</b>
<b>Input values in SI units and <b>degrees</b> and returns values in mGal!</b>
@param sphere data structure describing the sphere
@param lonp longitude of the computation point P
@param latp latitude of the computation point P
@param rp radial coordinate of the computation point P
@return field calculated at P
*/
extern double sphere_gx(SPHERE sphere, double lonp, double latp, double rp);
/** Calculates gy caused by a sphere (Grombein et al., 2010).
\f[
g_y(r_p,\phi_p,\lambda_p) = G M \frac{r_c\cos\phi_c\sin(\phi_c-\phi_p)}{\ell^3}
\f]
The position of the sphere and computation point should be in spherical
coordinates.
The derivatives of the potential are made with respect to the local coordinate
system <b>x->North, y->East, z->out</b>
<b>Input values in SI units and <b>degrees</b> and returns values in mGal!</b>
@param sphere data structure describing the sphere
@param lonp longitude of the computation point P
@param latp latitude of the computation point P
@param rp radial coordinate of the computation point P
@return field calculated at P
*/
extern double sphere_gy(SPHERE sphere, double lonp, double latp, double rp);
/** Calculates gz caused by a sphere (Grombein et al., 2010).
\f[
g_z(r_p,\phi_p,\lambda_p) = G M \frac{r_c\cos\psi - r_p}{\ell^3}
\f]
The position of the sphere and computation point should be in spherical
coordinates.
The derivatives of the potential are made with respect to the local coordinate
system <b>x->North, y->East, z->out</b>
<b>Input values in SI units and <b>degrees</b> and returns values in mGal!</b>
@param sphere data structure describing the sphere
@param lonp longitude of the computation point P
@param latp latitude of the computation point P
@param rp radial coordinate of the computation point P
@return field calculated at P
*/
extern double sphere_gz(SPHERE sphere, double lonp, double latp, double rp);
/** Calculates gxx caused by a sphere (Grombein et al., 2010).
\f[
g_{xx}(r_p,\phi_p,\lambda_p) = G M \frac{3(r_c K_{\phi})^2 - \ell^2}{\ell^5}
\f]
The position of the sphere and computation point are in spherical coordinates.
The derivatives of the potential are made with respect to the local coordinate
system <b>x->North, y->East, z->out</b>
<b>Input values in SI units and <b>degrees</b> and returns values in Eotvos!</b>
@param sphere data structure describing the sphere
@param lonp longitude of the computation point P
@param latp latitude of the computation point P
@param rp radial coordinate of the computation point P
@return field calculated at P
*/
extern double sphere_gxx(SPHERE sphere, double lonp, double latp, double rp);
/** Calculates gxy caused by a sphere (Grombein et al., 2010).
\f[
g_{xy}(r_p,\phi_p,\lambda_p) = G M \frac{3r_c^2 K_{\phi}\cos\phi_c
\sin(\lambda_c - \lambda_p)}{\ell^5}
\f]
The position of the sphere and computation point are in spherical coordinates.
The derivatives of the potential are made with respect to the local coordinate
system <b>x->North, y->East, z->out</b>
<b>Input values in SI units and <b>degrees</b> and returns values in Eotvos!</b>
@param sphere data structure describing the sphere
@param lonp longitude of the computation point P
@param latp latitude of the computation point P
@param rp radial coordinate of the computation point P
@return field calculated at P
*/
extern double sphere_gxy(SPHERE sphere, double lonp, double latp, double rp);
/** Calculates gxz caused by a sphere (Grombein et al., 2010).
\f[
g_{xz}(r_p,\phi_p,\lambda_p) = G M \frac{3 r_c K_{\phi}(r_c \cos\psi - r_p)}
{\ell^5}
\f]
The position of the sphere and computation point are in spherical coordinates.
The derivatives of the potential are made with respect to the local coordinate
system <b>x->North, y->East, z->out</b>
<b>Input values in SI units and <b>degrees</b> and returns values in Eotvos!</b>
@param sphere data structure describing the sphere
@param lonp longitude of the computation point P
@param latp latitude of the computation point P
@param rp radial coordinate of the computation point P
@return field calculated at P
*/
extern double sphere_gxz(SPHERE sphere, double lonp, double latp, double rp);
/** Calculates gyy caused by a sphere (Grombein et al., 2010).
\f[
g_{yy}(r_p,\phi_p,\lambda_p) = G M \frac{3(r_c\cos\phi_c
\sin(\lambda_c - \lambda_p))^2 - \ell^2}{\ell^5}
\f]
The position of the sphere and computation point are in spherical coordinates.
The derivatives of the potential are made with respect to the local coordinate
system <b>x->North, y->East, z->out</b>
<b>Input values in SI units and <b>degrees</b> and returns values in Eotvos!</b>
@param sphere data structure describing the sphere
@param lonp longitude of the computation point P
@param latp latitude of the computation point P
@param rp radial coordinate of the computation point P
@return field calculated at P
*/
extern double sphere_gyy(SPHERE sphere, double lonp, double latp, double rp);
/** Calculates gyz caused by a sphere (Grombein et al., 2010).
\f[
g_{yz}(r_p,\phi_p,\lambda_p) = G M \frac{3 r_c \cos\phi_c \sin(\lambda_c -
\lambda_p)(r_c\cos\psi - r_p)}{\ell^5}
\f]
The position of the sphere and computation point are in spherical coordinates.
The derivatives of the potential are made with respect to the local coordinate
system <b>x->North, y->East, z->out</b>
<b>Input values in SI units and <b>degrees</b> and returns values in Eotvos!</b>
@param sphere data structure describing the sphere
@param lonp longitude of the computation point P
@param latp latitude of the computation point P
@param rp radial coordinate of the computation point P
@return field calculated at P
*/
extern double sphere_gyz(SPHERE sphere, double lonp, double latp, double rp);
/** Calculates gzz caused by a sphere (Grombein et al., 2010).
\f[
g_{zz}(r_p,\phi_p,\lambda_p) = G M \frac{3(r_c\cos\psi-r_p)^2 - \ell^2}{\ell^5}
\f]
The position of the sphere and computation point are in spherical coordinates.
The derivatives of the potential are made with respect to the local coordinate
system <b>x->North, y->East, z->out</b>
<b>Input values in SI units and <b>degrees</b> and returns values in Eotvos!</b>
@param sphere data structure describing the sphere
@param lonp longitude of the computation point P
@param latp latitude of the computation point P
@param rp radial coordinate of the computation point P
@return field calculated at P
*/
extern double sphere_gzz(SPHERE sphere, double lonp, double latp, double rp);
#endif

580
lib/grav_tess.c Normal file
View File

@ -0,0 +1,580 @@
/*
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"
#define STKSIZE 10000
/* 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++)
{
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);
glq_precompute_sincos(glq_lat);
res += field(model[tess], lonp, latp, rp, *glq_lon, *glq_lat, *glq_r);
}
return res;
}
/* 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, distance, lont, latt, rt, d2r = PI/180.,
coslatp, sinlatp, rp_sqr, rlonp,
Llon, Llat, Lr,
sinlatt, coslatt;
int t, n, nlon, nlat, nr, stktop = 0;
TESSEROID stack[STKSIZE], tess;
#define SQ(x) (x)*(x)
/* Pre-compute these things out of the loop */
rlonp = d2r*lonp;
rp_sqr = SQ(rp);
coslatp = cos(d2r*latp);
sinlatp = sin(d2r*latp);
res = 0;
for(t = 0; t < size; t++)
{
/* Initialize the tesseroid division stack (a LIFO structure) */
stack[0] = model[t];
stktop = 0;
while(stktop >= 0)
{
/* Pop the stack */
tess = stack[stktop];
stktop--;
/* Compute the distance from the computation point to the
* geometric center of the tesseroid. */
rt = 0.5*(tess.r2 + tess.r1);
lont = d2r*0.5*(tess.w + tess.e);
latt = d2r*0.5*(tess.s + tess.n);
sinlatt = sin(latt);
coslatt = cos(latt);
distance = sqrt(rp_sqr + SQ(rt) - 2*rp*rt*(
sinlatp*sinlatt + coslatp*coslatt*cos(rlonp - lont)));
/* Get the size of each dimension of the tesseroid in meters */
Llon = tess.r2*acos(
SQ(sinlatt) + SQ(coslatt)*cos(d2r*(tess.e - tess.w)));
Llat = tess.r2*acos(
sin(d2r*tess.n)*sin(d2r*tess.s) +
cos(d2r*tess.n)*cos(d2r*tess.s));
Lr = tess.r2 - tess.r1;
/* Number of times to split the tesseroid in each dimension */
nlon = 1;
nlat = 1;
nr = 1;
/* Check if the tesseroid is at a suitable distance (defined
* the value of "ratio"). If not, mark that dimension for
* division. */
if(distance < ratio*Llon)
{
nlon = 2;
}
if(distance < ratio*Llat)
{
nlat = 2;
}
if(distance < ratio*Lr)
{
nr = 2;
}
/* In case none of the dimensions need dividing,
* put the GLQ roots in the proper scale and compute the
* gravitational field of the tesseroid. */
/* Also compute the effect if the tesseroid stack if full
* (but warn the user that the computation might not be very
* precise). */
if((nlon == 1 && nlat == 1 && nr == 1)
|| (nlon*nlat*nr + stktop >= STKSIZE))
{
if(nlon*nlat*nr + stktop >= STKSIZE)
{
log_error(
"Stack overflow: "
"tesseroid %d in the model file on "
"lon=%lf lat=%lf height=%lf."
"\n Calculated without fully dividing the tesseroid. "
"Accuracy of the solution cannot be guaranteed."
"\n This is probably caused by a computation point "
"too close to the tesseroid."
"\n Try increasing the computation height."
"\n *Expert users* can try modifying the "
"distance-size ratio."
"\n *Beware* that this might affect "
"the accuracy of the solution.",
t + 1, lonp, latp, rp);
}
glq_set_limits(tess.w, tess.e, glq_lon);
glq_set_limits(tess.s, tess.n, glq_lat);
glq_set_limits(tess.r1, tess.r2, glq_r);
glq_precompute_sincos(glq_lat);
res += field(tess, lonp, latp, rp, *glq_lon, *glq_lat, *glq_r);
}
else
{
/* Divide the tesseroid in each dimension that needs dividing
* Put each of the smaller tesseroids on the stack for
* computing in the next iteration. */
n = split_tess(tess, nlon, nlat, nr, &stack[stktop + 1]);
stktop += n;
/* Sanity check */
if(n != nlon*nlat*nr)
{
log_error("Splitting into %d instead of %d", n,
nlon*nlat*nr);
}
}
}
}
#undef SQ
return res;
}
/* Calculates potential caused by a tesseroid. */
double tess_pot(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, rc, kappa, res,
cospsi, wlon, wlat, wr, scale;
register int i, j, k;
coslatp = cos(d2r*latp);
sinlatp = sin(d2r*latp);
res = 0;
for(k = 0; k < glq_lon.order; k++)
{
coslon = cos(d2r*(lonp - glq_lon.nodes[k]));
wlon = glq_lon.weights[k];
for(j = 0; j < glq_lat.order; j++)
{
sinlatc = glq_lat.nodes_sin[j];
coslatc = glq_lat.nodes_cos[j];
cospsi = sinlatp*sinlatc + coslatp*coslatc*coslon;
wlat = glq_lat.weights[j];
for(i = 0; i < glq_r.order; i++)
{
wr = glq_r.weights[i];
rc = glq_r.nodes[i];
l_sqr = rp*rp + rc*rc - 2*rp*rc*cospsi;
kappa = rc*rc*coslatc;
res += wlon*wlat*wr*kappa/sqrt(l_sqr);
}
}
}
scale = d2r*(tess.e - tess.w)*d2r*(tess.n - tess.s)*(tess.r2 - tess.r1)/8.;
res *= G*tess.density*scale;
return res;
}
/* Calculates gx caused by a tesseroid. */
double tess_gx(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,
cospsi, wlon, wlat, wr, scale;
register int i, j, k;
coslatp = cos(d2r*latp);
sinlatp = sin(d2r*latp);
res = 0;
for(k = 0; k < glq_lon.order; k++)
{
coslon = cos(d2r*(lonp - glq_lon.nodes[k]));
wlon = glq_lon.weights[k];
for(j = 0; j < glq_lat.order; j++)
{
sinlatc = glq_lat.nodes_sin[j];
coslatc = glq_lat.nodes_cos[j];
kphi = coslatp*sinlatc - sinlatp*coslatc*coslon;
cospsi = sinlatp*sinlatc + coslatp*coslatc*coslon;
wlat = glq_lat.weights[j];
for(i = 0; i < glq_r.order; i++)
{
wr = glq_r.weights[i];
rc = glq_r.nodes[i];
l_sqr = rp*rp + rc*rc - 2*rp*rc*cospsi;
kappa = rc*rc*coslatc;
res += wlon*wlat*wr*kappa*(rc*kphi)/pow(l_sqr, 1.5);
}
}
}
scale = d2r*(tess.e - tess.w)*d2r*(tess.n - tess.s)*(tess.r2 - tess.r1)/8.;
res *= SI2MGAL*G*tess.density*scale;
return res;
}
/* Calculates gy caused by a tesseroid. */
double tess_gy(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, res,
cospsi, wlon, wlat, wr, scale;
register int i, j, k;
coslatp = cos(d2r*latp);
sinlatp = sin(d2r*latp);
res = 0;
for(k = 0; k < glq_lon.order; k++)
{
coslon = cos(d2r*(lonp - glq_lon.nodes[k]));
sinlon = sin(d2r*(glq_lon.nodes[k] - lonp));
wlon = glq_lon.weights[k];
for(j = 0; j < glq_lat.order; j++)
{
sinlatc = glq_lat.nodes_sin[j];
coslatc = glq_lat.nodes_cos[j];
cospsi = sinlatp*sinlatc + coslatp*coslatc*coslon;
wlat = glq_lat.weights[j];
for(i = 0; i < glq_r.order; i++)
{
wr = glq_r.weights[i];
rc = glq_r.nodes[i];
l_sqr = rp*rp + rc*rc - 2*rp*rc*cospsi;
kappa = rc*rc*coslatc;
res += wlon*wlat*wr*kappa*(rc*coslatc*sinlon)/pow(l_sqr, 1.5);
}
}
}
scale = d2r*(tess.e - tess.w)*d2r*(tess.n - tess.s)*(tess.r2 - tess.r1)/8.;
res *= SI2MGAL*G*tess.density*scale;
return res;
}
/* Calculates gz caused by a tesseroid. */
double tess_gz(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, res,
wlon, wlat, wr, scale;
register int i, j, k;
coslatp = cos(d2r*latp);
sinlatp = sin(d2r*latp);
res = 0;
for(k = 0; k < glq_lon.order; k++)
{
coslon = cos(d2r*(lonp - glq_lon.nodes[k]));
wlon = glq_lon.weights[k];
for(j = 0; j < glq_lat.order; j++)
{
sinlatc = glq_lat.nodes_sin[j];
coslatc = glq_lat.nodes_cos[j];
cospsi = sinlatp*sinlatc + coslatp*coslatc*coslon;
wlat = glq_lat.weights[j];
for(i = 0; i < glq_r.order; i++)
{
wr = glq_r.weights[i];
rc = glq_r.nodes[i];
l_sqr = rp*rp + rc*rc - 2*rp*rc*cospsi;
kappa = rc*rc*coslatc;
res += wlon*wlat*wr*kappa*(rc*cospsi - rp)/pow(l_sqr, 1.5);
}
}
}
scale = d2r*(tess.e - tess.w)*d2r*(tess.n - tess.s)*(tess.r2 - tess.r1)/8.;
res *= SI2MGAL*G*tess.density*scale;
/* Used this to make z point down */
return -1*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, l5,
cospsi, wlon, wlat, wr, scale;
register int i, j, k;
coslatp = cos(d2r*latp);
sinlatp = sin(d2r*latp);
res = 0;
for(k = 0; k < glq_lon.order; k++)
{
coslon = cos(d2r*(lonp - glq_lon.nodes[k]));
wlon = glq_lon.weights[k];
for(j = 0; j < glq_lat.order; j++)
{
sinlatc = glq_lat.nodes_sin[j];
coslatc = glq_lat.nodes_cos[j];
kphi = coslatp*sinlatc - sinlatp*coslatc*coslon;
cospsi = sinlatp*sinlatc + coslatp*coslatc*coslon;
wlat = glq_lat.weights[j];
for(i = 0; i < glq_r.order; i++)
{
wr = glq_r.weights[i];
rc = glq_r.nodes[i];
l_sqr = rp*rp + rc*rc - 2*rp*rc*cospsi;
l5 = pow(l_sqr, 2.5);
kappa = rc*rc*coslatc;
res += wlon*wlat*wr*kappa*(3*rc*kphi*rc*kphi - l_sqr)/l5;
}
}
}
scale = d2r*(tess.e - tess.w)*d2r*(tess.n - tess.s)*(tess.r2 - tess.r1)/8.;
res *= SI2EOTVOS*G*tess.density*scale;
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,
cospsi, wlon, wlat, wr, scale;
register int i, j, k;
coslatp = cos(d2r*latp);
sinlatp = sin(d2r*latp);
res = 0;
for(k = 0; k < glq_lon.order; k++)
{
coslon = cos(d2r*(lonp - glq_lon.nodes[k]));
sinlon = sin(d2r*(glq_lon.nodes[k] - lonp));
wlon = glq_lon.weights[k];
for(j = 0; j < glq_lat.order; j++)
{
sinlatc = glq_lat.nodes_sin[j];
coslatc = glq_lat.nodes_cos[j];
kphi = coslatp*sinlatc - sinlatp*coslatc*coslon;
cospsi = sinlatp*sinlatc + coslatp*coslatc*coslon;
wlat = glq_lat.weights[j];
for(i = 0; i < glq_r.order; i++)
{
wr = glq_r.weights[i];
rc = glq_r.nodes[i];
l_sqr = rp*rp + rc*rc - 2*rp*rc*cospsi;
kappa = rc*rc*coslatc;
deltax = rc*kphi;
deltay = rc*coslatc*sinlon;
res += wlon*wlat*wr*kappa*(3*deltax*deltay)/pow(l_sqr, 2.5);
}
}
}
scale = d2r*(tess.e - tess.w)*d2r*(tess.n - tess.s)*(tess.r2 - tess.r1)/8.;
res *= SI2EOTVOS*G*tess.density*scale;
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,
wlon, wlat, wr, scale;
register int i, j, k;
coslatp = cos(d2r*latp);
sinlatp = sin(d2r*latp);
res = 0;
for(k = 0; k < glq_lon.order; k++)
{
coslon = cos(d2r*(lonp - glq_lon.nodes[k]));
wlon = glq_lon.weights[k];
for(j = 0; j < glq_lat.order; j++)
{
sinlatc = glq_lat.nodes_sin[j];
coslatc = glq_lat.nodes_cos[j];
cospsi = sinlatp*sinlatc + coslatp*coslatc*coslon;
kphi = coslatp*sinlatc - sinlatp*coslatc*coslon;
wlat = glq_lat.weights[j];
for(i = 0; i < glq_r.order; i++)
{
wr = glq_r.weights[i];
rc = glq_r.nodes[i];
l_sqr = rp*rp + rc*rc - 2*rp*rc*cospsi;
kappa = rc*rc*coslatc;
deltax = rc*kphi;
deltaz = rc*cospsi - rp;
res += wlon*wlat*wr*kappa*(3*deltax*deltaz)/pow(l_sqr, 2.5);
}
}
}
scale = d2r*(tess.e - tess.w)*d2r*(tess.n - tess.s)*(tess.r2 - tess.r1)/8.;
res *= SI2EOTVOS*G*tess.density*scale;
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, l5,
cospsi, wlon, wlat, wr, scale;
register int i, j, k;
coslatp = cos(d2r*latp);
sinlatp = sin(d2r*latp);
res = 0;
for(k = 0; k < glq_lon.order; k++)
{
coslon = cos(d2r*(lonp - glq_lon.nodes[k]));
sinlon = sin(d2r*(glq_lon.nodes[k] - lonp));
wlon = glq_lon.weights[k];
for(j = 0; j < glq_lat.order; j++)
{
sinlatc = glq_lat.nodes_sin[j];
coslatc = glq_lat.nodes_cos[j];
cospsi = sinlatp*sinlatc + coslatp*coslatc*coslon;
wlat = glq_lat.weights[j];
for(i = 0; i < glq_r.order; i++)
{
wr = glq_r.weights[i];
rc = glq_r.nodes[i];
l_sqr = rp*rp + rc*rc - 2*rp*rc*cospsi;
l5 = pow(l_sqr, 2.5);
kappa = rc*rc*coslatc;
deltay = rc*coslatc*sinlon;
res += wlon*wlat*wr*kappa*(3*deltay*deltay - l_sqr)/l5;
}
}
}
scale = d2r*(tess.e - tess.w)*d2r*(tess.n - tess.s)*(tess.r2 - tess.r1)/8.;
res *= SI2EOTVOS*G*tess.density*scale;
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,
wlon, wlat, wr, scale;
register int i, j, k;
coslatp = cos(d2r*latp);
sinlatp = sin(d2r*latp);
res = 0;
for(k = 0; k < glq_lon.order; k++)
{
coslon = cos(d2r*(lonp - glq_lon.nodes[k]));
sinlon = sin(d2r*(glq_lon.nodes[k] - lonp));
wlon = glq_lon.weights[k];
for(j = 0; j < glq_lat.order; j++)
{
sinlatc = glq_lat.nodes_sin[j];
coslatc = glq_lat.nodes_cos[j];
cospsi = sinlatp*sinlatc + coslatp*coslatc*coslon;
wlat = glq_lat.weights[j];
for(i = 0; i < glq_r.order; i++)
{
wr = glq_r.weights[i];
rc = glq_r.nodes[i];
l_sqr = rp*rp + rc*rc - 2*rp*rc*cospsi;
kappa = rc*rc*coslatc;
deltay = rc*coslatc*sinlon;
deltaz = rc*cospsi - rp;
res += wlon*wlat*wr*kappa*(3*deltay*deltaz)/pow(l_sqr, 2.5);
}
}
}
scale = d2r*(tess.e - tess.w)*d2r*(tess.n - tess.s)*(tess.r2 - tess.r1)/8.;
res *= SI2EOTVOS*G*tess.density*scale;
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,
wlon, wlat, wr, scale, l5;
register int i, j, k;
coslatp = cos(d2r*latp);
sinlatp = sin(d2r*latp);
res = 0;
for(k = 0; k < glq_lon.order; k++)
{
coslon = cos(d2r*(lonp - glq_lon.nodes[k]));
wlon = glq_lon.weights[k];
for(j = 0; j < glq_lat.order; j++)
{
sinlatc = glq_lat.nodes_sin[j];
coslatc = glq_lat.nodes_cos[j];
cospsi = sinlatp*sinlatc + coslatp*coslatc*coslon;
wlat = glq_lat.weights[j];
for(i = 0; i < glq_r.order; i++)
{
wr = glq_r.weights[i];
rc = glq_r.nodes[i];
l_sqr = rp*rp + rc*rc - 2*rp*rc*cospsi;
l5 = pow(l_sqr, 2.5);
kappa = rc*rc*coslatc;
deltaz = rc*cospsi - rp;
res += wlon*wlat*wr*kappa*(3*deltaz*deltaz - l_sqr)/l5;
}
}
}
scale = d2r*(tess.e - tess.w)*d2r*(tess.n - tess.s)*(tess.r2 - tess.r1)/8.;
res *= SI2EOTVOS*G*tess.density*scale;
return res;
}

501
lib/grav_tess.h Normal file
View File

@ -0,0 +1,501 @@
/*
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"
/** Calculates the field of a tesseroid model at a given point.
Uses a function pointer to call one of the apropriate field calculating
functions:
- tess_gx()
- tess_gy()
- tess_gz()
- tess_gxx()
- tess_gxy()
- tess_gxz()
- tess_gyy()
- tess_gyz()
- tess_gzz()
To pass a function pointer to a function use something like:
\verbatim
calc_tess_model(my_model, 10, 0, 10, 1, glqlon, glqlat, glqr, &tess_gx);
\endverbatim
This would calculate the gx effect of the model my_model with 10 tesseroids
at lon=0 lat=10 r=1.
Will re-use the same GLQ structures, and therefore the <b>same order, for all
the tesseroids</b>.
@param model TESSEROID array defining the model
@param size number of tesseroids in the model
@param lonp longitude of the computation point P
@param latp latitude of the computation point P
@param rp radial coordinate of the computation point P
@param glq_lon pointer to GLQ structure used for the longitudinal integration
@param glq_lat pointer to GLQ structure used for the latitudinal integration
@param glq_r pointer to GLQ structure used for the radial integration
@param field pointer to one of the field calculating functions
@return the sum of the fields of all the tesseroids in the model
*/
extern 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));
/** Adaptatively calculate the field of a tesseroid model at a given point by
splitting the tesseroids if necessary to maintain GLQ stability.
See calc_tess_model() for more details.
Will re-use the same GLQ structures, and therefore the <b>same order, for all
the tesseroids</b>.
@param model TESSEROID array defining the model
@param size number of tesseroids in the model
@param lonp longitude of the computation point P
@param latp latitude of the computation point P
@param rp radial coordinate of the computation point P
@param glq_lon pointer to GLQ structure used for the longitudinal integration
@param glq_lat pointer to GLQ structure used for the latitudinal integration
@param glq_r pointer to GLQ structure used for the radial integration
@param field pointer to one of the field calculating functions
@param ratio distance-to-size ratio for doing adaptative resizing
@return the sum of the fields of all the tesseroids in the model
*/
extern 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);
/** Calculates potential caused by a tesseroid.
\f[
V(r_p,\phi_p,\lambda_p) = G \rho \displaystyle\int_{\lambda_1}^{\lambda_2}
\displaystyle\int_{\phi_1}^{\phi_2} \displaystyle\int_{r_1}^{r_2}
\frac{1}{\ell}\kappa \ d r' d \phi' d \lambda'
\f]
<b>Input and output values in SI units and degrees</b>!
Use function glq_new() to create the GLQ parameters required. The integration
limits should be set to:
- glq_lon: lower = tess.w and upper = tess.e (in degrees)
- glq_lat: lower = tess.s and upper = tess.n (in degrees)
- glq_r: lower = tess.r1 and upper = tess.r2
@param tess data structure describing the tesseroid
@param lonp longitude of the computation point P
@param latp latitude of the computation point P
@param rp radial coordinate of the computation point P
@param glq_lon GLQ structure with the nodes, weights and integration limits set
for the longitudinal integration
@param glq_lat GLQ structure with the nodes, weights and integration limits set
for the latitudinal integration
@param glq_r GLQ structure with the nodes, weights and integration limits set
for the radial integration
@return field calculated at P
*/
extern double tess_pot(TESSEROID tess, double lonp, double latp, double rp,
GLQ glq_lon, GLQ glq_lat, GLQ glq_r);
/** Calculates gx caused by a tesseroid (Grombein et al., 2010).
\f[
g_x(r_p,\phi_p,\lambda_p) = G \rho \displaystyle\int_{\lambda_1}^{\lambda_2}
\displaystyle\int_{\phi_1}^{\phi_2} \displaystyle\int_{r_1}^{r_2}
\frac{r'K_{\phi}}{\ell^3}\kappa \ d r' d \phi' d \lambda'
\f]
The derivatives of the potential are made with respect to the local coordinate
system <b>x->North, y->East, z->out</b>
<b>Input values in SI units and <b>degrees</b> and returns values in mGal!</b>
Use function glq_new() to create the GLQ parameters required. The integration
limits should be set to:
- glq_lon: lower = tess.w and upper = tess.e (in degrees)
- glq_lat: lower = tess.s and upper = tess.n (in degrees)
- glq_r: lower = tess.r1 and upper = tess.r2
@param tess data structure describing the tesseroid
@param lonp longitude of the computation point P
@param latp latitude of the computation point P
@param rp radial coordinate of the computation point P
@param glq_lon GLQ structure with the nodes, weights and integration limits set
for the longitudinal integration
@param glq_lat GLQ structure with the nodes, weights and integration limits set
for the latitudinal integration
@param glq_r GLQ structure with the nodes, weights and integration limits set
for the radial integration
@return field calculated at P
*/
extern double tess_gx(TESSEROID tess, double lonp, double latp, double rp,
GLQ glq_lon, GLQ glq_lat, GLQ glq_r);
/** Calculates gy caused by a tesseroid (Grombein et al., 2010).
\f[
g_y(r_p,\phi_p,\lambda_p) = G \rho \displaystyle\int_{\lambda_1}^{\lambda_2}
\displaystyle\int_{\phi_1}^{\phi_2} \displaystyle\int_{r_1}^{r_2}
\frac{r'\cos\phi'\sin(\lambda'-\lambda)}{\ell^3}\kappa
\ d r' d \phi' d \lambda'
\f]
The derivatives of the potential are made with respect to the local coordinate
system <b>x->North, y->East, z->out</b>
<b>Input values in SI units and <b>degrees</b> and returns values in mGal!</b>
Use function glq_new() to create the GLQ parameters required. The integration
limits should be set to:
- glq_lon: lower = tess.w and upper = tess.e (in degrees)
- glq_lat: lower = tess.s and upper = tess.n (in degrees)
- glq_r: lower = tess.r1 and upper = tess.r2
@param tess data structure describing the tesseroid
@param lonp longitude of the computation point P
@param latp latitude of the computation point P
@param rp radial coordinate of the computation point P
@param glq_lon GLQ structure with the nodes, weights and integration limits set
for the longitudinal integration
@param glq_lat GLQ structure with the nodes, weights and integration limits set
for the latitudinal integration
@param glq_r GLQ structure with the nodes, weights and integration limits set
for the radial integration
@return field calculated at P
*/
extern double tess_gy(TESSEROID tess, double lonp, double latp, double rp,
GLQ glq_lon, GLQ glq_lat, GLQ glq_r);
/** Calculates gz caused by a tesseroid (Grombein et al., 2010).
\f[
g_z(r_p,\phi_p,\lambda_p) = G \rho \displaystyle\int_{\lambda_1}^{\lambda_2}
\displaystyle\int_{\phi_1}^{\phi_2} \displaystyle\int_{r_1}^{r_2}
\frac{r'\cos\psi - r_p}{\ell^3}\kappa \ d r' d \phi' d \lambda'
\f]
The derivatives of the potential are made with respect to the local coordinate
system <b>x->North, y->East, z->out</b>
<b>Input values in SI units and <b>degrees</b> and returns values in mGal!</b>
Use function glq_new() to create the GLQ parameters required. The integration
limits should be set to:
- glq_lon: lower = tess.w and upper = tess.e (in degrees)
- glq_lat: lower = tess.s and upper = tess.n (in degrees)
- glq_r: lower = tess.r1 and upper = tess.r2
@param tess data structure describing the tesseroid
@param lonp longitude of the computation point P
@param latp latitude of the computation point P
@param rp radial coordinate of the computation point P
@param glq_lon GLQ structure with the nodes, weights and integration limits set
for the longitudinal integration
@param glq_lat GLQ structure with the nodes, weights and integration limits set
for the latitudinal integration
@param glq_r GLQ structure with the nodes, weights and integration limits set
for the radial integration
@return field calculated at P
*/
extern double tess_gz(TESSEROID tess, double lonp, double latp, double rp,
GLQ glq_lon, GLQ glq_lat, GLQ glq_r);
/** Calculates gxx caused by a tesseroid (Grombein et al., 2010).
\f[
g_{xx}(r_p,\phi_p,\lambda_p) = G \rho \displaystyle\int_{\lambda_1}^{\lambda_2}
\displaystyle\int_{\phi_1}^{\phi_2} \displaystyle\int_{r_1}^{r_2}
\frac{3(r' K_{\phi})^2 - \ell^2}{\ell^5}\kappa \ d r' d \phi' d \lambda'
\f]
The derivatives of the potential are made with respect to the local coordinate
system <b>x->North, y->East, z->out</b>
<b>Input values in SI units and <b>degrees</b> and returns values in Eotvos!</b>
Use function glq_new() to create the GLQ parameters required. The integration
limits should be set to:
- glq_lon: lower = tess.w and upper = tess.e (in degrees)
- glq_lat: lower = tess.s and upper = tess.n (in degrees)
- glq_r: lower = tess.r1 and upper = tess.r2
@param tess data structure describing the tesseroid
@param lonp longitude of the computation point P
@param latp latitude of the computation point P
@param rp radial coordinate of the computation point P
@param glq_lon GLQ structure with the nodes, weights and integration limits set
for the longitudinal integration
@param glq_lat GLQ structure with the nodes, weights and integration limits set
for the latitudinal integration
@param glq_r GLQ structure with the nodes, weights and integration limits set
for the radial integration
@return field calculated at P
*/
extern double tess_gxx(TESSEROID tess, double lonp, double latp, double rp,
GLQ glq_lon, GLQ glq_lat, GLQ glq_r);
/** Calculates gxy caused by a tesseroid (Grombein et al., 2010).
\f[
g_{xy}(r_p,\phi_p,\lambda_p) = G \rho \displaystyle\int_{\lambda_1}^{\lambda_2}
\displaystyle\int_{\phi_1}^{\phi_2} \displaystyle\int_{r_1}^{r_2}
\frac{3{r'}^2 K_{\phi}\cos\phi'\sin(\lambda' - \lambda_p)}{\ell^5}
\kappa \ d r' d \phi' d \lambda'
\f]
The derivatives of the potential are made with respect to the local coordinate
system <b>x->North, y->East, z->out</b>
<b>Input values in SI units and <b>degrees</b> and returns values in Eotvos!</b>
Use function glq_new() to create the GLQ parameters required. The integration
limits should be set to:
- glq_lon: lower = tess.w and upper = tess.e (in degrees)
- glq_lat: lower = tess.s and upper = tess.n (in degrees)
- glq_r: lower = tess.r1 and upper = tess.r2
@param tess data structure describing the tesseroid
@param lonp longitude of the computation point P
@param latp latitude of the computation point P
@param rp radial coordinate of the computation point P
@param glq_lon GLQ structure with the nodes, weights and integration limits set
for the longitudinal integration
@param glq_lat GLQ structure with the nodes, weights and integration limits set
for the latitudinal integration
@param glq_r GLQ structure with the nodes, weights and integration limits set
for the radial integration
@return field calculated at P
*/
extern double tess_gxy(TESSEROID tess, double lonp, double latp, double rp,
GLQ glq_lon, GLQ glq_lat, GLQ glq_r);
/** Calculates gxz caused by a tesseroid (Grombein et al., 2010).
\f[
g_{xz}(r_p,\phi_p,\lambda_p) = G \rho \displaystyle\int_{\lambda_1}^{\lambda_2}
\displaystyle\int_{\phi_1}^{\phi_2} \displaystyle\int_{r_1}^{r_2}
\frac{3 r' K_{\phi}(r' \cos\psi - r_p)}{\ell^5}\kappa
\ d r' d \phi' d \lambda'
\f]
The derivatives of the potential are made with respect to the local coordinate
system <b>x->North, y->East, z->out</b>
<b>Input values in SI units and <b>degrees</b> and returns values in Eotvos!</b>
Use function glq_new() to create the GLQ parameters required. The integration
limits should be set to:
- glq_lon: lower = tess.w and upper = tess.e (in degrees)
- glq_lat: lower = tess.s and upper = tess.n (in degrees)
- glq_r: lower = tess.r1 and upper = tess.r2
@param tess data structure describing the tesseroid
@param lonp longitude of the computation point P
@param latp latitude of the computation point P
@param rp radial coordinate of the computation point P
@param glq_lon GLQ structure with the nodes, weights and integration limits set
for the longitudinal integration
@param glq_lat GLQ structure with the nodes, weights and integration limits set
for the latitudinal integration
@param glq_r GLQ structure with the nodes, weights and integration limits set
for the radial integration
@return field calculated at P
*/
extern double tess_gxz(TESSEROID tess, double lonp, double latp, double rp,
GLQ glq_lon, GLQ glq_lat, GLQ glq_r);
/** Calculates gyy caused by a tesseroid (Grombein et al., 2010).
\f[
g_{yy}(r_p,\phi_p,\lambda_p) = G \rho \displaystyle\int_{\lambda_1}^{\lambda_2}
\displaystyle\int_{\phi_1}^{\phi_2} \displaystyle\int_{r_1}^{r_2}
\frac{3(r'\cos\phi'\sin(\lambda' - \lambda_p))^2 - \ell^2}{\ell^5}
\kappa \ d r' d \phi' d \lambda'
\f]
The derivatives of the potential are made with respect to the local coordinate
system <b>x->North, y->East, z->out</b>
<b>Input values in SI units and <b>degrees</b> and returns values in Eotvos!</b>
Use function glq_new() to create the GLQ parameters required. The integration
limits should be set to:
- glq_lon: lower = tess.w and upper = tess.e (in degrees)
- glq_lat: lower = tess.s and upper = tess.n (in degrees)
- glq_r: lower = tess.r1 and upper = tess.r2
@param tess data structure describing the tesseroid
@param lonp longitude of the computation point P
@param latp latitude of the computation point P
@param rp radial coordinate of the computation point P
@param glq_lon GLQ structure with the nodes, weights and integration limits set
for the longitudinal integration
@param glq_lat GLQ structure with the nodes, weights and integration limits set
for the latitudinal integration
@param glq_r GLQ structure with the nodes, weights and integration limits set
for the radial integration
@return field calculated at P
*/
extern double tess_gyy(TESSEROID tess, double lonp, double latp, double rp,
GLQ glq_lon, GLQ glq_lat, GLQ glq_r);
/** Calculates gyz caused by a tesseroid (Grombein et al., 2010).
\f[
g_{yz}(r_p,\phi_p,\lambda_p) = G \rho \displaystyle\int_{\lambda_1}^{\lambda_2}
\displaystyle\int_{\phi_1}^{\phi_2} \displaystyle\int_{r_1}^{r_2}
\frac{3 r' \cos\phi' \sin(\lambda' - \lambda_p)(r'\cos\psi - r_p)}{\ell^5}
\kappa \ d r' d \phi' d \lambda'
\f]
The derivatives of the potential are made with respect to the local coordinate
system <b>x->North, y->East, z->out</b>
<b>Input values in SI units and <b>degrees</b> and returns values in Eotvos!</b>
Use function glq_new() to create the GLQ parameters required. The integration
limits should be set to:
- glq_lon: lower = tess.w and upper = tess.e (in degrees)
- glq_lat: lower = tess.s and upper = tess.n (in degrees)
- glq_r: lower = tess.r1 and upper = tess.r2
@param tess data structure describing the tesseroid
@param lonp longitude of the computation point P
@param latp latitude of the computation point P
@param rp radial coordinate of the computation point P
@param glq_lon GLQ structure with the nodes, weights and integration limits set
for the longitudinal integration
@param glq_lat GLQ structure with the nodes, weights and integration limits set
for the latitudinal integration
@param glq_r GLQ structure with the nodes, weights and integration limits set
for the radial integration
@return field calculated at P
*/
extern double tess_gyz(TESSEROID tess, double lonp, double latp, double rp,
GLQ glq_lon, GLQ glq_lat, GLQ glq_r);
/** Calculates gzz caused by a tesseroid (Grombein et al., 2010).
\f[
g_{zz}(r_p,\phi_p,\lambda_p) = G \rho \displaystyle\int_{\lambda_1}^{\lambda_2}
\displaystyle\int_{\phi_1}^{\phi_2} \displaystyle\int_{r_1}^{r_2}
\frac{3(r'\cos\psi-r_p)^2 - \ell^2}{\ell^5}\kappa \ d r' d \phi' d \lambda'
\f]
The derivatives of the potential are made with respect to the local coordinate
system <b>x->North, y->East, z->out</b>
<b>Input values in SI units and <b>degrees</b> and returns values in Eotvos!</b>
Use function glq_new() to create the GLQ parameters required. The integration
limits should be set to:
- glq_lon: lower = tess.w and upper = tess.e (in degrees)
- glq_lat: lower = tess.s and upper = tess.n (in degrees)
- glq_r: lower = tess.r1 and upper = tess.r2
@param tess data structure describing the tesseroid
@param lonp longitude of the computation point P
@param latp latitude of the computation point P
@param rp radial coordinate of the computation point P
@param glq_lon GLQ structure with the nodes, weights and integration limits set
for the longitudinal integration
@param glq_lat GLQ structure with the nodes, weights and integration limits set
for the latitudinal integration
@param glq_r GLQ structure with the nodes, weights and integration limits set
for the radial integration
@return field calculated at P
*/
extern double tess_gzz(TESSEROID tess, double lonp, double latp, double rp,
GLQ glq_lon, GLQ glq_lat, GLQ glq_r);
#endif

110
lib/logger.c Normal file
View File

@ -0,0 +1,110 @@
/*
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 */
/* These messages are always printed to stderr and the log file */
void log_debug(const char *fmt, ...)
{
char msg[10000];
va_list args;
va_start(args, fmt);
vsprintf(msg, fmt, args);
va_end(args);
fprintf(stderr, "DEBUG: %s\n", msg);
if(logger.filelogging)
{
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, "\nERROR: %s\n\n", msg);
}
if(logger.filelogging && logger.file_level <= LOG_ERROR)
{
fprintf(logger.logfile, "\nERROR: %s\n\n", msg);
}
}

166
lib/logger.h Normal 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! */
extern 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
*/
extern 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
*/
extern 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.
*/
extern 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.
*/
extern 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.
*/
extern 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.
*/
extern void log_error(const char *fmt, ...);
#endif

1410
lib/parsers.c Normal file

File diff suppressed because it is too large Load Diff

316
lib/parsers.h Normal file
View File

@ -0,0 +1,316 @@
/*
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;
/** Store input arguments and option flags for tessmass program */
typedef struct tessmass_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 */
int use_range; /**< flag to indicate wether to use a density range or not */
double low_dens; /**< lower bound for density range */
double high_dens; /**< upper bound for density range */
} TESSMASS_ARGS;
/** Store input arguments and option flags for tess2prism program */
typedef struct tess2prism_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 */
int flatten; /**< flag to indicate wether to use a flattened tesseroid or
a prism in spherical coordinates */
} TESS2PRISM_ARGS;
/** Store input arguments and option flags for tessmodgen program */
typedef struct tessmodgen_args
{
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 */
double dlon; /**< grid spacing in longitude */
double dlat; /**< grid spacing in latitude */
double ref; /**< depth of the reference level */
double dens; /**< density of the tesseroids */
int fix_density; /**< flag to tell wether using value passed by -d */
} TESSMODGEN_ARGS;
/** Store input arguments and option flags for tesslayers program */
typedef struct tesslayers_args
{
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 */
double dlon; /**< grid spacing in longitude */
double dlat; /**< grid spacing in latitude */
} TESSLAYERS_ARGS;
/** Store input arguments and option flags for tessg* programs */
typedef struct tessg_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 ratio; /**< distance-size ratio used for recusive division */
} TESSG_ARGS;
/** Store input arguments and option flags for tessgrd program */
typedef struct tessgrd_args
{
double w; /**< western border of the grid */
double e; /**< eastern border of the grid */
double s; /**< southern border of the grid */
double n; /**< northern border of the grid */
int nlon; /**< number of grid points in the longitudinal direction */
int nlat; /**< number of grid points in the latitudinal direction */
double height; /**< height above geoid of the grid */
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 */
} TESSGRD_ARGS;
/** Parse basic command line arguments for programs
Basic arguments are: -h (for help msg), -v (for verbose), -l (for log file),
--version and an input file.
@param argc number of command line arguments
@param argv command line arguments
@param progname name of the specific program
@param args to return the parsed arguments
@param print_help pointer to a function that prints the help message for the
program
@return Return code:
- 0: if all went well
- 1: if there were bad arguments and program should exit
- 2: if printed help or version info and program should exit
- 3: if input file was missing (doesn't log an error)
*/
extern int parse_basic_args(int argc, char **argv, const char *progname,
BASIC_ARGS *args, void (*print_help)(void));
/** Parse command line arguments for tessmass program
@param argc number of command line arguments
@param argv command line arguments
@param progname name of the program
@param args to return the parsed arguments
@param print_help pointer to a function that prints the help message for the
program
@return Return code:
- 0: if all went well
- 1: if there were bad arguments and program should exit
- 2: if printed help or version info and program should exit
- 3: if input file was missing (doesn't log an error)
*/
extern int parse_tessmass_args(int argc, char **argv, const char *progname,
TESSMASS_ARGS *args, void (*print_help)(void));
/** Parse command line arguments for tess2prism program
@param argc number of command line arguments
@param argv command line arguments
@param progname name of the program
@param args to return the parsed arguments
@param print_help pointer to a function that prints the help message for the
program
@return Return code:
- 0: if all went well
- 1: if there were bad arguments and program should exit
- 2: if printed help or version info and program should exit
- 3: if input file was missing (doesn't log an error)
*/
extern int parse_tess2prism_args(int argc, char **argv, const char *progname,
TESS2PRISM_ARGS *args, void (*print_help)(void));
/** Parse command line arguments for tessmodgen program
@param argc number of command line arguments
@param argv command line arguments
@param progname name of the program
@param args to return the parsed arguments
@param print_help pointer to a function that prints the help message for the
program
@return Return code:
- 0: if all went well
- 1: if there were bad arguments and program should exit
- 2: if printed help or version info and program should exit
*/
extern int parse_tessmodgen_args(int argc, char **argv, const char *progname,
TESSMODGEN_ARGS *args, void (*print_help)(void));
/** Parse command line arguments for tesslayers program
@param argc number of command line arguments
@param argv command line arguments
@param progname name of the program
@param args to return the parsed arguments
@param print_help pointer to a function that prints the help message for the
program
@return Return code:
- 0: if all went well
- 1: if there were bad arguments and program should exit
- 2: if printed help or version info and program should exit
*/
extern int parse_tesslayers_args(int argc, char **argv, const char *progname,
TESSLAYERS_ARGS *args, void (*print_help)(void));
/** Parse command line arguments for tessg* programs
logs the bad argument warnings using logger.h
@param argc number of command line arguments
@param argv command line arguments
@param progname name of the specific program
@param args to return the parsed arguments
@return Return code:
- 0: if all went well
- 1: if there were bad arguments and program should exit
- 2: if printed help or version info and program should exit
*/
extern int parse_tessg_args(int argc, char **argv, const char *progname,
TESSG_ARGS *args, void (*print_help)(const char *));
/** Parse command line arguments for tessgrd program
logs the bad argument warnings using logger.h
@param argc number of command line arguments
@param argv command line arguments
@param args to return the parsed arguments
@return Return code:
- 0: if all went well
- 1: if there were bad arguments and program should exit
- 2: if printed help or version info and program should exit
*/
extern int parse_tessgrd_args(int argc, char **argv, TESSGRD_ARGS *args,
void (*print_help)(void));
/** Strip trailing spaces and newlines from the end of a string
Done IN PLACE!
@param str string to strip
*/
extern void strstrip(char *str);
/** Read a single tesseroid from a string
@param str string with the tesseroid parameters
@param tess used to return the read tesseroid
@return 0 if all went well, 1 if failed to read.
*/
extern int gets_tess(const char *str, TESSEROID *tess);
/** Read tesseroids from an open file and store them in an array.
Allocates memory. Don't forget to free 'model'!
@param modelfile open FILE for reading with the tesseroid model
@param size used to return the size of the model read
@return pointer to array with the model. NULL if there was an error
*/
extern TESSEROID * read_tess_model(FILE *modelfile, int *size);
/** Read a single rectangular prism from a string
@param str string with the tesseroid parameters
@param prism used to return the read prism
@return 0 if all went well, 1 if failed to read.
*/
extern int gets_prism(const char *str, PRISM *prism);
/** Read a single rectangular prism and the spherical coordinates of its top
from a string
@param str string with the tesseroid parameters
@param prism used to return the read prism
@return 0 if all went well, 1 if failed to read.
*/
extern int gets_prism_sph(const char *str, PRISM *prism);
/** Read rectangular prisms from an open file and store them in an array.
Allocates memory. Don't forget to free 'model'!
@param modelfile open FILE for reading with the model
@param pos if not 0 (true) will read the spherical coordinates of the top as
well
@param size used to return the size of the model read
@return pointer to array with the model. NULL if there was an error
*/
extern PRISM * read_prism_model(FILE *modelfile, int pos, int *size);
/** Read the coordinates, height, thickness and densities of the layers and
convert it to tesseroids.
@param str string with the coordinates and layer parameters
@param dlon the size of the tesseroid in the longitudinal direction
@param dlat the size of the tesseroid in the latitudinal direction
@param tessbuff buffer used to return the tesseroids corresponding to the layer
@param buffsize the size of the buffer
@return the number of layers read and converted, -1 if there was an error
*/
extern int gets_layers(const char *str, double dlon, double dlat,
TESSEROID *tessbuff, int buffsize);
#endif

241
lib/prismg_main.c Normal file
View File

@ -0,0 +1,241 @@
/*
Generic main function for the prismg* programs.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "logger.h"
#include "version.h"
#include "grav_prism.h"
#include "geometry.h"
#include "parsers.h"
#include "prismg_main.h"
char global_progname[100];
/* Print the help message */
void print_help()
{
printf("Usage: %s MODELFILE [OPTIONS]\n\n", global_progname);
if(strcmp(global_progname + 5, "pot") == 0)
{
printf("Calculate the potential due to a rectangular prism model on\n");
}
else
{
printf("Calculate the %s component due to a rectangular prism model on\n",
global_progname + 5);
}
printf("specified observation points using Cartesian coordinates.\n\n");
printf("All input units are SI! Output is SI, mGal or Eotvos.\n\n");
printf("Coordinate system:\n");
printf(" The coordinate system for the prism is x->North, y->East\n");
printf(" and z->Down\n\n");
printf("Input:\n");
printf(" Computation points passed through standard input (stdin).\n");
printf(" Reads 3 or more values per line and inteprets the first 3 as:\n");
printf(" Easting(y) Northing(x) height \n");
printf(" (the coordinates of a computation point in meters).\n");
printf(" Other values in the line are ignored.\n");
printf(" Lines that start with # are ignored as comments.\n");
printf(" Lines should be no longer than 10000 (ten thousand) characters.");
printf(" \n\n");
printf("Output:\n");
printf(" Printed to standard output (stdout) in the form:\n");
printf(" y x height ... result\n");
printf(" ... represents any values that were read from input and\n");
printf(" ignored. In other words, the result is appended to the last\n");
printf(" column of the input. Use this to pipe prism* programs\n");
printf(" together.\n\n");
printf(" Comments about the provenance of the data are inserted into\n");
printf(" the top of the output\n\n");
printf("MODELFILE: File containing the prism model\n");
printf(" * Each prism is specified by the values of its borders\n");
printf(" and density\n");
printf(" * The file should contain one prism per line\n");
printf(" * If a line starts with # it will be considered a comment and\n");
printf(" will be ignored.\n");
printf(" * Each line should have the following column format:\n");
printf(" X1 X2 Y1 Y2 Z1 Z2 Density\n\n");
printf("Options:\n");
printf(" -h Print instructions.\n");
printf(" --version Print version and license information.\n");
printf(" -v Enable verbose printing to stderr.\n");
printf(" -lFILENAME Print log messages to file FILENAME.\n");
print_copyright();
}
/* Run the main for a generic prismg* program */
int run_prismg_main(int argc, char **argv, const char *progname,
double (*field)(PRISM, double, double, double))
{
BASIC_ARGS args;
PRISM *model;
int modelsize, rc, line, points = 0, error_exit = 0, bad_input = 0, i;
char buff[10000];
double x, y, height, res;
FILE *logfile = NULL, *modelfile = NULL;
time_t rawtime;
clock_t tstart;
struct tm * timeinfo;
log_init(LOG_INFO);
strcpy(global_progname, progname);
rc = parse_basic_args(argc, argv, progname, &args, &print_help);
if(rc == 3)
{
log_error("%s: missing input file", progname);
log_warning("Terminating due to bad input");
log_warning("Try '%s -h' for instructions", progname);
return 1;
}
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_INFO);
}
/* Print standard verbose */
log_info("%s (Tesseroids project) %s", progname, tesseroids_version);
time(&rawtime);
timeinfo = localtime(&rawtime);
log_info("(local time) %s", asctime(timeinfo));
/* Read the model file */
log_info("Reading prism model from file %s", args.inputfname);
modelfile = fopen(args.inputfname, "r");
if(modelfile == NULL)
{
log_error("failed to open model file %s", args.inputfname);
log_warning("Terminating due to bad input");
log_warning("Try '%s -h' for instructions", progname);
if(args.logtofile)
fclose(logfile);
return 1;
}
model = read_prism_model(modelfile, 0, &modelsize);
fclose(modelfile);
if(modelsize == 0)
{
log_error("prism file %s is empty", args.inputfname);
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.inputfname);
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 prism(s) read", modelsize);
/* Print a header on the output with provenance information */
if(strcmp(progname + 5, "pot") == 0)
{
printf("# Potential calculated with %s %s:\n", progname,
tesseroids_version);
}
else
{
printf("# %s component calculated with %s %s:\n", progname+5, progname,
tesseroids_version);
}
printf("# local time: %s", asctime(timeinfo));
printf("# model file: %s (%d prisms)\n", args.inputfname, modelsize);
/* Read each computation point from stdin and calculate */
log_info("Calculating (this may take a while)...");
tstart = clock();
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", &y, &x, &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);
for(res = 0, i = 0; i < modelsize; i++)
{
res += field(model[i], x, y, -height);
}
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);
log_info("Done");
if(args.logtofile)
fclose(logfile);
return 0;
}

31
lib/prismg_main.h Normal file
View File

@ -0,0 +1,31 @@
/*
Generic main function for the prismg* programs.
*/
#ifndef _TESSEROIDS_PRISMG_MAIN_H_
#define _TESSEROIDS_PRISMG_MAIN_H_
/* For the definitions of PRISM */
#include "geometry.h"
/** Print the help message
*/
extern void print_help();
/** Run the main for a generic prismg* program
@param argc number of command line arguments
@param argv command line arguments
@param progname name of the specific program
@param field pointer to function that calculates the field of a single prism
@return 0 is all went well. 1 if failed.
*/
extern int run_prismg_main(int argc, char **argv, const char *progname,
double (*field)(PRISM, double, double, double));
#endif

292
lib/tessg_main.c Normal file
View File

@ -0,0 +1,292 @@
/*
Generic main function for the tessg* 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 "tessg_main.h"
/* Print the help message for tessg* programs */
void print_tessg_help(const char *progname)
{
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("specified observation points.\n\n");
printf("Values are calculated in the local coordinate system of the\n");
printf("observation point: x-> North y-> East z-> Up (away from the\n");
printf("center of the Earth).\n");
printf("In order to maintain mainstream convention, component gz is\n");
printf("calculated with z-> Down.\n\n");
printf("All units either SI or degrees!\n\n");
printf("The computation of the gravitational effect of the tesseroids\n");
printf("is done using the Gauss-Legendre Quadrature (GLQ) numerical\n");
printf("integration method.\n\n");
printf("WARNING: Avoid computing directly on top or inside the\n");
printf(" tesseroids! This will break the GLQ and the formulas!\n");
printf("\n");
printf("Input:\n");
printf(" Computation points passed through standard input (stdin).\n");
printf(" Reads 3 or more values per line and inteprets the first 3 as:\n");
printf(" longitude, latitude and height\n");
printf(" of a computation points. Height should be in meters.\n");
printf(" Othervalues in the line are ignored.\n");
printf(" Lines that start with # are ignored as comments.\n");
printf(" Lines should be no longer than 10000 (ten thousand) characters.");
printf("\n\n");
printf("Output:\n");
printf(" Printed to standard output (stdout) in the form:\n");
printf(" lon lat height ... result\n");
printf(" ... represents any values that were read from input and\n");
printf(" ignored. In other words, the result is appended to the last\n");
printf(" column of the input. Use this to pipe tessg* programs\n");
printf(" together.\n");
printf(" * Comments about the provenance of the data are inserted into\n");
printf(" the top of the output\n\n");
printf("MODELFILE: File containing the tesseroid model\n");
printf(" * Each tesseroid is specified by the values of its borders\n");
printf(" and density\n");
printf(" * The file should contain one tesseroid per line\n");
printf(" * Each line should have the following column format:\n");
printf(" West East South North Top Bottom Density\n");
printf(" * Top and Bottom should be read as 'height to top' and \n");
printf(" 'height to bottom' from the mean Earth radius. Use negative\n");
printf(" values if bellow the surface, for example when modeling\n");
printf(" deep structures, and positive if above the surface, for\n");
printf(" example when modeling topography.\n");
printf(" * If a line starts with # it will be considered a comment and\n");
printf(" will be ignored.\n\n");
printf("Options:\n");
printf(" -a Disable the automatic subdividing of\n");
printf(" tesseroids. Subdividing is done to ensure the\n");
printf(" GLQ gives accurate results. ONLY USE THIS\n");
printf(" OPTION IF YOU KNOW WHAT YOU ARE DOING!\n");
printf(" -tRATIO Use a custom distance-size ratio for the\n");
printf(" automatic subdivision of tesseroids. ONLY USE\n");
printf(" THIS OPTION IF YOU KNOW WHAT YOU ARE DOING!\n");
printf(" -oOLON/OLAT/OR GLQ order to use in the longitudinal,\n");
printf(" latitudinal and radial integrations,\n");
printf(" respectively. Defaults to 2/2/2.\n");
printf(" Subdividing of tesseroids works best with the\n");
printf(" default order.\n");
printf(" -h Print instructions.\n");
printf(" --version Print version and license information.\n");
printf(" -v Enable verbose printing to stderr.\n");
printf(" -lFILENAME Print log messages to file FILENAME.\n");
print_copyright();
}
/* Run the main for a generic tessg* program */
int run_tessg_main(int argc, char **argv, const char *progname,
double (*field)(TESSEROID, double, double, double, GLQ, GLQ, GLQ),
double ratio)
{
TESSG_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;
FILE *logfile = NULL, *modelfile = NULL;
time_t rawtime;
clock_t tstart;
struct tm * timeinfo;
log_init(LOG_INFO);
rc = parse_tessg_args(argc, argv, progname, &args, &print_tessg_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.ratio != 0)
{
ratio = args.ratio;
}
/* 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 ratio for recusive division: %g", ratio);
/* 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 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_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 ratio for recusive division: %g\n", ratio);
/* Read each computation point from stdin and calculate */
log_info("Calculating (this may take a while)...");
tstart = clock();
for(line = 1; fgets(buff, 10000, stdin) != NULL; line++)
{
/* Check for comments and blank lines */
if(buff[0] == '#' || buff[0] == '\r' || buff[0] == '\n')
{
printf("%s", buff);
continue;
}
/* Need to remove \n and \r from end of buff first to print the
result in the end */
strstrip(buff);
if(sscanf(buff, "%lf %lf %lf", &lon, &lat, &height) != 3)
{
log_warning("bad/invalid computation point at line %d:", line);
log_warning(" '%s'", buff);
log_warning("skipping this line and continuing");
bad_input++;
continue;
}
if(args.adaptative)
{
res = calc_tess_model_adapt(model, modelsize, lon, lat,
height + MEAN_EARTH_RADIUS, glq_lon,
glq_lat, glq_r, field, ratio);
}
else
{
res = calc_tess_model(model, modelsize, lon, lat,
height + MEAN_EARTH_RADIUS, glq_lon,
glq_lat, glq_r, field);
}
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;
}

36
lib/tessg_main.h Normal file
View File

@ -0,0 +1,36 @@
/*
Generic main function for the tessg* programs.
*/
#ifndef _TESSEROIDS_TESSG_MAIN_H_
#define _TESSEROIDS_TESSG_MAIN_H_
/* For the definitions of GLQ and TESSEROID */
#include "glq.h"
#include "geometry.h"
/** Print the help message for tessg* programs
@param progname name of the specific tessg* program
*/
extern void print_tessg_help(const char *progname);
/** Run the main for a generic tessg* program
@param argc number of command line arguments
@param argv command line arguments
@param progname name of the specific program
@param field pointer to function that calculates the field of a single tesseroid
@param ratio distance-to-size ratio for doing adaptative resizing
@return 0 is all went well. 1 if failed.
*/
extern int run_tessg_main(int argc, char **argv, const char *progname,
double (*field)(TESSEROID, double, double, double, GLQ, GLQ, GLQ),
double ratio);
#endif

32
lib/version.c Normal file
View File

@ -0,0 +1,32 @@
#include "version.h"
/*
* The following definitions are copied from the original version.template file.
* And the version number is set to tesseroids-1.6 directly.
*
* By Yi Zhang. 2021-05-05
*/
/* Current project version number */
const char tesseroids_version[] = "tesseroids-1.6";
/* Print version number*/
void print_version(const char* version_num)
{
printf("%s", version_num);
}
/* Print a copyright notice */
void print_copyright()
{
printf("\nPart of the Tesseroids package (v%s).\n", tesseroids_version);
printf("\nProject site: <http://www.leouieda.com/tesseroids/>\n");
printf("Report bugs at: ");
printf("<https://github.com/leouieda/tesseroids/issues>\n");
printf("\nCopyright (C) 2011-$YEAR, Leonardo Uieda.\n");
printf("This software is distributed under the terms of the BSD License:\n");
printf("<http://tesseroids.readthedocs.org/en/latest/license.html>\n");
printf("This is free software: ");
printf("you are free to change and redistribute it.\n");
printf("There is NO WARRANTY, to the extent permitted by law.\n");
}

19
lib/version.h Normal file
View File

@ -0,0 +1,19 @@
/*
Hold the version number of the project.
*/
#ifndef _TESSEROIDS_VERSION_H_
#define _TESSEROIDS_VERSION_H_
#include "stdio.h"
/** Current project version number */
extern const char tesseroids_version[];
/** Print version number */
extern void print_version(const char* version_num);
/** Print version number */
extern void print_copyright();
#endif // _TESSEROIDS_VERSION_H_

15
test/CMakeLists.txt Normal file
View File

@ -0,0 +1,15 @@
#
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2")
if(WIN32)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --std=c++11 -O2")
endif()
#
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin/test)
#
add_executable(test_all test_all.c)
#
target_link_libraries(test_all PUBLIC tesseroids)

112
test/minunit.h Executable file
View File

@ -0,0 +1,112 @@
/* This is a modified version of the MinUnit testing tool.
As with the original, you may use this code for any purpose, with the
understanding that it comes with NO WARRANTY.
The original can be found at http://www.jera.com/techinfo/jtns/jtn002.html
USAGE:
Simmply include minunit.h and implement the testing functions using the
assertions. To run the tests, call mu_run_test. It will run the tests, print
out the verbose and if the test passed or failed. Use mu_print_summary to
print out a summary of the tests (how many were run, how long it took, how many
failed and how many passed).
Ex:
#include "minunit.h"
#include "myfuncs.h"
int tests_run = 0, tests_passed = 0, tests_failed = 0;
char * test_func1()
{
// Assert that func1 returns 3 when passed 1.2
// assertion will return the fail message if fails
mu_assert(func1(1.2) == 3, "func1 did not return 3 when passed 1.2");
// If the assertion passed, return 0
return 0;
}
int main()
{
mu_run_test(test_func1, "testing func1");
// If passed the time it took to run the tests will print it. Pass 0.0 to
// ommit the time
mu_print_summary(0.0);
return 0;
}
Simply compile and run the test program.
Author: Leonardo Uieda
Date: 25 Jan 2011
*/
#ifndef _MINUNIT_H_
#define _MINUNIT_H_
#include <stdio.h>
#include <math.h>
/* Global counters. WARNING: Don't forget to initialize in the main program
before running the tests! */
extern int tests_run, tests_passed, tests_failed;
/* Basic assertion. If fails, returns msg. If passes, returns 0 */
#define mu_assert(test, msg) do { if (!(test)) return msg; } while (0)
/* Assert if val equals expect within a certain precision prec */
#define mu_assert_almost_equals(val, expect, prec, msg) do { \
if(!(val <= expect + prec && val >= expect - prec)) { return msg; }\
} while (0)
/* Assert if val equals expect within a certain precision precision given in % */
#define mu_assert_almost_equals_rel(val, expect, prec, msg) do { \
if(fabs(val - expect) > 0.01*prec*fabs(expect)) { return msg; }\
} while (0)
/* Run a test case, print the verbose and check if passed or failed */
int mu_run_test(char *(*test)(void), char *verbose)
{
char *msg;
printf("\n%s... ", verbose);
msg = test();
tests_run++;
if(msg)
{
tests_failed++;
printf("FAIL:%s", msg);
return 1;
}
else
{
tests_passed++;
printf("pass");
return 0;
}
}
/* Print a summary of the tests ran and how long it took */
#define mu_print_summary(test_time) \
printf("\n\n-----------------------------------------------------------"); \
printf("\nRan %d test(s)", tests_run); \
if(test_time) { printf(" in %g seconds", test_time); } \
printf(". %d passed and %d failed.\n", tests_passed, tests_failed);
/* Utility for copying one array onto another */
int mu_counter;
#define mu_arraycp(original, copy, size) \
do {for(mu_counter=0; mu_counter<size; mu_counter++){ \
copy[mu_counter]=original[mu_counter]; } \
} while (0)
#endif

42
test/test_all.c Executable file
View File

@ -0,0 +1,42 @@
/*
Run all unit tests. This is compiled into a single executable (tesstest).
*/
#include <stdio.h>
#include <time.h>
#include "../lib/logger.h"
#include "minunit.h"
#include "test_glq.c"
#include "test_geometry.c"
#include "test_parsers.c"
#include "test_grav_prism.c"
#include "test_grav_prism_sph.c"
#include "test_grav_tess.c"
int tests_run = 0, tests_passed = 0, tests_failed = 0;
int main()
{
clock_t start = clock();
int failed = 0;
log_init(LOG_INFO);
failed += glq_run_all();
failed += geometry_run_all();
failed += parsers_run_all();
failed += grav_prism_run_all();
failed += grav_prism_sph_run_all();
failed += grav_tess_run_all();
mu_print_summary((double)(clock() - start)/CLOCKS_PER_SEC);
if(failed)
{
return 1;
}
else
{
return 0;
}
}

289
test/test_geometry.c Executable file
View File

@ -0,0 +1,289 @@
/*
Unit tests for geometry module.
*/
#include <stdio.h>
#include <math.h>
#include "minunit.h"
#include "../lib/geometry.h"
#include "../lib/constants.h"
/* To store fail messages */
char msg[1000];
static char * test_split_tess()
{
TESSEROID tess = {1, 2, 4, -1, 1, 5, 7},
expect[] = {{1, 2, 3, -1, 0, 5, 6}, {1, 3, 4, -1, 0, 5, 6},
{1, 2, 3, 0, 1, 5, 6}, {1, 3, 4, 0, 1, 5, 6},
{1, 2, 3, -1, 0, 6, 7}, {1, 3, 4, -1, 0, 6, 7},
{1, 2, 3, 0, 1, 6, 7}, {1, 3, 4, 0, 1, 6, 7}},
res[8];
int i, n;
n = split_tess(tess, 2, 2, 2, res);
sprintf(msg, "splitting in %d instead of 8", n);
mu_assert(n == 8, msg);
for(i = 0; i < 8; i++)
{
sprintf(msg, "failed for split %d: %g %g %g %g %g %g %g", i, res[i].w,
res[i].e, res[i].s, res[i].n, res[i].r1, res[i].r2,
res[i].density);
mu_assert(res[i].w == expect[i].w && res[i].e == expect[i].e &&
res[i].s == expect[i].s && res[i].n == expect[i].n &&
res[i].r1 == expect[i].r1 && res[i].r2 == expect[i].r2 &&
res[i].density == expect[i].density, msg);
}
return 0;
}
static char * test_split_uneven_tess()
{
TESSEROID tess = {1, 2, 4, -1, 1, 5, 7},
expect[] = {{1, 2, 3, -1, 0, 5, 7}, {1, 3, 4, -1, 0, 5, 7},
{1, 2, 3, 0, 1, 5, 7}, {1, 3, 4, 0, 1, 5, 7}},
res[4];
int i, n;
n = split_tess(tess, 2, 2, 1, res);
sprintf(msg, "splitting in %d instead of 4", n);
mu_assert(n == 4, msg);
for(i = 0; i < 4; i++)
{
sprintf(msg, "failed for split %d: %g %g %g %g %g %g %g", i, res[i].w,
res[i].e, res[i].s, res[i].n, res[i].r1, res[i].r2,
res[i].density);
mu_assert(res[i].w == expect[i].w && res[i].e == expect[i].e &&
res[i].s == expect[i].s && res[i].n == expect[i].n &&
res[i].r1 == expect[i].r1 && res[i].r2 == expect[i].r2 &&
res[i].density == expect[i].density, msg);
}
return 0;
}
static char * test_prism_volume()
{
PRISM prisms[4] = {
{0,0,1,0,1,0,1,0,0,0},
{0,0,2,0,1,0,1,0,0,0},
{0,0,2,0,2,0,2,0,0,0},
{0,1,2,-1,1,2,3,0,0,0}};
double pvolumes[4] = {1, 2, 8, 2};
double res;
int i;
for(i = 0; i < 4; i++)
{
res = prism_volume(prisms[i]);
sprintf(msg, "(prism %d) expected %g, got %g", i, pvolumes[i], res);
mu_assert(res == pvolumes[i], msg);
}
return 0;
}
static char * test_tess_volume()
{
TESSEROID tesses[4] = {{0,0,360,-90,90,0,1}, {0,0,360,0,90,0,1},
{0,180,360,0,90,0,1}, {0,0,90,-90,0,0,1}};
double tvolumes[4] = {4.188790205, 2.094395102, 1.047197551, 0.523598776};
double res;
int i;
for(i = 0; i < 4; i++)
{
res = tess_volume(tesses[i]);
sprintf(msg, "(tess %d) expected %g, got %g", i, tvolumes[i], res);
mu_assert_almost_equals(res, tvolumes[i], pow(10, -8), msg);
}
return 0;
}
static char * test_tess_total_mass()
{
TESSEROID tesses[4] = {{1,0,360,-90,90,0,1}, {1,0,360,0,90,0,1},
{1,180,360,0,90,0,1}, {1,0,90,-90,0,0,1}};
double tvolumes[4] = {4.188790205, 2.094395102, 1.047197551, 0.523598776};
double res, expect;
int i;
res = tess_total_mass(tesses, 4);
for(expect = 0, i = 0; i < 4; i++)
{
expect += tvolumes[i];
}
sprintf(msg, "(tess %d) expected %g, got %g", i, expect, res);
mu_assert_almost_equals(res, expect, pow(10, -6), msg);
return 0;
}
static char * test_tess_range_mass()
{
TESSEROID tesses[4] = {{1,0,360,-90,90,0,1}, {-1,0,360,0,90,0,1},
{-1,180,360,0,90,0,1}, {1,0,90,-90,0,0,1}};
double tvolumes[4] = {4.188790205, 2.094395102, 1.047197551, 0.523598776};
double res, expect;
res = tess_range_mass(tesses, 4, 0, 1);
expect = tvolumes[0] + tvolumes[3];
sprintf(msg, "Expected %g, got %g", expect, res);
mu_assert_almost_equals(res, expect, pow(10, -6), msg);
return 0;
}
static char * test_tess2prism()
{
int i;
double expect, res;
double lons[4] = {0.5, 185, 180, -2.5},
lats[4] = {0.5, 82.5, -80, 4},
rs[4] = {6001000, 6301000, 6000000, 6505000},
zs[4] = {1000, 1000, 500000, 5000};
PRISM prism;
TESSEROID tesses[4] = {
{1,0,1,0,1,6000000,6001000},
{1,180,190,80,85,6300000,6301000},
{1,160,200,-90,-70,5500000,6000000},
{1,-10,5,-7,15,6500000,6505000}};
for(i = 0; i < 4; i++)
{
tess2prism(tesses[i], &prism);
/* check the volume */
res = prism_volume(prism);
expect = tess_volume(tesses[i]);
sprintf(msg, "(tess %d) expected volume %g, got %g", i, expect, res);
mu_assert_almost_equals((double)(res - expect)/expect, 0., 0.01, msg);
/* check the mass */
res *= prism.density;
expect *= tesses[i].density;
sprintf(msg, "(tess %d) expected mass %g, got %g", i, expect, res);
mu_assert_almost_equals((double)(res - expect)/expect, 0., 0.01, msg);
/* check the coordinates */
res = prism.lon;
expect = lons[i];
sprintf(msg, "(tess %d) expected lon %g, got %g", i, expect, res);
mu_assert_almost_equals((double)(res - expect)/expect, 0., 0.0001, msg);
res = prism.lat;
expect = lats[i];
sprintf(msg, "(tess %d) expected lat %g, got %g", i, expect, res);
mu_assert_almost_equals((double)(res - expect)/expect, 0., 0.0001, msg);
res = prism.r;
expect = rs[i];
sprintf(msg, "(tess %d) expected r %g, got %g", i, expect, res);
mu_assert_almost_equals((double)(res - expect)/expect, 0., 0.0001, msg);
res = prism.z1;
expect = 0.;
sprintf(msg, "(tess %d) expected z1 %g, got %g", i, expect, res);
mu_assert_almost_equals(res, 0., 0.000000000000001, msg);
res = prism.z2;
expect = zs[i];
sprintf(msg, "(tess %d) expected z2 %g, got %g", i, expect, res);
mu_assert_almost_equals((double)(res - expect)/expect, 0., 0.0001, msg);
}
return 0;
}
static char * test_tess2prism_flatten()
{
double expect, res;
PRISM prism;
int i;
TESSEROID tesses[4] = {
{1,0,1,0,1,6000000,6001000},
{1,180,190,80,85,6300000,6301000},
{1,160,200,-90,-70,5500000,6000000},
{1,-10,5,-7,15,6500000,6505000}};
for(i = 0; i < 4; i++)
{
tess2prism_flatten(tesses[i], &prism);
res = prism_volume(prism)*prism.density;
expect = tess_volume(tesses[i])*tesses[i].density;
sprintf(msg, "(tess %d) expected mass %g, got %g", i, expect, res);
mu_assert_almost_equals((double)(res - expect)/expect, 0., 0.01, msg);
}
return 0;
}
static char * test_tess2sphere()
{
double expect, res;
SPHERE sphere;
int i;
TESSEROID tesses[4] = {
{1,0,1,0,1,6000000,6001000},
{1,180,190,80,85,6300000,6301000},
{1,160,200,-90,-70,5500000,6000000},
{1,-10,5,-7,15,6500000,6505000}};
for(i = 0; i < 4; i++)
{
tess2sphere(tesses[i], &sphere);
res = sphere_volume(sphere);
expect = tess_volume(tesses[i]);
sprintf(msg, "(tess %d) expected volume %g, got %g", i, expect, res);
mu_assert_almost_equals(res/expect, 1., 0.01, msg);
}
return 0;
}
static char * test_prism2sphere()
{
double expect, res;
SPHERE sphere;
int i;
PRISM prisms[4] = {
{1,0,1000,0,2000,100,2000,0,0,0},
{1,-500,200,300,500,-1000,4000,0,0,0},
{1,-10000000,5000000,5000000,8000000,0,3000000,0,0,0},
{1,-1000000,50000,500000,800000,0,300000,0,0,0}};
for(i = 0; i < 4; i++)
{
prism2sphere(prisms[i], 0., 0., 0., &sphere);
res = sphere_volume(sphere);
expect = prism_volume(prisms[i]);
sprintf(msg, "(prism %d) expected volume %g, got %g", i, expect, res);
mu_assert_almost_equals(res/expect, 1., 0.001, msg);
}
return 0;
}
int geometry_run_all()
{
int failed = 0;
failed += mu_run_test(test_prism_volume, "prism_volume return correct results");
failed += mu_run_test(test_tess_volume, "tess_volume return correct results");
failed += mu_run_test(test_tess_total_mass, "tess_total_mass returns correct result");
failed += mu_run_test(test_tess_range_mass, "tess_range_mass returns correct result");
failed += mu_run_test(test_tess2prism, "tess2prism produces prism with right volume");
failed += mu_run_test(test_tess2prism_flatten,
"tess2prism_flatten produces prism with right mass");
failed += mu_run_test(test_tess2sphere,
"tess2sphere produces sphere with right volume");
failed += mu_run_test(test_prism2sphere,
"prism2sphere produces sphere with right volume");
failed += mu_run_test(test_split_tess, "split_tess returns correct results for 2, 2, 2 split");
failed += mu_run_test(test_split_uneven_tess, "split_tess returns correct results for 2, 2, 1 split");
return failed;
}

514
test/test_glq.c Executable file
View File

@ -0,0 +1,514 @@
/*
Unit tests for GLQ functions.
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "minunit.h"
#include "../lib/glq.h"
#include "../lib/constants.h"
/* Test data taken from:
http://mathworld.wolfram.com/Legendre-GaussQuadrature.html */
double o2roots[2] = {-0.577350269, 0.577350269},
o3roots[3] = {-0.774596669, 0., 0.774596669},
o4roots[4] = {-0.861136312, -0.339981044, 0.339981044, 0.861136312},
o5roots[5] = {-0.906179846, -0.53846931, 0., 0.53846931, 0.906179846},
o19roots[19] = {-0.992406843843584350,
-0.960208152134830020,
-0.903155903614817900,
-0.822714656537142820,
-0.720966177335229390,
-0.600545304661680990,
-0.464570741375960940,
-0.316564099963629830,
-0.160358645640225370,
0.000000000000000000,
0.160358645640225370,
0.316564099963629830,
0.464570741375960940,
0.600545304661680990,
0.720966177335229390,
0.822714656537142820,
0.903155903614817900,
0.960208152134830020,
0.992406843843584350};
double o2weights[2] = {1., 1.},
o3weights[3] = {0.555555556, 0.888888889, 0.555555556},
o4weights[4] = {0.347854845, 0.652145155, 0.652145155, 0.347854845},
o5weights[5] = {0.236926885, 0.47862867, 0.568888889, 0.47862867,
0.236926885};
/* To store fail messages */
char msg[1000];
/* UNIT TESTS */
static char * test_glq_next_root_fail()
{
double roots[10];
int i, order, rc;
/* Test order fail */
i = 1;
order = -1;
rc = glq_next_root(0.5, i, order, roots);
sprintf(msg, "(order %d) return code %d, expected 1", order, rc);
mu_assert(rc == 1, msg);
order = 0;
rc = glq_next_root(-0.1, i, order, roots);
sprintf(msg, "(order %d) return code %d, expected 1", order, rc);
mu_assert(rc == 1, msg);
order = 1;
rc = glq_next_root(1.1, i, order, roots);
sprintf(msg, "(order %d) return code %d, expected 1", order, rc);
mu_assert(rc == 1, msg);
/* Test index fail */
order = 5;
i = -1;
rc = glq_next_root(0.5, i, order, roots);
sprintf(msg, "(index %d, order %d) return code %d, expected 2", order, i,
rc);
mu_assert(rc == 2, msg);
i = 5;
rc = glq_next_root(0.5, i, order, roots);
sprintf(msg, "(index %d, order %d) return code %d, expected 2", order, i,
rc);
mu_assert(rc == 2, msg);
i = 10;
rc = glq_next_root(0.5, i, order, roots);
sprintf(msg, "(index %d, order %d) return code %d, expected 2", order, i,
rc);
mu_assert(rc == 2, msg);
return 0;
}
static char * test_glq_next_root()
{
double prec = pow(10, -9), root[19], initial;
int rc, i, order;
/* Test order 2 */
order = 2;
for(i = 0; i < order; i++)
{
initial = cos(PI*((order - i) - 0.25)/(order + 0.5));
rc = glq_next_root(initial, i, order, root);
sprintf(msg, "(order %d, root %d) return code %d, expected 0", order, i,
rc);
mu_assert(rc == 0, msg);
sprintf(msg, "(order %d, root %d) expected %.15f got %.15f", order, i,
o2roots[i], root[i]);
mu_assert_almost_equals(root[i], o2roots[i], prec, msg);
}
/* Test order 3 */
order = 3;
for(i = 0; i < order; i++)
{
initial = cos(PI*((order - i) - 0.25)/(order + 0.5));
rc = glq_next_root(initial, i, order, root);
sprintf(msg, "(order %d, root %d) return code %d, expected 0", order, i,
rc);
mu_assert(rc == 0, msg);
sprintf(msg, "(order %d, root %d) expected %.15f got %.15f", order, i,
o3roots[i], root[i]);
mu_assert_almost_equals(root[i], o3roots[i], prec, msg);
}
/* Test order 4 */
order = 4;
for(i = 0; i < order; i++)
{
initial = cos(PI*((order - i) - 0.25)/(order + 0.5));
rc = glq_next_root(initial, i, order, root);
sprintf(msg, "(order %d, root %d) return code %d, expected 0", order, i,
rc);
mu_assert(rc == 0, msg);
sprintf(msg, "(order %d, root %d) expected %.15f got %.15f", order, i,
o4roots[i], root[i]);
mu_assert_almost_equals(root[i], o4roots[i], prec, msg);
}
/* Test order 5 */
order = 5;
for(i = 0; i < order; i++)
{
initial = cos(PI*((order - i) - 0.25)/(order + 0.5));
rc = glq_next_root(initial, i, order, root);
sprintf(msg, "(order %d, root %d) return code %d, expected 0", order, i,
rc);
mu_assert(rc == 0, msg);
sprintf(msg, "(order %d, root %d) expected %.15f got %.15f", order, i,
o5roots[i], root[i]);
mu_assert_almost_equals(root[i], o5roots[i], prec, msg);
}
/* Test order 19 */
order = 19;
for(i = 0; i < order; i++)
{
initial = cos(PI*((order - i) - 0.25)/(order + 0.5));
rc = glq_next_root(initial, i, order, root);
sprintf(msg, "(order %d, root %d) return code %d, expected 0", order, i,
rc);
mu_assert(rc == 0, msg);
sprintf(msg, "(order %d, root %d) expected %.15f got %.15f", order, i,
o19roots[i], root[i]);
mu_assert_almost_equals(root[i], o19roots[i], prec, msg);
}
return 0;
}
static char * test_glq_weights()
{
double prec = pow(10, -9), weights[5];
int rc, i, order;
/* Test order 2 */
order = 2;
rc = glq_weights(order, o2roots, weights);
sprintf(msg, "(order %d) return code %d, expected 0", order, rc);
mu_assert(rc == 0, msg);
for(i = 0; i < order; i++)
{
sprintf(msg, "(order %d, weight %d) expected %.15f got %.15f", order,
i, o2weights[i], weights[i]);
mu_assert_almost_equals(weights[i], o2weights[i], prec, msg);
}
/* Test order 3 */
order = 3;
rc = glq_weights(order, o3roots, weights);
sprintf(msg, "(order %d) return code %d, expected 0", order, rc);
mu_assert(rc == 0, msg);
for(i = 0; i < order; i++)
{
sprintf(msg, "(order %d, weight %d) expected %.15f got %.15f", order,
i, o3weights[i], weights[i]);
mu_assert_almost_equals(weights[i], o3weights[i], prec, msg);
}
/* Test order 4 */
order = 4;
rc = glq_weights(order, o4roots, weights);
sprintf(msg, "(order %d) return code %d, expected 0", order, rc);
mu_assert(rc == 0, msg);
for(i = 0; i < order; i++)
{
sprintf(msg, "(order %d, weight %d) expected %.15f got %.15f", order,
i, o4weights[i], weights[i]);
mu_assert_almost_equals(weights[i], o4weights[i], prec, msg);
}
/* Test order 5 */
order = 5;
rc = glq_weights(order, o5roots, weights);
sprintf(msg, "(order %d) return code %d, expected 0", order, rc);
mu_assert(rc == 0, msg);
for(i = 0; i < order; i++)
{
sprintf(msg, "(order %d, weight %d) expected %.15f got %.15f", order,
i, o5weights[i], weights[i]);
mu_assert_almost_equals(weights[i], o5weights[i], prec, msg);
}
return 0;
}
static char * test_glq_nodes()
{
double prec = pow(10, -9), nodes[19];
int rc, i, order;
/* Test order 2 */
order = 2;
rc = glq_nodes(order, nodes);
sprintf(msg, "(order %d) return code %d, expected 0", order, rc);
mu_assert(rc == 0, msg);
for(i = 0; i < order; i++)
{
sprintf(msg, "(order %d, node %d) expected %.15f got %.15f", order,
i, o2roots[i], nodes[i]);
mu_assert_almost_equals(nodes[i], o2roots[i], prec, msg);
}
/* Test order 3 */
order = 3;
rc = glq_nodes(order, nodes);
sprintf(msg, "(order %d) return code %d, expected 0", order, rc);
mu_assert(rc == 0, msg);
for(i = 0; i < order; i++)
{
sprintf(msg, "(order %d, node %d) expected %.15f got %.15f", order,
i, o3roots[i], nodes[i]);
mu_assert_almost_equals(nodes[i], o3roots[i], prec, msg);
}
/* Test order 4 */
order = 4;
rc = glq_nodes(order, nodes);
sprintf(msg, "(order %d) return code %d, expected 0", order, rc);
mu_assert(rc == 0, msg);
for(i = 0; i < order; i++)
{
sprintf(msg, "(order %d, node %d) expected %.15f got %.15f", order,
i, o4roots[i], nodes[i]);
mu_assert_almost_equals(nodes[i], o4roots[i], prec, msg);
}
/* Test order 5 */
order = 5;
rc = glq_nodes(order, nodes);
sprintf(msg, "(order %d) return code %d, expected 0", order, rc);
mu_assert(rc == 0, msg);
for(i = 0; i < order; i++)
{
sprintf(msg, "(order %d, node %d) expected %.15f got %.15f", order,
i, o5roots[i], nodes[i]);
mu_assert_almost_equals(nodes[i], o5roots[i], prec, msg);
}
/* Test order 19 */
order = 19;
rc = glq_nodes(order, nodes);
sprintf(msg, "(order %d) return code %d, expected 0", order, rc);
mu_assert(rc == 0, msg);
for(i = 0; i < order; i++)
{
sprintf(msg, "(order %d, node %d) expected %.15f got %.15f", order,
i, o19roots[i], nodes[i]);
mu_assert_almost_equals(nodes[i], o19roots[i], prec, msg);
}
return 0;
}
static char * test_glq_set_limits()
{
double prec = pow(10, -9), unscaled[5], scaled[5], a, b, correct;
int rc, i;
GLQ glq;
glq.nodes_unscaled = unscaled;
glq.nodes = scaled;
glq.order = 2;
a = -2.54;
b = 14.9;
mu_arraycp(o2roots, glq.nodes_unscaled, glq.order);
rc = glq_set_limits(a, b, &glq);
sprintf(msg, "(order %d, a %g, b %g) return code %d, expected 0", glq.order,
a, b, rc);
mu_assert(rc == 0, msg);
for(i = 0; i < glq.order; i++)
{
correct = 8.72*o2roots[i] + 6.18;
sprintf(msg,
"(order %d, index %d, a %g, b %g) expected %.15f, got %.15f",
glq.order, i, a, b, correct, glq.nodes[i]);
mu_assert_almost_equals(glq.nodes[i], correct, prec, msg);
}
glq.order = 3;
a = 125.6;
b = 234.84;
mu_arraycp(o3roots, glq.nodes_unscaled, glq.order);
rc = glq_set_limits(a, b, &glq);
sprintf(msg, "(order %d, a %g, b %g) return code %d, expected 0", glq.order,
a, b, rc);
mu_assert(rc == 0, msg);
for(i = 0; i < glq.order; i++)
{
correct = 54.62*o3roots[i] + 180.22;
sprintf(msg,
"(order %d, index %d, a %g, b %g) expected %.15f, got %.15f",
glq.order, i, a, b, correct, glq.nodes[i]);
mu_assert_almost_equals(glq.nodes[i], correct, prec, msg);
}
glq.order = 4;
a = 3.5;
b = -12.4;
mu_arraycp(o4roots, glq.nodes_unscaled, glq.order);
rc = glq_set_limits(a, b, &glq);
sprintf(msg, "(order %d, a %g, b %g) return code %d, expected 0", glq.order,
a, b, rc);
mu_assert(rc == 0, msg);
for(i = 0; i < glq.order; i++)
{
correct = -7.95*o4roots[i] - 4.45;
sprintf(msg,
"(order %d, index %d, a %g, b %g) expected %.15f, got %.15f",
glq.order, i, a, b, correct, glq.nodes[i]);
mu_assert_almost_equals(glq.nodes[i], correct, prec, msg);
}
glq.order = 5;
a = 0.0;
b = 0.0;
mu_arraycp(o5roots, glq.nodes_unscaled, glq.order);
rc = glq_set_limits(a, b, &glq);
sprintf(msg, "(order %d, a %g, b %g) return code %d, expected 0", glq.order,
a, b, rc);
mu_assert(rc == 0, msg);
for(i = 0; i < glq.order; i++)
{
correct = 0.0;
sprintf(msg,
"(order %d, index %d, a %g, b %g) expected %.15f, got %.15f",
glq.order, i, a, b, correct, glq.nodes[i]);
mu_assert_almost_equals(glq.nodes[i], correct, prec, msg);
}
return 0;
}
static char * test_glq_intcos()
{
double result, expected;
double angles[6];
int i, t, orders[6] = {2, 3, 5, 8, 15, 25};
GLQ *glq;
angles[0] = PI*0.1;
angles[1] = PI;
angles[2] = PI*1.2;
angles[3] = PI*1.9;
angles[4] = PI*4.3;
angles[5] = PI*6.9;
for(t = 0; t < 6; t++)
{
glq = glq_new(orders[t], 0., angles[t]);
if(glq == NULL)
{
sprintf(msg,
"(order %d, angle %g) failed to create new GLQ struct",
orders[t], angles[t]);
mu_assert(0, msg);
}
for(i = 0, result = 0; i < orders[t]; i++)
{
result += glq->weights[i]*cos(glq->nodes[i]);
}
result *= 0.5*angles[t];
expected = sin(angles[t]);
glq_free(glq);
sprintf(msg, "(order %d, angle %g) expected %f, got %f", orders[t],
angles[t], expected, result);
mu_assert_almost_equals(result, expected, pow(10, -5), msg);
}
return 0;
}
static char * test_glq_sincos()
{
GLQ *glq;
int i;
double result, d2r = PI/180.;
glq = glq_new(10, 0, 90);
glq_precompute_sincos(glq);
for(i = 0; i < glq->order; i++)
{
result = sin(d2r*glq->nodes[i]);
sprintf(msg, "expected sin(%g)=%g, got %g", glq->nodes[i], result,
glq->nodes_sin[i]);
mu_assert_almost_equals(result, glq->nodes_sin[i], pow(10, -15), msg);
result = cos(d2r*glq->nodes[i]);
sprintf(msg, "expected cos(%g)=%g, got %g", glq->nodes[i], result,
glq->nodes_cos[i]);
mu_assert_almost_equals(result, glq->nodes_cos[i], pow(10, -15), msg);
}
return 0;
}
int glq_run_all()
{
int failed = 0;
failed += mu_run_test(test_glq_next_root_fail,
"glq_next_root returns correct fail code");
failed += mu_run_test(test_glq_next_root, "glq_next_root produces correct results");
failed += mu_run_test(test_glq_nodes, "glq_nodes produces correct results");
failed += mu_run_test(test_glq_set_limits,
"glq_set_limits produces correct results");
failed += mu_run_test(test_glq_weights, "glq_weights produces correct results");
failed += mu_run_test(test_glq_intcos,
"glq cossine integration produces correct results");
failed += mu_run_test(test_glq_sincos,
"glq precomputes sin and cos correctly");
return failed;
}

888
test/test_grav_prism.c Executable file
View File

@ -0,0 +1,888 @@
/*
Unit tests for grav_prism.c functions.
*/
#include <stdio.h>
#include <math.h>
#include "../lib/grav_sphere.h"
#include "../lib/grav_prism.h"
#include "../lib/geometry.h"
#include "../lib/constants.h"
char msg[1000];
int sign(double x)
{
if(x >= 0)
{
return 1;
}
else
{
return -1;
}
}
static char * test_safe_atan2_sign()
{
double res,
y[] = {1, -1, 1, -1},
x[] = {1, 1, -1, -1};
register int i;
for(i = 0; i < 4; i++)
{
res = safe_atan2(y[i], x[i]);
sprintf(msg, "safe_atan2=%g for y=%g x=%g", res, y[i], x[i]);
mu_assert(sign(y[i]*x[i]) == sign(res), msg);
}
return 0;
}
static char * test_safe_atan2_zero()
{
double res,
x[] = {1, -1, 0};
register int i;
for(i = 0; i < 3; i++)
{
res = safe_atan2(0, x[i]);
sprintf(msg, "safe_atan2=%g for x=%g", res, x[i]);
mu_assert(res == 0, msg);
}
return 0;
}
static char * test_pot_around()
{
PRISM prism = {1000,-3000,3000,-3000,3000,-3000,3000,0,0,0};
double planes[6], dist = 5000, i, j;
register int p, k;
for(i = -10000; i <= 10000; i += 100)
{
for(j = -10000; j <= 10000; j += 100)
{
planes[0] = prism_pot(prism, i, j, -dist);
planes[1] = prism_pot(prism, i, j, dist);
planes[2] = prism_pot(prism, -dist, i, j);
planes[3] = prism_pot(prism, dist, i, j);
planes[4] = prism_pot(prism, i, -dist, j);
planes[5] = prism_pot(prism, i, dist, j);
for(p = 0; p < 5; p++)
{
for(k = p + 1; k < 6; k++)
{
sprintf(msg, "point (%g, %g) on planes %d n %d = (%.8f %.8f)",
i, j, p, k, planes[p], planes[k]);
mu_assert_almost_equals(planes[p], planes[k], 10E-10, msg);
}
}
}
}
return 0;
}
static char * test_gx_around()
{
PRISM prism = {1000,-3000,3000,-3000,3000,-3000,3000,0,0,0};
double gz, above, below, north, south, east, west, dist = 5000, i, j;
for(i = -10000; i <= 10000; i += 100)
{
for(j = -10000; j <= 10000; j += 100)
{
above = prism_gx(prism, i, j, -dist);
below = prism_gx(prism, i, j, dist);
north = prism_gx(prism, dist, i, j);
south = prism_gx(prism, -dist, i, j);
east = prism_gx(prism, i, dist, j);
west = prism_gx(prism, i, -dist, j);
gz = prism_gz(prism, i, j, -dist);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "above", "below", above, below);
mu_assert_almost_equals(above, below, 10E-10, msg);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "north", "south", north, south);
mu_assert_almost_equals(north, -south, 10E-10, msg);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "east", "west", east, west);
mu_assert_almost_equals(east, west, 10E-10, msg);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "east", "above", east, above);
mu_assert_almost_equals(east, above, 10E-10, msg);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "north", "gz", north, gz);
mu_assert_almost_equals(north, -gz, 10E-10, msg);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "south", "gz", south, gz);
mu_assert_almost_equals(south, gz, 10E-10, msg);
}
}
return 0;
}
static char * test_gy_around()
{
PRISM prism = {1000,-3000,3000,-3000,3000,-3000,3000,0,0,0};
double gz, above, below, north, south, east, west, dist = 5000, i, j;
for(i = -10000; i <= 10000; i += 100)
{
for(j = -10000; j <= 10000; j += 100)
{
above = prism_gy(prism, i, j, -dist);
below = prism_gy(prism, i, j, dist);
north = prism_gy(prism, dist, j, i);
south = prism_gy(prism, -dist, j, i);
east = prism_gy(prism, i, dist, j);
west = prism_gy(prism, i, -dist, j);
gz = prism_gz(prism, i, j, -dist);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "above", "below", above, below);
mu_assert_almost_equals(above, below, 10E-10, msg);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "north", "south", north, south);
mu_assert_almost_equals(north, south, 10E-10, msg);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "east", "west", east, west);
mu_assert_almost_equals(east, -west, 10E-10, msg);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "north", "above", north, above);
mu_assert_almost_equals(north, above, 10E-10, msg);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "east", "gz", east, gz);
mu_assert_almost_equals(east, -gz, 10E-10, msg);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "west", "gz", west, gz);
mu_assert_almost_equals(west, gz, 10E-10, msg);
}
}
return 0;
}
static char * test_gz_around()
{
PRISM prism = {1000,-3000,3000,-3000,3000,-3000,3000,0,0,0};
double gy, above, below, north, south, east, west, dist = 5000, i, j;
for(i = -10000; i <= 10000; i += 100)
{
for(j = -10000; j <= 10000; j += 100)
{
above = prism_gz(prism, i, j, -dist);
below = prism_gz(prism, i, j, dist);
north = prism_gz(prism, dist, i, j);
south = prism_gz(prism, -dist, i, j);
east = prism_gz(prism, i, dist, j);
west = prism_gz(prism, i, -dist, j);
gy = prism_gy(prism, i, j, -dist);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "above", "below", above, below);
mu_assert_almost_equals(above, -below, 10E-10, msg);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "north", "south", north, south);
mu_assert_almost_equals(north, south, 10E-10, msg);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "east", "west", east, west);
mu_assert_almost_equals(east, west, 10E-10, msg);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "north", "gy", north, gy);
mu_assert_almost_equals(north, gy, 10E-10, msg);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "south", "gy", south, gy);
mu_assert_almost_equals(south, gy, 10E-10, msg);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "east", "gy", east, gy);
mu_assert_almost_equals(east, gy, 10E-10, msg);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "west", "gy", west, gy);
mu_assert_almost_equals(west, gy, 10E-10, msg);
}
}
return 0;
}
static char * test_gxx_around()
{
PRISM prism = {1000,-3000,3000,-3000,3000,-3000,3000,0,0,0};
double gzz, above, below, north, south, east, west, dist = 5000, i, j;
for(i = -10000; i <= 10000; i += 100)
{
for(j = -10000; j <= 10000; j += 100)
{
above = prism_gxx(prism, i, j, -dist);
below = prism_gxx(prism, i, j, dist);
north = prism_gxx(prism, dist, i, j);
south = prism_gxx(prism, -dist, i, j);
east = prism_gxx(prism, i, dist, j);
west = prism_gxx(prism, i, -dist, j);
gzz = prism_gzz(prism, i, j, -dist);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "above", "below", above, below);
mu_assert_almost_equals(above, below, 10E-10, msg);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "north", "south", north, south);
mu_assert_almost_equals(north, south, 10E-10, msg);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "east", "west", east, west);
mu_assert_almost_equals(east, west, 10E-10, msg);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "east", "above", east, above);
mu_assert_almost_equals(east, above, 10E-10, msg);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "north", "gzz", north, gzz);
mu_assert_almost_equals(north, gzz, 10E-10, msg);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "south", "gzz", south, gzz);
mu_assert_almost_equals(south, gzz, 10E-10, msg);
}
}
return 0;
}
static char * test_gxy_around()
{
PRISM prism = {1000, -3000, 3000, -3000, 3000, -3000, 3000, 0, 0, 0};
double gyz, above, below, north, south, east, west, dist = 5000, i, j;
for(i = -10000; i <= 10000; i += 100)
{
for(j = -10000; j <= 10000; j += 100)
{
above = prism_gxy(prism, i, j, -dist);
below = prism_gxy(prism, i, j, dist);
north = prism_gxy(prism, dist, j, i);
south = prism_gxy(prism, -dist, j, i);
east = prism_gxy(prism, j, dist, i);
west = prism_gxy(prism, j, -dist, i);
gyz = prism_gyz(prism, i, j, -dist);
sprintf(msg, " p (%g %g %g) on planes %s n %s = (%.15f n %.15f)",
i, j, dist, "above", "below", above, below);
mu_assert_almost_equals(above, below, 1e-5, msg);
sprintf(msg, " p (%g %g %g) on planes %s n %s = (%.15f n %.15f)",
i, j, dist, "north", "south", north, south);
mu_assert_almost_equals(north, -south, 1e-5, msg);
sprintf(msg, " p (%g %g %g) on planes %s n %s = (%.15f n %.15f)",
i, j, dist, "east", "west", east, west);
mu_assert_almost_equals(east, -west, 1e-5, msg);
sprintf(msg, " p (%g %g %g) on planes %s n %s = (%.15f n %.15f)",
i, j, dist, "east", "north", east, north);
mu_assert_almost_equals(east, north, 1e-5, msg);
sprintf(msg, " p (%g %g %g) on planes %s n %s = (%.15f n %.15f)",
i, j, dist, "west", "south", west, south);
mu_assert_almost_equals(west, south, 1e-5, msg);
sprintf(msg, " p (%g %g %g) on planes %s n %s = (%.15f n %.15f)",
i, j, dist, "north", "gyz", north, gyz);
mu_assert_almost_equals(north, -gyz, 1e-5, msg);
sprintf(msg, " p (%g %g %g) on planes %s n %s = (%.15f n %.15f)",
i, j, dist, "south", "gyz", south, gyz);
mu_assert_almost_equals(south, gyz, 1e-5, msg);
}
}
return 0;
}
static char * test_gxz_around()
{
PRISM prism = {3000, -3000, 3000, -3000, 3000, -3000, 3000, 0, 0, 0};
double other, above, below, north, south, east, west, dist = 5000, i, j;
for(i = -10000; i <= 10000; i += 100)
{
for(j = -10000; j <= 10000; j += 100)
{
above = prism_gxz(prism, i, j, -dist);
below = prism_gxz(prism, i, j, dist);
north = prism_gxz(prism, dist, j, i);
south = prism_gxz(prism, -dist, j, i);
east = prism_gxz(prism, i, dist, j);
west = prism_gxz(prism, i, -dist, j);
other = prism_gxy(prism, i, j, -dist);
sprintf(msg, " p (%g %g %g) on planes %s n %s = (%.15f %.15f)",
i, j, dist, "above", "below", above, below);
mu_assert_almost_equals(above, -below, 1e-5, msg);
sprintf(msg, " p (%g %g %g) on planes %s n %s = (%.15f %.15f)",
i, j, dist, "north", "south", north, south);
mu_assert_almost_equals(north, -south, 1e-5, msg);
sprintf(msg, " p (%g %g %g) on planes %s n %s = (%.15f %.15f)",
i, j, dist, "east", "west", east, west);
mu_assert_almost_equals(east, west, 1e-5, msg);
sprintf(msg, " p (%g %g %g) on planes %s n %s = (%.15f %.15f)",
i, j, dist, "below", "north", below, north);
mu_assert_almost_equals(below, north, 1e-5, msg);
sprintf(msg, " p (%g %g %g) on planes %s n %s = (%.15f %.15f)",
i, j, dist, "above", "south", above, south);
mu_assert_almost_equals(above, south, 1e-5, msg);
sprintf(msg, " p (%g %g %g) on planes %s n %s = (%.15f %.15f)",
i, j, dist, "east", "gxy", east, other);
mu_assert_almost_equals(east, other, 1e-5, msg);
sprintf(msg, " p (%g %g %g) on planes %s n %s = (%.15f %.15f)",
i, j, dist, "west", "gxy", west, other);
mu_assert_almost_equals(west, other, 1e-5, msg);
}
}
return 0;
}
static char * test_gyy_around()
{
PRISM prism = {1000,-3000,3000,-3000,3000,-3000,3000,0,0,0};
double other, above, below, north, south, east, west, dist = 5000, i, j;
for(i = -10000; i <= 10000; i += 100)
{
for(j = -10000; j <= 10000; j += 100)
{
above = prism_gyy(prism, i, j, -dist);
below = prism_gyy(prism, i, j, dist);
north = prism_gyy(prism, dist, j, i);
south = prism_gyy(prism, -dist, j, i);
east = prism_gyy(prism, i, dist, j);
west = prism_gyy(prism, i, -dist, j);
other = prism_gzz(prism, i, j, -dist);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "above", "below", above, below);
mu_assert_almost_equals(above, below, 10E-10, msg);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "north", "south", north, south);
mu_assert_almost_equals(north, south, 10E-10, msg);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "east", "west", east, west);
mu_assert_almost_equals(east, west, 10E-10, msg);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "above", "north", above, north);
mu_assert_almost_equals(above, north, 10E-10, msg);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "east", "gzz", east, other);
mu_assert_almost_equals(east, other, 10E-10, msg);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "west", "gzz", west, other);
mu_assert_almost_equals(west, other, 10E-10, msg);
}
}
return 0;
}
static char * test_gyz_around()
{
PRISM prism = {1000, -3000, 3000, -3000, 3000, -3000, 3000, 0, 0, 0};
double other, above, below, north, south, east, west, dist = 5000, i, j;
for(i = -10000; i <= 10000; i += 100)
{
for(j = -10000; j <= 10000; j += 100)
{
above = prism_gyz(prism, i, j, -dist);
below = prism_gyz(prism, i, j, dist);
north = prism_gyz(prism, dist, j, i);
south = prism_gyz(prism, -dist, j, i);
east = prism_gyz(prism, i, dist, j);
west = prism_gyz(prism, i, -dist, j);
other = prism_gxy(prism, i, j, -dist);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "above", "below", above, below);
mu_assert_almost_equals(above, -below, 1e-5, msg);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "north", "south", north, south);
mu_assert_almost_equals(north, south, 1e-5, msg);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "east", "west", east, west);
mu_assert_almost_equals(east, -west, 1e-5, msg);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "below", "east", below, east);
mu_assert_almost_equals(below, east, 1e-5, msg);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "above", "west", above, west);
mu_assert_almost_equals(above, west, 1e-5, msg);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "north", "gxy", north, other);
mu_assert_almost_equals(north, other, 1e-5, msg);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "south", "gxy", south, other);
mu_assert_almost_equals(south, other, 1e-5, msg);
}
}
return 0;
}
static char * test_gzz_around()
{
PRISM prism = {1000,-3000,3000,-3000,3000,-3000,3000,0,0,0};
double other, above, below, north, south, east, west, dist = 5000, i, j;
for(i = -10000; i <= 10000; i += 100)
{
for(j = -10000; j <= 10000; j += 100)
{
above = prism_gzz(prism, i, j, -dist);
below = prism_gzz(prism, i, j, dist);
north = prism_gzz(prism, dist, i, j);
south = prism_gzz(prism, -dist, i, j);
east = prism_gzz(prism, i, dist, j);
west = prism_gzz(prism, i, -dist, j);
other = prism_gyy(prism, i, j, -dist);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "above", "below", above, below);
mu_assert_almost_equals(above, below, 10E-10, msg);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "north", "south", north, south);
mu_assert_almost_equals(north, south, 10E-10, msg);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "east", "west", east, west);
mu_assert_almost_equals(east, west, 10E-10, msg);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "north", "east", north, east);
mu_assert_almost_equals(north, east, 10E-10, msg);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "north", "gyy", north, other);
mu_assert_almost_equals(north, other, 10E-10, msg);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "south", "gyy", south, other);
mu_assert_almost_equals(south, other, 10E-10, msg);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "east", "gyy", east, other);
mu_assert_almost_equals(east, other, 10E-10, msg);
sprintf(msg, "point (%g, %g) on planes %s n %s = (%.8f %.8f)",
i, j, "west", "gyy", west, other);
mu_assert_almost_equals(west, other, 10E-10, msg);
}
}
return 0;
}
static char * test_gxx_below()
{
PRISM prism = {3000,-5000,5000,-5000,5000,-5000,5000,0,0,0};
double dist, restop, resbelow;
for(dist=5010; dist <= 500000; dist += 100)
{
restop = prism_gxx(prism, 0, 0,-dist);
resbelow = prism_gxx(prism, 0, 0, dist);
sprintf(msg, "(distance %g m) top = %.5f below = %.5f", dist,
restop, resbelow);
mu_assert_almost_equals(resbelow, restop, 0.1, msg);
}
return 0;
}
static char * test_gxy_below()
{
PRISM prism = {3000,-5000,5000,-5000,5000,-5000,5000,0,0,0};
double dist, restop, resbelow;
for(dist=5010; dist <= 500000; dist += 100)
{
restop = prism_gxy(prism, 5000, 5000, -dist);
resbelow = prism_gxy(prism, 5000, 5000, dist);
sprintf(msg, "(distance %g m) top = %.5f below = %.5f", dist,
restop, resbelow);
mu_assert_almost_equals(resbelow, restop, 1, msg);
}
return 0;
}
static char * test_gxz_below()
{
PRISM prism = {3000,-5000,5000,-5000,5000,-5000,5000,0,0,0};
double dist, restop, resbelow;
for(dist=5010; dist <= 500000; dist += 100)
{
restop = prism_gxz(prism, 5000, 0,-dist);
resbelow = prism_gxz(prism, 5000, 0, dist);
sprintf(msg, "(distance %g m) top = %.5f below = %.5f", dist,
restop, resbelow);
mu_assert_almost_equals(resbelow, -restop, 0.1, msg);
}
return 0;
}
static char * test_gyy_below()
{
PRISM prism = {3000,-5000,5000,-5000,5000,-5000,5000,0,0,0};
double dist, restop, resbelow;
for(dist=5010; dist <= 500000; dist += 100)
{
restop = prism_gyy(prism, 0, 0,-dist);
resbelow = prism_gyy(prism, 0, 0, dist);
sprintf(msg, "(distance %g m) top = %.5f below = %.5f", dist,
restop, resbelow);
mu_assert_almost_equals_rel(resbelow, restop, 1, msg);
}
return 0;
}
static char * test_gyz_below()
{
PRISM prism = {3000,-5000,5000,-5000,5000,-5000,5000,0,0,0};
double dist, restop, resbelow;
for(dist=5010; dist <= 500000; dist += 100)
{
restop = prism_gyz(prism, 0, 5000, -dist);
resbelow = prism_gyz(prism, 0, 5000, dist);
sprintf(msg, "(distance %g m) top = %.5f below = %.5f", dist,
restop, resbelow);
mu_assert_almost_equals(resbelow, -restop, 0.1, msg);
}
return 0;
}
static char * test_gzz_below()
{
PRISM prism = {3000,-5000,5000,-5000,5000,-5000,5000,0,0,0};
double dist, restop, resbelow;
for(dist=5010; dist <= 500000; dist += 100)
{
restop = prism_gzz(prism, 0, 0, -dist);
resbelow = prism_gzz(prism, 0, 0, dist);
sprintf(msg, "(distance %g m) top = %.5f below = %.5f", dist,
restop, resbelow);
mu_assert_almost_equals(resbelow, restop, 0.1, msg);
}
return 0;
}
static char * test_prism2sphere_pot()
{
SPHERE sphere;
PRISM prism = {3000,-5000,5000,-5000,5000,-5000,5000,0,0,0};
double dist, resprism, ressphere;
/* Make a sphere with the same mass as the prism and put it at the origin */
prism2sphere(prism, 0, 0, 0, &sphere);
for(dist=50000; dist <= 500000; dist += 500)
{
resprism = prism_pot(prism,0,0,-dist);
ressphere = sphere_pot(sphere,0,90,dist);
sprintf(msg, "(distance %g m) prism = %.5f sphere = %.5f", dist,
resprism, ressphere);
mu_assert_almost_equals(resprism, ressphere, 0.001, msg);
}
return 0;
}
static char * test_prism2sphere_gx()
{
SPHERE sphere;
PRISM prism = {3000,-5000,5000,-5000,5000,-5000,5000,0,0,0};
double dist, resprism, ressphere;
/* Make a sphere with the same mass as the prism and put it at the origin */
prism2sphere(prism, 0, 0, 0, &sphere);
for(dist=10000; dist <= 500000; dist += 500)
{
resprism = prism_gx(prism,0,0,-dist);
ressphere = sphere_gx(sphere,0,90,dist);
sprintf(msg, "(distance %g m) prism = %.5f sphere = %.5f", dist,
resprism, ressphere);
mu_assert_almost_equals(resprism, ressphere, 0.00000001, msg);
}
return 0;
}
static char * test_prism2sphere_gy()
{
SPHERE sphere;
PRISM prism = {3000,-5000,5000,-5000,5000,-5000,5000,0,0,0};
double dist, resprism, ressphere;
/* Make a sphere with the same mass as the prism and put it at the origin */
prism2sphere(prism, 0, 0, 0, &sphere);
for(dist=10000; dist <= 500000; dist += 500)
{
resprism = prism_gy(prism,0,0,-dist);
ressphere = sphere_gy(sphere,0,90,dist);
sprintf(msg, "(distance %g m) prism = %.5f sphere = %.5f", dist,
resprism, ressphere);
mu_assert_almost_equals(resprism, ressphere, 0.00000001, msg);
}
return 0;
}
static char * test_prism2sphere_gz()
{
SPHERE sphere;
PRISM prism = {3000,-5000,5000,-5000,5000,-5000,5000,0,0,0};
double dist, resprism, ressphere;
/* Make a sphere with the same mass as the prism and put it at the origin */
prism2sphere(prism, 0, 0, 0, &sphere);
for(dist=50000; dist <= 500000; dist += 500)
{
resprism = prism_gz(prism,0,0,-dist);
ressphere = sphere_gz(sphere,0,90,dist);
sprintf(msg, "(distance %g m) prism = %.5f sphere = %.5f", dist,
resprism, ressphere);
mu_assert_almost_equals(resprism, -1*ressphere, 0.01, msg);
}
return 0;
}
static char * test_prism2sphere_gxx()
{
SPHERE sphere;
PRISM prism = {3000,-5000,5000,-5000,5000,-5000,5000,0,0,0};
double dist, resprism, ressphere;
/* Make a sphere with the same mass as the prism and put it at the origin */
prism2sphere(prism, 0, 0, 0, &sphere);
for(dist=50000; dist <= 500000; dist += 500)
{
resprism = prism_gxx(prism,0,0,-dist);
ressphere = sphere_gxx(sphere,0,90,dist);
sprintf(msg, "(distance %g m) prism = %.5f sphere = %.5f", dist,
resprism, ressphere);
mu_assert_almost_equals(resprism, ressphere, 0.001, msg);
}
return 0;
}
static char * test_prism2sphere_gxy()
{
SPHERE sphere;
PRISM prism = {3000,-5000,5000,-5000,5000,-5000,5000,0,0,0};
double dist, resprism, ressphere;
/* Make a sphere with the same mass as the prism and put it at the origin */
prism2sphere(prism, 0, 0, 0, &sphere);
for(dist=50000; dist <= 500000; dist += 500)
{
resprism = prism_gxy(prism,0,0,-dist);
ressphere = sphere_gxy(sphere,0,90,dist);
sprintf(msg, "(distance %g m) prism = %.5f sphere = %.5f", dist,
resprism, ressphere);
mu_assert_almost_equals(resprism, ressphere, 0.001, msg);
}
return 0;
}
static char * test_prism2sphere_gxz()
{
SPHERE sphere;
PRISM prism = {3000,-5000,5000,-5000,5000,-5000,5000,0,0,0};
double dist, resprism, ressphere;
/* Make a sphere with the same mass as the prism and put it at the origin */
prism2sphere(prism, 0, 0, 0, &sphere);
for(dist=50000; dist <= 500000; dist += 500)
{
resprism = prism_gxz(prism,0,0,-dist);
ressphere = sphere_gxz(sphere,0,90,dist);
sprintf(msg, "(distance %g m) prism = %.5f sphere = %.5f", dist,
resprism, ressphere);
mu_assert_almost_equals(resprism, -1*ressphere, 0.001, msg);
}
return 0;
}
static char * test_prism2sphere_gyy()
{
SPHERE sphere;
PRISM prism = {3000,-5000,5000,-5000,5000,-5000,5000,0,0,0};
double dist, resprism, ressphere;
/* Make a sphere with the same mass as the prism and put it at the origin */
prism2sphere(prism, 0, 0, 0, &sphere);
for(dist=50000; dist <= 500000; dist += 500)
{
resprism = prism_gyy(prism,0,0,-dist);
ressphere = sphere_gyy(sphere,0,90,dist);
sprintf(msg, "(distance %g m) prism = %.5f sphere = %.5f", dist,
resprism, ressphere);
mu_assert_almost_equals(resprism, ressphere, 0.001, msg);
}
return 0;
}
static char * test_prism2sphere_gyz()
{
SPHERE sphere;
PRISM prism = {3000,-5000,5000,-5000,5000,-5000,5000,0,0,0};
double dist, resprism, ressphere;
/* Make a sphere with the same mass as the prism and put it at the origin */
prism2sphere(prism, 0, 0, 0, &sphere);
for(dist=50000; dist <= 500000; dist += 500)
{
resprism = prism_gyz(prism,0,0,-dist);
ressphere = sphere_gyz(sphere,0,90,dist);
sprintf(msg, "(distance %g m) prism = %.5f sphere = %.5f", dist,
resprism, ressphere);
mu_assert_almost_equals(resprism, -1*ressphere, 0.001, msg);
}
return 0;
}
static char * test_prism2sphere_gzz()
{
SPHERE sphere;
PRISM prism = {3000,-5000,5000,-5000,5000,-5000,5000,0,0,0};
double dist, resprism, ressphere;
/* Make a sphere with the same mass as the prism and put it at the origin */
prism2sphere(prism, 0, 0, 0, &sphere);
for(dist=60000; dist <= 500000; dist += 500)
{
resprism = prism_gzz(prism,0,0,-dist);
ressphere = sphere_gzz(sphere,0,90,dist);
sprintf(msg, "(distance %g m) prism = %.5f sphere = %.5f", dist,
resprism, ressphere);
mu_assert_almost_equals(resprism, ressphere, 0.001, msg);
}
return 0;
}
static char * test_prism_tensor_trace()
{
#define N 4
TESSEROID tesses[N] = {
{1,0,1,0,1,6000000,6001000},
{1,180,183,80,81.5,6300000,6302000},
{1,200,203,-90,-88,5500000,5500100},
{1,-10,-7,7,7.5,6500000,6505000}};
PRISM prism;
int i;
double trace, dist, x, y;
for(i = 0; i < N; i++)
{
tess2prism_flatten(tesses[i], &prism);
x = 0.5*(prism.x1 + prism.x2);
y = 0.5*(prism.y1 + prism.y2);
for(dist=1000; dist <= 5000000; dist += 1000)
{
trace = prism_gxx(prism, x, y, prism.z1 - dist)
+ prism_gyy(prism, x, y, prism.z1 - dist)
+ prism_gzz(prism, x, y, prism.z1 - dist);
sprintf(msg, "(prism %d dist %g) trace %.10f", i, dist, trace);
mu_assert_almost_equals(trace, 0, 0.0000000001, msg);
}
}
#undef N
return 0;
}
int grav_prism_run_all()
{
int failed = 0;
failed += mu_run_test(test_safe_atan2_sign,
"safe_atan2 result has same sign as angle");
failed += mu_run_test(test_safe_atan2_zero,
"safe_atan2 returns 0 for y == 0");
failed += mu_run_test(test_pot_around,
"prism_pot results equal around the prism");
failed += mu_run_test(test_gx_around,
"prism_gx results consistent around the prism");
failed += mu_run_test(test_gy_around,
"prism_gy results consistent around the prism");
failed += mu_run_test(test_gz_around,
"prism_gz results consistent around the prism");
failed += mu_run_test(test_gxx_around,
"prism_gxx results consistent around the prism");
failed += mu_run_test(test_gxy_around,
"prism_gxy results consistent around the prism");
failed += mu_run_test(test_gxz_around,
"prism_gxz results consistent around the prism");
failed += mu_run_test(test_gyy_around,
"prism_gyy results consistent around the prism");
failed += mu_run_test(test_gyz_around,
"prism_gyz results consistent around the prism");
failed += mu_run_test(test_gzz_around,
"prism_gzz results consistent around the prism");
failed += mu_run_test(test_gxx_below,
"prism_gxx results equal above and below the prism");
failed += mu_run_test(test_gxy_below,
"prism_gxy results equal above and below the prism");
failed += mu_run_test(test_gxz_below,
"prism_gxz results equal above and below the prism");
failed += mu_run_test(test_gyy_below,
"prism_gyy results equal above and below the prism");
failed += mu_run_test(test_gyz_below,
"prism_gyz results equal above and below the prism");
failed += mu_run_test(test_gzz_below,
"prism_gzz results equal above and below the prism");
failed += mu_run_test(test_prism2sphere_pot,
"prism_pot results equal to sphere of same mass at distance");
failed += mu_run_test(test_prism2sphere_gx,
"prism_gx results equal to sphere of same mass at distance");
failed += mu_run_test(test_prism2sphere_gy,
"prism_gy results equal to sphere of same mass at distance");
failed += mu_run_test(test_prism2sphere_gz,
"prism_gz results equal to sphere of same mass at distance");
failed += mu_run_test(test_prism2sphere_gxx,
"prism_gxx results equal to sphere of same mass at distance");
failed += mu_run_test(test_prism2sphere_gxy,
"prism_gxy results equal to sphere of same mass at distance");
failed += mu_run_test(test_prism2sphere_gxz,
"prism_gxz results equal to sphere of same mass at distance");
failed += mu_run_test(test_prism2sphere_gyy,
"prism_gyy results equal to sphere of same mass at distance");
failed += mu_run_test(test_prism2sphere_gyz,
"prism_gyz results equal to sphere of same mass at distance");
failed += mu_run_test(test_prism2sphere_gzz,
"prism_gzz results equal to sphere of same mass at distance");
failed += mu_run_test(test_prism_tensor_trace,
"trace of GGT for prism in Cartesian coordinates is zero");
return failed;
}

160
test/test_grav_prism_sph.c Executable file
View File

@ -0,0 +1,160 @@
/*
Unit tests for grav_prism.c functions.
*/
#include <stdio.h>
#include <math.h>
#include "../lib/grav_prism_sph.h"
#include "../lib/grav_prism.h"
#include "../lib/geometry.h"
#include "../lib/constants.h"
char msg[1000];
/* Test coordinate transformation */
static char * test_global2local()
{
#define R 6378137.0
#define N 3
PRISM prisms[N] = {
{3000,-5000,5000,-5000,5000,0,5000, 2.45, -36.32, R},
{2000,-3000,3000,-2000,2000,0,800, -45.45, -103.1, R},
{1000,-2000,2000,-1000,1000,0,234, -80.45, 183.2, R}};
double x, y, z, newz[N] = {-3000, 1234, -2.3456};
int i;
for(i = 0; i < N; i++)
{
global2local(prisms[i].lon, prisms[i].lat, R - newz[i], prisms[i],
&x, &y, &z);
sprintf(msg, "(prism %d) x: expect %.10g got %.10g", i, 0., x);
mu_assert_almost_equals(x, 0., 0.00000001, msg);
sprintf(msg, "(prism %d) y: expect %.10g got %.10g", i, 0., y);
mu_assert_almost_equals(y, 0., 0.00000001, msg);
sprintf(msg, "(prism %d) z: expect %.10g got %.10g", i, newz[i], z);
mu_assert_almost_equals(z, newz[i], 0.00000001, msg);
}
#undef R
#undef N
return 0;
}
/* Test agains grav_prism */
static char * test_prism_pot_sph()
{
#define R 6378137.0
PRISM prism = {3000,-5000,5000,-5000,5000,0,5000,187,38,R};
double res, expect;
int fix;
fix = 1;
res = prism_pot_sph(prism, 187, 38, R + 1000);
expect = prism_pot(prism, 0, 0, -1000);
sprintf(msg, "(fixture %d) expect %.10g got %.10g", fix, expect, res);
mu_assert_almost_equals(res, expect, 0.0000000001, msg);
#undef R
return 0;
}
static char * test_prism_g_sph()
{
#define R 6378137.0
PRISM prism = {3000,-5000,5000,-5000,5000,0,5000,27,-78,R};
double resx, resy, resz, expectx, expecty, expectz;
int fix;
fix = 1;
prism_g_sph(prism, 27, -78, R + 1000, &resx, &resy, &resz);
expectx = prism_gx(prism, 0, 0, -1000);
expecty = prism_gy(prism, 0, 0, -1000);
expectz = prism_gz(prism, 0, 0, -1000);
sprintf(msg, "(fixture %d) gx: expect %.10g got %.10g", fix, expectx, resx);
mu_assert_almost_equals(resx, expectx, 0.0000000001, msg);
sprintf(msg, "(fixture %d) gy: expect %.10g got %.10g", fix, expecty, resy);
mu_assert_almost_equals(resy, expecty, 0.0000000001, msg);
sprintf(msg, "(fixture %d) gz: expect %.10g got %.10g", fix, expectz, resz);
mu_assert_almost_equals(resz, expectz, 0.0000000001, msg);
#undef R
return 0;
}
static char * test_prism_ggt_sph()
{
#define R 6378137.0
PRISM prism = {3000,-5000,5000,-5000,5000,0,5000,-7,8,R};
double res[6], expect[6];
int fix, i;
fix = 1;
prism_ggt_sph(prism, -7, 8, R + 1000, res);
expect[0] = prism_gxx(prism, 0, 0, -1000);
expect[1] = prism_gxy(prism, 0, 0, -1000);
expect[2] = prism_gxz(prism, 0, 0, -1000);
expect[3] = prism_gyy(prism, 0, 0, -1000);
expect[4] = prism_gyz(prism, 0, 0, -1000);
expect[5] = prism_gzz(prism, 0, 0, -1000);
for(i = 0; i < 6; i++)
{
sprintf(msg, "(fixture %d) cmp %d: expect %.10f got %.10f", fix, i,
expect[i], res[i]);
mu_assert_almost_equals(res[i], expect[i], 0.000000001, msg);
}
#undef R
return 0;
}
static char * test_prism_tensor_sph_trace()
{
#define N 4
#define GXX 0
#define GYY 3
#define GZZ 5
TESSEROID tesses[N] = {
{1,0,1,0,1,6000000,6001000},
{1,180,183,80,81.5,6300000,6302000},
{1,200,203,-90,-88,5500000,5500100},
{1,-10,-7,7,7.5,6500000,6505000}};
PRISM prism;
int i;
double trace, dist, tensor[6];
for(i = 0; i < N; i++)
{
tess2prism(tesses[i], &prism);
for(dist=1000; dist <= 5000000; dist += 1000)
{
prism_ggt_sph(prism, prism.lon, prism.lat, prism.r + dist, tensor);
trace = tensor[GXX] + tensor[GYY] + tensor[GZZ];
sprintf(msg, "(prism %d dist %g) trace %.10f", i, dist, trace);
mu_assert_almost_equals(trace, 0, 0.0000000001, msg);
}
}
#undef N
#undef GXX
#undef GYY
#undef GZZ
return 0;
}
int grav_prism_sph_run_all()
{
int failed = 0;
failed += mu_run_test(test_prism_pot_sph,
"prism_pot_sph results equal to prism_pot when on top of prism");
failed += mu_run_test(test_prism_g_sph,
"prism_g_sph results equal to prism_gx, etc, when on top of prism");
failed += mu_run_test(test_prism_ggt_sph,
"prism_ggt_sph results equal to prism_gxx, etc, when on top of prism");
failed += mu_run_test(test_prism_tensor_sph_trace,
"trace of GGT for prism in spherical coordinates is zero");
failed += mu_run_test(test_global2local,
"global2local returns correct result");
return failed;
}

633
test/test_grav_tess.c Executable file
View File

@ -0,0 +1,633 @@
/*
Unit tests for grav_tess.c functions.
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "../lib/grav_sphere.h"
#include "../lib/grav_tess.h"
#include "../lib/glq.h"
#include "../lib/geometry.h"
#include "../lib/constants.h"
char msg[1000];
static char * test_tess2sphere_pot()
{
SPHERE sphere;
TESSEROID tess;
double radius, dist, restess, ressphere;
GLQ *glqlon, *glqlat, *glqr;
tess.density = 1000.;
tess.w = 44;
tess.e = 46;
tess.s = -1;
tess.n = 1;
tess.r1 = MEAN_EARTH_RADIUS - 100000;
tess.r2 = MEAN_EARTH_RADIUS;
glqlon = glq_new(8, tess.w, tess.e);
if(glqlon == NULL)
mu_assert(0, "GLQ allocation error");
glqlat = glq_new(8, tess.s, tess.n);
if(glqlat == NULL)
mu_assert(0, "GLQ allocation error");
glqr = glq_new(8, tess.r1, tess.r2);
if(glqr == NULL)
mu_assert(0, "GLQ allocation error");
glq_precompute_sincos(glqlat);
radius = tess.r2;
/* Make a sphere with the same mass as the tesseroid */
tess2sphere(tess, &sphere);
for(dist=1000000; dist <= 2000000; dist += 1000)
{
restess = tess_pot(tess,0,40,radius+dist,*glqlon,*glqlat,*glqr);
ressphere = sphere_pot(sphere,0,40,radius+dist);
sprintf(msg, "(distance %g m) tess = %.5f sphere = %.5f", dist,
restess, ressphere);
mu_assert_almost_equals(restess, ressphere, 0.01, msg);
}
return 0;
}
static char * test_tess2sphere_gx()
{
SPHERE sphere;
TESSEROID tess;
double radius, dist, restess, ressphere;
GLQ *glqlon, *glqlat, *glqr;
tess.density = 1000.;
tess.w = 44;
tess.e = 46;
tess.s = -1;
tess.n = 1;
tess.r1 = MEAN_EARTH_RADIUS - 100000;
tess.r2 = MEAN_EARTH_RADIUS;
glqlon = glq_new(8, tess.w, tess.e);
if(glqlon == NULL)
mu_assert(0, "GLQ allocation error");
glqlat = glq_new(8, tess.s, tess.n);
if(glqlat == NULL)
mu_assert(0, "GLQ allocation error");
glqr = glq_new(8, tess.r1, tess.r2);
if(glqr == NULL)
mu_assert(0, "GLQ allocation error");
glq_precompute_sincos(glqlat);
radius = tess.r2;
/* Make a sphere with the same mass as the tesseroid */
tess2sphere(tess, &sphere);
for(dist=1000000; dist <= 2000000; dist += 1000)
{
restess = tess_gx(tess,0,40,radius+dist,*glqlon,*glqlat,*glqr);
ressphere = sphere_gx(sphere,0,40,radius+dist);
sprintf(msg, "(distance %g m) tess = %.5f sphere = %.5f", dist,
restess, ressphere);
mu_assert_almost_equals(restess, ressphere, 0.1, msg);
}
return 0;
}
static char * test_tess2sphere_gy()
{
SPHERE sphere;
TESSEROID tess;
double radius, dist, restess, ressphere;
GLQ *glqlon, *glqlat, *glqr;
tess.density = 1000.;
tess.w = 44;
tess.e = 46;
tess.s = -1;
tess.n = 1;
tess.r1 = MEAN_EARTH_RADIUS - 100000;
tess.r2 = MEAN_EARTH_RADIUS;
glqlon = glq_new(8, tess.w, tess.e);
if(glqlon == NULL)
mu_assert(0, "GLQ allocation error");
glqlat = glq_new(8, tess.s, tess.n);
if(glqlat == NULL)
mu_assert(0, "GLQ allocation error");
glqr = glq_new(8, tess.r1, tess.r2);
if(glqr == NULL)
mu_assert(0, "GLQ allocation error");
glq_precompute_sincos(glqlat);
radius = tess.r2;
/* Make a sphere with the same mass as the tesseroid */
tess2sphere(tess, &sphere);
for(dist=1000000; dist <= 2000000; dist += 1000)
{
restess = tess_gy(tess,5,45,radius+dist,*glqlon,*glqlat,*glqr);
ressphere = sphere_gy(sphere,5,45,radius+dist);
sprintf(msg, "(distance %g m) tess = %.5f sphere = %.5f", dist,
restess, ressphere);
mu_assert_almost_equals(restess, ressphere, 0.1, msg);
}
return 0;
}
static char * test_tess2sphere_gz()
{
SPHERE sphere;
TESSEROID tess;
double radius, dist, restess, ressphere;
GLQ *glqlon, *glqlat, *glqr;
tess.density = 1000.;
tess.w = 44;
tess.e = 46;
tess.s = -1;
tess.n = 1;
tess.r1 = MEAN_EARTH_RADIUS - 100000;
tess.r2 = MEAN_EARTH_RADIUS;
glqlon = glq_new(8, tess.w, tess.e);
if(glqlon == NULL)
mu_assert(0, "GLQ allocation error");
glqlat = glq_new(8, tess.s, tess.n);
if(glqlat == NULL)
mu_assert(0, "GLQ allocation error");
glqr = glq_new(8, tess.r1, tess.r2);
if(glqr == NULL)
mu_assert(0, "GLQ allocation error");
glq_precompute_sincos(glqlat);
radius = tess.r2;
/* Make a sphere with the same mass as the tesseroid */
tess2sphere(tess, &sphere);
for(dist=1500000; dist <= 2000000; dist += 1000)
{
restess = -tess_gz(tess,0,45,radius+dist,*glqlon,*glqlat,*glqr);
ressphere = sphere_gz(sphere,0,45,radius+dist);
sprintf(msg, "(distance %g m) tess = %.5f sphere = %.5f", dist,
restess, ressphere);
mu_assert_almost_equals(restess, ressphere, 0.1, msg);
}
return 0;
}
static char * test_tess2sphere_gxx()
{
SPHERE sphere;
TESSEROID tess;
double radius, dist, restess, ressphere;
GLQ *glqlon, *glqlat, *glqr;
tess.density = 1000.;
tess.w = 44;
tess.e = 46;
tess.s = -1;
tess.n = 1;
tess.r1 = MEAN_EARTH_RADIUS - 100000;
tess.r2 = MEAN_EARTH_RADIUS;
glqlon = glq_new(8, tess.w, tess.e);
if(glqlon == NULL)
mu_assert(0, "GLQ allocation error");
glqlat = glq_new(8, tess.s, tess.n);
if(glqlat == NULL)
mu_assert(0, "GLQ allocation error");
glqr = glq_new(8, tess.r1, tess.r2);
if(glqr == NULL)
mu_assert(0, "GLQ allocation error");
glq_precompute_sincos(glqlat);
radius = tess.r2;
/* Make a sphere with the same mass as the tesseroid */
tess2sphere(tess, &sphere);
for(dist=1300000; dist <= 2000000; dist += 1000)
{
restess = tess_gxx(tess,0,45,radius+dist,*glqlon,*glqlat,*glqr);
ressphere = sphere_gxx(sphere,0,45,radius+dist);
sprintf(msg, "(distance %g m) tess = %.5f sphere = %.5f", dist,
restess, ressphere);
mu_assert_almost_equals(restess, ressphere, 0.001, msg);
}
return 0;
}
static char * test_tess2sphere_gxy()
{
SPHERE sphere;
TESSEROID tess;
double radius, dist, restess, ressphere;
GLQ *glqlon, *glqlat, *glqr;
tess.density = 1000.;
tess.w = 44;
tess.e = 46;
tess.s = -1;
tess.n = 1;
tess.r1 = MEAN_EARTH_RADIUS - 100000;
tess.r2 = MEAN_EARTH_RADIUS;
glqlon = glq_new(8, tess.w, tess.e);
if(glqlon == NULL)
mu_assert(0, "GLQ allocation error");
glqlat = glq_new(8, tess.s, tess.n);
if(glqlat == NULL)
mu_assert(0, "GLQ allocation error");
glqr = glq_new(8, tess.r1, tess.r2);
if(glqr == NULL)
mu_assert(0, "GLQ allocation error");
glq_precompute_sincos(glqlat);
radius = tess.r2;
/* Make a sphere with the same mass as the tesseroid */
tess2sphere(tess, &sphere);
for(dist=1500000; dist <= 2000000; dist += 1000)
{
restess = tess_gxy(tess,5,50,radius+dist,*glqlon,*glqlat,*glqr);
ressphere = sphere_gxy(sphere,5,50,radius+dist);
sprintf(msg, "(distance %g m) tess = %.5f sphere = %.5f", dist,
restess, ressphere);
mu_assert_almost_equals(restess, ressphere, 0.001, msg);
}
return 0;
}
static char * test_tess2sphere_gxz()
{
SPHERE sphere;
TESSEROID tess;
double radius, dist, restess, ressphere;
GLQ *glqlon, *glqlat, *glqr;
tess.density = 1000.;
tess.w = 44;
tess.e = 46;
tess.s = -1;
tess.n = 1;
tess.r1 = MEAN_EARTH_RADIUS - 100000;
tess.r2 = MEAN_EARTH_RADIUS;
glqlon = glq_new(8, tess.w, tess.e);
if(glqlon == NULL)
mu_assert(0, "GLQ allocation error");
glqlat = glq_new(8, tess.s, tess.n);
if(glqlat == NULL)
mu_assert(0, "GLQ allocation error");
glqr = glq_new(8, tess.r1, tess.r2);
if(glqr == NULL)
mu_assert(0, "GLQ allocation error");
glq_precompute_sincos(glqlat);
radius = tess.r2;
/* Make a sphere with the same mass as the tesseroid */
tess2sphere(tess, &sphere);
for(dist=1500000; dist <= 2000000; dist += 1000)
{
restess = tess_gxz(tess,0,50,radius+dist,*glqlon,*glqlat,*glqr);
ressphere = sphere_gxz(sphere,0,50,radius+dist);
sprintf(msg, "(distance %g m) tess = %.5f sphere = %.5f", dist,
restess, ressphere);
mu_assert_almost_equals(restess, ressphere, 0.001, msg);
}
return 0;
}
static char * test_tess2sphere_gyy()
{
SPHERE sphere;
TESSEROID tess;
double radius, dist, restess, ressphere;
GLQ *glqlon, *glqlat, *glqr;
tess.density = 1000.;
tess.w = 44;
tess.e = 46;
tess.s = -1;
tess.n = 1;
tess.r1 = MEAN_EARTH_RADIUS - 100000;
tess.r2 = MEAN_EARTH_RADIUS;
glqlon = glq_new(8, tess.w, tess.e);
if(glqlon == NULL)
mu_assert(0, "GLQ allocation error");
glqlat = glq_new(8, tess.s, tess.n);
if(glqlat == NULL)
mu_assert(0, "GLQ allocation error");
glqr = glq_new(8, tess.r1, tess.r2);
if(glqr == NULL)
mu_assert(0, "GLQ allocation error");
glq_precompute_sincos(glqlat);
radius = tess.r2;
/* Make a sphere with the same mass as the tesseroid */
tess2sphere(tess, &sphere);
for(dist=1500000; dist <= 2000000; dist += 1000)
{
restess = tess_gyy(tess,0,45,radius+dist,*glqlon,*glqlat,*glqr);
ressphere = sphere_gyy(sphere,0,45,radius+dist);
sprintf(msg, "(distance %g m) tess = %.5f sphere = %.5f", dist,
restess, ressphere);
mu_assert_almost_equals(restess, ressphere, 0.001, msg);
}
return 0;
}
static char * test_tess2sphere_gyz()
{
SPHERE sphere;
TESSEROID tess;
double radius, dist, restess, ressphere;
GLQ *glqlon, *glqlat, *glqr;
tess.density = 1000.;
tess.w = 44;
tess.e = 46;
tess.s = -1;
tess.n = 1;
tess.r1 = MEAN_EARTH_RADIUS - 100000;
tess.r2 = MEAN_EARTH_RADIUS;
glqlon = glq_new(8, tess.w, tess.e);
if(glqlon == NULL)
mu_assert(0, "GLQ allocation error");
glqlat = glq_new(8, tess.s, tess.n);
if(glqlat == NULL)
mu_assert(0, "GLQ allocation error");
glqr = glq_new(8, tess.r1, tess.r2);
if(glqr == NULL)
mu_assert(0, "GLQ allocation error");
glq_precompute_sincos(glqlat);
radius = tess.r2;
/* Make a sphere with the same mass as the tesseroid */
tess2sphere(tess, &sphere);
for(dist=1500000; dist <= 2000000; dist += 1000)
{
restess = tess_gyz(tess,5,45,radius+dist,*glqlon,*glqlat,*glqr);
ressphere = sphere_gyz(sphere,5,45,radius+dist);
sprintf(msg, "(distance %g m) tess = %.5f sphere = %.5f", dist,
restess, ressphere);
mu_assert_almost_equals(restess, ressphere, 0.001, msg);
}
return 0;
}
static char * test_tess2sphere_gzz()
{
SPHERE sphere;
TESSEROID tess;
double radius, dist, restess, ressphere;
GLQ *glqlon, *glqlat, *glqr;
tess.density = 1000.;
tess.w = 44;
tess.e = 46;
tess.s = -1;
tess.n = 1;
tess.r1 = MEAN_EARTH_RADIUS - 100000;
tess.r2 = MEAN_EARTH_RADIUS;
glqlon = glq_new(8, tess.w, tess.e);
if(glqlon == NULL)
mu_assert(0, "GLQ allocation error");
glqlat = glq_new(8, tess.s, tess.n);
if(glqlat == NULL)
mu_assert(0, "GLQ allocation error");
glqr = glq_new(8, tess.r1, tess.r2);
if(glqr == NULL)
mu_assert(0, "GLQ allocation error");
glq_precompute_sincos(glqlat);
radius = tess.r2;
/* Make a sphere with the same mass as the tesseroid */
tess2sphere(tess, &sphere);
for(dist=1500000; dist <= 2000000; dist += 1000)
{
restess = tess_gzz(tess,0,45,radius+dist,*glqlon,*glqlat,*glqr);
ressphere = sphere_gzz(sphere,0,45,radius+dist);
sprintf(msg, "(distance %g m) tess = %.5f sphere = %.5f", dist,
restess, ressphere);
mu_assert_almost_equals(restess, ressphere, 0.001, msg);
}
return 0;
}
static char * test_tess_tensor_trace()
{
#define N 4
TESSEROID tesses[N] = {
{1,0,1,0,1,6000000,6001000},
{1,180,183,80,81.5,6300000,6302000},
{1,200,203,-90,-88,5500000,5500100},
{1,-10,-7,7,7.5,6500000,6505000}};
GLQ *glqlon, *glqlat, *glqr;
int i;
double lon, lat, r, trace, dist;
glqlon = glq_new(8, tesses[0].w, tesses[0].e);
if(glqlon == NULL)
mu_assert(0, "GLQ allocation error");
glqlat = glq_new(8, tesses[0].s, tesses[0].n);
if(glqlat == NULL)
mu_assert(0, "GLQ allocation error");
glqr = glq_new(8, tesses[0].r1, tesses[0].r2);
if(glqr == NULL)
mu_assert(0, "GLQ allocation error");
for(i = 0; i < N; i++)
{
lon = 0.5*(tesses[i].w + tesses[i].e);
lat = 0.5*(tesses[i].n + tesses[i].s);
r = tesses[i].r2;
for(dist=100000; dist <= 5000000; dist += 5000)
{
trace = calc_tess_model_adapt(&tesses[i], 1, lon, lat, r + dist,
glqlon, glqlat, glqr, tess_gxx,
TESSEROID_GXX_SIZE_RATIO) +
calc_tess_model_adapt(&tesses[i], 1, lon, lat, r + dist,
glqlon, glqlat, glqr, tess_gyy,
TESSEROID_GYY_SIZE_RATIO) +
calc_tess_model_adapt(&tesses[i], 1, lon, lat, r + dist,
glqlon, glqlat, glqr, tess_gzz,
TESSEROID_GZZ_SIZE_RATIO);
sprintf(msg, "(tess %d dist %g) trace %.10f", i, dist, trace);
mu_assert_almost_equals(trace, 0, 0.0000000001, msg);
}
}
glq_free(glqlon);
glq_free(glqlat);
glq_free(glqr);
#undef N
return 0;
}
static char * test_adaptative()
{
/* Check if the adaptative is dividing properly and returning the same thing
as the non-adaptative (do spliting by hand) */
TESSEROID tess,
split[10000];
GLQ *glqlon, *glqlat, *glqr;
double mindist, resadapt, resnormal;
double lon, lat;
int n;
tess.density = 1000.;
tess.w = -0.5;
tess.e = 0.5;
tess.s = -0.5;
tess.n = 0.5;
tess.r1 = MEAN_EARTH_RADIUS - 10000;
tess.r2 = MEAN_EARTH_RADIUS;
glqlon = glq_new(2, tess.w, tess.e);
if(glqlon == NULL)
mu_assert(0, "GLQ allocation error");
glqlat = glq_new(2, tess.s, tess.n);
if(glqlat == NULL)
mu_assert(0, "GLQ allocation error");
glqr = glq_new(2, tess.r1, tess.r2);
if(glqr == NULL)
mu_assert(0, "GLQ allocation error");
mindist = 100000;
/* If at half mindist should only divide once */
for(lon = -0.5; lon <= 0.5; lon += 0.05)
{
for(lat = -0.5; lat <= 0.5; lat += 0.05)
{
resadapt = calc_tess_model_adapt(&tess, 1, lon, lat,
0.5*mindist + MEAN_EARTH_RADIUS,
glqlon, glqlat, glqr,
tess_gzz,
TESSEROID_GZZ_SIZE_RATIO);
n = split_tess(tess, 20, 20, 20, split);
sprintf(msg, "splitting in %d instead of 8000", n);
mu_assert(n == 8000, msg);
resnormal = calc_tess_model(split, n, lon, lat,
0.5*mindist + MEAN_EARTH_RADIUS, glqlon,
glqlat, glqr, tess_gzz);
sprintf(msg, "adapt = %.10f normal = %.10f", resadapt, resnormal);
mu_assert_almost_equals(resadapt, resnormal, pow(10, -2), msg);
}
}
return 0;
}
int grav_tess_run_all()
{
int failed = 0;
failed += mu_run_test(test_tess2sphere_pot,
"tess_pot results equal to sphere of same mass at distance");
failed += mu_run_test(test_tess2sphere_gx,
"tess_gx results equal to sphere of same mass at distance");
failed += mu_run_test(test_tess2sphere_gy,
"tess_gy results equal to sphere of same mass at distance");
failed += mu_run_test(test_tess2sphere_gz,
"tess_gz results equal to sphere of same mass at distance");
failed += mu_run_test(test_tess2sphere_gxx,
"tess_gxx results equal to sphere of same mass at distance");
failed += mu_run_test(test_tess2sphere_gxy,
"tess_gxy results equal to sphere of same mass at distance");
failed += mu_run_test(test_tess2sphere_gxz,
"tess_gxz results equal to sphere of same mass at distance");
failed += mu_run_test(test_tess2sphere_gyy,
"tess_gyy results equal to sphere of same mass at distance");
failed += mu_run_test(test_tess2sphere_gyz,
"tess_gyz results equal to sphere of same mass at distance");
failed += mu_run_test(test_tess2sphere_gzz,
"tess_gzz results equal to sphere of same mass at distance");
failed += mu_run_test(test_tess_tensor_trace, "trace of GGT for tesseroid is zero");
failed += mu_run_test(test_adaptative,
"calc_tess_model_adapt results as non-adapt with split by hand");
return failed;
}

229
test/test_parsers.c Executable file
View File

@ -0,0 +1,229 @@
/*
Unit tests for I/O parser functions.
*/
#include <stdio.h>
#include <math.h>
#include "minunit.h"
#include "../lib/parsers.h"
#include "../lib/constants.h"
/* To store fail messages */
char msg[1000];
/* UNIT TESTS */
static char * test_gets_tess()
{
int i;
char str[1000];
TESSEROID res;
TESSEROID tesses[4] = {
{1,0,1,0,1,6000000,6001000},
{1,180,190,80,85,6300000,6301000},
{1,160,200,-90,-70,5500000,6000000},
{1,-10,5,-7,15,6500000,6505000}};
for(i = 0; i < 4; i++)
{
sprintf(str, "%15.5f %15.5f %15.5f %15.5f %15.5f %15.5f %15.5f",
tesses[i].w, tesses[i].e, tesses[i].s, tesses[i].n,
tesses[i].r2 - MEAN_EARTH_RADIUS,
tesses[i].r1 - MEAN_EARTH_RADIUS,
tesses[i].density);
gets_tess(str, &res);
sprintf(msg, "(tess %d) failed to read w. read=%g true=%g diff=%g", i,
res.w, tesses[i].w, res.w - tesses[i].w);
mu_assert_almost_equals(res.w, tesses[i].w, 10E-10, msg);
sprintf(msg, "(tess %d) failed to read e. read=%g true=%g diff=%g", i,
res.e, tesses[i].e, res.e - tesses[i].e);
mu_assert_almost_equals(res.e, tesses[i].e, 10E-10, msg);
sprintf(msg, "(tess %d) failed to read s. read=%g true=%g diff=%g", i,
res.s, tesses[i].s, res.s - tesses[i].s);
mu_assert_almost_equals(res.s, tesses[i].s, 10E-10, msg);
sprintf(msg, "(tess %d) failed to read n. read=%g true=%g diff=%g", i,
res.n, tesses[i].n, res.n - tesses[i].n);
mu_assert_almost_equals(res.n, tesses[i].n, 10E-10, msg);
sprintf(msg, "(tess %d) failed to read r2. read=%g true=%g diff=%g",
i, res.r2, tesses[i].r2, res.r2 - tesses[i].r2);
mu_assert_almost_equals(res.r2, tesses[i].r2, 10E-10, msg);
sprintf(msg, "(tess %d) failed to read r1. read=%g true=%g diff=%g",
i, res.r1, tesses[i].r1, res.r1 - tesses[i].r1);
mu_assert_almost_equals(res.r1, tesses[i].r1, 10E-10, msg);
sprintf(msg, "(tess %d) failed to read dens. read=%g true=%g diff=%g",
i, res.density, tesses[i].density,
res.density - tesses[i].density);
mu_assert_almost_equals(res.density, tesses[i].density, 10E-10, msg);
}
return 0;
}
static char * test_gets_prism()
{
int i;
char str[1000];
PRISM res;
PRISM prisms[4] = {
{1,0,1000,0,2000,100,2000,0,0,0},
{1,-500,200,300,500,-1000,4000,0,0,0},
{1,-10000000,5000000,5000000,8000000,0,3000000,0,0,0},
{1,-1000000,50000,500000,800000,0,300000,0,0,0}};
for(i = 0; i < 4; i++)
{
sprintf(str, "%g %g %g %g %g %g %g", prisms[i].x1, prisms[i].x2,
prisms[i].y1, prisms[i].y2, prisms[i].z1, prisms[i].z2,
prisms[i].density);
if(gets_prism(str, &res))
{
sprintf(msg, "(prism %d) gets_prism returned 1", i);
mu_assert(0, msg);
}
sprintf(msg, "(prism %d) failed to read x1. read=%g true=%g", i, res.x1,
prisms[i].x1);
mu_assert(res.x1 == prisms[i].x1, msg);
sprintf(msg, "(prism %d) failed to read x2. read=%g true=%g", i, res.x2,
prisms[i].x2);
mu_assert(res.x2 == prisms[i].x2, msg);
sprintf(msg, "(prism %d) failed to read y1. read=%g true=%g", i, res.y1,
prisms[i].y1);
mu_assert(res.y1 == prisms[i].y1, msg);
sprintf(msg, "(prism %d) failed to read y2. read=%g true=%g", i, res.y2,
prisms[i].y2);
mu_assert(res.y2 == prisms[i].y2, msg);
sprintf(msg, "(prism %d) failed to read z1. read=%g true=%g", i, res.z1,
prisms[i].z1);
mu_assert(res.z1 == prisms[i].z1, msg);
sprintf(msg, "(prism %d) failed to read z2. read=%g true=%g", i, res.z2,
prisms[i].z2);
mu_assert(res.z2 == prisms[i].z2, msg);
sprintf(msg, "(prism %d) failed to read density. read=%g true=%g", i,
res.density, prisms[i].density);
mu_assert(res.density == prisms[i].density, msg);
}
return 0;
}
static char * test_gets_prism_sph()
{
int i;
char str[1000];
PRISM res;
PRISM prisms[4] = {
{1,-1000,1000,-2000,2000,0,2000,2,3,1},
{1,-500,500,-500,500,0,4000,-3,1.2344,18.048},
{1,-10000000,10000000,-8000000,8000000,0,3000000,2123.2,2,45.33},
{1,-50000,50000,-800000,800000,0,300000,783.245,3.57,345}};
for(i = 0; i < 4; i++)
{
sprintf(str, "%g %g %g %g %g %g %g",
prisms[i].x2 - prisms[i].x1,
prisms[i].y2 - prisms[i].y1,
prisms[i].z2 - prisms[i].z1,
prisms[i].density,
prisms[i].lon, prisms[i].lat, prisms[i].r);
if(gets_prism_sph(str, &res))
{
sprintf(msg, "(prism %d) gets_prism_sph returned 1", i);
mu_assert(0, msg);
}
sprintf(msg, "(prism %d) failed to read x1. read=%g true=%g", i, res.x1,
prisms[i].x1);
mu_assert(res.x1 == prisms[i].x1, msg);
sprintf(msg, "(prism %d) failed to read x2. read=%g true=%g", i, res.x2,
prisms[i].x2);
mu_assert(res.x2 == prisms[i].x2, msg);
sprintf(msg, "(prism %d) failed to read y1. read=%g true=%g", i, res.y1,
prisms[i].y1);
mu_assert(res.y1 == prisms[i].y1, msg);
sprintf(msg, "(prism %d) failed to read y2. read=%g true=%g", i, res.y2,
prisms[i].y2);
mu_assert(res.y2 == prisms[i].y2, msg);
sprintf(msg, "(prism %d) failed to read z1. read=%g true=%g", i, res.z1,
prisms[i].z1);
mu_assert(res.z1 == prisms[i].z1, msg);
sprintf(msg, "(prism %d) failed to read z2. read=%g true=%g", i, res.z2,
prisms[i].z2);
mu_assert(res.z2 == prisms[i].z2, msg);
sprintf(msg, "(prism %d) failed to read density. read=%g true=%g", i,
res.density, prisms[i].density);
mu_assert(res.density == prisms[i].density, msg);
sprintf(msg, "(prism %d) failed to read lon. read=%g true=%g", i,
res.lon, prisms[i].lon);
mu_assert(res.lon == prisms[i].lon, msg);
sprintf(msg, "(prism %d) failed to read lat. read=%g true=%g", i,
res.lat, prisms[i].lat);
mu_assert(res.lat == prisms[i].lat, msg);
sprintf(msg, "(prism %d) failed to read r. read=%g true=%g", i,
res.r, prisms[i].r);
mu_assert(res.r == prisms[i].r, msg);
}
return 0;
}
static char * test_gets_prism_fail()
{
int i = 0, j;
char str[1000];
PRISM res;
PRISM prisms[4] = {
{1,0,1000,0,2000,100,2000,0,0,0},
{1,-500,200,300,500,-1000,4000,0,0,0},
{1,-10000000,5000000,5000000,8000000,0,3000000,0,0,0},
{1,-1000000,50000,500000,800000,0,300000,0,0,0}};
j = 1;
sprintf(str, "%g %g %g %g %g %g %g 1", prisms[i].x1, prisms[i].x2,
prisms[i].y1, prisms[i].y2, prisms[i].z1, prisms[i].z2,
prisms[i].density);
sprintf(msg, "(test %d) gets_prism did not fail for bad input", j);
mu_assert(gets_prism(str, &res), msg);
j = 2;
sprintf(str, "%g %g %g %g %g %g %g 1.3", prisms[i].x1, prisms[i].x2,
prisms[i].y1, prisms[i].y2, prisms[i].z1, prisms[i].z2,
prisms[i].density);
sprintf(msg, "(test %d) gets_prism did not fail for bad input", j);
mu_assert(gets_prism(str, &res), msg);
j = 3;
sprintf(str, "%g %g %g %g %g %g %g meh", prisms[i].x1, prisms[i].x2,
prisms[i].y1, prisms[i].y2, prisms[i].z1, prisms[i].z2,
prisms[i].density);
sprintf(msg, "(test %d) gets_prism did not fail for bad input", j);
mu_assert(gets_prism(str, &res), msg);
j = 4;
sprintf(str, "%g %g %g %g %g %g %g 1 4.5 234556 blablabla",
prisms[i].x1, prisms[i].x2,
prisms[i].y1, prisms[i].y2, prisms[i].z1, prisms[i].z2,
prisms[i].density);
sprintf(msg, "(test %d) gets_prism did not fail for bad input", j);
mu_assert(gets_prism(str, &res), msg);
return 0;
}
int parsers_run_all()
{
int failed = 0;
failed += mu_run_test(test_gets_tess, "gets_tess reads correctly from string");
failed += mu_run_test(test_gets_prism, "gets_prism reads correctly from string");
failed += mu_run_test(test_gets_prism_sph,
"gets_prism_sph reads correctly from string");
failed += mu_run_test(test_gets_prism_fail, "gets_prism fails for bad input");
return failed;
}

53
toolkits/CMakeLists.txt Normal file
View File

@ -0,0 +1,53 @@
#
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2")
if(WIN32)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --std=c++11 -O2")
endif()
#
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin/toolkits)
# tools
macro(add_tools name)
#
add_executable(${name} ${name}.c)
#
set_target_properties(${name} PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib)
#
target_link_libraries(${name} PUBLIC tesseroids)
# /usr/local/sbin
install(TARGETS ${name} RUNTIME DESTINATION sbin/tesseroids)
endmacro()
# tools
add_tools(prismgx)
add_tools(prismgy)
add_tools(prismgz)
add_tools(prismgxx)
add_tools(prismgxy)
add_tools(prismgxz)
add_tools(prismgyy)
add_tools(prismgyz)
add_tools(prismgzz)
add_tools(prismgs)
add_tools(prismpot)
add_tools(prismpots)
add_tools(prismggts)
add_tools(tessgx)
add_tools(tessgy)
add_tools(tessgz)
add_tools(tessgxx)
add_tools(tessgxy)
add_tools(tessgxz)
add_tools(tessgyy)
add_tools(tessgyz)
add_tools(tessgzz)
add_tools(tessdefaults)
add_tools(tess2prism)
add_tools(tessgrd)
add_tools(tesslayers)
add_tools(tessmass)
add_tools(tessmodgen)
add_tools(tesspot)

249
toolkits/prismggts.c Normal file
View File

@ -0,0 +1,249 @@
/*
Program to calculate the potential of a rectangular prism model in spherical
coordinates.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "../lib/logger.h"
#include "../lib/version.h"
#include "../lib/grav_prism_sph.h"
#include "../lib/geometry.h"
#include "../lib/constants.h"
#include "../lib/parsers.h"
/* Print the help message */
void print_help()
{
printf("Usage: prismggts MODELFILE [OPTIONS]\n\n");
printf("Calculates the 6 component gravity gradient tensor due to a\n");
printf("rectangular prism model on specified observation points using\n");
printf("spherical coordinates.\n\n");
printf("All input units are SI! Output is in Eotvos.\n\n");
printf("Coordinate system:\n");
printf(" The coordinate system used for the calculations is:\n");
printf(" x->North, y->East, and z->Up\n");
printf("Input:\n");
printf(" Computation points are passed through standard input (stdin).\n");
printf(" Reads 3 or more values per line and inteprets the first 3 as:\n");
printf(" longitude latitude height \n");
printf(" longitude and latitude should be in decimal degrees, and\n");
printf(" height in meters.\n");
printf(" Other values in the line are ignored.\n");
printf(" Lines that start with # are ignored as comments.\n");
printf(" Lines should be no longer than 10000 (ten thousand) characters.");
printf(" \n\n");
printf("Output:\n");
printf(" Printed to standard output (stdout) in the form:\n");
printf(" lon lat height ... gxx gxy gxz gyy gyz gzz\n");
printf(" ... represents any values that were read from input and\n");
printf(" ignored. In other words, the result is appended to the last\n");
printf(" column of the input. Use this to pipe prism* programs\n");
printf(" together.\n\n");
printf(" Comments about the provenance of the data are inserted into\n");
printf(" the top of the output\n\n");
printf("MODELFILE: File containing the prism model\n");
printf(" * Each prism is specified by the values of its dimensions,\n");
printf(" density, and spherical coordinates of the center of its\n");
printf(" top.\n");
printf(" * The file should contain one prism per line\n");
printf(" * If a line starts with # it will be considered a comment and\n");
printf(" will be ignored.\n");
printf(" * Each line should have the following column format:\n");
printf(" DX DY DZ Density lon lat r\n");
printf(" This is the format output by tess2prism.\n\n");
printf("Options:\n");
printf(" -h Print instructions.\n");
printf(" --version Print version and license information.\n");
printf(" -v Enable verbose printing to stderr.\n");
printf(" -lFILENAME Print log messages to file FILENAME.\n");
printf("\nPart of the Tesseroids package.\n");
printf("Project site: <http://fatiando.org/software/tesseroids>\n");
printf("Report bugs at: ");
printf("<http://code.google.com/p/tesseroids/issues/list>\n");
}
/* Run the main for a generic prismg* program */
int main(int argc, char **argv)
{
BASIC_ARGS args;
PRISM *model;
int modelsize, rc, line, points = 0, error_exit = 0, bad_input = 0, i;
char buff[10000];
char progname[] = "prismggts";
double lon, lat, height, ggt[6], tmp[6];
FILE *logfile = NULL, *modelfile = NULL;
time_t rawtime;
clock_t tstart;
struct tm * timeinfo;
log_init(LOG_INFO);
strcpy(progname, progname);
rc = parse_basic_args(argc, argv, progname, &args, &print_help);
if(rc == 3)
{
log_error("%s: missing input file", progname);
log_warning("Terminating due to bad input");
log_warning("Try '%s -h' for instructions", progname);
return 1;
}
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_INFO);
}
/* Print standard verbose */
log_info("%s (Tesseroids project) %s", progname, tesseroids_version);
time(&rawtime);
timeinfo = localtime(&rawtime);
log_info("(local time) %s", asctime(timeinfo));
/* Read the model file */
log_info("Reading prism model from file %s", args.inputfname);
modelfile = fopen(args.inputfname, "r");
if(modelfile == NULL)
{
log_error("failed to open model file %s", args.inputfname);
log_warning("Terminating due to bad input");
log_warning("Try '%s -h' for instructions", progname);
if(args.logtofile)
fclose(logfile);
return 1;
}
model = read_prism_model(modelfile, 1, &modelsize);
fclose(modelfile);
if(modelsize == 0)
{
log_error("prism file %s is empty", args.inputfname);
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.inputfname);
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 prism(s) read", modelsize);
/* Print a header on the output with provenance information */
printf("# Gravity gradient tensor calculated in spherical coordinates with %s %s:\n",
progname, tesseroids_version);
printf("# local time: %s", asctime(timeinfo));
printf("# model file: %s (%d prisms)\n", args.inputfname, modelsize);
/* Read each computation point from stdin and calculate */
log_info("Calculating (this may take a while)...");
tstart = clock();
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);
ggt[0] = 0;
ggt[1] = 0;
ggt[2] = 0;
ggt[3] = 0;
ggt[4] = 0;
ggt[5] = 0;
for(i = 0; i < modelsize; i++)
{
prism_ggt_sph(model[i], lon, lat, height + MEAN_EARTH_RADIUS,
tmp);
ggt[0] += tmp[0];
ggt[1] += tmp[1];
ggt[2] += tmp[2];
ggt[3] += tmp[3];
ggt[4] += tmp[4];
ggt[5] += tmp[5];
}
printf("%s %.15g %.15g %.15g %.15g %.15g %.15g\n", buff,
ggt[0],
ggt[1],
ggt[2],
ggt[3],
ggt[4],
ggt[5]);
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);
log_info("Done");
if(args.logtofile)
fclose(logfile);
return 0;
}

239
toolkits/prismgs.c Normal file
View File

@ -0,0 +1,239 @@
/*
Program to calculate the potential of a rectangular prism model in spherical
coordinates.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "../lib/logger.h"
#include "../lib/version.h"
#include "../lib/grav_prism_sph.h"
#include "../lib/geometry.h"
#include "../lib/constants.h"
#include "../lib/parsers.h"
/* Print the help message */
void print_help()
{
printf("Usage: prismgs MODELFILE [OPTIONS]\n\n");
printf("Calculates the 3 component gravity vector due to a rectangular\n");
printf("prism model on specified observation points using spherical\n");
printf("coordinates.\n\n");
printf("All input units are SI! Output is in mGal.\n\n");
printf("Coordinate system:\n");
printf(" The coordinate system used for the calculations is:\n");
printf(" x->North, y->East, and z->Up\n");
printf("In order to maintain mainstream convention, component gz is\n");
printf("calculated with z-> Down.\n\n");
printf("Input:\n");
printf(" Computation points are passed through standard input (stdin).\n");
printf(" Reads 3 or more values per line and inteprets the first 3 as:\n");
printf(" longitude latitude height \n");
printf(" longitude and latitude should be in decimal degrees, and\n");
printf(" height in meters.\n");
printf(" Other values in the line are ignored.\n");
printf(" Lines that start with # are ignored as comments.\n");
printf(" Lines should be no longer than 10000 (ten thousand) characters.");
printf(" \n\n");
printf("Output:\n");
printf(" Printed to standard output (stdout) in the form:\n");
printf(" lon lat height ... gx gy gz\n");
printf(" ... represents any values that were read from input and\n");
printf(" ignored. In other words, the result is appended to the last\n");
printf(" column of the input. Use this to pipe prism* programs\n");
printf(" together.\n\n");
printf(" Comments about the provenance of the data are inserted into\n");
printf(" the top of the output\n\n");
printf("MODELFILE: File containing the prism model\n");
printf(" * Each prism is specified by the values of its dimensions,\n");
printf(" density, and spherical coordinates of the center of its\n");
printf(" top.\n");
printf(" * The file should contain one prism per line\n");
printf(" * If a line starts with # it will be considered a comment and\n");
printf(" will be ignored.\n");
printf(" * Each line should have the following column format:\n");
printf(" DX DY DZ Density lon lat r\n");
printf(" This is the format output by tess2prism.\n\n");
printf("Options:\n");
printf(" -h Print instructions.\n");
printf(" --version Print version and license information.\n");
printf(" -v Enable verbose printing to stderr.\n");
printf(" -lFILENAME Print log messages to file FILENAME.\n");
printf("\nPart of the Tesseroids package.\n");
printf("Project site: <http://fatiando.org/software/tesseroids>\n");
printf("Report bugs at: ");
printf("<http://code.google.com/p/tesseroids/issues/list>\n");
}
/* Run the main for a generic prismg* program */
int main(int argc, char **argv)
{
BASIC_ARGS args;
PRISM *model;
int modelsize, rc, line, points = 0, error_exit = 0, bad_input = 0, i;
char buff[10000];
char progname[] = "prismgs";
double lon, lat, height, gx, gy, gz, tmpx, tmpy, tmpz;
FILE *logfile = NULL, *modelfile = NULL;
time_t rawtime;
clock_t tstart;
struct tm * timeinfo;
log_init(LOG_INFO);
strcpy(progname, progname);
rc = parse_basic_args(argc, argv, progname, &args, &print_help);
if(rc == 3)
{
log_error("%s: missing input file", progname);
log_warning("Terminating due to bad input");
log_warning("Try '%s -h' for instructions", progname);
return 1;
}
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_INFO);
}
/* Print standard verbose */
log_info("%s (Tesseroids project) %s", progname, tesseroids_version);
time(&rawtime);
timeinfo = localtime(&rawtime);
log_info("(local time) %s", asctime(timeinfo));
/* Read the model file */
log_info("Reading prism model from file %s", args.inputfname);
modelfile = fopen(args.inputfname, "r");
if(modelfile == NULL)
{
log_error("failed to open model file %s", args.inputfname);
log_warning("Terminating due to bad input");
log_warning("Try '%s -h' for instructions", progname);
if(args.logtofile)
fclose(logfile);
return 1;
}
model = read_prism_model(modelfile, 1, &modelsize);
fclose(modelfile);
if(modelsize == 0)
{
log_error("prism file %s is empty", args.inputfname);
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.inputfname);
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 prism(s) read", modelsize);
/* Print a header on the output with provenance information */
printf("# Gravity vector calculated in spherical coordinates with %s %s:\n",
progname, tesseroids_version);
printf("# local time: %s", asctime(timeinfo));
printf("# model file: %s (%d prisms)\n", args.inputfname, modelsize);
/* Read each computation point from stdin and calculate */
log_info("Calculating (this may take a while)...");
tstart = clock();
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);
gx = 0;
gy = 0;
gz = 0;
for(i = 0; i < modelsize; i++)
{
prism_g_sph(model[i], lon, lat, height + MEAN_EARTH_RADIUS,
&tmpx, &tmpy, &tmpz);
gx += tmpx;
gy += tmpy;
gz += tmpz;
}
printf("%s %.15g %.15g %.15g\n", buff, gx, gy, gz);
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);
log_info("Done");
if(args.logtofile)
fclose(logfile);
return 0;
}

14
toolkits/prismgx.c Normal file
View File

@ -0,0 +1,14 @@
/*
Program to calculate gx of a rectangular prism model on a set of points.
*/
#include "../lib/grav_prism.h"
#include "../lib/prismg_main.h"
/** Main */
int main(int argc, char **argv)
{
return run_prismg_main(argc, argv, "prismgx", &prism_gx);
}

14
toolkits/prismgxx.c Normal file
View File

@ -0,0 +1,14 @@
/*
Program to calculate gxx of a rectangular prism model on a set of points.
*/
#include "../lib/grav_prism.h"
#include "../lib/prismg_main.h"
/** Main */
int main(int argc, char **argv)
{
return run_prismg_main(argc, argv, "prismgxx", &prism_gxx);
}

14
toolkits/prismgxy.c Normal file
View File

@ -0,0 +1,14 @@
/*
Program to calculate gxy of a rectangular prism model on a set of points.
*/
#include "../lib/grav_prism.h"
#include "../lib/prismg_main.h"
/** Main */
int main(int argc, char **argv)
{
return run_prismg_main(argc, argv, "prismgxy", &prism_gxy);
}

14
toolkits/prismgxz.c Normal file
View File

@ -0,0 +1,14 @@
/*
Program to calculate gxz of a rectangular prism model on a set of points.
*/
#include "../lib/grav_prism.h"
#include "../lib/prismg_main.h"
/** Main */
int main(int argc, char **argv)
{
return run_prismg_main(argc, argv, "prismgxz", &prism_gxz);
}

14
toolkits/prismgy.c Normal file
View File

@ -0,0 +1,14 @@
/*
Program to calculate gy of a rectangular prism model on a set of points.
*/
#include "../lib/grav_prism.h"
#include "../lib/prismg_main.h"
/** Main */
int main(int argc, char **argv)
{
return run_prismg_main(argc, argv, "prismgy", &prism_gy);
}

14
toolkits/prismgyy.c Normal file
View File

@ -0,0 +1,14 @@
/*
Program to calculate gyy of a rectangular prism model on a set of points.
*/
#include "../lib/grav_prism.h"
#include "../lib/prismg_main.h"
/** Main */
int main(int argc, char **argv)
{
return run_prismg_main(argc, argv, "prismgyy", &prism_gyy);
}

14
toolkits/prismgyz.c Normal file
View File

@ -0,0 +1,14 @@
/*
Program to calculate gyz of a rectangular prism model on a set of points.
*/
#include "../lib/grav_prism.h"
#include "../lib/prismg_main.h"
/** Main */
int main(int argc, char **argv)
{
return run_prismg_main(argc, argv, "prismgyz", &prism_gyz);
}

14
toolkits/prismgz.c Normal file
View File

@ -0,0 +1,14 @@
/*
Program to calculate gz of a rectangular prism model on a set of points.
*/
#include "../lib/grav_prism.h"
#include "../lib/prismg_main.h"
/** Main */
int main(int argc, char **argv)
{
return run_prismg_main(argc, argv, "prismgz", &prism_gz);
}

14
toolkits/prismgzz.c Normal file
View File

@ -0,0 +1,14 @@
/*
Program to calculate gzz of a rectangular prism model on a set of points.
*/
#include "../lib/grav_prism.h"
#include "../lib/prismg_main.h"
/** Main */
int main(int argc, char **argv)
{
return run_prismg_main(argc, argv, "prismgzz", &prism_gzz);
}

14
toolkits/prismpot.c Normal file
View File

@ -0,0 +1,14 @@
/*
Program to calculate potential of a rectangular prism model on a set of points.
*/
#include "../lib/grav_prism.h"
#include "../lib/prismg_main.h"
/** Main */
int main(int argc, char **argv)
{
return run_prismg_main(argc, argv, "prismpot", &prism_pot);
}

230
toolkits/prismpots.c Normal file
View File

@ -0,0 +1,230 @@
/*
Program to calculate the potential of a rectangular prism model in spherical
coordinates.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "../lib/logger.h"
#include "../lib/version.h"
#include "../lib/grav_prism_sph.h"
#include "../lib/geometry.h"
#include "../lib/constants.h"
#include "../lib/parsers.h"
/* Print the help message */
void print_help()
{
printf("Usage: prismpots MODELFILE [OPTIONS]\n\n");
printf("Calculate the potential due to a rectangular prism model on\n");
printf("specified observation points using spherical coordinates.\n\n");
printf("All input and output units are SI!\n\n");
printf("Coordinate system:\n");
printf(" The coordinate system used for the calculations is:\n");
printf(" x->North, y->East, and z->Up\n\n");
printf("Input:\n");
printf(" Computation points are passed through standard input (stdin).\n");
printf(" Reads 3 or more values per line and inteprets the first 3 as:\n");
printf(" longitude latitude height \n");
printf(" longitude and latitude should be in decimal degrees, and\n");
printf(" height in meters.\n");
printf(" Other values in the line are ignored.\n");
printf(" Lines that start with # are ignored as comments.\n");
printf(" Lines should be no longer than 10000 (ten thousand) characters.");
printf(" \n\n");
printf("Output:\n");
printf(" Printed to standard output (stdout) in the form:\n");
printf(" lon lat height ... potential\n");
printf(" ... represents any values that were read from input and\n");
printf(" ignored. In other words, the result is appended to the last\n");
printf(" column of the input. Use this to pipe prism* programs\n");
printf(" together.\n\n");
printf(" Comments about the provenance of the data are inserted into\n");
printf(" the top of the output\n\n");
printf("MODELFILE: File containing the prism model\n");
printf(" * Each prism is specified by the values of its dimensions,\n");
printf(" density, and spherical coordinates of the center of its\n");
printf(" top.\n");
printf(" * The file should contain one prism per line\n");
printf(" * If a line starts with # it will be considered a comment and\n");
printf(" will be ignored.\n");
printf(" * Each line should have the following column format:\n");
printf(" DX DY DZ Density lon lat r\n");
printf(" This is the format output by tess2prism.\n\n");
printf("Options:\n");
printf(" -h Print instructions.\n");
printf(" --version Print version and license information.\n");
printf(" -v Enable verbose printing to stderr.\n");
printf(" -lFILENAME Print log messages to file FILENAME.\n");
printf("\nPart of the Tesseroids package.\n");
printf("Project site: <http://fatiando.org/software/tesseroids>\n");
printf("Report bugs at: ");
printf("<http://code.google.com/p/tesseroids/issues/list>\n");
}
/* Run the main for a generic prismg* program */
int main(int argc, char **argv)
{
BASIC_ARGS args;
PRISM *model;
int modelsize, rc, line, points = 0, error_exit = 0, bad_input = 0, i;
char buff[10000];
char progname[] = "prismpots";
double lon, lat, height, res;
FILE *logfile = NULL, *modelfile = NULL;
time_t rawtime;
clock_t tstart;
struct tm * timeinfo;
log_init(LOG_INFO);
strcpy(progname, progname);
rc = parse_basic_args(argc, argv, progname, &args, &print_help);
if(rc == 3)
{
log_error("%s: missing input file", progname);
log_warning("Terminating due to bad input");
log_warning("Try '%s -h' for instructions", progname);
return 1;
}
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_INFO);
}
/* Print standard verbose */
log_info("%s (Tesseroids project) %s", progname, tesseroids_version);
time(&rawtime);
timeinfo = localtime(&rawtime);
log_info("(local time) %s", asctime(timeinfo));
/* Read the model file */
log_info("Reading prism model from file %s", args.inputfname);
modelfile = fopen(args.inputfname, "r");
if(modelfile == NULL)
{
log_error("failed to open model file %s", args.inputfname);
log_warning("Terminating due to bad input");
log_warning("Try '%s -h' for instructions", progname);
if(args.logtofile)
fclose(logfile);
return 1;
}
model = read_prism_model(modelfile, 1, &modelsize);
fclose(modelfile);
if(modelsize == 0)
{
log_error("prism file %s is empty", args.inputfname);
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.inputfname);
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 prism(s) read", modelsize);
/* Print a header on the output with provenance information */
printf("# Potential calculated in spherical coordinates with %s %s:\n",
progname, tesseroids_version);
printf("# local time: %s", asctime(timeinfo));
printf("# model file: %s (%d prisms)\n", args.inputfname, modelsize);
/* Read each computation point from stdin and calculate */
log_info("Calculating (this may take a while)...");
tstart = clock();
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);
for(res = 0, i = 0; i < modelsize; i++)
{
res += prism_pot_sph(model[i], lon, lat,
height + MEAN_EARTH_RADIUS);
}
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);
log_info("Done");
if(args.logtofile)
fclose(logfile);
return 0;
}

222
toolkits/tess2prism.c Normal file
View File

@ -0,0 +1,222 @@
/*
Convert a tesseroid model into a prism model in spherical coordinates
*/
#include <stdio.h>
#include <time.h>
#include "../lib/version.h"
#include "../lib/parsers.h"
#include "../lib/logger.h"
#include "../lib/geometry.h"
/** Print the help message */
void print_help()
{
printf("Usage: tess2prim TESSFILE [OPTIONS]\n\n");
printf("Convert a tesseroid model into a rectangular prism model\n");
printf("(for use with the prism* programs).\n\n");
printf("The converted prisms have the same mass as the tesseroids.\n\n");
printf("Along with each prism are given the spherical coordinates of the\n");
printf("center of the top face of the tesseroid (used as the origin of\n");
printf("the prisms coordinate system). This is needed to compute the.\n");
printf("effect of the prisms in spherical coordinates.\n\n");
printf("If option --flatten is used, the tesseroids are converted by\n");
printf("approximating 1 degree by 111.11km and no spherical coordinates\n");
printf("are given. Use this option when you want to calculate in\n");
printf("Cartesian coordinates.\n\n");
printf("In both cases, the density of the prism is adjusted so that it\n");
printf("has the same mass as the tesseroid.\n\n");
printf("All units either SI or degrees!\n\n");
printf("Input:\n");
printf(" If TESSFILE is omited, will read from standard input (stdin)\n");
printf(" TESSFILE: File containing the tesseroid model\n");
printf(" * Each tesseroid is specified by the values of its borders\n");
printf(" and density\n");
printf(" * The file should contain one tesseroid per line\n");
printf(" * Each line should have the following column format:\n");
printf(" West East South North Top Bottom Density\n");
printf(" * Top and Bottom should be read as 'height to top' and \n");
printf(" 'height to bottom' from the mean Earth radius. Use negative\n");
printf(" values if bellow the surface, for example when modeling\n");
printf(" deep structures, and positive if above the surface, for\n");
printf(" example when modeling topography.\n");
printf(" * If a line starts with # it will be considered a comment\n");
printf(" and will be ignored\n\n");
printf("Output:\n");
printf(" Printed to standard output (stdout) one prism per line in the\n");
printf(" format:\n");
printf(" dx dy dz density lon lat r\n");
printf(" lon, lat, r are the spherical coordinates of the center of\n");
printf(" top face of the prism. This is used as the origin of the\n");
printf(" local coordinate system of the prism.\n");
printf(" If options --flatten is used, the output format is:\n");
printf(" x1 x2 y1 y2 z1 z2 density\n");
printf(" Comments about the provenance of the data are inserted into\n");
printf(" the top of the output.\n\n");
printf("Options:\n");
printf(" --flatten Convert the tesseroids by approximating 1 degree\n");
printf(" by 111.11 km (for compatibility with prism*\n");
printf(" programs).\n");
printf(" -h Print instructions.\n");
printf(" --version Print version and license information.\n");
printf(" -v Enable verbose printing to stderr.\n");
printf(" -lFILENAME Print log messages to file FILENAME.\n");
print_copyright();
}
/** Main */
int main(int argc, char **argv)
{
char *progname = "tess2prism";
TESS2PRISM_ARGS args;
int rc, line, converted = 0, error_exit = 0, bad_input = 0;
char buff[10000];
TESSEROID tess;
PRISM prism;
FILE *logfile = NULL, *modelfile = NULL;
time_t rawtime;
struct tm * timeinfo;
log_init(LOG_INFO);
rc = parse_tess2prism_args(argc, argv, progname, &args, &print_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_INFO);
}
/* Print standard verbose */
log_info("%s (Tesseroids project) %s", progname, tesseroids_version);
time(&rawtime);
timeinfo = localtime(&rawtime);
log_info("(local time) %s", asctime(timeinfo));
/* If an input file is not given, read from stdin. Else open the file */
if(rc == 3)
{
log_info("Reading tesseroids from stdin");
modelfile = stdin;
}
else
{
log_info("Reading tesseroids from file %s", args.inputfname);
modelfile = fopen(args.inputfname, "r");
if(modelfile == NULL)
{
log_error("failed to open file %s", args.inputfname);
log_warning("Terminating due to bad input");
log_warning("Try '%s -h' for instructions", progname);
if(args.logtofile)
fclose(logfile);
return 1;
}
}
/* Print provenance data to stdout */
printf("# Prisms converted from tesseroid model with %s %s\n", progname,
tesseroids_version);
printf("# local time: %s", asctime(timeinfo));
printf("# tesseroids file: %s\n", rc == 3 ? "stdin" : args.inputfname);
printf("# conversion type: %s\n",
args.flatten ? "equal mass|flatten" :
"equal mass|spherical coordinates");
if(args.flatten)
{
printf("# format: x1 x2 y1 y2 z1 z2 density\n");
}
else
{
printf("# format: dx dy dz density lon lat r\n");
}
/* Read the tesseroids, convert and print to stdout */
for(line = 1; !feof(modelfile); line++)
{
if(fgets(buff, 10000, modelfile) == 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;
}
/* Remove any trailing spaces or newlines */
strstrip(buff);
if(gets_tess(buff, &tess))
{
log_warning("bad/invalid tesseroid at line %d", line);
bad_input++;
continue;
}
if(args.flatten)
{
tess2prism_flatten(tess, &prism);
printf("%.15g %.15g %.15g %.15g %.15g %.15g %.15g\n",
prism.x1, prism.x2, prism.y1, prism.y2, prism.z1,
prism.z2, prism.density);
}
else
{
tess2prism(tess, &prism);
printf("%.15g %.15g %.15g %.15g %.15g %.15g %.15g\n",
prism.x2 - prism.x1, prism.y2 - prism.y1,
prism.z2 - prism.z1, prism.density,
prism.lon, prism.lat, prism.r);
}
converted++;
}
}
if(bad_input)
{
log_warning("Encountered %d bad input line(s) 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("Converted %d tesseroids", converted);
}
/* Clean up */
fclose(modelfile);
if(args.logtofile)
fclose(logfile);
return 0;
}

123
toolkits/tessdefaults.c Normal file
View File

@ -0,0 +1,123 @@
/*
Print the default values of the constants used in the calculations.
*/
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "../lib/version.h"
#include "../lib/logger.h"
#include "../lib/constants.h"
#include "../lib/glq.h"
/** Print the help message */
void print_help()
{
printf("Usage: tessdefaults [OPTIONS]\n\n");
printf("Print default values of constants used.\n\n");
printf("All units either SI or degrees!\n\n");
printf("Output:\n");
printf(" Constants are printed to standard output (stdout) in the form\n");
printf(" CONST_NAME = VALUE\n");
printf(" Lines that start with a # are treated as comments.\n\n");
printf("Options:\n");
printf(" -h Print instructions.\n");
printf(" --version Print version and license information.\n");
print_copyright();
}
/** Main */
int main(int argc, char **argv)
{
char progname[] = "tessdefaults";
int i, bad_args = 0;
char *params;
log_init(LOG_INFO);
/* 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 0;
case '-':
{
params = &argv[i][2];
if(strcmp(params, "version"))
{
log_error("invalid argument '%s'", argv[i]);
bad_args++;
}
else
{
print_version(progname);
return 0;
}
break;
}
default:
log_error("invalid argument '%s'", argv[i]);
bad_args++;
break;
}
}
else
{
log_error("invalid argument '%s'", argv[i]);
bad_args++;
}
}
/* Check if parsing went well */
if(bad_args > 0)
{
log_error("%d bad input argument(s)", bad_args);
log_warning("Terminating due to bad input");
log_warning("Try '%s -h' for instructions", progname);
return 1;
}
/* Print the constants from constants.c */
printf("# Mean Earth radius (m)\n");
printf("MEAN_EARTH_RADIUS = %.1f\n\n", MEAN_EARTH_RADIUS);
printf("# Gravitational constant (m^3 kg^-1 s^-1)\n");
printf("G = %.4g\n\n", G);
printf("# Conversion factor from SI units to Eotvos s^-2 = 10^9 Eotvos\n");
printf("SI2EOTVOS = %g\n\n", SI2EOTVOS);
printf("# Conversion factor from SI units to mGal m s^-2} = 10^5 mGal\n");
printf("SI2MGAL = %g\n\n", SI2MGAL);
printf("# Just pi\n");
printf("PI = %.31f\n\n", PI);
printf("# Minimum distance/size ratio for computations to be\n");
printf("# accurate. Used for knowing when to divide the tesseroids.\n");
printf("TESSEROID_POT_SIZE_RATIO = %g\n", TESSEROID_POT_SIZE_RATIO);
printf("TESSEROID_GX_SIZE_RATIO = %g\n", TESSEROID_GX_SIZE_RATIO);
printf("TESSEROID_GY_SIZE_RATIO = %g\n", TESSEROID_GY_SIZE_RATIO);
printf("TESSEROID_GZ_SIZE_RATIO = %g\n", TESSEROID_GZ_SIZE_RATIO);
printf("TESSEROID_GXX_SIZE_RATIO = %g\n", TESSEROID_GXX_SIZE_RATIO);
printf("TESSEROID_GXY_SIZE_RATIO = %g\n", TESSEROID_GXY_SIZE_RATIO);
printf("TESSEROID_GXZ_SIZE_RATIO = %g\n", TESSEROID_GXZ_SIZE_RATIO);
printf("TESSEROID_GYY_SIZE_RATIO = %g\n", TESSEROID_GYY_SIZE_RATIO);
printf("TESSEROID_GYZ_SIZE_RATIO = %g\n", TESSEROID_GYZ_SIZE_RATIO);
printf("TESSEROID_GZZ_SIZE_RATIO = %g\n\n", TESSEROID_GZZ_SIZE_RATIO);
/* Print the constants from glq.c */
printf("# Max iterations of the Legendre polynomial root-finder \
algorithm\n");
printf("GLQ_MAXIT = %d\n\n", GLQ_MAXIT);
printf("# Max error allowed for the Legendre polynomial root-finder \
algorithm\n");
printf("GLQ_MAXERROR = %g\n", GLQ_MAXERROR);
return 0;
}

Some files were not shown because too many files have changed in this diff Show More