Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Forward modelling for point masses in Cartesian coordiantes #71

Merged
merged 24 commits into from
Jul 24, 2019
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
84b86bb
Extend point_mass_gravity to Cartesian coordinates
santisoler Jul 17, 2019
35e6d47
Add missing use_numba mark to Cartesian test funcs
santisoler Jul 17, 2019
df02c8c
Add double ` where needed
santisoler Jul 18, 2019
858ebed
Merge branch 'master' into point-mass-cartesian
santisoler Jul 18, 2019
e6ee2ce
Add gallery example for point_mass_gravity
santisoler Jul 18, 2019
ee4d1e6
Replace vertical for downward acceleration in docs
santisoler Jul 18, 2019
2a1de8c
Put masses at different depths on example
santisoler Jul 18, 2019
221466b
Fix typo
santisoler Jul 19, 2019
a316cc6
Remove "besides" from point mass example
santisoler Jul 19, 2019
a571884
Simplify point mass example title
santisoler Jul 19, 2019
50dbbd4
Fix typo
santisoler Jul 19, 2019
29003c7
Extend docstring of point_mass_gravity
santisoler Jul 19, 2019
6847a49
Split long line from docstring in two
santisoler Jul 19, 2019
bd7e145
Change direction of z to downwards
santisoler Jul 19, 2019
d002888
Merge branch 'master' into point-mass-cartesian
santisoler Jul 22, 2019
f3f51b2
Rename vertical to down and add warning
santisoler Jul 22, 2019
2fe98e3
Run black
santisoler Jul 22, 2019
c99564a
Replace vertical for down in example and tests
santisoler Jul 22, 2019
6d3850e
Merge branch 'master' into point-mass-cartesian
santisoler Jul 23, 2019
95fc562
Change title of point mass gallery example
santisoler Jul 24, 2019
bbbf611
Add note to explain the negative mass
santisoler Jul 24, 2019
39c8b71
Add remainder that z points down
santisoler Jul 24, 2019
6ccd381
Add definition of gravitational constant G
santisoler Jul 24, 2019
a73b3fd
Minor change on point mass docstring warning
santisoler Jul 24, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 130 additions & 31 deletions harmonica/forward/point_mass.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,46 @@
from ..constants import GRAVITATIONAL_CONST


def point_mass_gravity(coordinates, points, masses, field, dtype="float64"):
def point_mass_gravity(
coordinates, points, masses, field, coordinate_system="cartesian", dtype="float64"
):
"""
Compute gravitational fields of a point mass on spherical coordinates.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to elaborate a bit more on the docstring (citation, definitions, equations [?]).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, absolutely! I tend to forget to do it because I know where I'm getting the equations from, but I really appreciate finding math on the docstrings when I try to use a new library or function.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added some math and references. I think we must make clearer that the third coordinate in Cartesian system is pointing downwards.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The warning mentioned above should be enough for making it very clear.


Parameters
----------
coordinates : list or array
List or array containing `longitude`, `latitude` and `radius` of computation
points defined on a spherical geocentric coordinate system.
List or array containing the coordinates of computation points in the following
order: `easting`, `northing` and `vertical` (if coordinates given in Cartesian
coordiantes), or `longitude`, `latitude` and `radius` (if given on a spherical
geocentric coordinate system).
All `easting`, `northing` and `vertical` should be in meters.
santisoler marked this conversation as resolved.
Show resolved Hide resolved
Both `longitude` and `latitude` should be in degrees and `radius` in meters.
points : list or array
List or array containing the coordinates of the point masses `longitude_p`,
`latitude_p`, `radius_p` defined on a spherical geocentric coordinate system.
Both `longitude_p` and `latitude_p` should be in degrees and `radius` in meters.
List or array containing the coordinates of the point masses in the following
order: `easting`, `northing` and `vertical` (if coordinates given in Cartesian
coordiantes), or `longitude`, `latitude` and `radius` (if given on a spherical
geocentric coordinate system).
All `easting`, `northing` and `vertical` should be in meters.
Both `longitude` and `latitude` should be in degrees and `radius` in meters.
masses : list or array
List or array containing the mass of each point mass in kg.
field : str
Gravitational field that wants to be computed.
The available fields are:
The available fields in Cartesian coordinates are:

- Gravitational potential: ``potential``
- Vertical acceleration: ``g_z``

The available fields in spherical geocentric coordinates are:

- Gravitational potential: ``potential``
- Radial acceleration: ``g_r``

coordinate_system : str (optional)
Coordinate system of the coordinates of the computation points and the point
masses. Available coordinates systems: ``cartesian``, ``spherical``.
Default ``cartesian``.
dtype : data-type (optional)
Data type assigned to resulting gravitational field, and coordinates of point
masses and computation points. Default to ``np.float64``.
Expand All @@ -42,45 +60,126 @@ def point_mass_gravity(coordinates, points, masses, field, dtype="float64"):
The potential is given in SI units, the accelerations in mGal and the Marussi
tensor components in Eotvos.
"""
kernels = {"potential": kernel_potential, "g_r": kernel_g_r}
if field not in kernels:
# Organize dispatchers and kernel functions inside dictionaries
dispatchers = {
"cartesian": jit_point_mass_cartesian,
"spherical": jit_point_mass_spherical,
}
kernels = {
"cartesian": {"potential": kernel_potential_cartesian, "g_z": kernel_g_z},
"spherical": {"potential": kernel_potential_spherical, "g_r": kernel_g_r},
}
# Sanity checks for coordinate_system and field
if coordinate_system not in ("cartesian", "spherical"):
raise ValueError(
"Coordinate system {} not recognized".format(coordinate_system)
)
if field not in kernels[coordinate_system]:
raise ValueError("Gravity field {} not recognized".format(field))
# Figure out the shape and size of the output array
cast = np.broadcast(*coordinates[:3])
result = np.zeros(cast.size, dtype=dtype)
# Prepare arrays to be passed to the jitted functions
longitude, latitude, radius = (
np.atleast_1d(i).ravel().astype(dtype) for i in coordinates[:3]
)
longitude_p, latitude_p, radius_p = (
np.atleast_1d(i).ravel().astype(dtype) for i in points[:3]
)
coordinates = (np.atleast_1d(i).ravel().astype(dtype) for i in coordinates[:3])
points = (np.atleast_1d(i).ravel().astype(dtype) for i in points[:3])
masses = np.atleast_1d(masses).astype(dtype).ravel()
# Compute gravitational field
jit_point_mass_gravity(
longitude,
latitude,
radius,
longitude_p,
latitude_p,
radius_p,
masses,
result,
kernels[field],
dispatchers[coordinate_system](
*coordinates, *points, masses, result, kernels[coordinate_system][field]
)
result *= GRAVITATIONAL_CONST
# Convert to more convenient units
if field == "g_r":
if field in ("g_r", "g_z"):
result *= 1e5 # SI to mGal
return result.reshape(cast.shape)


@jit(nopython=True)
def jit_point_mass_gravity(
def jit_point_mass_cartesian(
easting, northing, vertical, easting_p, northing_p, vertical_p, masses, out, kernel
): # pylint: disable=invalid-name
"""
Compute gravity field of point masses on computation points in Cartesian coordinates

Parameters
----------
easting, northing, vertical : 1d-arrays
Coordinates of computation points in Cartesian coordinate system.
easting_p, northing_p, vertical_p : 1d-arrays
Coordinates of point masses in Cartesian coordinate system.
masses : 1d-array
Mass of each point mass in SI units.
out : 1d-array
Array where the gravitational field on each computation point will be appended.
It must have the same size of ``easting``, ``northing`` and ``vertical``.
kernel : func
Kernel function that will be used to compute the gravity field on the
computation points.
"""
for l in range(easting.size):
for m in range(easting_p.size):
out[l] += masses[m] * kernel(
easting[l],
northing[l],
vertical[l],
easting_p[m],
northing_p[m],
vertical_p[m],
)


@jit(nopython=True)
def kernel_potential_cartesian(
easting, northing, vertical, easting_p, northing_p, vertical_p
):
"""
Kernel function for potential gravity field in Cartesian coordinates
"""
return 1 / _distance_cartesian(
[easting, northing, vertical], [easting_p, northing_p, vertical_p]
)


@jit(nopython=True)
def kernel_g_z(easting, northing, vertical, easting_p, northing_p, vertical_p):
"""
Kernel function for downward component of gravity gradient in Cartesian coordinates
"""
distance_sq = _distance_cartesian_sq(
[easting, northing, vertical], [easting_p, northing_p, vertical_p]
)
return (vertical - vertical_p) / distance_sq ** (3 / 2)


@jit(nopython=True)
def _distance_cartesian_sq(point_a, point_b):
"""
Calculate the square distance between two points given in Cartesian coordinates
"""
easting, northing, vertical = point_a[:]
easting_p, northing_p, vertical_p = point_b[:]
distance_sq = (
(easting - easting_p) ** 2
+ (northing - northing_p) ** 2
+ (vertical - vertical_p) ** 2
)
return distance_sq


@jit(nopython=True)
def _distance_cartesian(point_a, point_b):
"""
Calculate the distance between two points given in Cartesian coordinates
"""
return np.sqrt(_distance_cartesian_sq(point_a, point_b))


@jit(nopython=True)
def jit_point_mass_spherical(
longitude, latitude, radius, longitude_p, latitude_p, radius_p, masses, out, kernel
): # pylint: disable=invalid-name
"""
Compute gravity field of point masses on computation points.
Compute gravity field of point masses on computation points in spherical coordiantes

Parameters
----------
Expand Down Expand Up @@ -123,11 +222,11 @@ def jit_point_mass_gravity(


@jit(nopython=True)
def kernel_potential(
def kernel_potential_spherical(
longitude, cosphi, sinphi, radius, longitude_p, cosphi_p, sinphi_p, radius_p
):
"""
Kernel function for potential gravity field
Kernel function for potential gravity field in spherical coordinates
"""
coslambda = np.cos(longitude_p - longitude)
cospsi = sinphi_p * sinphi + cosphi_p * cosphi * coslambda
Expand All @@ -140,7 +239,7 @@ def kernel_g_r(
longitude, cosphi, sinphi, radius, longitude_p, cosphi_p, sinphi_p, radius_p
):
"""
Kernel function for radial component of gravity gradient
Kernel function for radial component of gravity gradient in spherical coordinates
"""
coslambda = np.cos(longitude_p - longitude)
cospsi = sinphi_p * sinphi + cosphi_p * cosphi * coslambda
Expand Down
6 changes: 3 additions & 3 deletions harmonica/forward/tesseroid.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from numpy.polynomial.legendre import leggauss

from ..constants import GRAVITATIONAL_CONST
from .point_mass import jit_point_mass_gravity, kernel_potential, kernel_g_r
from .point_mass import jit_point_mass_spherical, kernel_potential_spherical, kernel_g_r

STACK_SIZE = 100
MAX_DISCRETIZATIONS = 100000
Expand Down Expand Up @@ -110,7 +110,7 @@ def tesseroid_gravity(
array(-112.54539933)

"""
kernels = {"potential": kernel_potential, "g_r": kernel_g_r}
kernels = {"potential": kernel_potential_spherical, "g_r": kernel_g_r}
if field not in kernels:
raise ValueError("Gravity field {} not recognized".format(field))
# Figure out the shape and size of the output array
Expand Down Expand Up @@ -258,7 +258,7 @@ def jit_tesseroid_gravity(
weights,
)
# Compute gravity fields
jit_point_mass_gravity(
jit_point_mass_spherical(
computation_point[0:1],
computation_point[1:2],
computation_point[2:3],
Expand Down
Loading