Skip to content

Commit

Permalink
Added a couple of functions to for converting between decimal and deg…
Browse files Browse the repository at this point in the history
…rees, minutes and seconds coordinates.
  • Loading branch information
jonnymaserati committed Dec 20, 2023
1 parent 1b4580a commit 308751d
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 2 deletions.
56 changes: 55 additions & 1 deletion tests/test_utils.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,23 @@
import inspect
import numpy as np
from numpy.typing import NDArray
import sys

from welleng.units import ureg
from welleng.utils import annular_volume
from welleng.utils import annular_volume, decimal2dms, dms2decimal


LAT, LON = (52, 4, 43.1868), (4, 17, 19.6368)


def _generate_random_dms(n: int) -> NDArray:
"""Generates a bunch of lat, lon coordinates.
"""
deg = np.random.randint(-180, 180, n)
min = np.random.randint(0, 60, n)
sec = np.random.uniform(0, 60, n)

return np.stack((deg, min, sec), axis=-1).reshape((-1, 2, 3))


def test_annular_volume():
Expand All @@ -18,6 +33,45 @@ def test_annular_volume():
pass


def test_decimal2dms():
degrees, minutes, seconds = decimal2dms(LAT[0] + LAT[1] / 60 + LAT[2] / 3600)
assert (degrees, minutes, round(seconds, 4)) == LAT

dms = decimal2dms(np.array([
-(LAT[0] + LAT[1] / 60 + LAT[2] / 3600),
LON[0] + LON[1] / 60 + LON[2] / 3600
]))
assert np.allclose(
dms,
np.array((np.array(LAT) * np.array((-1, 1, 1)), np.array(LON)))
)


def test_deg2decimal():
decimal = dms2decimal((-LAT[0], LAT[1], LAT[2])) # check it handles westerly
assert decimal == -(LAT[0] + LAT[1] / 60 + LAT[2] / 3600)

decimals = dms2decimal((LAT, LON))
assert np.allclose(decimals, np.array((dms2decimal(LAT), dms2decimal(LON))))

decimals = dms2decimal(((LAT, LON), (LON, LAT)))
assert np.allclose(
decimals,
np.array((
(dms2decimal(LAT), dms2decimal(LON)),
(dms2decimal(LON), dms2decimal(LAT))
))
)


def test_dms2decimal2dms():
_dms = _generate_random_dms(int(1e3))
decimal = dms2decimal(_dms)
dms = decimal2dms(decimal)

assert np.allclose(_dms, dms)


def one_function_to_run_them_all():
"""
Function to gather the test functions so that they can be tested by
Expand Down
82 changes: 82 additions & 0 deletions welleng/utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from typing import Annotated, Literal, Union

import numpy as np
from numpy.exceptions import AxisError
from numpy.typing import NDArray
from scipy.spatial.transform import Rotation as R

Expand Down Expand Up @@ -686,3 +687,84 @@ def annular_volume(od: float, id: float = None, length: float = None):
annular_volume = annular_unit_volume * length

return annular_volume


@np.vectorize(signature='()->(n)')
def _decimal2dms(decimal: float) -> tuple:
minutes, seconds = divmod(abs(decimal) * 3600, 60)
_, minutes = divmod(minutes, 60)
return np.array([int(decimal), minutes, seconds])


def decimal2dms(decimal: float | tuple) -> tuple | NDArray:
"""Converts a decimal lat, lon to degrees, minutes and seconds.
Parameters
----------
decimal : float | arraylike
A decimal lat or lon or arraylike of lat, lon coordinates.
Returns
-------
dms: tuple | arraylike
A tuple or array of (degrees, minutes, seconds).
Examples
--------
If you want to convert the lat/lon coordinates for Den Haag from decimals
to degrees, minutes and seconds:
>>> LAT, LON = [52.078663000000006, 4.288788]
>>> dms = decimal2dms((LAT, LON))
>>> print(dms)
[[52. 4. 43.1868]
[ 4. 17. 19.6368]]
"""
dms = _decimal2dms(decimal)

if dms.shape == (3,):
return tuple(dms)
else:
return dms


def _dms2decimal(dms: tuple) -> float:
degrees, minutes, seconds = dms
result = abs(degrees) + minutes / 60 + seconds / 3600

if degrees == 0: # avoid divide by zero errors
return result
else:
return result * abs(degrees) / degrees


def dms2decimal(dms: tuple | NDArray) -> float | NDArray:
"""Converts a degrees, minutes and seconds lat, lon to decimals.
Parameters
----------
dms : tuple | arraylike
A tuple or arraylike of (degrees, minutes, seconds) lat and/or lon or
arraylike of lat, lon coordinates.
Returns
-------
degrees: tuple | arraylike
A tuple or array of lats and/or longs in decimals.
Examples
--------
If you want to convert the lat/lon coordinates for Den Haag from degrees,
minutes and seconds to decimals:
>>> LAT, LON = (52, 4, 43.1868), (4, 17, 19.6368)
>>> decimal = dms2decimal((LAT, LON))
>>> print(decimal)
[52.078663 4.288788]
"""
result = np.apply_along_axis(_dms2decimal, -1, np.array(dms))

if result.shape == ():
return float(result)
else:
return result
2 changes: 1 addition & 1 deletion welleng/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '0.7.6'
__version__ = '0.7.7'

0 comments on commit 308751d

Please sign in to comment.