initial upload
4
.gitignore
vendored
@ -50,3 +50,7 @@ modules.order
|
||||
Module.symvers
|
||||
Mkfile.old
|
||||
dkms.conf
|
||||
|
||||
build/
|
||||
.vscode/
|
||||
.DS_Store
|
70
CITATION.txt
Executable 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
@ -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
@ -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
@ -0,0 +1,210 @@
|
||||
# 
|
||||
|
||||
[Documentation](http://tesseroids.leouieda.com) |
|
||||
[Download](https://github.com/leouieda/tesseroids/releases)
|
||||
|
||||
[](https://github.com/leouieda/tesseroids/releases)
|
||||
[](https://travis-ci.org/leouieda/tesseroids)
|
||||
[](https://github.com/leouieda/tesseroids/blob/master/LICENSE.txt)
|
||||
[](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.
|
||||
|
||||
[](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`.
|
10
cookbook/custom_ratio/custom_ratio.bat
Executable 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
|
11
cookbook/custom_ratio/custom_ratio.sh
Executable 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
|
2
cookbook/custom_ratio/model.txt
Executable 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
@ -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
22
cookbook/dem_brasil/dem_brasil.bat
Executable 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
|
22
cookbook/dem_brasil/dem_brasil.sh
Executable 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
|
13
cookbook/dem_brasil/dem_density.py
Executable 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
@ -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')
|
BIN
cookbook/dem_brasil/sample-dem-dens.png
Executable file
After Width: | Height: | Size: 150 KiB |
22801
cookbook/dem_brasil/sample-dem-dens.txt
Executable file
BIN
cookbook/dem_brasil/sample-dem-ggt.png
Executable file
After Width: | Height: | Size: 372 KiB |
22806
cookbook/dem_brasil/sample-dem-tess.txt
Executable file
BIN
cookbook/dem_brasil/sample-dem.png
Executable file
After Width: | Height: | Size: 260 KiB |
3
cookbook/simple_prism/model.txt
Executable 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
@ -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))
|
11
cookbook/simple_prism/simple_prism.bat
Executable 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
|
BIN
cookbook/simple_prism/simple_prism.png
Executable file
After Width: | Height: | Size: 585 KiB |
11
cookbook/simple_prism/simple_prism.sh
Executable 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
@ -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
@ -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')
|
12
cookbook/simple_tess/simple_tess.bat
Executable 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
|
BIN
cookbook/simple_tess/simple_tess.png
Executable file
After Width: | Height: | Size: 389 KiB |
14
cookbook/simple_tess/simple_tess.sh
Executable 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
@ -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
@ -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 |
11
cookbook/tess2prism/sample-prism-model.txt
Executable 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
|
6
cookbook/tess2prism/tess-model.txt
Executable 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
|
21
cookbook/tess2prism/tess2prism.bat
Executable 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
|
BIN
cookbook/tess2prism/tess2prism.png
Executable file
After Width: | Height: | Size: 888 KiB |
21
cookbook/tess2prism/tess2prism.sh
Executable 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
|
25
cookbook/tess2prism_flatten/plot.py
Executable 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))
|
9
cookbook/tess2prism_flatten/sample-prism-model.txt
Executable 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
|
4
cookbook/tess2prism_flatten/tess-model.txt
Executable 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
|
21
cookbook/tess2prism_flatten/tess2prism_flatten.bat
Executable 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
|
BIN
cookbook/tess2prism_flatten/tess2prism_flatten.png
Executable file
After Width: | Height: | Size: 575 KiB |
21
cookbook/tess2prism_flatten/tess2prism_flatten.sh
Executable 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
After Width: | Height: | Size: 45 KiB |
1683
cookbook/tesslayers/layers.txt
Executable file
34
cookbook/tesslayers/makelayers.py
Executable 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
@ -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))
|
1684
cookbook/tesslayers/sample-tessmodel.txt
Executable file
13
cookbook/tesslayers/tesslayers.bat
Executable 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
|
BIN
cookbook/tesslayers/tesslayers.png
Executable file
After Width: | Height: | Size: 154 KiB |
13
cookbook/tesslayers/tesslayers.sh
Executable 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
@ -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)
|
||||
|
||||
# 以下部分为库的编译
|
||||
# 注意目标名必须唯一 所以不能直接生成相同名称的动态库与静态库
|
||||
# 注意此处不必为目标名称添加lib前缀和相应后缀,cmake会自行添加
|
||||
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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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, 552–560.
|
||||
*/
|
||||
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include "geometry.h"
|
||||
#include "constants.h"
|
||||
#include "grav_prism.h"
|
||||
|
||||
double safe_atan2(double y, double x)
|
||||
{
|
||||
if(y == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if((y > 0) && (x < 0))
|
||||
{
|
||||
return atan2(y, x) - PI;
|
||||
}
|
||||
if((y < 0) && (x < 0))
|
||||
{
|
||||
return atan2(y, x) + PI;
|
||||
}
|
||||
return atan2(y, x);
|
||||
}
|
||||
|
||||
double safe_log(double x)
|
||||
{
|
||||
if(x == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return log(x);
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculates the potential cause by a prism. */
|
||||
double prism_pot(PRISM prism, double xp, double yp, double zp)
|
||||
{
|
||||
double x[2], y[2], z[2], kernel, res, r;
|
||||
register int i, j, k;
|
||||
|
||||
/* First thing to do is make P the origin of the coordinate system */
|
||||
x[0] = prism.x2 - xp;
|
||||
x[1] = prism.x1 - xp;
|
||||
y[0] = prism.y2 - yp;
|
||||
y[1] = prism.y1 - yp;
|
||||
z[0] = prism.z2 - zp;
|
||||
z[1] = prism.z1 - zp;
|
||||
|
||||
res = 0;
|
||||
|
||||
/* Evaluate the integration limits */
|
||||
for(k=0; k<=1; k++)
|
||||
{
|
||||
for(j=0; j<=1; j++)
|
||||
{
|
||||
for(i=0; i<=1; i++)
|
||||
{
|
||||
r = sqrt(x[i]*x[i] + y[j]*y[j] + z[k]*z[k]);
|
||||
kernel = (x[i]*y[j]*safe_log(z[k] + r)
|
||||
+ y[j]*z[k]*safe_log(x[i] + r)
|
||||
+ x[i]*z[k]*safe_log(y[j] + r)
|
||||
- 0.5*x[i]*x[i]*safe_atan2(z[k]*y[j], x[i]*r)
|
||||
- 0.5*y[j]*y[j]*safe_atan2(z[k]*x[i], y[j]*r)
|
||||
- 0.5*z[k]*z[k]*safe_atan2(x[i]*y[j], z[k]*r));
|
||||
res += pow(-1, i + j + k)*kernel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Now all that is left is to multiply res by the gravitational constant and
|
||||
density */
|
||||
res *= G*prism.density;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* Calculates the x component of gravitational attraction cause by a prism. */
|
||||
double prism_gx(PRISM prism, double xp, double yp, double zp)
|
||||
{
|
||||
double x[2], y[2], z[2], kernel, res, r;
|
||||
register int i, j, k;
|
||||
|
||||
/* First thing to do is make P the origin of the coordinate system */
|
||||
x[0] = prism.x2 - xp;
|
||||
x[1] = prism.x1 - xp;
|
||||
y[0] = prism.y2 - yp;
|
||||
y[1] = prism.y1 - yp;
|
||||
z[0] = prism.z2 - zp;
|
||||
z[1] = prism.z1 - zp;
|
||||
|
||||
res = 0;
|
||||
|
||||
/* Evaluate the integration limits */
|
||||
for(k=0; k<=1; k++)
|
||||
{
|
||||
for(j=0; j<=1; j++)
|
||||
{
|
||||
for(i=0; i<=1; i++)
|
||||
{
|
||||
r = sqrt(x[i]*x[i] + y[j]*y[j] + z[k]*z[k]);
|
||||
|
||||
kernel = -(y[j]*safe_log(z[k] + r) + z[k]*safe_log(y[j] + r)
|
||||
- x[i]*safe_atan2(z[k]*y[j], x[i]*r));
|
||||
|
||||
res += pow(-1, i + j + k)*kernel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Now all that is left is to multiply res by the gravitational constant and
|
||||
density and convert it to mGal units */
|
||||
res *= G*SI2MGAL*prism.density;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* Calculates the y component of gravitational attraction cause by a prism. */
|
||||
double prism_gy(PRISM prism, double xp, double yp, double zp)
|
||||
{
|
||||
double x[2], y[2], z[2], kernel, res, r;
|
||||
register int i, j, k;
|
||||
|
||||
/* First thing to do is make P the origin of the coordinate system */
|
||||
x[0] = prism.x2 - xp;
|
||||
x[1] = prism.x1 - xp;
|
||||
y[0] = prism.y2 - yp;
|
||||
y[1] = prism.y1 - yp;
|
||||
z[0] = prism.z2 - zp;
|
||||
z[1] = prism.z1 - zp;
|
||||
|
||||
res = 0;
|
||||
|
||||
/* Evaluate the integration limits */
|
||||
for(k=0; k<=1; k++)
|
||||
{
|
||||
for(j=0; j<=1; j++)
|
||||
{
|
||||
for(i=0; i<=1; i++)
|
||||
{
|
||||
r = sqrt(x[i]*x[i] + y[j]*y[j] + z[k]*z[k]);
|
||||
|
||||
kernel = -(z[k]*safe_log(x[i] + r) + x[i]*safe_log(z[k] + r)
|
||||
- y[j]*safe_atan2(z[k]*x[i], y[j]*r));
|
||||
|
||||
res += pow(-1, i + j + k)*kernel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Now all that is left is to multiply res by the gravitational constant and
|
||||
density and convert it to mGal units */
|
||||
res *= G*SI2MGAL*prism.density;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* Calculates the z component of gravitational attraction cause by a prism. */
|
||||
double prism_gz(PRISM prism, double xp, double yp, double zp)
|
||||
{
|
||||
double x[2], y[2], z[2], kernel, res, r;
|
||||
register int i, j, k;
|
||||
|
||||
/* First thing to do is make P the origin of the coordinate system */
|
||||
x[0] = prism.x2 - xp;
|
||||
x[1] = prism.x1 - xp;
|
||||
y[0] = prism.y2 - yp;
|
||||
y[1] = prism.y1 - yp;
|
||||
z[0] = prism.z2 - zp;
|
||||
z[1] = prism.z1 - zp;
|
||||
|
||||
res = 0;
|
||||
|
||||
/* Evaluate the integration limits */
|
||||
for(k=0; k<=1; k++)
|
||||
{
|
||||
for(j=0; j<=1; j++)
|
||||
{
|
||||
for(i=0; i<=1; i++)
|
||||
{
|
||||
r = sqrt(x[i]*x[i] + y[j]*y[j] + z[k]*z[k]);
|
||||
|
||||
kernel = -(x[i]*safe_log(y[j] + r) + y[j]*safe_log(x[i] + r)
|
||||
- z[k]*safe_atan2(x[i]*y[j], z[k]*r));
|
||||
|
||||
res += pow(-1, i + j + k)*kernel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Now all that is left is to multiply res by the gravitational constant and
|
||||
density and convert it to mGal units */
|
||||
res *= G*SI2MGAL*prism.density;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* Calculates the gxx gravity gradient tensor component cause by a prism. */
|
||||
double prism_gxx(PRISM prism, double xp, double yp, double zp)
|
||||
{
|
||||
double x[2], y[2], z[2], kernel, res, r;
|
||||
register int i, j, k;
|
||||
|
||||
/* First thing to do is make P the origin of the coordinate system */
|
||||
x[0] = prism.x2 - xp;
|
||||
x[1] = prism.x1 - xp;
|
||||
y[0] = prism.y2 - yp;
|
||||
y[1] = prism.y1 - yp;
|
||||
z[0] = prism.z2 - zp;
|
||||
z[1] = prism.z1 - zp;
|
||||
|
||||
res = 0;
|
||||
|
||||
/* Evaluate the integration limits */
|
||||
for(k=0; k<=1; k++)
|
||||
{
|
||||
for(j=0; j<=1; j++)
|
||||
{
|
||||
for(i=0; i<=1; i++)
|
||||
{
|
||||
r = sqrt(x[i]*x[i] + y[j]*y[j] + z[k]*z[k]);
|
||||
kernel = -safe_atan2(z[k]*y[j], x[i]*r);
|
||||
res += pow(-1, i + j + k)*kernel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Now all that is left is to multiply res by the gravitational constant and
|
||||
density and convert it to Eotvos units */
|
||||
res *= G*SI2EOTVOS*prism.density;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Calculates the gxy gravity gradient tensor component cause by a prism. */
|
||||
double prism_gxy(PRISM prism, double xp, double yp, double zp)
|
||||
{
|
||||
double x[2], y[2], z[2], kernel, res, r, xtmp, ytmp;
|
||||
register int i, j, k;
|
||||
|
||||
/* First thing to do is make P the origin of the coordinate system */
|
||||
x[0] = prism.x2 - xp;
|
||||
x[1] = prism.x1 - xp;
|
||||
y[0] = prism.y2 - yp;
|
||||
y[1] = prism.y1 - yp;
|
||||
z[0] = prism.z2 - zp;
|
||||
z[1] = prism.z1 - zp;
|
||||
|
||||
res = 0;
|
||||
|
||||
/* Evaluate the integration limits */
|
||||
for(k=0; k<=1; k++)
|
||||
{
|
||||
for(j=0; j<=1; j++)
|
||||
{
|
||||
for(i=0; i<=1; i++)
|
||||
{
|
||||
if(x[i] == 0 && y[j] == 0 && z[k] < 0)
|
||||
{
|
||||
xtmp = 0.0001*(prism.x2 - prism.x1);
|
||||
ytmp = 0.0001*(prism.y2 - prism.y1);
|
||||
r = sqrt(xtmp*xtmp + ytmp*ytmp + z[k]*z[k]);
|
||||
}
|
||||
else
|
||||
{
|
||||
r = sqrt(x[i]*x[i] + y[j]*y[j] + z[k]*z[k]);
|
||||
}
|
||||
kernel = safe_log(z[k] + r);
|
||||
res += pow(-1, i + j + k)*kernel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Now all that is left is to multiply res by the gravitational constant and
|
||||
density and convert it to Eotvos units */
|
||||
res *= G*SI2EOTVOS*prism.density;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* Calculates the gxz gravity gradient tensor component cause by a prism. */
|
||||
double prism_gxz(PRISM prism, double xp, double yp, double zp)
|
||||
{
|
||||
double x[2], y[2], z[2], kernel, res, r, xtmp, ztmp;
|
||||
register int i, j, k;
|
||||
|
||||
/* First thing to do is make P the origin of the coordinate system */
|
||||
x[0] = prism.x2 - xp;
|
||||
x[1] = prism.x1 - xp;
|
||||
y[0] = prism.y2 - yp;
|
||||
y[1] = prism.y1 - yp;
|
||||
z[0] = prism.z2 - zp;
|
||||
z[1] = prism.z1 - zp;
|
||||
|
||||
res = 0;
|
||||
|
||||
/* Evaluate the integration limits */
|
||||
for(k=0; k<=1; k++)
|
||||
{
|
||||
for(j=0; j<=1; j++)
|
||||
{
|
||||
for(i=0; i<=1; i++)
|
||||
{
|
||||
if(x[i] == 0 && z[k] == 0 && y[j] < 0)
|
||||
{
|
||||
xtmp = 0.0001*(prism.x2 - prism.x1);
|
||||
ztmp = 0.0001*(prism.z2 - prism.z1);
|
||||
r = sqrt(xtmp*xtmp + ztmp*ztmp + y[j]*y[j]);
|
||||
}
|
||||
else
|
||||
{
|
||||
r = sqrt(x[i]*x[i] + y[j]*y[j] + z[k]*z[k]);
|
||||
}
|
||||
kernel = safe_log(y[j] + r);
|
||||
res += pow(-1, i + j + k)*kernel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Now all that is left is to multiply res by the gravitational constant and
|
||||
density and convert it to Eotvos units */
|
||||
res *= G*SI2EOTVOS*prism.density;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* Calculates the gyy gravity gradient tensor component cause by a prism. */
|
||||
double prism_gyy(PRISM prism, double xp, double yp, double zp)
|
||||
{
|
||||
double x[2], y[2], z[2], kernel, res, r;
|
||||
register int i, j, k;
|
||||
|
||||
/* First thing to do is make P the origin of the coordinate system */
|
||||
x[0] = prism.x2 - xp;
|
||||
x[1] = prism.x1 - xp;
|
||||
y[0] = prism.y2 - yp;
|
||||
y[1] = prism.y1 - yp;
|
||||
z[0] = prism.z2 - zp;
|
||||
z[1] = prism.z1 - zp;
|
||||
|
||||
res = 0;
|
||||
|
||||
/* Evaluate the integration limits */
|
||||
for(k=0; k<=1; k++)
|
||||
{
|
||||
for(j=0; j<=1; j++)
|
||||
{
|
||||
for(i=0; i<=1; i++)
|
||||
{
|
||||
r = sqrt(x[i]*x[i] + y[j]*y[j] + z[k]*z[k]);
|
||||
kernel = -safe_atan2(z[k]*x[i], y[j]*r);
|
||||
res += pow(-1, i + j + k)*kernel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Now all that is left is to multiply res by the gravitational constant and
|
||||
density and convert it to Eotvos units */
|
||||
res *= G*SI2EOTVOS*prism.density;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* Calculates the gyz gravity gradient tensor component cause by a prism. */
|
||||
double prism_gyz(PRISM prism, double xp, double yp, double zp)
|
||||
{
|
||||
double x[2], y[2], z[2], kernel, res, r, ytmp, ztmp;
|
||||
register int i, j, k;
|
||||
|
||||
/* First thing to do is make P the origin of the coordinate system */
|
||||
x[0] = prism.x2 - xp;
|
||||
x[1] = prism.x1 - xp;
|
||||
y[0] = prism.y2 - yp;
|
||||
y[1] = prism.y1 - yp;
|
||||
z[0] = prism.z2 - zp;
|
||||
z[1] = prism.z1 - zp;
|
||||
|
||||
res = 0;
|
||||
|
||||
/* Evaluate the integration limits */
|
||||
for(k=0; k<=1; k++)
|
||||
{
|
||||
for(j=0; j<=1; j++)
|
||||
{
|
||||
for(i=0; i<=1; i++)
|
||||
{
|
||||
if(z[k] == 0 && y[j] == 0 && x[i] < 0)
|
||||
{
|
||||
ytmp = 0.0001*(prism.y2 - prism.y1);
|
||||
ztmp = 0.0001*(prism.z2 - prism.z1);
|
||||
r = sqrt(ztmp*ztmp + ytmp*ytmp + x[i]*x[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
r = sqrt(x[i]*x[i] + y[j]*y[j] + z[k]*z[k]);
|
||||
}
|
||||
kernel = safe_log(x[i] + r);
|
||||
res += pow(-1, i + j + k)*kernel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Now all that is left is to multiply res by the gravitational constant and
|
||||
density and convert it to Eotvos units */
|
||||
res *= G*SI2EOTVOS*prism.density;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* Calculates the gzz gravity gradient tensor component cause by a prism. */
|
||||
double prism_gzz(PRISM prism, double xp, double yp, double zp)
|
||||
{
|
||||
double x[2], y[2], z[2], kernel, res, r;
|
||||
register int i, j, k;
|
||||
|
||||
/* First thing to do is make P the origin of the coordinate system */
|
||||
x[0] = prism.x2 - xp;
|
||||
x[1] = prism.x1 - xp;
|
||||
y[0] = prism.y2 - yp;
|
||||
y[1] = prism.y1 - yp;
|
||||
z[0] = prism.z2 - zp;
|
||||
z[1] = prism.z1 - zp;
|
||||
|
||||
res = 0;
|
||||
|
||||
/* Evaluate the integration limits */
|
||||
for(k=0; k<=1; k++)
|
||||
{
|
||||
for(j=0; j<=1; j++)
|
||||
{
|
||||
for(i=0; i<=1; i++)
|
||||
{
|
||||
r = sqrt(x[i]*x[i] + y[j]*y[j] + z[k]*z[k]);
|
||||
kernel = -safe_atan2(x[i]*y[j], z[k]*r);
|
||||
res += pow(-1, i + j + k)*kernel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Now all that is left is to multiply res by the gravitational constant and
|
||||
density and convert it to Eotvos units */
|
||||
res *= G*SI2EOTVOS*prism.density;
|
||||
|
||||
return res;
|
||||
}
|
36
lib/grav_prism.h
Normal 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, 552–560.
|
||||
*/
|
||||
|
||||
|
||||
#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
@ -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, 552–560.
|
||||
*/
|
||||
|
||||
|
||||
#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
@ -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, 552–560.
|
||||
*/
|
||||
|
||||
|
||||
#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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
316
lib/parsers.h
Normal 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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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;
|
||||
}
|