diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..d7d6d58 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,24 @@ +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.3.0 + hooks: + - id: trailing-whitespace + - id: check-ast + - id: debug-statements + - id: check-added-large-files + - id: requirements-txt-fixer + - id: file-contents-sorter + +- repo: https://gitlab.com/pycqa/flake8 + rev: 3.9.2 + hooks: + - id: flake8 + +- repo: https://github.com/codespell-project/codespell + rev: v2.1.0 + hooks: + - id: codespell + exclude: > + (?x)^( + .*\.yaml + )$ diff --git a/pygc/__init__.py b/pygc/__init__.py index f4411cd..b959b8c 100644 --- a/pygc/__init__.py +++ b/pygc/__init__.py @@ -1,6 +1,8 @@ from pygc.gc import great_circle from pygc.gc import great_distance +__all__ = ["great_circle", "great_distance"] + try: from ._version import __version__ except ImportError: diff --git a/pygc/gc.py b/pygc/gc.py index 2f149c9..5a110b4 100644 --- a/pygc/gc.py +++ b/pygc/gc.py @@ -182,8 +182,13 @@ def vinc_dist(f, a, phi1, lembda1, phi2, lembda2): # Iterate the following equations, # until there is no significant change in lembda + max_loop = 100 + count_loop = 0 while (last_lembda < -3000000.0 or lembda != 0 and np.absolute((last_lembda - lembda) / lembda) > 1.0e-9): - + if count_loop > max_loop: + print("max loop reached, break") + break + count_loop += 1 sqr_sin_sigma = np.power( np.cos(U2) * np.sin(lembda), 2) + \ np.power((np.cos(U1) * np.sin(U2) - np.sin(U1) * np.cos(U2) * np.cos(lembda)), 2) diff --git a/pygc/tests/test_gc.py b/pygc/tests/test_gc.py index 3796d57..d560768 100644 --- a/pygc/tests/test_gc.py +++ b/pygc/tests/test_gc.py @@ -1,68 +1,87 @@ -import unittest import numpy as np + from pygc import great_circle -class GreatCircleTest(unittest.TestCase): +def test_great_circle_scalars(): + # One decimal degree is 111000m + latitude = 40.0 + longitude = -76.0 - def test_great_circle_scalars(self): - # One decimal degree is 111000m - latitude = 40.0 - longitude = -76.0 + azimuth = 90 + new_gc = great_circle( + distance=111000, azimuth=azimuth, latitude=latitude, longitude=longitude + ) + # We should have gone to the right + assert new_gc["longitude"] > longitude + 0.9 - azimuth = 90 - new_gc = great_circle(distance=111000, azimuth=azimuth, latitude=latitude, longitude=longitude) - # We should have gone to the right - assert new_gc["longitude"] > longitude + 0.9 + azimuth = 270 + new_gc = great_circle( + distance=111000, azimuth=azimuth, latitude=latitude, longitude=longitude + ) + # We should have gone to the left + assert new_gc["longitude"] < longitude - 0.9 - azimuth = 270 - new_gc = great_circle(distance=111000, azimuth=azimuth, latitude=latitude, longitude=longitude) - # We should have gone to the left - assert new_gc["longitude"] < longitude - 0.9 + azimuth = 180 + new_gc = great_circle( + distance=111000, azimuth=azimuth, latitude=latitude, longitude=longitude + ) + # We should have gone down + assert new_gc["latitude"] < latitude - 0.9 - azimuth = 180 - new_gc = great_circle(distance=111000, azimuth=azimuth, latitude=latitude, longitude=longitude) - # We should have gone down - assert new_gc["latitude"] < latitude - 0.9 + azimuth = 0 + new_gc = great_circle( + distance=111000, azimuth=azimuth, latitude=latitude, longitude=longitude + ) + # We should have gone up + assert new_gc["latitude"] > latitude + 0.9 - azimuth = 0 - new_gc = great_circle(distance=111000, azimuth=azimuth, latitude=latitude, longitude=longitude) - # We should have gone up - assert new_gc["latitude"] > latitude + 0.9 + azimuth = 315 + new_gc = great_circle( + distance=111000, azimuth=azimuth, latitude=latitude, longitude=longitude + ) + # We should have gone up and to the left + assert new_gc["latitude"] > latitude + 0.45 + assert new_gc["longitude"] < longitude - 0.45 - azimuth = 315 - new_gc = great_circle(distance=111000, azimuth=azimuth, latitude=latitude, longitude=longitude) - # We should have gone up and to the left - assert new_gc["latitude"] > latitude + 0.45 - assert new_gc["longitude"] < longitude - 0.45 - def test_great_circle_numpy(self): - # One decimal degree is 111000m - latitude = np.asarray([40.0, 50.0, 60.0]) - longitude = np.asarray([-76.0, -86.0, -96.0]) +def test_great_circle_numpy(): + # One decimal degree is 111000m + latitude = np.asarray([40.0, 50.0, 60.0]) + longitude = np.asarray([-76.0, -86.0, -96.0]) - azimuth = 90 - new_gc = great_circle(distance=111000, azimuth=azimuth, latitude=latitude, longitude=longitude) - # We should have gone to the right - assert (new_gc["longitude"] > longitude + 0.9).all() + azimuth = 90 + new_gc = great_circle( + distance=111000, azimuth=azimuth, latitude=latitude, longitude=longitude + ) + # We should have gone to the right + assert (new_gc["longitude"] > longitude + 0.9).all() - azimuth = 270 - new_gc = great_circle(distance=111000, azimuth=azimuth, latitude=latitude, longitude=longitude) - # We should have gone to the left - assert (new_gc["longitude"] < longitude - 0.9).all() + azimuth = 270 + new_gc = great_circle( + distance=111000, azimuth=azimuth, latitude=latitude, longitude=longitude + ) + # We should have gone to the left + assert (new_gc["longitude"] < longitude - 0.9).all() - azimuth = 180 - new_gc = great_circle(distance=111000, azimuth=azimuth, latitude=latitude, longitude=longitude) - # We should have gone down - assert (new_gc["latitude"] < latitude - 0.9).all() + azimuth = 180 + new_gc = great_circle( + distance=111000, azimuth=azimuth, latitude=latitude, longitude=longitude + ) + # We should have gone down + assert (new_gc["latitude"] < latitude - 0.9).all() - azimuth = 0 - new_gc = great_circle(distance=111000, azimuth=azimuth, latitude=latitude, longitude=longitude) - # We should have gone up - assert (new_gc["latitude"] > latitude + 0.9).all() + azimuth = 0 + new_gc = great_circle( + distance=111000, azimuth=azimuth, latitude=latitude, longitude=longitude + ) + # We should have gone up + assert (new_gc["latitude"] > latitude + 0.9).all() - azimuth = 315 - new_gc = great_circle(distance=111000, azimuth=azimuth, latitude=latitude, longitude=longitude) - # We should have gone up and to the left - assert (new_gc["latitude"] > latitude + 0.45).all() - assert (new_gc["longitude"] < longitude - 0.45).all() + azimuth = 315 + new_gc = great_circle( + distance=111000, azimuth=azimuth, latitude=latitude, longitude=longitude + ) + # We should have gone up and to the left + assert (new_gc["latitude"] > latitude + 0.45).all() + assert (new_gc["longitude"] < longitude - 0.45).all() diff --git a/pygc/tests/test_gd.py b/pygc/tests/test_gd.py index 0297fb8..5e2bfa4 100644 --- a/pygc/tests/test_gd.py +++ b/pygc/tests/test_gd.py @@ -1,106 +1,183 @@ -import os -import unittest +from pathlib import Path + import numpy as np +import pytest + from pygc import great_distance +test_path = Path(__file__).parent.absolute() + + +def test_great_distance_scalars(): + # One decimal degree at the equator is about 111.32km + latitude_start = 0.0 + latitude_end = 0.0 + longitude_start = 50.0 + longitude_end = 52.0 + gd = great_distance( + start_latitude=latitude_start, + start_longitude=longitude_start, + end_latitude=latitude_end, + end_longitude=longitude_end, + ) + assert np.round(gd["distance"] / 1000, 2) == 111.32 * 2 + + # One decimal degree is 111000m + latitude_start = 0.0 + latitude_end = 0.0 + longitude_start = [49.0, 75.0] + longitude_end = [50.0, 76.0] + gd = great_distance( + start_latitude=latitude_start, + start_longitude=longitude_start, + end_latitude=latitude_end, + end_longitude=longitude_end, + ) + assert np.allclose(gd["distance"] / 1000, 111.32) + + latitude_start = np.nan + latitude_end = np.nan + longitude_start = np.nan + longitude_end = np.nan + gd = great_distance( + start_latitude=latitude_start, + start_longitude=longitude_start, + end_latitude=latitude_end, + end_longitude=longitude_end, + ) + assert np.isnan(gd["distance"]) + + +def test_great_distance_numpy(): + latitude_start = np.asarray([0.0]) + latitude_end = np.asarray([0.0]) + longitude_start = np.asarray([50.0]) + longitude_end = np.asarray([52.0]) + gd = great_distance( + start_latitude=latitude_start, + start_longitude=longitude_start, + end_latitude=latitude_end, + end_longitude=longitude_end, + ) + assert np.round(gd["distance"] / 1000, 2) == 111.32 * 2 + + latitude_start = np.asarray([0.0]) + latitude_end = np.asarray([0.0]) + longitude_start = 50.0 + longitude_end = 52.0 + gd = great_distance( + start_latitude=latitude_start, + start_longitude=longitude_start, + end_latitude=latitude_end, + end_longitude=longitude_end, + ) + assert np.round(gd["distance"] / 1000, 2) == 111.32 * 2 + + +def test_great_distance_masked_numpy(): + with pytest.raises(ValueError): + latitude_start = np.ma.asarray([0.0]) + latitude_end = 0.0 + longitude_start = 50.0 + longitude_end = 52.0 + great_distance( + start_latitude=latitude_start, + start_longitude=longitude_start, + end_latitude=latitude_end, + end_longitude=longitude_end, + ) + + latitude_start = np.ma.asarray([0.0]) + latitude_end = np.ma.asarray([0.0]) + longitude_start = np.ma.asarray([50.0]) + longitude_end = np.ma.asarray([52.0]) + gd = great_distance( + start_latitude=latitude_start, + start_longitude=longitude_start, + end_latitude=latitude_end, + end_longitude=longitude_end, + ) + assert np.round(gd["distance"] / 1000, 2) == 111.32 * 2 + + xmask = np.load(test_path.joinpath("xmask.npy")) + ymask = np.load(test_path.joinpath("ymask.npy")) + xdata = np.load(test_path.joinpath("x.npy")) + x = np.ma.fix_invalid(xdata, mask=xmask) + ydata = np.load(test_path.joinpath("y.npy")) + y = np.ma.fix_invalid(ydata, mask=ymask) + gd = great_distance( + start_latitude=y[0:-1], + start_longitude=x[0:-1], + end_latitude=y[1:], + end_longitude=x[1:], + ) + + latitude_start = np.ma.MaskedArray(np.ma.asarray([0.0]), mask=[1]) + latitude_end = np.ma.MaskedArray(np.ma.asarray([0.0]), mask=[1]) + longitude_start = np.ma.MaskedArray(np.ma.asarray([50.0]), mask=[1]) + longitude_end = np.ma.MaskedArray(np.ma.asarray([52.0]), mask=[1]) + gd = great_distance( + start_latitude=latitude_start, + start_longitude=longitude_start, + end_latitude=latitude_end, + end_longitude=longitude_end, + ) + assert np.all(gd["distance"].mask == True) # noqa + assert np.all(gd["azimuth"].mask == True) # noqa + assert np.all(gd["reverse_azimuth"].mask == True) # noqa + + latitude_start = np.ma.MaskedArray(np.ma.asarray([0.0, 1.0]), mask=[1, 0]) + latitude_end = np.ma.MaskedArray(np.ma.asarray([0.0, 1.0]), mask=[1, 0]) + longitude_start = np.ma.MaskedArray(np.ma.asarray([49.0, 75.0]), mask=[1, 0]) + longitude_end = np.ma.MaskedArray(np.ma.asarray([50.0, 76.0]), mask=[1, 0]) + gd = great_distance( + start_latitude=latitude_start, + start_longitude=longitude_start, + end_latitude=latitude_end, + end_longitude=longitude_end, + ) + assert gd["distance"].mask.tolist() == [True, False] + assert gd["azimuth"].mask.tolist() == [True, False] + assert gd["reverse_azimuth"].mask.tolist() == [True, False] + + latitude_start = np.ma.MaskedArray(np.ma.asarray([0.0, 1.0]), mask=[1, 1]) + latitude_end = np.ma.MaskedArray(np.ma.asarray([0.0, 1.0]), mask=[1, 1]) + longitude_start = np.ma.MaskedArray(np.ma.asarray([49.0, 75.0]), mask=[1, 1]) + longitude_end = np.ma.MaskedArray(np.ma.asarray([50.0, 76.0]), mask=[1, 1]) + gd = great_distance( + start_latitude=latitude_start, + start_longitude=longitude_start, + end_latitude=latitude_end, + end_longitude=longitude_end, + ) + assert gd["distance"].mask.tolist() == [True, True] + assert gd["azimuth"].mask.tolist() == [True, True] + assert gd["reverse_azimuth"].mask.tolist() == [True, True] + + +def test_great_distance_empty_numpy(): + latitude_start = np.ma.asarray([]) + latitude_end = np.ma.asarray([]) + longitude_start = np.ma.asarray([]) + longitude_end = np.ma.asarray([]) + gd = great_distance( + start_latitude=latitude_start, + start_longitude=longitude_start, + end_latitude=latitude_end, + end_longitude=longitude_end, + ) + assert np.all(gd["distance"].mask == True) # noqa + assert np.all(gd["azimuth"].mask == True) # noqa + assert np.all(gd["reverse_azimuth"].mask == True) # noqa + + +def test_great_distance_infinite_loop(): + gd = great_distance( + start_latitude=52.11, + start_longitude=312.44, + end_latitude=-52.31, + end_longitude=132.54, + ) -class GreatDistanceTest(unittest.TestCase): - - def test_great_distance_scalars(self): - # One decimal degree at the equator is about 111.32km - latitude_start = 0. - latitude_end = 0. - longitude_start = 50. - longitude_end = 52. - gd = great_distance(start_latitude=latitude_start, start_longitude=longitude_start, end_latitude=latitude_end, end_longitude=longitude_end) - assert np.round(gd['distance'] / 1000, 2) == 111.32 * 2 - - # One decimal degree is 111000m - latitude_start = 0. - latitude_end = 0. - longitude_start = [49., 75.] - longitude_end = [50., 76.] - gd = great_distance(start_latitude=latitude_start, start_longitude=longitude_start, end_latitude=latitude_end, end_longitude=longitude_end) - assert np.allclose(gd["distance"] / 1000, 111.32) - - latitude_start = np.nan - latitude_end = np.nan - longitude_start = np.nan - longitude_end = np.nan - gd = great_distance(start_latitude=latitude_start, start_longitude=longitude_start, end_latitude=latitude_end, end_longitude=longitude_end) - assert np.isnan(gd['distance']) - - def test_great_distance_numpy(self): - latitude_start = np.asarray([0.]) - latitude_end = np.asarray([0.]) - longitude_start = np.asarray([50.]) - longitude_end = np.asarray([52.]) - gd = great_distance(start_latitude=latitude_start, start_longitude=longitude_start, end_latitude=latitude_end, end_longitude=longitude_end) - assert np.round(gd['distance'] / 1000, 2) == 111.32 * 2 - - latitude_start = np.asarray([0.]) - latitude_end = np.asarray([0.]) - longitude_start = 50. - longitude_end = 52. - gd = great_distance(start_latitude=latitude_start, start_longitude=longitude_start, end_latitude=latitude_end, end_longitude=longitude_end) - assert np.round(gd['distance'] / 1000, 2) == 111.32 * 2 - - def test_great_distance_masked_numpy(self): - with self.assertRaises(ValueError): - latitude_start = np.ma.asarray([0.]) - latitude_end = 0. - longitude_start = 50. - longitude_end = 52. - great_distance(start_latitude=latitude_start, start_longitude=longitude_start, end_latitude=latitude_end, end_longitude=longitude_end) - - latitude_start = np.ma.asarray([0.]) - latitude_end = np.ma.asarray([0.]) - longitude_start = np.ma.asarray([50.]) - longitude_end = np.ma.asarray([52.]) - gd = great_distance(start_latitude=latitude_start, start_longitude=longitude_start, end_latitude=latitude_end, end_longitude=longitude_end) - assert np.round(gd['distance'] / 1000, 2) == 111.32 * 2 - - xmask = np.load(os.path.join(os.path.dirname(__file__), 'xmask.npy')) - ymask = np.load(os.path.join(os.path.dirname(__file__), 'ymask.npy')) - xdata = np.load(os.path.join(os.path.dirname(__file__), 'x.npy')) - x = np.ma.fix_invalid(xdata, mask=xmask) - ydata = np.load(os.path.join(os.path.dirname(__file__), 'y.npy')) - y = np.ma.fix_invalid(ydata, mask=ymask) - gd = great_distance(start_latitude=y[0:-1], start_longitude=x[0:-1], end_latitude=y[1:], end_longitude=x[1:]) - - latitude_start = np.ma.MaskedArray(np.ma.asarray([0.]), mask=[1]) - latitude_end = np.ma.MaskedArray(np.ma.asarray([0.]), mask=[1]) - longitude_start = np.ma.MaskedArray(np.ma.asarray([50.]), mask=[1]) - longitude_end = np.ma.MaskedArray(np.ma.asarray([52.]), mask=[1]) - gd = great_distance(start_latitude=latitude_start, start_longitude=longitude_start, end_latitude=latitude_end, end_longitude=longitude_end) - assert np.all(gd['distance'].mask == True) # noqa - assert np.all(gd['azimuth'].mask == True) # noqa - assert np.all(gd['reverse_azimuth'].mask == True) # noqa - - latitude_start = np.ma.MaskedArray(np.ma.asarray([0., 1.]), mask=[1, 0]) - latitude_end = np.ma.MaskedArray(np.ma.asarray([0., 1.]), mask=[1, 0]) - longitude_start = np.ma.MaskedArray(np.ma.asarray([49., 75.]), mask=[1, 0]) - longitude_end = np.ma.MaskedArray(np.ma.asarray([50., 76.]), mask=[1, 0]) - gd = great_distance(start_latitude=latitude_start, start_longitude=longitude_start, end_latitude=latitude_end, end_longitude=longitude_end) - assert gd['distance'].mask.tolist() == [True, False] - assert gd['azimuth'].mask.tolist() == [True, False] - assert gd['reverse_azimuth'].mask.tolist() == [True, False] - - latitude_start = np.ma.MaskedArray(np.ma.asarray([0., 1.]), mask=[1, 1]) - latitude_end = np.ma.MaskedArray(np.ma.asarray([0., 1.]), mask=[1, 1]) - longitude_start = np.ma.MaskedArray(np.ma.asarray([49., 75.]), mask=[1, 1]) - longitude_end = np.ma.MaskedArray(np.ma.asarray([50., 76.]), mask=[1, 1]) - gd = great_distance(start_latitude=latitude_start, start_longitude=longitude_start, end_latitude=latitude_end, end_longitude=longitude_end) - assert gd['distance'].mask.tolist() == [True, True] - assert gd['azimuth'].mask.tolist() == [True, True] - assert gd['reverse_azimuth'].mask.tolist() == [True, True] - - def test_great_distance_empty_numpy(self): - latitude_start = np.ma.asarray([]) - latitude_end = np.ma.asarray([]) - longitude_start = np.ma.asarray([]) - longitude_end = np.ma.asarray([]) - gd = great_distance(start_latitude=latitude_start, start_longitude=longitude_start, end_latitude=latitude_end, end_longitude=longitude_end) - assert np.all(gd['distance'].mask == True) # noqa - assert np.all(gd['azimuth'].mask == True) # noqa - assert np.all(gd['reverse_azimuth'].mask == True) # noqa + expected = 19973984.51165855 + np.testing.assert_array_almost_equal(gd["distance"], expected, decimal=6) diff --git a/setup.cfg b/setup.cfg index da4a8c7..0e62f4c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -36,4 +36,26 @@ formats = gztar [check-manifest] ignore = *.yml - .coveragerc + +[tool:pytest] +addopts = -s -rxs -v +flake8-max-line-length = 100 +flake8-ignore = + *.py E265 E501 E221 E203 E201 E124 E202 E241 E251 W293 W291 W504 + +[flake8] +max-line-length = 100 +per-file-ignores = + *.py: E265 E501 E221 E203 E201 E124 E202 E241 E251 W293 W291 W504 + +[tool:isort] +line_length=100 +indent=' ' +balanced_wrapping=1 +multi_line_output=3 +default_section=FIRSTPARTY +use_parentheses=1 +reverse_relative=1 +length_sort=1 +combine_star=1 +order_by_type=0 diff --git a/setup.py b/setup.py index 052ec8b..b9d89bf 100644 --- a/setup.py +++ b/setup.py @@ -7,4 +7,4 @@ "write_to_template": '__version__ = "{version}"', "tag_regex": r"^(?Pv)?(?P[^\+]+)(?P.*)?$", }, -) \ No newline at end of file +)