From 7090e0677fbf21aa67338b00e1f9b0b4bf65383b Mon Sep 17 00:00:00 2001 From: Mathilde Leuridan Date: Thu, 12 Oct 2023 14:10:00 +0100 Subject: [PATCH 01/37] make first fdb extraction work --- polytope/datacube/backends/FDB_datacube.py | 35 +++++++++++++++------ tests/.DS_Store | Bin 8196 -> 8196 bytes tests/test_fdb_datacube.py | 12 +++---- 3 files changed, 31 insertions(+), 16 deletions(-) diff --git a/polytope/datacube/backends/FDB_datacube.py b/polytope/datacube/backends/FDB_datacube.py index 846ac840e..4343217c4 100644 --- a/polytope/datacube/backends/FDB_datacube.py +++ b/polytope/datacube/backends/FDB_datacube.py @@ -1,3 +1,4 @@ +import math from copy import deepcopy import pyfdb @@ -5,10 +6,6 @@ from .datacube import Datacube, IndexTree -def glue(path, unmap_path): - return {"t": 0} - - def update_fdb_dataarray(fdb_dataarray): fdb_dataarray["values"] = [0.0] return fdb_dataarray @@ -30,8 +27,8 @@ def __init__(self, config={}, axis_options={}): partial_request = config # Find values in the level 3 FDB datacube # Will be in the form of a dictionary? {axis_name:values_available, ...} - fdb = pyfdb.FDB() - fdb_dataarray = fdb.axes(partial_request).as_dict() + self.fdb = pyfdb.FDB() + fdb_dataarray = self.fdb.axes(partial_request).as_dict() dataarray = update_fdb_dataarray(fdb_dataarray) self.dataarray = dataarray @@ -61,10 +58,28 @@ def get(self, requests: IndexTree): axis = self._axes[key] (path, unmapped_path) = axis.unmap_total_path_to_datacube(path, unmapped_path) path = self.fit_path(path) - subxarray = glue(path, unmapped_path) - key = list(subxarray.keys())[0] - value = subxarray[key] - r.result = (key, value) + # merge path and unmapped path into a single path + path.update(unmapped_path) + + # fit request into something for pyfdb + fdb_request_val = path["values"] + path.pop("values") + fdb_request_key = path + + # TODO: should do this in the merge transformation, if it doesn't break xarray backend + fdb_request_key["date"] = fdb_request_key["date"].replace('-', '') + fdb_request_key["time"] = fdb_request_key["time"].replace(":", "") + + fdb_requests = [(fdb_request_key, [(fdb_request_val, fdb_request_val+1)])] + + # need to request data from the fdb + + subxarray = self.fdb.extract(fdb_requests) + subxarray_output_tuple = subxarray[0][0] + output_value = subxarray_output_tuple[0][0][0] + + if not math.isnan(output_value): + r.result = output_value else: r.remove_branch() diff --git a/tests/.DS_Store b/tests/.DS_Store index a3976a99336542543e657a5a6e812cda6ef38fb3..28aa9c59f3e8cfd1d76bfcb4e242dc62551a9375 100644 GIT binary patch delta 66 zcmV-I0KNZ&K!iY$PXQ0HP`eKS50eZKJCh9+3X|~=K9dU-43m2iK9hkGPLppD46{2E Y<^i*76>0&qgA9ZNvj-UW1hIJr1Fsbn%m4rY delta 356 zcmZp1XmOa}&nUhzU^hRb_+%adYvp8ye1=?x0)|9}B8E(cVjwS%A)djKAsZ+f&tM3m zCmRTfhOcK}V9@&y20#`A0}De6P)`X%qGwKia#Buy5>QNlfq_vLNF%Fb2ddFyNC%sq z#9)M~nkjv9gMjqpKmj{OfyonqtcijmtRNHSO>PkgWmE!+$+CmoR>F`mIZjAVh$$V- zc(9Vmi9!?Go(z`6Ov*A>OUtC$*2G_Q?`g9m7$QK6i5~W%_#x8Bozn|%EeiM zeq-d@EF<`rkvE Date: Thu, 12 Oct 2023 15:55:26 +0100 Subject: [PATCH 02/37] fix unmerging of date and time --- polytope/datacube/backends/FDB_datacube.py | 4 ---- polytope/datacube/backends/xarray.py | 3 +++ polytope/datacube/transformations/datacube_merger.py | 4 ++++ tests/test_merge_cyclic_octahedral.py | 6 +++--- tests/test_merge_transformation.py | 6 +++--- 5 files changed, 13 insertions(+), 10 deletions(-) diff --git a/polytope/datacube/backends/FDB_datacube.py b/polytope/datacube/backends/FDB_datacube.py index 4343217c4..2525d5057 100644 --- a/polytope/datacube/backends/FDB_datacube.py +++ b/polytope/datacube/backends/FDB_datacube.py @@ -66,10 +66,6 @@ def get(self, requests: IndexTree): path.pop("values") fdb_request_key = path - # TODO: should do this in the merge transformation, if it doesn't break xarray backend - fdb_request_key["date"] = fdb_request_key["date"].replace('-', '') - fdb_request_key["time"] = fdb_request_key["time"].replace(":", "") - fdb_requests = [(fdb_request_key, [(fdb_request_val, fdb_request_val+1)])] # need to request data from the fdb diff --git a/polytope/datacube/backends/xarray.py b/polytope/datacube/backends/xarray.py index 321f0f644..47847deba 100644 --- a/polytope/datacube/backends/xarray.py +++ b/polytope/datacube/backends/xarray.py @@ -76,6 +76,9 @@ def datacube_natural_indexes(self, axis, subarray): return indexes def select(self, path, unmapped_path): + print("now") + print(path) + print(self.dataarray) subarray = self.dataarray.sel(path, method="nearest") subarray = subarray.sel(unmapped_path) return subarray diff --git a/polytope/datacube/transformations/datacube_merger.py b/polytope/datacube/transformations/datacube_merger.py index eb404498d..e38a57d8c 100644 --- a/polytope/datacube/transformations/datacube_merger.py +++ b/polytope/datacube/transformations/datacube_merger.py @@ -44,6 +44,10 @@ def unmerge(self, merged_val): first_linker_size = len(self._linkers[0]) second_linked_size = len(self._linkers[1]) second_val = merged_val[first_idx + first_linker_size : -second_linked_size] + + # TODO: maybe replacing like this is too specific to time/dates? + first_val = str(first_val).replace('-', '') + second_val = second_val.replace(":", "") return (first_val, second_val) def change_val_type(self, axis_name, values): diff --git a/tests/test_merge_cyclic_octahedral.py b/tests/test_merge_cyclic_octahedral.py index ac5d5abc5..7f633c0be 100644 --- a/tests/test_merge_cyclic_octahedral.py +++ b/tests/test_merge_cyclic_octahedral.py @@ -15,14 +15,14 @@ def setup_method(self, method): np.random.randn(1, 1, 4289589, 3), dims=("date", "time", "values", "step"), coords={ - "date": ["2000-01-01"], - "time": ["06:00"], + "date": ["20000101"], + "time": ["0600"], "values": list(range(4289589)), "step": [0, 1, 2], }, ) self.options = { - "date": {"transformation": {"merge": {"with": "time", "linkers": ["T", ":00"]}}}, + "date": {"transformation": {"merge": {"with": "time", "linkers": ["T", "00"]}}}, "values": { "transformation": { "mapper": {"type": "octahedral", "resolution": 1280, "axes": ["latitude", "longitude"]} diff --git a/tests/test_merge_transformation.py b/tests/test_merge_transformation.py index af3b0d79c..fe15cf987 100644 --- a/tests/test_merge_transformation.py +++ b/tests/test_merge_transformation.py @@ -15,11 +15,11 @@ def setup_method(self, method): np.random.randn(1, 1), dims=("date", "time"), coords={ - "date": ["2000-01-01"], - "time": ["06:00"], + "date": ["20000101"], + "time": ["0600"], }, ) - self.options = {"date": {"transformation": {"merge": {"with": "time", "linkers": [" ", ":00"]}}}} + self.options = {"date": {"transformation": {"merge": {"with": "time", "linkers": [" ", "00"]}}}} self.xarraydatacube = XArrayDatacube(self.array) self.slicer = HullSlicer() self.API = Polytope(datacube=self.array, engine=self.slicer, axis_options=self.options) From c6385aba9f483711a9ac7524442a20cdbc261d32 Mon Sep 17 00:00:00 2001 From: Mathilde Leuridan Date: Fri, 13 Oct 2023 11:15:47 +0100 Subject: [PATCH 03/37] add regular grid mapping for fdb and test, which does not work yet --- polytope/datacube/backends/xarray.py | 3 - .../transformations/datacube_mappers.py | 44 +++++++++- tests/test_regular_grid.py | 86 +++++++++++++++++++ 3 files changed, 129 insertions(+), 4 deletions(-) create mode 100644 tests/test_regular_grid.py diff --git a/polytope/datacube/backends/xarray.py b/polytope/datacube/backends/xarray.py index 47847deba..321f0f644 100644 --- a/polytope/datacube/backends/xarray.py +++ b/polytope/datacube/backends/xarray.py @@ -76,9 +76,6 @@ def datacube_natural_indexes(self, axis, subarray): return indexes def select(self, path, unmapped_path): - print("now") - print(path) - print(self.dataarray) subarray = self.dataarray.sel(path, method="nearest") subarray = subarray.sel(unmapped_path) return subarray diff --git a/polytope/datacube/transformations/datacube_mappers.py b/polytope/datacube/transformations/datacube_mappers.py index bac6bcf92..a8e56aaf5 100644 --- a/polytope/datacube/transformations/datacube_mappers.py +++ b/polytope/datacube/transformations/datacube_mappers.py @@ -69,6 +69,46 @@ def unmap(self, first_val, second_val): return final_transformation.unmap(first_val, second_val) +class RegularGridMapper(DatacubeMapper): + def __init__(self, base_axis, mapped_axes, resolution): + self._mapped_axes = mapped_axes + self._base_axis = base_axis + self._resolution = resolution + self.deg_increment = 90/self._resolution + + def first_axis_vals(self): + first_ax_vals = [-90 + i * self.deg_increment for i in range(2*self._resolution)] + return first_ax_vals + + def map_first_axis(self, lower, upper): + axis_lines = self.first_axis_vals() + return_vals = [val for val in axis_lines if lower <= val <= upper] + return return_vals + + def second_axis_vals(self, first_val): + second_ax_vals = [i * self.deg_increment for i in range(4*self._resolution)] + return second_ax_vals + + def map_second_axis(self, first_val, lower, upper): + axis_lines = self.second_axis_vals(first_val) + return_vals = [val for val in axis_lines if lower <= val <= upper] + return return_vals + + def axes_idx_to_regular_idx(self, first_idx, second_idx): + final_idx = first_idx * 4 * self._resolution + second_idx + return final_idx + + def unmap(self, first_val, second_val): + print("used unmap for regular grid !!!!!") + tol = 1e-8 + first_val = [i for i in self.first_axis_vals() if first_val - tol <= i <= first_val + tol][0] + first_idx = self.first_axis_vals().index(first_val) + second_val = [i for i in self.second_axis_vals(first_val) if second_val - tol <= i <= second_val + tol][0] + second_idx = self.second_axis_vals(first_val).index(second_val) + final_index = self.axes_idx_to_regular_idx(first_idx, second_idx) + return final_index + + class HealpixGridMapper(DatacubeMapper): def __init__(self, base_axis, mapped_axes, resolution): self._mapped_axes = mapped_axes @@ -2872,4 +2912,6 @@ def unmap(self, first_val, second_val): return octahedral_index -_type_to_datacube_mapper_lookup = {"octahedral": "OctahedralGridMapper", "healpix": "HealpixGridMapper"} +_type_to_datacube_mapper_lookup = {"octahedral": "OctahedralGridMapper", + "healpix": "HealpixGridMapper", + "regular": "RegularGridMapper"} diff --git a/tests/test_regular_grid.py b/tests/test_regular_grid.py new file mode 100644 index 000000000..5e7ea358f --- /dev/null +++ b/tests/test_regular_grid.py @@ -0,0 +1,86 @@ +import numpy as np +import pytest +from earthkit import data +from eccodes import codes_grib_find_nearest, codes_grib_new_from_file +from helper_functions import download_test_data + +from polytope.datacube.backends.xarray import XArrayDatacube +from polytope.engine.hullslicer import HullSlicer +from polytope.polytope import Polytope, Request +from polytope.shapes import Box, Select + + +class TestRegularGrid: + def setup_method(self, method): + # TODO: for this test, need to fdb write era5 data and use fdb backend + nexus_url = "https://get.ecmwf.int/test-data/polytope/test-data/era5-levels-members.grib" + download_test_data(nexus_url, "era5-levels-members.grib") + + ds = data.from_source("file", "./tests/data/era5-levels-members.grib") + self.latlon_array = ds.to_xarray().isel(step=0).t + self.xarraydatacube = XArrayDatacube(self.latlon_array) + self.options = { + "values": { + "transformation": { + "mapper": {"type": "regular", "resolution": 640, "axes": ["latitude", "longitude"]} + } + }, + "isobaricInhPa": {"transformation": {"reverse": {True}}} + } + self.slicer = HullSlicer() + self.API = Polytope(datacube=self.latlon_array, engine=self.slicer, axis_options=self.options) + + def find_nearest_latlon(self, grib_file, target_lat, target_lon): + # Open the GRIB file + f = open(grib_file) + + # Load the GRIB messages from the file + messages = [] + while True: + message = codes_grib_new_from_file(f) + if message is None: + break + messages.append(message) + + # Find the nearest grid points + nearest_points = [] + for message in messages: + nearest_index = codes_grib_find_nearest(message, target_lat, target_lon) + nearest_points.append(nearest_index) + + # Close the GRIB file + f.close() + + return nearest_points + + @pytest.mark.internet + def test_regular_grid(self): + request = Request( + Box(["number", "isobaricInhPa"], [3, 0.0], [3, 500.0]), + Select("time", ["2017-01-02T12:00:00"]), + Box(["latitude", "longitude"], lower_corner=[0.0, 0.0], upper_corner=[3.0, 3.0]), + Select("step", [np.timedelta64(0, "s")]), + ) + result = self.API.retrieve(request) + result.pprint() + assert len(result.leaves) == 4 + + # lats = [] + # lons = [] + # eccodes_lats = [] + # tol = 1e-8 + # for i in range(len(result.leaves)): + # cubepath = result.leaves[i].flatten() + # lat = cubepath["latitude"] + # lon = cubepath["longitude"] + # lats.append(lat) + # lons.append(lon) + # nearest_points = self.find_nearest_latlon("./tests/data/foo.grib", lat, lon) + # eccodes_lat = nearest_points[0][0]["lat"] + # eccodes_lon = nearest_points[0][0]["lon"] + # eccodes_lats.append(eccodes_lat) + # assert eccodes_lat - tol <= lat + # assert lat <= eccodes_lat + tol + # assert eccodes_lon - tol <= lon + # assert lon <= eccodes_lon + tol + # assert len(eccodes_lats) == 9 From a6f938ccc466dcd005ff2929639bad70ebe794e9 Mon Sep 17 00:00:00 2001 From: Mathilde Leuridan Date: Fri, 13 Oct 2023 12:48:16 +0100 Subject: [PATCH 04/37] fix regular grid test --- polytope/datacube/backends/FDB_datacube.py | 1 + tests/test_regular_grid.py | 73 ++++++++++++---------- 2 files changed, 40 insertions(+), 34 deletions(-) diff --git a/polytope/datacube/backends/FDB_datacube.py b/polytope/datacube/backends/FDB_datacube.py index 2525d5057..63f5cc701 100644 --- a/polytope/datacube/backends/FDB_datacube.py +++ b/polytope/datacube/backends/FDB_datacube.py @@ -47,6 +47,7 @@ def __init__(self, config={}, axis_options={}): self._check_and_add_axes(options, name, val) def get(self, requests: IndexTree): + requests.pprint() for r in requests.leaves: path = r.flatten() path = self.remap_path(path) diff --git a/tests/test_regular_grid.py b/tests/test_regular_grid.py index 5e7ea358f..4ee3adc23 100644 --- a/tests/test_regular_grid.py +++ b/tests/test_regular_grid.py @@ -1,10 +1,9 @@ -import numpy as np +import pandas as pd import pytest -from earthkit import data from eccodes import codes_grib_find_nearest, codes_grib_new_from_file from helper_functions import download_test_data -from polytope.datacube.backends.xarray import XArrayDatacube +from polytope.datacube.backends.FDB_datacube import FDBDatacube from polytope.engine.hullslicer import HullSlicer from polytope.polytope import Polytope, Request from polytope.shapes import Box, Select @@ -12,23 +11,21 @@ class TestRegularGrid: def setup_method(self, method): - # TODO: for this test, need to fdb write era5 data and use fdb backend nexus_url = "https://get.ecmwf.int/test-data/polytope/test-data/era5-levels-members.grib" download_test_data(nexus_url, "era5-levels-members.grib") - - ds = data.from_source("file", "./tests/data/era5-levels-members.grib") - self.latlon_array = ds.to_xarray().isel(step=0).t - self.xarraydatacube = XArrayDatacube(self.latlon_array) self.options = { "values": { "transformation": { - "mapper": {"type": "regular", "resolution": 640, "axes": ["latitude", "longitude"]} + "mapper": {"type": "regular", "resolution": 30, "axes": ["latitude", "longitude"]} } }, - "isobaricInhPa": {"transformation": {"reverse": {True}}} + "date": {"transformation": {"merge": {"with": "time", "linkers": [" ", "00"]}}}, + "step": {"transformation": {"type_change": "int"}}, } + self.config = {"class": "ea", "expver": "0001", "levtype": "pl", "step": 0} + self.fdbdatacube = FDBDatacube(self.config, axis_options=self.options) self.slicer = HullSlicer() - self.API = Polytope(datacube=self.latlon_array, engine=self.slicer, axis_options=self.options) + self.API = Polytope(datacube=self.fdbdatacube, engine=self.slicer, axis_options=self.options) def find_nearest_latlon(self, grib_file, target_lat, target_lon): # Open the GRIB file @@ -56,31 +53,39 @@ def find_nearest_latlon(self, grib_file, target_lat, target_lon): @pytest.mark.internet def test_regular_grid(self): request = Request( - Box(["number", "isobaricInhPa"], [3, 0.0], [3, 500.0]), - Select("time", ["2017-01-02T12:00:00"]), - Box(["latitude", "longitude"], lower_corner=[0.0, 0.0], upper_corner=[3.0, 3.0]), - Select("step", [np.timedelta64(0, "s")]), + Select("step", [0]), + Select("levtype", ["pl"]), + Select("date", [pd.Timestamp("20170102T120000")]), + Select("domain", ["g"]), + Select("expver", ["0001"]), + Select("param", ["129"]), + Select("class", ["ea"]), + Select("stream", ["enda"]), + Select("type", ["an"]), + Box(["latitude", "longitude"], [0, 0], [3, 3]), + Select("levelist", ["500"]), + Select("number", ["0"]) ) result = self.API.retrieve(request) result.pprint() assert len(result.leaves) == 4 - # lats = [] - # lons = [] - # eccodes_lats = [] - # tol = 1e-8 - # for i in range(len(result.leaves)): - # cubepath = result.leaves[i].flatten() - # lat = cubepath["latitude"] - # lon = cubepath["longitude"] - # lats.append(lat) - # lons.append(lon) - # nearest_points = self.find_nearest_latlon("./tests/data/foo.grib", lat, lon) - # eccodes_lat = nearest_points[0][0]["lat"] - # eccodes_lon = nearest_points[0][0]["lon"] - # eccodes_lats.append(eccodes_lat) - # assert eccodes_lat - tol <= lat - # assert lat <= eccodes_lat + tol - # assert eccodes_lon - tol <= lon - # assert lon <= eccodes_lon + tol - # assert len(eccodes_lats) == 9 + lats = [] + lons = [] + eccodes_lats = [] + tol = 1e-8 + for i in range(len(result.leaves)): + cubepath = result.leaves[i].flatten() + lat = cubepath["latitude"] + lon = cubepath["longitude"] + lats.append(lat) + lons.append(lon) + nearest_points = self.find_nearest_latlon("./tests/data/era5-levels-members.grib", lat, lon) + eccodes_lat = nearest_points[0][0]["lat"] + eccodes_lon = nearest_points[0][0]["lon"] + eccodes_lats.append(eccodes_lat) + assert eccodes_lat - tol <= lat + assert lat <= eccodes_lat + tol + assert eccodes_lon - tol <= lon + assert lon <= eccodes_lon + tol + assert len(eccodes_lats) == 4 From 17776a885ef89d4c48ae6feabfa1e60bbd5d6772 Mon Sep 17 00:00:00 2001 From: Mathilde Leuridan Date: Fri, 13 Oct 2023 13:46:31 +0100 Subject: [PATCH 05/37] small fixes and first performance test --- performance/fdb_performance.py | 47 ++++++++++++++++++++++ polytope/datacube/backends/FDB_datacube.py | 1 - tests/test_fdb_datacube.py | 21 ++++++++++ tests/test_regular_grid.py | 23 ++++++++--- 4 files changed, 86 insertions(+), 6 deletions(-) create mode 100644 performance/fdb_performance.py diff --git a/performance/fdb_performance.py b/performance/fdb_performance.py new file mode 100644 index 000000000..57969bade --- /dev/null +++ b/performance/fdb_performance.py @@ -0,0 +1,47 @@ +import time + +import pandas as pd +import pytest + +from polytope.datacube.backends.FDB_datacube import FDBDatacube +from polytope.engine.hullslicer import HullSlicer +from polytope.polytope import Polytope, Request +from polytope.shapes import Box, Select + + +class TestSlicingFDBDatacube: + def setup_method(self, method): + # Create a dataarray with 3 labelled axes using different index types + self.options = { + "values": { + "transformation": { + "mapper": {"type": "octahedral", "resolution": 1280, "axes": ["latitude", "longitude"]} + } + }, + "date": {"transformation": {"merge": {"with": "time", "linkers": [" ", "00"]}}}, + "step": {"transformation": {"type_change": "int"}}, + } + self.config = {"class": "od", "expver": "0001", "levtype": "sfc", "step": 0} + self.fdbdatacube = FDBDatacube(self.config, axis_options=self.options) + self.slicer = HullSlicer() + self.API = Polytope(datacube=self.fdbdatacube, engine=self.slicer, axis_options=self.options) + + # Testing different shapes + @pytest.mark.skip(reason="can't install fdb branch on CI") + def test_fdb_datacube(self): + request = Request( + Select("step", [0]), + Select("levtype", ["sfc"]), + Select("date", [pd.Timestamp("20230625T120000")]), + Select("domain", ["g"]), + Select("expver", ["0001"]), + Select("param", ["167"]), + Select("class", ["od"]), + Select("stream", ["oper"]), + Select("type", ["an"]), + Box(["latitude", "longitude"], [0, 0], [10, 10]), + ) + time1 = time.time() + result = self.API.retrieve(request) + print(time.time() - time1) + assert len(result.leaves) == 19226 diff --git a/polytope/datacube/backends/FDB_datacube.py b/polytope/datacube/backends/FDB_datacube.py index 63f5cc701..2525d5057 100644 --- a/polytope/datacube/backends/FDB_datacube.py +++ b/polytope/datacube/backends/FDB_datacube.py @@ -47,7 +47,6 @@ def __init__(self, config={}, axis_options={}): self._check_and_add_axes(options, name, val) def get(self, requests: IndexTree): - requests.pprint() for r in requests.leaves: path = r.flatten() path = self.remap_path(path) diff --git a/tests/test_fdb_datacube.py b/tests/test_fdb_datacube.py index 4e48613d9..952b0bb7b 100644 --- a/tests/test_fdb_datacube.py +++ b/tests/test_fdb_datacube.py @@ -6,6 +6,9 @@ from polytope.polytope import Polytope, Request from polytope.shapes import Box, Select +# import geopandas as gpd +# import matplotlib.pyplot as plt + class TestSlicingFDBDatacube: def setup_method(self, method): @@ -42,3 +45,21 @@ def test_fdb_datacube(self): result = self.API.retrieve(request) result.pprint() assert len(result.leaves) == 9 + + # lats = [] + # lons = [] + # tol = 1e-8 + # for i in range(len(result.leaves)): + # cubepath = result.leaves[i].flatten() + # lat = cubepath["latitude"] + # lon = cubepath["longitude"] + # lats.append(lat) + # lons.append(lon) + + # worldmap = gpd.read_file(gpd.datasets.get_path("naturalearth_lowres")) + # fig, ax = plt.subplots(figsize=(12, 6)) + # worldmap.plot(color="darkgrey", ax=ax) + + # plt.scatter(lons, lats, s=16, c="red", cmap="YlOrRd") + # plt.colorbar(label="Temperature") + # plt.show() diff --git a/tests/test_regular_grid.py b/tests/test_regular_grid.py index 4ee3adc23..7247f73f6 100644 --- a/tests/test_regular_grid.py +++ b/tests/test_regular_grid.py @@ -6,7 +6,10 @@ from polytope.datacube.backends.FDB_datacube import FDBDatacube from polytope.engine.hullslicer import HullSlicer from polytope.polytope import Polytope, Request -from polytope.shapes import Box, Select +from polytope.shapes import Disk, Select + +# import geopandas as gpd +# import matplotlib.pyplot as plt class TestRegularGrid: @@ -51,6 +54,7 @@ def find_nearest_latlon(self, grib_file, target_lat, target_lon): return nearest_points @pytest.mark.internet + @pytest.mark.skip(reason="can't install fdb branch on CI") def test_regular_grid(self): request = Request( Select("step", [0]), @@ -62,13 +66,13 @@ def test_regular_grid(self): Select("class", ["ea"]), Select("stream", ["enda"]), Select("type", ["an"]), - Box(["latitude", "longitude"], [0, 0], [3, 3]), + Disk(["latitude", "longitude"], [0, 0], [15, 15]), Select("levelist", ["500"]), - Select("number", ["0"]) + Select("number", ["0", "1"]) ) result = self.API.retrieve(request) result.pprint() - assert len(result.leaves) == 4 + assert len(result.leaves) == 46*2 lats = [] lons = [] @@ -88,4 +92,13 @@ def test_regular_grid(self): assert lat <= eccodes_lat + tol assert eccodes_lon - tol <= lon assert lon <= eccodes_lon + tol - assert len(eccodes_lats) == 4 + + # worldmap = gpd.read_file(gpd.datasets.get_path("naturalearth_lowres")) + # fig, ax = plt.subplots(figsize=(12, 6)) + # worldmap.plot(color="darkgrey", ax=ax) + + # plt.scatter(lons, lats, s=16, c="red", cmap="YlOrRd") + # plt.colorbar(label="Temperature") + # plt.show() + + assert len(eccodes_lats) == 46*2 From bb76ea4a88180bfe6b9385dfaf7e2d34002b4037 Mon Sep 17 00:00:00 2001 From: Mathilde Leuridan Date: Wed, 18 Oct 2023 11:37:45 +0200 Subject: [PATCH 06/37] make octahedral grid mapping faster and first fdb performance --- performance/fdb_performance.py | 2 +- polytope/datacube/backends/FDB_datacube.py | 20 ++++- polytope/datacube/backends/__init__.py | 1 + polytope/datacube/datacube_axis.py | 18 +++- .../transformations/datacube_mappers.py | 89 ++++++++++++------- .../transformations/datacube_merger.py | 2 +- .../transformations/datacube_type_change.py | 13 +-- polytope/utility/list_tools.py | 22 +++++ 8 files changed, 120 insertions(+), 47 deletions(-) create mode 100644 polytope/datacube/backends/__init__.py create mode 100644 polytope/utility/list_tools.py diff --git a/performance/fdb_performance.py b/performance/fdb_performance.py index 57969bade..9bcac25b7 100644 --- a/performance/fdb_performance.py +++ b/performance/fdb_performance.py @@ -27,7 +27,7 @@ def setup_method(self, method): self.API = Polytope(datacube=self.fdbdatacube, engine=self.slicer, axis_options=self.options) # Testing different shapes - @pytest.mark.skip(reason="can't install fdb branch on CI") + # @pytest.mark.skip(reason="can't install fdb branch on CI") def test_fdb_datacube(self): request = Request( Select("step", [0]), diff --git a/polytope/datacube/backends/FDB_datacube.py b/polytope/datacube/backends/FDB_datacube.py index 2525d5057..61404cd6f 100644 --- a/polytope/datacube/backends/FDB_datacube.py +++ b/polytope/datacube/backends/FDB_datacube.py @@ -1,4 +1,5 @@ import math +import time from copy import deepcopy import pyfdb @@ -47,16 +48,22 @@ def __init__(self, config={}, axis_options={}): self._check_and_add_axes(options, name, val) def get(self, requests: IndexTree): + time0 = time.time() + time_changing_path = 0 + accumulated_fdb_time = 0 for r in requests.leaves: path = r.flatten() path = self.remap_path(path) if len(path.items()) == self.axis_counter: # first, find the grid mapper transform + unmapped_path = {} path_copy = deepcopy(path) + time2 = time.time() for key in path_copy: axis = self._axes[key] (path, unmapped_path) = axis.unmap_total_path_to_datacube(path, unmapped_path) + time_changing_path += time.time() - time2 path = self.fit_path(path) # merge path and unmapped path into a single path path.update(unmapped_path) @@ -66,18 +73,23 @@ def get(self, requests: IndexTree): path.pop("values") fdb_request_key = path - fdb_requests = [(fdb_request_key, [(fdb_request_val, fdb_request_val+1)])] - + fdb_requests = [(fdb_request_key, [(fdb_request_val, fdb_request_val + 1)])] # need to request data from the fdb - + time1 = time.time() subxarray = self.fdb.extract(fdb_requests) + accumulated_fdb_time += time.time() - time1 subxarray_output_tuple = subxarray[0][0] output_value = subxarray_output_tuple[0][0][0] - if not math.isnan(output_value): r.result = output_value else: r.remove_branch() + print("FDB TIME") + print(accumulated_fdb_time) + print("GET TIME") + print(time.time() - time0) + print("TIME CHANGING PATH") + print(time_changing_path) def datacube_natural_indexes(self, axis, subarray): indexes = subarray[axis.name] diff --git a/polytope/datacube/backends/__init__.py b/polytope/datacube/backends/__init__.py new file mode 100644 index 000000000..63902115a --- /dev/null +++ b/polytope/datacube/backends/__init__.py @@ -0,0 +1 @@ +from ..backends.datacube import * diff --git a/polytope/datacube/datacube_axis.py b/polytope/datacube/datacube_axis.py index 77a223710..91b5c6b61 100644 --- a/polytope/datacube/datacube_axis.py +++ b/polytope/datacube/datacube_axis.py @@ -1,6 +1,7 @@ from abc import ABC, abstractmethod from copy import deepcopy from typing import Any, List +import time import numpy as np import pandas as pd @@ -118,6 +119,7 @@ def find_indexes(path, datacube): old_unmap_total_path_to_datacube = cls.unmap_total_path_to_datacube def unmap_total_path_to_datacube(path, unmapped_path): + time1 = time.time() for transform in cls.transformations: if isinstance(transform, DatacubeAxisCyclic): transformation = transform @@ -127,6 +129,8 @@ def unmap_total_path_to_datacube(path, unmapped_path): new_val = _remap_val_to_axis_range(old_val) path[cls.name] = new_val (path, unmapped_path) = old_unmap_total_path_to_datacube(path, unmapped_path) + print("CYCLIC UNMAP TIME") + print(time.time() - time1) return (path, unmapped_path) old_unmap_to_datacube = cls.unmap_to_datacube @@ -235,11 +239,15 @@ def unmap_to_datacube(path, unmapped_path): old_unmap_total_path_to_datacube = cls.unmap_total_path_to_datacube def unmap_total_path_to_datacube(path, unmapped_path): + # TODO: to be faster, could just compute the first lat unmapped idx, and do +1 for each subsequent lat idx? + # time1 = time.time() (path, unmapped_path) = old_unmap_total_path_to_datacube(path, unmapped_path) for transform in cls.transformations: if isinstance(transform, DatacubeMapper): + # time2 = time.time() transformation = transform if cls.name == transformation._mapped_axes()[0]: + # axis = cls.name # if we are on the first axis, then need to add the first val to unmapped_path first_val = path.get(cls.name, None) path.pop(cls.name, None) @@ -251,6 +259,7 @@ def unmap_total_path_to_datacube(path, unmapped_path): if cls.name == transformation._mapped_axes()[1]: # if we are on the second axis, then the val of the first axis is stored # inside unmapped_path so can get it from there + # axis = cls.name second_val = path.get(cls.name, None) path.pop(cls.name, None) first_val = unmapped_path.get(transformation._mapped_axes()[0], None) @@ -259,9 +268,16 @@ def unmap_total_path_to_datacube(path, unmapped_path): if first_val is None: first_val = path.get(transformation._mapped_axes()[0], None) path.pop(transformation._mapped_axes()[0], None) - if first_val is not None and second_val is not None: + if second_val is not None: unmapped_idx = transformation.unmap(first_val, second_val) unmapped_path[transformation.old_axis] = unmapped_idx + # time3 = time.time() + # print("MAPPER UNMAP TIME") + # print(time3 - time1) + # print("AXIS THIS IS FOR") + # print(axis) + # print("MAPPER TIME ONCE CHOSEN THE MAPPING") + # print(time3 - time2) return (path, unmapped_path) def remap_to_requested(path, unmapped_path): diff --git a/polytope/datacube/transformations/datacube_mappers.py b/polytope/datacube/transformations/datacube_mappers.py index a8e56aaf5..d3b6958df 100644 --- a/polytope/datacube/transformations/datacube_mappers.py +++ b/polytope/datacube/transformations/datacube_mappers.py @@ -1,6 +1,10 @@ import math from copy import deepcopy from importlib import import_module +from ...utility.list_tools import bisect_left_cmp, bisect_right_cmp +import bisect +import time +import array from .datacube_transformations import DatacubeAxisTransformation @@ -14,6 +18,7 @@ def __init__(self, name, mapper_options): self.grid_resolution = mapper_options["resolution"] self.grid_axes = mapper_options["axes"] self.old_axis = name + self._final_transformation = self.generate_final_transformation() def generate_final_transformation(self): map_type = _type_to_datacube_mapper_lookup[self.grid_type] @@ -26,8 +31,8 @@ def blocked_axes(self): return [] def transformation_axes_final(self): - final_transformation = self.generate_final_transformation() - final_axes = final_transformation._mapped_axes + # final_transformation = self.generate_final_transformation() + final_axes = self._final_transformation._mapped_axes return final_axes # Needs to also implement its own methods @@ -38,8 +43,8 @@ def change_val_type(self, axis_name, values): def _mapped_axes(self): # NOTE: Each of the mapper method needs to call it's sub mapper method - final_transformation = self.generate_final_transformation() - final_axes = final_transformation._mapped_axes + # final_transformation = self.generate_final_transformation() + final_axes = self._final_transformation._mapped_axes return final_axes def _base_axis(self): @@ -49,24 +54,24 @@ def _resolution(self): pass def first_axis_vals(self): - final_transformation = self.generate_final_transformation() - return final_transformation.first_axis_vals() + # final_transformation = self.generate_final_transformation() + return self._final_transformation.first_axis_vals() def second_axis_vals(self, first_val): - final_transformation = self.generate_final_transformation() - return final_transformation.second_axis_vals(first_val) + # final_transformation = self.generate_final_transformation() + return self._final_transformation.second_axis_vals(first_val) def map_first_axis(self, lower, upper): - final_transformation = self.generate_final_transformation() - return final_transformation.map_first_axis(lower, upper) + # final_transformation = self.generate_final_transformation() + return self._final_transformation.map_first_axis(lower, upper) def map_second_axis(self, first_val, lower, upper): - final_transformation = self.generate_final_transformation() - return final_transformation.map_second_axis(first_val, lower, upper) + # final_transformation = self.generate_final_transformation() + return self._final_transformation.map_second_axis(first_val, lower, upper) def unmap(self, first_val, second_val): - final_transformation = self.generate_final_transformation() - return final_transformation.unmap(first_val, second_val) + # final_transformation = self.generate_final_transformation() + return self._final_transformation.unmap(first_val, second_val) class RegularGridMapper(DatacubeMapper): @@ -74,10 +79,10 @@ def __init__(self, base_axis, mapped_axes, resolution): self._mapped_axes = mapped_axes self._base_axis = base_axis self._resolution = resolution - self.deg_increment = 90/self._resolution + self.deg_increment = 90 / self._resolution def first_axis_vals(self): - first_ax_vals = [-90 + i * self.deg_increment for i in range(2*self._resolution)] + first_ax_vals = [-90 + i * self.deg_increment for i in range(2 * self._resolution)] return first_ax_vals def map_first_axis(self, lower, upper): @@ -86,7 +91,7 @@ def map_first_axis(self, lower, upper): return return_vals def second_axis_vals(self, first_val): - second_ax_vals = [i * self.deg_increment for i in range(4*self._resolution)] + second_ax_vals = [i * self.deg_increment for i in range(4 * self._resolution)] return second_ax_vals def map_second_axis(self, first_val, lower, upper): @@ -99,7 +104,6 @@ def axes_idx_to_regular_idx(self, first_idx, second_idx): return final_idx def unmap(self, first_val, second_val): - print("used unmap for regular grid !!!!!") tol = 1e-8 first_val = [i for i in self.first_axis_vals() if first_val - tol <= i <= first_val + tol][0] first_idx = self.first_axis_vals().index(first_val) @@ -201,6 +205,7 @@ def __init__(self, base_axis, mapped_axes, resolution): self._mapped_axes = mapped_axes self._base_axis = base_axis self._resolution = resolution + self._first_axis_vals = self.first_axis_vals() def gauss_first_guess(self): i = 0 @@ -2859,30 +2864,41 @@ def first_axis_vals(self): return new_vals def map_first_axis(self, lower, upper): - axis_lines = self.first_axis_vals() - return_vals = [val for val in axis_lines if lower <= val <= upper] + axis_lines = self._first_axis_vals + # return_vals = [val for val in axis_lines if lower <= val <= upper] + end_idx = bisect_left_cmp(axis_lines, lower, cmp=lambda x, y: x > y) + 1 + start_idx = bisect_right_cmp(axis_lines, upper, cmp=lambda x, y: x > y) + return_vals = axis_lines[start_idx:end_idx] return return_vals def second_axis_vals(self, first_val): - first_axis_vals = self.first_axis_vals() + first_axis_vals = self._first_axis_vals tol = 1e-10 - first_val = [val for val in first_axis_vals if first_val - tol < val < first_val + tol][0] - first_idx = first_axis_vals.index(first_val) + # first_val = [val for val in first_axis_vals if first_val - tol < val < first_val + tol][0] + # first_idx = first_axis_vals.index(first_val) + first_idx = bisect_left_cmp(first_axis_vals, first_val - tol, cmp=lambda x, y: x > y) if first_idx >= self._resolution: first_idx = (2 * self._resolution) - 1 - first_idx first_idx = first_idx + 1 npoints = 4 * first_idx + 16 second_axis_spacing = 360 / npoints - second_axis_start = 0 - second_axis_vals = [second_axis_start + i * second_axis_spacing for i in range(int(npoints))] + second_axis_vals = [i * second_axis_spacing for i in range(npoints)] return second_axis_vals def map_second_axis(self, first_val, lower, upper): second_axis_vals = self.second_axis_vals(first_val) - return_vals = [val for val in second_axis_vals if lower <= val <= upper] + # NOTE: here this seems faster than the bisect.bisect? + # return_vals = [val for val in second_axis_vals if lower <= val <= upper] + start_idx = bisect_left_cmp(second_axis_vals, lower, cmp=lambda x, y: x < y) + 1 + end_idx = bisect_right_cmp(second_axis_vals, upper, cmp=lambda x, y: x < y) + 1 + return_vals = second_axis_vals[start_idx:end_idx] + # start_idx = bisect.bisect_left(second_axis_vals, lower) + # end_idx = bisect.bisect_right(second_axis_vals, upper) + # return_vals = second_axis_vals[start_idx:end_idx] return return_vals def axes_idx_to_octahedral_idx(self, first_idx, second_idx): + # NOTE: for now this takes ~2e-4s per point, so taking significant time octa_idx = 0 if first_idx == 1: octa_idx = second_idx @@ -2901,17 +2917,22 @@ def axes_idx_to_octahedral_idx(self, first_idx, second_idx): return octa_idx def unmap(self, first_val, second_val): - first_axis_vals = self.first_axis_vals() + first_axis_vals = self._first_axis_vals tol = 1e-10 - first_val = [val for val in first_axis_vals if first_val - tol < val < first_val + tol][0] - first_idx = first_axis_vals.index(first_val) + 1 + # first_val = [val for val in first_axis_vals if first_val - tol < val < first_val + tol][0] + # first_idx = first_axis_vals.index(first_val) + 1 + # first_idx = len(first_axis_vals) - bisect.bisect_left(first_axis_vals[::-1], first_val - tol) + first_idx = bisect_left_cmp(first_axis_vals, first_val - tol, cmp=lambda x, y: x > y) + 1 second_axis_vals = self.second_axis_vals(first_val) - second_val = [val for val in second_axis_vals if second_val - tol < val < second_val + tol][0] - second_idx = second_axis_vals.index(second_val) + # second_val = [val for val in second_axis_vals if second_val - tol < val < second_val + tol][0] + # second_idx = second_axis_vals.index(second_val) + second_idx = bisect.bisect_left(second_axis_vals, second_val - tol) octahedral_index = self.axes_idx_to_octahedral_idx(first_idx, second_idx) return octahedral_index -_type_to_datacube_mapper_lookup = {"octahedral": "OctahedralGridMapper", - "healpix": "HealpixGridMapper", - "regular": "RegularGridMapper"} +_type_to_datacube_mapper_lookup = { + "octahedral": "OctahedralGridMapper", + "healpix": "HealpixGridMapper", + "regular": "RegularGridMapper", +} diff --git a/polytope/datacube/transformations/datacube_merger.py b/polytope/datacube/transformations/datacube_merger.py index e38a57d8c..e8ff67145 100644 --- a/polytope/datacube/transformations/datacube_merger.py +++ b/polytope/datacube/transformations/datacube_merger.py @@ -46,7 +46,7 @@ def unmerge(self, merged_val): second_val = merged_val[first_idx + first_linker_size : -second_linked_size] # TODO: maybe replacing like this is too specific to time/dates? - first_val = str(first_val).replace('-', '') + first_val = str(first_val).replace("-", "") second_val = second_val.replace(":", "") return (first_val, second_val) diff --git a/polytope/datacube/transformations/datacube_type_change.py b/polytope/datacube/transformations/datacube_type_change.py index e3e8a682c..0f4cedd21 100644 --- a/polytope/datacube/transformations/datacube_type_change.py +++ b/polytope/datacube/transformations/datacube_type_change.py @@ -11,6 +11,7 @@ def __init__(self, name, type_options): self.name = name self.transformation_options = type_options self.new_type = type_options + self._final_transformation = self.generate_final_transformation() def generate_final_transformation(self): map_type = _type_to_datacube_type_change_lookup[self.new_type] @@ -20,16 +21,16 @@ def generate_final_transformation(self): return transformation def transformation_axes_final(self): - final_transformation = self.generate_final_transformation() - return [final_transformation.axis_name] + # final_transformation = self.generate_final_transformation() + return [self._final_transformation.axis_name] def change_val_type(self, axis_name, values): - transformation = self.generate_final_transformation() - return [transformation.transform_type(val) for val in values] + # transformation = self.generate_final_transformation() + return [self._final_transformation.transform_type(val) for val in values] def make_str(self, value): - transformation = self.generate_final_transformation() - return transformation.make_str(value) + # transformation = self.generate_final_transformation() + return self._final_transformation.make_str(value) def blocked_axes(self): return [] diff --git a/polytope/utility/list_tools.py b/polytope/utility/list_tools.py new file mode 100644 index 000000000..2d18917c1 --- /dev/null +++ b/polytope/utility/list_tools.py @@ -0,0 +1,22 @@ +def bisect_left_cmp(arr, val, cmp): + left = -1 + r = len(arr) + while r - left > 1: + e = (left + r) >> 1 + if cmp(arr[e], val): + left = e + else: + r = e + return left + + +def bisect_right_cmp(arr, val, cmp): + left = -1 + r = len(arr) + while r - left > 1: + e = (left + r) >> 1 + if cmp(arr[e], val): + left = e + else: + r = e + return r From 6f2dbd8299c6aeff7f7921c4f4034a96f63d2fad Mon Sep 17 00:00:00 2001 From: Mathilde Leuridan Date: Wed, 18 Oct 2023 15:35:46 +0200 Subject: [PATCH 07/37] create dictionary of latitude lines in octahedral mapping --- polytope/datacube/datacube_axis.py | 14 +++ .../transformations/datacube_mappers.py | 115 +++++++++++++++++- 2 files changed, 125 insertions(+), 4 deletions(-) diff --git a/polytope/datacube/datacube_axis.py b/polytope/datacube/datacube_axis.py index 91b5c6b61..07edd8d40 100644 --- a/polytope/datacube/datacube_axis.py +++ b/polytope/datacube/datacube_axis.py @@ -260,17 +260,31 @@ def unmap_total_path_to_datacube(path, unmapped_path): # if we are on the second axis, then the val of the first axis is stored # inside unmapped_path so can get it from there # axis = cls.name + # print("TIME time handling path") + # time2 = time.time() second_val = path.get(cls.name, None) path.pop(cls.name, None) first_val = unmapped_path.get(transformation._mapped_axes()[0], None) + unmapped_path.pop(transformation._mapped_axes()[0], None) + # print(time.time() - time2) + # NOTE: here we first calculate the starting idx of the first_val grid line + # and then append the second_idx to get the final unmapped_idx + # To do this, also need to find second_idx from second_val... + # second_idx = transformation.find_second_idx(first_val, second_val) + # first_line_idx = transformation.unmap_first_val_to_start_line_idx(first_val) + # if the first_val was not in the unmapped_path, then it's still in path + # print("AAAAAND TIME TAKEN DOING UNMAP") if first_val is None: first_val = path.get(transformation._mapped_axes()[0], None) path.pop(transformation._mapped_axes()[0], None) if second_val is not None: + # time4 = time.time() + # unmapped_idx = first_line_idx + second_idx unmapped_idx = transformation.unmap(first_val, second_val) unmapped_path[transformation.old_axis] = unmapped_idx + # print(time.time() - time4) # time3 = time.time() # print("MAPPER UNMAP TIME") # print(time3 - time1) diff --git a/polytope/datacube/transformations/datacube_mappers.py b/polytope/datacube/transformations/datacube_mappers.py index d3b6958df..06b7b57d1 100644 --- a/polytope/datacube/transformations/datacube_mappers.py +++ b/polytope/datacube/transformations/datacube_mappers.py @@ -69,6 +69,12 @@ def map_second_axis(self, first_val, lower, upper): # final_transformation = self.generate_final_transformation() return self._final_transformation.map_second_axis(first_val, lower, upper) + def find_second_idx(self, first_val, second_val): + return self._final_transformation.find_second_idx(first_val, second_val) + + def unmap_first_val_to_start_line_idx(self, first_val): + return self._final_transformation.unmap_first_val_to_start_line_idx(first_val) + def unmap(self, first_val, second_val): # final_transformation = self.generate_final_transformation() return self._final_transformation.unmap(first_val, second_val) @@ -103,6 +109,18 @@ def axes_idx_to_regular_idx(self, first_idx, second_idx): final_idx = first_idx * 4 * self._resolution + second_idx return final_idx + def find_second_idx(self, first_val, second_val): + tol = 1e-10 + second_axis_vals = self.second_axis_vals(first_val) + second_idx = bisect.bisect_left(second_axis_vals, second_val - tol) + return second_idx + + def unmap_first_val_to_start_line_idx(self, first_val): + tol = 1e-8 + first_val = [i for i in self.first_axis_vals() if first_val - tol <= i <= first_val + tol][0] + first_idx = self.first_axis_vals().index(first_val) + return first_idx * 4 * self._resolution + def unmap(self, first_val, second_val): tol = 1e-8 first_val = [i for i in self.first_axis_vals() if first_val - tol <= i <= first_val + tol][0] @@ -190,6 +208,33 @@ def axes_idx_to_healpix_idx(self, first_idx, second_idx): idx += second_idx return idx + def find_second_idx(self, first_val, second_val): + tol = 1e-10 + second_axis_vals = self.second_axis_vals(first_val) + second_idx = bisect.bisect_left(second_axis_vals, second_val - tol) + return second_idx + + def unmap_first_val_to_start_line_idx(self, first_val): + tol = 1e-8 + first_val = [i for i in self.first_axis_vals() if first_val - tol <= i <= first_val + tol][0] + first_idx = self.first_axis_vals().index(first_val) + idx = 0 + for i in range(self._resolution - 1): + if i != first_idx: + idx += 4 * (i + 1) + else: + return idx + for i in range(self._resolution - 1, 3 * self._resolution): + if i != first_idx: + idx += 4 * self._resolution + else: + return idx + for i in range(3 * self._resolution, 4 * self._resolution - 1): + if i != first_idx: + idx += 4 * (4 * self._resolution - 1 - i + 1) + else: + return idx + def unmap(self, first_val, second_val): tol = 1e-8 first_val = [i for i in self.first_axis_vals() if first_val - tol <= i <= first_val + tol][0] @@ -206,6 +251,7 @@ def __init__(self, base_axis, mapped_axes, resolution): self._base_axis = base_axis self._resolution = resolution self._first_axis_vals = self.first_axis_vals() + self._first_idx_map = self.create_first_idx_map() def gauss_first_guess(self): i = 0 @@ -2898,10 +2944,67 @@ def map_second_axis(self, first_val, lower, upper): return return_vals def axes_idx_to_octahedral_idx(self, first_idx, second_idx): - # NOTE: for now this takes ~2e-4s per point, so taking significant time + # NOTE: for now this takes ~2e-4s per point, so taking significant time -> for 20k points, takes 4s + # Would it be better to store a dictionary of first_idx with cumulative number of points on that idx? + # Because this is what we are doing here, but we are calculating for each point... + # But then this would only work for special grid resolutions, so need to do like a O1280 version of this + + # NOTE: OR somehow cache this for a given first_idx and then only modify the axis idx for second_idx when the + # first_idx changes + # time1 = time.time() + octa_idx = self._first_idx_map[first_idx-1] + second_idx + # octa_idx = 0 + # if first_idx == 1: + # octa_idx = second_idx + # else: + # for i in range(first_idx - 1): + # if i <= self._resolution - 1: + # octa_idx += 20 + 4 * i + # else: + # i = i - self._resolution + 1 + # if i == 1: + # octa_idx += 16 + 4 * self._resolution + # else: + # i = i - 1 + # octa_idx += 16 + 4 * (self._resolution - i) + # octa_idx += second_idx + # print("TIME UNMAPPING TO OCT IDX") + # print(time.time() - time1) + return octa_idx + + def find_second_idx(self, first_val, second_val): + tol = 1e-10 + second_axis_vals = self.second_axis_vals(first_val) + second_idx = bisect.bisect_left(second_axis_vals, second_val - tol) + return second_idx + + def create_first_idx_map(self): + # first_idx_list = [0] * (2*self._resolution) + first_idx_list = {} + idx = 0 + for i in range(2*self._resolution): + first_idx_list[i] = idx + if i <= self._resolution - 1: + idx += 20 + 4 * i + else: + i = i - self._resolution + 1 + if i == 1: + idx += 16 + 4 * self._resolution + else: + i = i - 1 + idx += 16 + 4 * (self._resolution - i) + return first_idx_list + + def unmap_first_val_to_start_line_idx(self, first_val): + first_axis_vals = self._first_axis_vals + tol = 1e-10 + # first_val = [val for val in first_axis_vals if first_val - tol < val < first_val + tol][0] + # first_idx = first_axis_vals.index(first_val) + 1 + # first_idx = len(first_axis_vals) - bisect.bisect_left(first_axis_vals[::-1], first_val - tol) + first_idx = bisect_left_cmp(first_axis_vals, first_val - tol, cmp=lambda x, y: x > y) + 1 octa_idx = 0 if first_idx == 1: - octa_idx = second_idx + return octa_idx else: for i in range(first_idx - 1): if i <= self._resolution - 1: @@ -2913,10 +3016,10 @@ def axes_idx_to_octahedral_idx(self, first_idx, second_idx): else: i = i - 1 octa_idx += 16 + 4 * (self._resolution - i) - octa_idx += second_idx - return octa_idx + return octa_idx def unmap(self, first_val, second_val): + time1 = time.time() first_axis_vals = self._first_axis_vals tol = 1e-10 # first_val = [val for val in first_axis_vals if first_val - tol < val < first_val + tol][0] @@ -2927,7 +3030,11 @@ def unmap(self, first_val, second_val): # second_val = [val for val in second_axis_vals if second_val - tol < val < second_val + tol][0] # second_idx = second_axis_vals.index(second_val) second_idx = bisect.bisect_left(second_axis_vals, second_val - tol) + print("TIME SPENT DOING VAL TO IDX") + print(time.time() - time1) octahedral_index = self.axes_idx_to_octahedral_idx(first_idx, second_idx) + print("OCTAHEDRAL UNMAP TIME") + print(time.time() - time1) return octahedral_index From 7b18dce42a45c0265430f6c2a3243e703b3676bc Mon Sep 17 00:00:00 2001 From: Mathilde Leuridan Date: Thu, 19 Oct 2023 13:11:49 +0200 Subject: [PATCH 08/37] add some sort of caching for longitude values in unmap --- .../transformations/datacube_mappers.py | 2598 ++++++++++++++++- 1 file changed, 2591 insertions(+), 7 deletions(-) diff --git a/polytope/datacube/transformations/datacube_mappers.py b/polytope/datacube/transformations/datacube_mappers.py index 06b7b57d1..40870f1ac 100644 --- a/polytope/datacube/transformations/datacube_mappers.py +++ b/polytope/datacube/transformations/datacube_mappers.py @@ -5,6 +5,8 @@ import bisect import time import array +import numpy as np +from sortedcontainers import SortedDict, SortedList from .datacube_transformations import DatacubeAxisTransformation @@ -251,7 +253,10 @@ def __init__(self, base_axis, mapped_axes, resolution): self._base_axis = base_axis self._resolution = resolution self._first_axis_vals = self.first_axis_vals() + self._inv_first_axis_vals = self._first_axis_vals[::-1] + # self._inv_first_axis_vals = {v:k for k,v in self._first_axis_vals.items()} self._first_idx_map = self.create_first_idx_map() + self.treated_first_vals = dict() def gauss_first_guess(self): i = 0 @@ -319,6 +324,2572 @@ def gauss_first_guess(self): def get_precomputed_values_N1280(self): lats = [0] * 2560 + # lats = SortedList() + # lats = {} + lats[0] = 89.946187715665616 + lats[1] = 89.876478353332288 + lats[2] = 89.806357319542244 + lats[3] = 89.736143271609578 + lats[4] = 89.6658939412157 + lats[5] = 89.595627537554492 + lats[6] = 89.525351592371393 + lats[7] = 89.45506977912261 + lats[8] = 89.3847841013921 + lats[9] = 89.314495744374256 + lats[10] = 89.24420545380525 + lats[11] = 89.173913722284126 + lats[12] = 89.103620888238879 + lats[13] = 89.033327191845927 + lats[14] = 88.96303280826325 + lats[15] = 88.892737868230952 + lats[16] = 88.822442471310097 + lats[17] = 88.752146694650691 + lats[18] = 88.681850598961759 + lats[19] = 88.611554232668382 + lats[20] = 88.541257634868515 + lats[21] = 88.470960837474877 + lats[22] = 88.40066386679355 + lats[23] = 88.330366744702559 + lats[24] = 88.26006948954614 + lats[25] = 88.189772116820762 + lats[26] = 88.119474639706425 + lats[27] = 88.049177069484486 + lats[28] = 87.978879415867283 + lats[29] = 87.908581687261687 + lats[30] = 87.838283890981543 + lats[31] = 87.767986033419561 + lats[32] = 87.697688120188062 + lats[33] = 87.627390156234085 + lats[34] = 87.557092145935584 + lats[35] = 87.486794093180748 + lats[36] = 87.416496001434894 + lats[37] = 87.346197873795816 + lats[38] = 87.275899713041966 + lats[39] = 87.205601521672108 + lats[40] = 87.135303301939786 + lats[41] = 87.065005055882821 + lats[42] = 86.994706785348129 + lats[43] = 86.924408492014166 + lats[44] = 86.854110177408927 + lats[45] = 86.783811842927179 + lats[46] = 86.713513489844246 + lats[47] = 86.643215119328573 + lats[48] = 86.572916732453024 + lats[49] = 86.502618330203831 + lats[50] = 86.432319913489792 + lats[51] = 86.362021483149363 + lats[52] = 86.291723039957418 + lats[53] = 86.221424584631109 + lats[54] = 86.151126117835304 + lats[55] = 86.080827640187209 + lats[56] = 86.010529152260403 + lats[57] = 85.940230654588888 + lats[58] = 85.869932147670127 + lats[59] = 85.799633631968391 + lats[60] = 85.729335107917464 + lats[61] = 85.659036575922883 + lats[62] = 85.588738036364362 + lats[63] = 85.518439489597966 + lats[64] = 85.448140935957483 + lats[65] = 85.377842375756586 + lats[66] = 85.307543809290152 + lats[67] = 85.237245236835548 + lats[68] = 85.16694665865414 + lats[69] = 85.09664807499216 + lats[70] = 85.026349486081983 + lats[71] = 84.95605089214304 + lats[72] = 84.885752293382765 + lats[73] = 84.81545368999717 + lats[74] = 84.745155082171991 + lats[75] = 84.674856470082915 + lats[76] = 84.604557853896708 + lats[77] = 84.534259233771479 + lats[78] = 84.463960609857125 + lats[79] = 84.393661982296322 + lats[80] = 84.323363351224444 + lats[81] = 84.253064716770425 + lats[82] = 84.18276607905679 + lats[83] = 84.112467438200326 + lats[84] = 84.042168794312317 + lats[85] = 83.971870147498763 + lats[86] = 83.901571497860914 + lats[87] = 83.831272845495249 + lats[88] = 83.760974190494011 + lats[89] = 83.690675532945292 + lats[90] = 83.620376872933264 + lats[91] = 83.550078210538487 + lats[92] = 83.479779545838113 + lats[93] = 83.409480878905782 + lats[94] = 83.339182209812321 + lats[95] = 83.268883538625232 + lats[96] = 83.198584865409657 + lats[97] = 83.128286190227698 + lats[98] = 83.057987513139125 + lats[99] = 82.987688834201322 + lats[100] = 82.917390153469313 + lats[101] = 82.84709147099602 + lats[102] = 82.77679278683226 + lats[103] = 82.706494101026948 + lats[104] = 82.63619541362705 + lats[105] = 82.56589672467787 + lats[106] = 82.495598034222837 + lats[107] = 82.425299342304029 + lats[108] = 82.355000648961692 + lats[109] = 82.284701954234833 + lats[110] = 82.214403258160871 + lats[111] = 82.144104560776 + lats[112] = 82.073805862115165 + lats[113] = 82.003507162211946 + lats[114] = 81.933208461098829 + lats[115] = 81.862909758807191 + lats[116] = 81.792611055367345 + lats[117] = 81.722312350808508 + lats[118] = 81.652013645158945 + lats[119] = 81.581714938445955 + lats[120] = 81.511416230696042 + lats[121] = 81.441117521934686 + lats[122] = 81.370818812186627 + lats[123] = 81.300520101475826 + lats[124] = 81.230221389825374 + lats[125] = 81.159922677257711 + lats[126] = 81.089623963794551 + lats[127] = 81.019325249456955 + lats[128] = 80.949026534265244 + lats[129] = 80.878727818239184 + lats[130] = 80.808429101397948 + lats[131] = 80.73813038376008 + lats[132] = 80.667831665343556 + lats[133] = 80.59753294616587 + lats[134] = 80.527234226243991 + lats[135] = 80.456935505594302 + lats[136] = 80.386636784232863 + lats[137] = 80.316338062175078 + lats[138] = 80.246039339436052 + lats[139] = 80.175740616030438 + lats[140] = 80.105441891972376 + lats[141] = 80.035143167275749 + lats[142] = 79.9648444419539 + lats[143] = 79.894545716019948 + lats[144] = 79.824246989486554 + lats[145] = 79.753948262366038 + lats[146] = 79.683649534670437 + lats[147] = 79.61335080641139 + lats[148] = 79.543052077600308 + lats[149] = 79.472753348248219 + lats[150] = 79.402454618365894 + lats[151] = 79.332155887963822 + lats[152] = 79.261857157052191 + lats[153] = 79.191558425640977 + lats[154] = 79.121259693739859 + lats[155] = 79.050960961358285 + lats[156] = 78.980662228505423 + lats[157] = 78.910363495190211 + lats[158] = 78.840064761421445 + lats[159] = 78.769766027207638 + lats[160] = 78.699467292557102 + lats[161] = 78.629168557477882 + lats[162] = 78.558869821977908 + lats[163] = 78.488571086064923 + lats[164] = 78.418272349746417 + lats[165] = 78.347973613029708 + lats[166] = 78.277674875922045 + lats[167] = 78.207376138430348 + lats[168] = 78.137077400561424 + lats[169] = 78.066778662322022 + lats[170] = 77.996479923718596 + lats[171] = 77.926181184757539 + lats[172] = 77.855882445445019 + lats[173] = 77.785583705787161 + lats[174] = 77.71528496578982 + lats[175] = 77.644986225458879 + lats[176] = 77.574687484799924 + lats[177] = 77.504388743818524 + lats[178] = 77.434090002520122 + lats[179] = 77.363791260909963 + lats[180] = 77.293492518993247 + lats[181] = 77.22319377677502 + lats[182] = 77.15289503426024 + lats[183] = 77.082596291453768 + lats[184] = 77.012297548360323 + lats[185] = 76.941998804984564 + lats[186] = 76.871700061330955 + lats[187] = 76.801401317404 + lats[188] = 76.731102573208048 + lats[189] = 76.660803828747362 + lats[190] = 76.59050508402602 + lats[191] = 76.520206339048215 + lats[192] = 76.449907593817869 + lats[193] = 76.379608848338933 + lats[194] = 76.3093101026152 + lats[195] = 76.239011356650423 + lats[196] = 76.16871261044831 + lats[197] = 76.098413864012443 + lats[198] = 76.028115117346374 + lats[199] = 75.957816370453543 + lats[200] = 75.887517623337317 + lats[201] = 75.81721887600105 + lats[202] = 75.746920128447996 + lats[203] = 75.67662138068134 + lats[204] = 75.60632263270422 + lats[205] = 75.536023884519707 + lats[206] = 75.465725136130786 + lats[207] = 75.395426387540439 + lats[208] = 75.325127638751567 + lats[209] = 75.254828889766983 + lats[210] = 75.184530140589501 + lats[211] = 75.114231391221821 + lats[212] = 75.043932641666672 + lats[213] = 74.973633891926625 + lats[214] = 74.903335142004323 + lats[215] = 74.833036391902269 + lats[216] = 74.762737641622991 + lats[217] = 74.692438891168877 + lats[218] = 74.622140140542356 + lats[219] = 74.551841389745761 + lats[220] = 74.481542638781434 + lats[221] = 74.411243887651622 + lats[222] = 74.340945136358584 + lats[223] = 74.270646384904481 + lats[224] = 74.200347633291472 + lats[225] = 74.13004888152166 + lats[226] = 74.059750129597163 + lats[227] = 73.98945137751997 + lats[228] = 73.919152625292114 + lats[229] = 73.848853872915541 + lats[230] = 73.778555120392184 + lats[231] = 73.70825636772399 + lats[232] = 73.637957614912779 + lats[233] = 73.567658861960396 + lats[234] = 73.497360108868662 + lats[235] = 73.427061355639339 + lats[236] = 73.356762602274188 + lats[237] = 73.2864638487749 + lats[238] = 73.216165095143182 + lats[239] = 73.145866341380668 + lats[240] = 73.075567587489019 + lats[241] = 73.005268833469799 + lats[242] = 72.934970079324657 + lats[243] = 72.864671325055056 + lats[244] = 72.794372570662574 + lats[245] = 72.724073816148703 + lats[246] = 72.653775061514935 + lats[247] = 72.583476306762691 + lats[248] = 72.513177551893421 + lats[249] = 72.442878796908545 + lats[250] = 72.3725800418094 + lats[251] = 72.302281286597392 + lats[252] = 72.231982531273843 + lats[253] = 72.161683775840089 + lats[254] = 72.091385020297409 + lats[255] = 72.02108626464711 + lats[256] = 71.950787508890414 + lats[257] = 71.880488753028587 + lats[258] = 71.810189997062835 + lats[259] = 71.739891240994368 + lats[260] = 71.669592484824364 + lats[261] = 71.599293728553988 + lats[262] = 71.528994972184378 + lats[263] = 71.458696215716685 + lats[264] = 71.388397459152031 + lats[265] = 71.318098702491469 + lats[266] = 71.247799945736105 + lats[267] = 71.177501188887007 + lats[268] = 71.107202431945211 + lats[269] = 71.036903674911756 + lats[270] = 70.966604917787635 + lats[271] = 70.896306160573886 + lats[272] = 70.826007403271475 + lats[273] = 70.755708645881384 + lats[274] = 70.685409888404578 + lats[275] = 70.615111130841967 + lats[276] = 70.544812373194532 + lats[277] = 70.474513615463138 + lats[278] = 70.404214857648739 + lats[279] = 70.333916099752187 + lats[280] = 70.263617341774406 + lats[281] = 70.193318583716191 + lats[282] = 70.123019825578467 + lats[283] = 70.052721067362043 + lats[284] = 69.982422309067744 + lats[285] = 69.912123550696421 + lats[286] = 69.841824792248843 + lats[287] = 69.771526033725834 + lats[288] = 69.701227275128161 + lats[289] = 69.630928516456592 + lats[290] = 69.560629757711908 + lats[291] = 69.490330998894862 + lats[292] = 69.420032240006194 + lats[293] = 69.349733481046613 + lats[294] = 69.279434722016902 + lats[295] = 69.209135962917699 + lats[296] = 69.138837203749759 + lats[297] = 69.068538444513763 + lats[298] = 68.998239685210365 + lats[299] = 68.927940925840304 + lats[300] = 68.85764216640419 + lats[301] = 68.787343406902693 + lats[302] = 68.717044647336493 + lats[303] = 68.646745887706189 + lats[304] = 68.576447128012447 + lats[305] = 68.506148368255865 + lats[306] = 68.435849608437067 + lats[307] = 68.365550848556666 + lats[308] = 68.295252088615257 + lats[309] = 68.224953328613438 + lats[310] = 68.154654568551791 + lats[311] = 68.084355808430871 + lats[312] = 68.014057048251274 + lats[313] = 67.943758288013555 + lats[314] = 67.873459527718282 + lats[315] = 67.803160767365966 + lats[316] = 67.732862006957205 + lats[317] = 67.662563246492482 + lats[318] = 67.592264485972336 + lats[319] = 67.521965725397308 + lats[320] = 67.451666964767895 + lats[321] = 67.381368204084609 + lats[322] = 67.311069443347961 + lats[323] = 67.240770682558434 + lats[324] = 67.170471921716526 + lats[325] = 67.100173160822706 + lats[326] = 67.029874399877471 + lats[327] = 66.95957563888129 + lats[328] = 66.889276877834618 + lats[329] = 66.818978116737924 + lats[330] = 66.748679355591662 + lats[331] = 66.678380594396273 + lats[332] = 66.608081833152212 + lats[333] = 66.537783071859891 + lats[334] = 66.467484310519808 + lats[335] = 66.397185549132331 + lats[336] = 66.326886787697887 + lats[337] = 66.256588026216932 + lats[338] = 66.186289264689833 + lats[339] = 66.115990503117033 + lats[340] = 66.045691741498899 + lats[341] = 65.975392979835888 + lats[342] = 65.905094218128355 + lats[343] = 65.834795456376696 + lats[344] = 65.764496694581283 + lats[345] = 65.694197932742526 + lats[346] = 65.623899170860767 + lats[347] = 65.553600408936404 + lats[348] = 65.483301646969792 + lats[349] = 65.413002884961315 + lats[350] = 65.342704122911286 + lats[351] = 65.272405360820116 + lats[352] = 65.202106598688133 + lats[353] = 65.131807836515677 + lats[354] = 65.061509074303089 + lats[355] = 64.991210312050711 + lats[356] = 64.920911549758912 + lats[357] = 64.850612787427963 + lats[358] = 64.780314025058246 + lats[359] = 64.710015262650074 + lats[360] = 64.639716500203733 + lats[361] = 64.569417737719576 + lats[362] = 64.499118975197902 + lats[363] = 64.428820212639039 + lats[364] = 64.358521450043284 + lats[365] = 64.288222687410922 + lats[366] = 64.21792392474228 + lats[367] = 64.147625162037642 + lats[368] = 64.07732639929732 + lats[369] = 64.00702763652157 + lats[370] = 63.93672887371072 + lats[371] = 63.866430110865004 + lats[372] = 63.796131347984762 + lats[373] = 63.725832585070251 + lats[374] = 63.655533822121711 + lats[375] = 63.585235059139464 + lats[376] = 63.514936296123757 + lats[377] = 63.444637533074854 + lats[378] = 63.374338769993031 + lats[379] = 63.304040006878537 + lats[380] = 63.23374124373165 + lats[381] = 63.163442480552604 + lats[382] = 63.093143717341647 + lats[383] = 63.022844954099064 + lats[384] = 62.952546190825068 + lats[385] = 62.882247427519928 + lats[386] = 62.811948664183866 + lats[387] = 62.741649900817137 + lats[388] = 62.67135113741999 + lats[389] = 62.60105237399263 + lats[390] = 62.530753610535321 + lats[391] = 62.460454847048261 + lats[392] = 62.3901560835317 + lats[393] = 62.319857319985871 + lats[394] = 62.249558556410982 + lats[395] = 62.179259792807258 + lats[396] = 62.108961029174914 + lats[397] = 62.038662265514176 + lats[398] = 61.968363501825259 + lats[399] = 61.898064738108381 + lats[400] = 61.827765974363729 + lats[401] = 61.757467210591535 + lats[402] = 61.687168446791986 + lats[403] = 61.616869682965287 + lats[404] = 61.546570919111666 + lats[405] = 61.476272155231321 + lats[406] = 61.405973391324409 + lats[407] = 61.335674627391185 + lats[408] = 61.265375863431785 + lats[409] = 61.195077099446451 + lats[410] = 61.124778335435344 + lats[411] = 61.054479571398652 + lats[412] = 60.984180807336578 + lats[413] = 60.913882043249295 + lats[414] = 60.843583279137007 + lats[415] = 60.773284514999872 + lats[416] = 60.702985750838074 + lats[417] = 60.632686986651805 + lats[418] = 60.562388222441243 + lats[419] = 60.492089458206543 + lats[420] = 60.421790693947884 + lats[421] = 60.35149192966545 + lats[422] = 60.28119316535939 + lats[423] = 60.21089440102989 + lats[424] = 60.140595636677112 + lats[425] = 60.070296872301235 + lats[426] = 59.999998107902378 + lats[427] = 59.929699343480763 + lats[428] = 59.859400579036503 + lats[429] = 59.78910181456979 + lats[430] = 59.718803050080759 + lats[431] = 59.64850428556958 + lats[432] = 59.578205521036402 + lats[433] = 59.507906756481383 + lats[434] = 59.43760799190467 + lats[435] = 59.3673092273064 + lats[436] = 59.29701046268675 + lats[437] = 59.226711698045854 + lats[438] = 59.156412933383855 + lats[439] = 59.086114168700909 + lats[440] = 59.015815403997145 + lats[441] = 58.945516639272725 + lats[442] = 58.875217874527763 + lats[443] = 58.804919109762423 + lats[444] = 58.73462034497684 + lats[445] = 58.664321580171141 + lats[446] = 58.594022815345468 + lats[447] = 58.523724050499972 + lats[448] = 58.453425285634758 + lats[449] = 58.383126520749968 + lats[450] = 58.312827755845746 + lats[451] = 58.242528990922203 + lats[452] = 58.172230225979497 + lats[453] = 58.101931461017728 + lats[454] = 58.031632696037022 + lats[455] = 57.961333931037537 + lats[456] = 57.891035166019364 + lats[457] = 57.820736400982646 + lats[458] = 57.75043763592749 + lats[459] = 57.680138870854037 + lats[460] = 57.60984010576238 + lats[461] = 57.539541340652676 + lats[462] = 57.469242575525016 + lats[463] = 57.398943810379521 + lats[464] = 57.328645045216312 + lats[465] = 57.258346280035504 + lats[466] = 57.188047514837208 + lats[467] = 57.117748749621541 + lats[468] = 57.047449984388614 + lats[469] = 56.977151219138541 + lats[470] = 56.90685245387143 + lats[471] = 56.836553688587379 + lats[472] = 56.766254923286517 + lats[473] = 56.695956157968951 + lats[474] = 56.625657392634771 + lats[475] = 56.555358627284086 + lats[476] = 56.485059861917016 + lats[477] = 56.41476109653366 + lats[478] = 56.34446233113411 + lats[479] = 56.274163565718467 + lats[480] = 56.203864800286865 + lats[481] = 56.133566034839362 + lats[482] = 56.063267269376091 + lats[483] = 55.992968503897131 + lats[484] = 55.922669738402583 + lats[485] = 55.852370972892551 + lats[486] = 55.782072207367136 + lats[487] = 55.711773441826416 + lats[488] = 55.641474676270505 + lats[489] = 55.571175910699488 + lats[490] = 55.500877145113449 + lats[491] = 55.430578379512511 + lats[492] = 55.360279613896743 + lats[493] = 55.289980848266232 + lats[494] = 55.219682082621084 + lats[495] = 55.149383316961377 + lats[496] = 55.07908455128721 + lats[497] = 55.008785785598668 + lats[498] = 54.938487019895831 + lats[499] = 54.868188254178797 + lats[500] = 54.797889488447652 + lats[501] = 54.727590722702473 + lats[502] = 54.657291956943347 + lats[503] = 54.586993191170357 + lats[504] = 54.516694425383605 + lats[505] = 54.446395659583146 + lats[506] = 54.376096893769081 + lats[507] = 54.305798127941479 + lats[508] = 54.235499362100448 + lats[509] = 54.165200596246031 + lats[510] = 54.094901830378333 + lats[511] = 54.024603064497434 + lats[512] = 53.954304298603383 + lats[513] = 53.884005532696307 + lats[514] = 53.813706766776235 + lats[515] = 53.743408000843282 + lats[516] = 53.673109234897495 + lats[517] = 53.602810468938962 + lats[518] = 53.53251170296776 + lats[519] = 53.462212936983953 + lats[520] = 53.391914170987633 + lats[521] = 53.321615404978871 + lats[522] = 53.251316638957725 + lats[523] = 53.181017872924265 + lats[524] = 53.110719106878584 + lats[525] = 53.040420340820731 + lats[526] = 52.970121574750792 + lats[527] = 52.899822808668837 + lats[528] = 52.829524042574917 + lats[529] = 52.759225276469131 + lats[530] = 52.688926510351514 + lats[531] = 52.618627744222159 + lats[532] = 52.548328978081123 + lats[533] = 52.478030211928477 + lats[534] = 52.407731445764284 + lats[535] = 52.337432679588609 + lats[536] = 52.26713391340153 + lats[537] = 52.196835147203096 + lats[538] = 52.126536380993372 + lats[539] = 52.056237614772435 + lats[540] = 51.985938848540336 + lats[541] = 51.915640082297152 + lats[542] = 51.845341316042933 + lats[543] = 51.775042549777737 + lats[544] = 51.704743783501634 + lats[545] = 51.634445017214695 + lats[546] = 51.56414625091697 + lats[547] = 51.493847484608516 + lats[548] = 51.423548718289396 + lats[549] = 51.353249951959683 + lats[550] = 51.282951185619417 + lats[551] = 51.21265241926865 + lats[552] = 51.14235365290746 + lats[553] = 51.072054886535909 + lats[554] = 51.001756120154049 + lats[555] = 50.931457353761914 + lats[556] = 50.86115858735959 + lats[557] = 50.790859820947119 + lats[558] = 50.720561054524559 + lats[559] = 50.650262288091959 + lats[560] = 50.579963521649397 + lats[561] = 50.509664755196901 + lats[562] = 50.439365988734544 + lats[563] = 50.369067222262359 + lats[564] = 50.298768455780426 + lats[565] = 50.228469689288779 + lats[566] = 50.158170922787484 + lats[567] = 50.087872156276575 + lats[568] = 50.017573389756123 + lats[569] = 49.947274623226157 + lats[570] = 49.876975856686762 + lats[571] = 49.80667709013796 + lats[572] = 49.736378323579807 + lats[573] = 49.66607955701236 + lats[574] = 49.595780790435676 + lats[575] = 49.525482023849783 + lats[576] = 49.455183257254745 + lats[577] = 49.384884490650613 + lats[578] = 49.314585724037435 + lats[579] = 49.244286957415234 + lats[580] = 49.173988190784094 + lats[581] = 49.103689424144044 + lats[582] = 49.03339065749514 + lats[583] = 48.963091890837418 + lats[584] = 48.892793124170929 + lats[585] = 48.822494357495721 + lats[586] = 48.752195590811837 + lats[587] = 48.681896824119335 + lats[588] = 48.611598057418242 + lats[589] = 48.541299290708608 + lats[590] = 48.47100052399049 + lats[591] = 48.400701757263917 + lats[592] = 48.330402990528938 + lats[593] = 48.260104223785596 + lats[594] = 48.189805457033941 + lats[595] = 48.119506690274015 + lats[596] = 48.049207923505868 + lats[597] = 47.978909156729507 + lats[598] = 47.908610389945018 + lats[599] = 47.838311623152421 + lats[600] = 47.76801285635176 + lats[601] = 47.697714089543084 + lats[602] = 47.627415322726435 + lats[603] = 47.557116555901828 + lats[604] = 47.486817789069342 + lats[605] = 47.416519022228997 + lats[606] = 47.346220255380835 + lats[607] = 47.275921488524894 + lats[608] = 47.205622721661214 + lats[609] = 47.13532395478984 + lats[610] = 47.065025187910805 + lats[611] = 46.994726421024154 + lats[612] = 46.924427654129929 + lats[613] = 46.85412888722815 + lats[614] = 46.783830120318882 + lats[615] = 46.713531353402139 + lats[616] = 46.643232586477971 + lats[617] = 46.572933819546414 + lats[618] = 46.502635052607502 + lats[619] = 46.432336285661272 + lats[620] = 46.362037518707766 + lats[621] = 46.291738751747012 + lats[622] = 46.221439984779053 + lats[623] = 46.151141217803925 + lats[624] = 46.080842450821663 + lats[625] = 46.01054368383231 + lats[626] = 45.94024491683588 + lats[627] = 45.869946149832437 + lats[628] = 45.799647382821995 + lats[629] = 45.729348615804589 + lats[630] = 45.659049848780263 + lats[631] = 45.588751081749038 + lats[632] = 45.51845231471097 + lats[633] = 45.448153547666081 + lats[634] = 45.377854780614399 + lats[635] = 45.30755601355596 + lats[636] = 45.237257246490813 + lats[637] = 45.166958479418959 + lats[638] = 45.096659712340461 + lats[639] = 45.026360945255341 + lats[640] = 44.956062178163634 + lats[641] = 44.885763411065362 + lats[642] = 44.81546464396056 + lats[643] = 44.745165876849271 + lats[644] = 44.674867109731515 + lats[645] = 44.604568342607337 + lats[646] = 44.534269575476756 + lats[647] = 44.463970808339802 + lats[648] = 44.39367204119651 + lats[649] = 44.323373274046915 + lats[650] = 44.253074506891046 + lats[651] = 44.182775739728925 + lats[652] = 44.112476972560586 + lats[653] = 44.042178205386072 + lats[654] = 43.971879438205391 + lats[655] = 43.9015806710186 + lats[656] = 43.831281903825705 + lats[657] = 43.760983136626741 + lats[658] = 43.690684369421732 + lats[659] = 43.620385602210717 + lats[660] = 43.550086834993728 + lats[661] = 43.479788067770777 + lats[662] = 43.409489300541907 + lats[663] = 43.339190533307139 + lats[664] = 43.26889176606651 + lats[665] = 43.19859299882004 + lats[666] = 43.128294231567757 + lats[667] = 43.057995464309691 + lats[668] = 42.987696697045862 + lats[669] = 42.917397929776307 + lats[670] = 42.847099162501053 + lats[671] = 42.776800395220121 + lats[672] = 42.706501627933541 + lats[673] = 42.63620286064134 + lats[674] = 42.565904093343548 + lats[675] = 42.495605326040177 + lats[676] = 42.425306558731272 + lats[677] = 42.355007791416853 + lats[678] = 42.284709024096927 + lats[679] = 42.214410256771551 + lats[680] = 42.144111489440725 + lats[681] = 42.073812722104492 + lats[682] = 42.003513954762873 + lats[683] = 41.933215187415882 + lats[684] = 41.862916420063563 + lats[685] = 41.792617652705921 + lats[686] = 41.722318885343 + lats[687] = 41.6520201179748 + lats[688] = 41.581721350601363 + lats[689] = 41.511422583222718 + lats[690] = 41.441123815838885 + lats[691] = 41.370825048449873 + lats[692] = 41.300526281055724 + lats[693] = 41.230227513656445 + lats[694] = 41.159928746252085 + lats[695] = 41.089629978842645 + lats[696] = 41.01933121142816 + lats[697] = 40.949032444008644 + lats[698] = 40.878733676584126 + lats[699] = 40.808434909154634 + lats[700] = 40.738136141720176 + lats[701] = 40.667837374280786 + lats[702] = 40.597538606836487 + lats[703] = 40.527239839387299 + lats[704] = 40.456941071933244 + lats[705] = 40.386642304474343 + lats[706] = 40.316343537010617 + lats[707] = 40.246044769542102 + lats[708] = 40.175746002068806 + lats[709] = 40.105447234590748 + lats[710] = 40.035148467107952 + lats[711] = 39.964849699620437 + lats[712] = 39.894550932128247 + lats[713] = 39.824252164631375 + lats[714] = 39.753953397129855 + lats[715] = 39.683654629623703 + lats[716] = 39.613355862112947 + lats[717] = 39.543057094597607 + lats[718] = 39.472758327077692 + lats[719] = 39.402459559553229 + lats[720] = 39.332160792024254 + lats[721] = 39.261862024490775 + lats[722] = 39.191563256952804 + lats[723] = 39.121264489410365 + lats[724] = 39.050965721863491 + lats[725] = 38.980666954312184 + lats[726] = 38.910368186756479 + lats[727] = 38.840069419196389 + lats[728] = 38.769770651631937 + lats[729] = 38.699471884063136 + lats[730] = 38.629173116490001 + lats[731] = 38.558874348912568 + lats[732] = 38.488575581330842 + lats[733] = 38.418276813744846 + lats[734] = 38.347978046154608 + lats[735] = 38.277679278560143 + lats[736] = 38.20738051096145 + lats[737] = 38.137081743358586 + lats[738] = 38.066782975751536 + lats[739] = 37.99648420814033 + lats[740] = 37.926185440524989 + lats[741] = 37.855886672905527 + lats[742] = 37.785587905281965 + lats[743] = 37.715289137654317 + lats[744] = 37.644990370022605 + lats[745] = 37.574691602386856 + lats[746] = 37.504392834747065 + lats[747] = 37.434094067103274 + lats[748] = 37.363795299455489 + lats[749] = 37.293496531803719 + lats[750] = 37.223197764147997 + lats[751] = 37.152898996488332 + lats[752] = 37.082600228824752 + lats[753] = 37.012301461157264 + lats[754] = 36.942002693485883 + lats[755] = 36.871703925810628 + lats[756] = 36.801405158131523 + lats[757] = 36.731106390448581 + lats[758] = 36.660807622761808 + lats[759] = 36.590508855071242 + lats[760] = 36.520210087376888 + lats[761] = 36.449911319678755 + lats[762] = 36.379612551976876 + lats[763] = 36.309313784271254 + lats[764] = 36.239015016561908 + lats[765] = 36.16871624884886 + lats[766] = 36.098417481132117 + lats[767] = 36.028118713411708 + lats[768] = 35.957819945687639 + lats[769] = 35.887521177959933 + lats[770] = 35.817222410228595 + lats[771] = 35.746923642493655 + lats[772] = 35.676624874755113 + lats[773] = 35.606326107012997 + lats[774] = 35.536027339267314 + lats[775] = 35.465728571518085 + lats[776] = 35.395429803765317 + lats[777] = 35.325131036009047 + lats[778] = 35.254832268249267 + lats[779] = 35.184533500486005 + lats[780] = 35.114234732719261 + lats[781] = 35.043935964949064 + lats[782] = 34.973637197175435 + lats[783] = 34.903338429398374 + lats[784] = 34.833039661617903 + lats[785] = 34.762740893834028 + lats[786] = 34.692442126046771 + lats[787] = 34.622143358256153 + lats[788] = 34.551844590462188 + lats[789] = 34.481545822664863 + lats[790] = 34.411247054864234 + lats[791] = 34.340948287060286 + lats[792] = 34.270649519253041 + lats[793] = 34.200350751442521 + lats[794] = 34.130051983628725 + lats[795] = 34.059753215811682 + lats[796] = 33.989454447991392 + lats[797] = 33.919155680167876 + lats[798] = 33.848856912341155 + lats[799] = 33.778558144511237 + lats[800] = 33.708259376678136 + lats[801] = 33.637960608841851 + lats[802] = 33.567661841002426 + lats[803] = 33.497363073159853 + lats[804] = 33.42706430531414 + lats[805] = 33.356765537465314 + lats[806] = 33.286466769613391 + lats[807] = 33.216168001758369 + lats[808] = 33.145869233900278 + lats[809] = 33.075570466039117 + lats[810] = 33.005271698174909 + lats[811] = 32.934972930307666 + lats[812] = 32.864674162437396 + lats[813] = 32.794375394564113 + lats[814] = 32.724076626687825 + lats[815] = 32.653777858808567 + lats[816] = 32.583479090926325 + lats[817] = 32.513180323041112 + lats[818] = 32.442881555152965 + lats[819] = 32.372582787261891 + lats[820] = 32.302284019367875 + lats[821] = 32.231985251470959 + lats[822] = 32.161686483571145 + lats[823] = 32.091387715668439 + lats[824] = 32.021088947762863 + lats[825] = 31.950790179854422 + lats[826] = 31.880491411943137 + lats[827] = 31.810192644029012 + lats[828] = 31.739893876112063 + lats[829] = 31.669595108192297 + lats[830] = 31.599296340269738 + lats[831] = 31.528997572344384 + lats[832] = 31.458698804416255 + lats[833] = 31.388400036485361 + lats[834] = 31.318101268551715 + lats[835] = 31.247802500615318 + lats[836] = 31.177503732676204 + lats[837] = 31.107204964734358 + lats[838] = 31.036906196789811 + lats[839] = 30.966607428842572 + lats[840] = 30.896308660892647 + lats[841] = 30.826009892940046 + lats[842] = 30.755711124984781 + lats[843] = 30.685412357026873 + lats[844] = 30.615113589066322 + lats[845] = 30.544814821103138 + lats[846] = 30.47451605313735 + lats[847] = 30.404217285168947 + lats[848] = 30.333918517197947 + lats[849] = 30.263619749224372 + lats[850] = 30.19332098124822 + lats[851] = 30.123022213269511 + lats[852] = 30.052723445288244 + lats[853] = 29.98242467730444 + lats[854] = 29.91212590931811 + lats[855] = 29.841827141329258 + lats[856] = 29.771528373337894 + lats[857] = 29.701229605344039 + lats[858] = 29.630930837347698 + lats[859] = 29.560632069348884 + lats[860] = 29.490333301347597 + lats[861] = 29.420034533343859 + lats[862] = 29.349735765337677 + lats[863] = 29.279436997329057 + lats[864] = 29.209138229318015 + lats[865] = 29.138839461304556 + lats[866] = 29.068540693288696 + lats[867] = 28.998241925270449 + lats[868] = 28.927943157249814 + lats[869] = 28.857644389226806 + lats[870] = 28.787345621201432 + lats[871] = 28.717046853173709 + lats[872] = 28.646748085143642 + lats[873] = 28.576449317111244 + lats[874] = 28.506150549076519 + lats[875] = 28.435851781039485 + lats[876] = 28.365553013000145 + lats[877] = 28.29525424495851 + lats[878] = 28.224955476914594 + lats[879] = 28.154656708868405 + lats[880] = 28.084357940819952 + lats[881] = 28.014059172769244 + lats[882] = 27.94376040471629 + lats[883] = 27.873461636661098 + lats[884] = 27.803162868603682 + lats[885] = 27.732864100544052 + lats[886] = 27.662565332482213 + lats[887] = 27.592266564418171 + lats[888] = 27.521967796351948 + lats[889] = 27.451669028283543 + lats[890] = 27.381370260212968 + lats[891] = 27.311071492140236 + lats[892] = 27.240772724065348 + lats[893] = 27.170473955988321 + lats[894] = 27.100175187909159 + lats[895] = 27.029876419827872 + lats[896] = 26.959577651744471 + lats[897] = 26.889278883658971 + lats[898] = 26.818980115571364 + lats[899] = 26.748681347481678 + lats[900] = 26.678382579389908 + lats[901] = 26.608083811296069 + lats[902] = 26.53778504320017 + lats[903] = 26.467486275102218 + lats[904] = 26.397187507002222 + lats[905] = 26.326888738900195 + lats[906] = 26.256589970796135 + lats[907] = 26.186291202690064 + lats[908] = 26.115992434581983 + lats[909] = 26.045693666471902 + lats[910] = 25.975394898359827 + lats[911] = 25.90509613024577 + lats[912] = 25.834797362129745 + lats[913] = 25.764498594011751 + lats[914] = 25.694199825891793 + lats[915] = 25.623901057769892 + lats[916] = 25.553602289646051 + lats[917] = 25.483303521520277 + lats[918] = 25.413004753392578 + lats[919] = 25.342705985262967 + lats[920] = 25.272407217131445 + lats[921] = 25.202108448998025 + lats[922] = 25.13180968086272 + lats[923] = 25.061510912725527 + lats[924] = 24.991212144586456 + lats[925] = 24.920913376445526 + lats[926] = 24.850614608302738 + lats[927] = 24.780315840158096 + lats[928] = 24.710017072011613 + lats[929] = 24.639718303863294 + lats[930] = 24.569419535713152 + lats[931] = 24.499120767561195 + lats[932] = 24.428821999407425 + lats[933] = 24.358523231251851 + lats[934] = 24.288224463094483 + lats[935] = 24.217925694935328 + lats[936] = 24.1476269267744 + lats[937] = 24.077328158611696 + lats[938] = 24.007029390447226 + lats[939] = 23.936730622281004 + lats[940] = 23.866431854113038 + lats[941] = 23.796133085943328 + lats[942] = 23.725834317771888 + lats[943] = 23.655535549598721 + lats[944] = 23.585236781423838 + lats[945] = 23.514938013247242 + lats[946] = 23.444639245068949 + lats[947] = 23.374340476888957 + lats[948] = 23.304041708707278 + lats[949] = 23.233742940523921 + lats[950] = 23.163444172338895 + lats[951] = 23.0931454041522 + lats[952] = 23.022846635963852 + lats[953] = 22.952547867773848 + lats[954] = 22.882249099582204 + lats[955] = 22.811950331388925 + lats[956] = 22.741651563194019 + lats[957] = 22.671352794997489 + lats[958] = 22.60105402679935 + lats[959] = 22.530755258599601 + lats[960] = 22.460456490398254 + lats[961] = 22.390157722195315 + lats[962] = 22.319858953990789 + lats[963] = 22.249560185784691 + lats[964] = 22.179261417577013 + lats[965] = 22.108962649367779 + lats[966] = 22.038663881156989 + lats[967] = 21.968365112944642 + lats[968] = 21.898066344730758 + lats[969] = 21.827767576515338 + lats[970] = 21.757468808298391 + lats[971] = 21.687170040079913 + lats[972] = 21.616871271859928 + lats[973] = 21.546572503638437 + lats[974] = 21.47627373541544 + lats[975] = 21.40597496719095 + lats[976] = 21.335676198964972 + lats[977] = 21.265377430737512 + lats[978] = 21.195078662508585 + lats[979] = 21.124779894278181 + lats[980] = 21.054481126046323 + lats[981] = 20.984182357813012 + lats[982] = 20.913883589578251 + lats[983] = 20.843584821342048 + lats[984] = 20.773286053104417 + lats[985] = 20.702987284865355 + lats[986] = 20.632688516624874 + lats[987] = 20.562389748382977 + lats[988] = 20.492090980139672 + lats[989] = 20.421792211894967 + lats[990] = 20.35149344364887 + lats[991] = 20.28119467540138 + lats[992] = 20.210895907152516 + lats[993] = 20.140597138902272 + lats[994] = 20.070298370650661 + lats[995] = 19.999999602397686 + lats[996] = 19.929700834143357 + lats[997] = 19.859402065887682 + lats[998] = 19.789103297630657 + lats[999] = 19.718804529372303 + lats[1000] = 19.648505761112613 + lats[1001] = 19.578206992851602 + lats[1002] = 19.507908224589269 + lats[1003] = 19.437609456325632 + lats[1004] = 19.367310688060684 + lats[1005] = 19.297011919794439 + lats[1006] = 19.226713151526898 + lats[1007] = 19.15641438325807 + lats[1008] = 19.086115614987968 + lats[1009] = 19.015816846716586 + lats[1010] = 18.945518078443939 + lats[1011] = 18.875219310170031 + lats[1012] = 18.804920541894862 + lats[1013] = 18.734621773618446 + lats[1014] = 18.664323005340787 + lats[1015] = 18.594024237061891 + lats[1016] = 18.523725468781763 + lats[1017] = 18.453426700500408 + lats[1018] = 18.383127932217832 + lats[1019] = 18.312829163934047 + lats[1020] = 18.242530395649048 + lats[1021] = 18.172231627362851 + lats[1022] = 18.101932859075458 + lats[1023] = 18.031634090786874 + lats[1024] = 17.96133532249711 + lats[1025] = 17.89103655420616 + lats[1026] = 17.820737785914044 + lats[1027] = 17.75043901762076 + lats[1028] = 17.680140249326314 + lats[1029] = 17.60984148103071 + lats[1030] = 17.539542712733962 + lats[1031] = 17.469243944436066 + lats[1032] = 17.39894517613704 + lats[1033] = 17.328646407836878 + lats[1034] = 17.258347639535586 + lats[1035] = 17.188048871233182 + lats[1036] = 17.117750102929655 + lats[1037] = 17.04745133462502 + lats[1038] = 16.977152566319283 + lats[1039] = 16.906853798012452 + lats[1040] = 16.836555029704527 + lats[1041] = 16.766256261395515 + lats[1042] = 16.69595749308542 + lats[1043] = 16.625658724774254 + lats[1044] = 16.555359956462013 + lats[1045] = 16.485061188148713 + lats[1046] = 16.41476241983435 + lats[1047] = 16.344463651518936 + lats[1048] = 16.274164883202477 + lats[1049] = 16.203866114884974 + lats[1050] = 16.133567346566434 + lats[1051] = 16.063268578246863 + lats[1052] = 15.992969809926265 + lats[1053] = 15.922671041604652 + lats[1054] = 15.852372273282016 + lats[1055] = 15.78207350495838 + lats[1056] = 15.711774736633735 + lats[1057] = 15.641475968308091 + lats[1058] = 15.571177199981456 + lats[1059] = 15.500878431653829 + lats[1060] = 15.430579663325226 + lats[1061] = 15.360280894995643 + lats[1062] = 15.289982126665089 + lats[1063] = 15.219683358333569 + lats[1064] = 15.149384590001089 + lats[1065] = 15.07908582166765 + lats[1066] = 15.008787053333259 + lats[1067] = 14.938488284997929 + lats[1068] = 14.868189516661655 + lats[1069] = 14.797890748324447 + lats[1070] = 14.727591979986309 + lats[1071] = 14.657293211647247 + lats[1072] = 14.586994443307265 + lats[1073] = 14.516695674966371 + lats[1074] = 14.446396906624567 + lats[1075] = 14.376098138281863 + lats[1076] = 14.305799369938256 + lats[1077] = 14.23550060159376 + lats[1078] = 14.165201833248371 + lats[1079] = 14.0949030649021 + lats[1080] = 14.024604296554955 + lats[1081] = 13.954305528206934 + lats[1082] = 13.884006759858046 + lats[1083] = 13.813707991508297 + lats[1084] = 13.743409223157688 + lats[1085] = 13.673110454806226 + lats[1086] = 13.602811686453919 + lats[1087] = 13.532512918100766 + lats[1088] = 13.46221414974678 + lats[1089] = 13.391915381391959 + lats[1090] = 13.32161661303631 + lats[1091] = 13.251317844679837 + lats[1092] = 13.181019076322551 + lats[1093] = 13.110720307964451 + lats[1094] = 13.040421539605545 + lats[1095] = 12.970122771245832 + lats[1096] = 12.899824002885323 + lats[1097] = 12.829525234524022 + lats[1098] = 12.759226466161934 + lats[1099] = 12.688927697799061 + lats[1100] = 12.618628929435411 + lats[1101] = 12.548330161070988 + lats[1102] = 12.478031392705796 + lats[1103] = 12.407732624339841 + lats[1104] = 12.337433855973126 + lats[1105] = 12.267135087605659 + lats[1106] = 12.196836319237443 + lats[1107] = 12.126537550868482 + lats[1108] = 12.056238782498781 + lats[1109] = 11.985940014128348 + lats[1110] = 11.915641245757183 + lats[1111] = 11.845342477385294 + lats[1112] = 11.775043709012685 + lats[1113] = 11.704744940639358 + lats[1114] = 11.634446172265324 + lats[1115] = 11.564147403890583 + lats[1116] = 11.493848635515141 + lats[1117] = 11.423549867139002 + lats[1118] = 11.35325109876217 + lats[1119] = 11.282952330384653 + lats[1120] = 11.212653562006453 + lats[1121] = 11.142354793627575 + lats[1122] = 11.072056025248026 + lats[1123] = 11.001757256867807 + lats[1124] = 10.931458488486923 + lats[1125] = 10.861159720105382 + lats[1126] = 10.790860951723188 + lats[1127] = 10.720562183340341 + lats[1128] = 10.65026341495685 + lats[1129] = 10.579964646572719 + lats[1130] = 10.509665878187954 + lats[1131] = 10.439367109802557 + lats[1132] = 10.369068341416533 + lats[1133] = 10.298769573029887 + lats[1134] = 10.228470804642624 + lats[1135] = 10.158172036254747 + lats[1136] = 10.087873267866264 + lats[1137] = 10.017574499477174 + lats[1138] = 9.9472757310874869 + lats[1139] = 9.8769769626972046 + lats[1140] = 9.8066781943063344 + lats[1141] = 9.7363794259148779 + lats[1142] = 9.6660806575228388 + lats[1143] = 9.5957818891302242 + lats[1144] = 9.5254831207370376 + lats[1145] = 9.4551843523432826 + lats[1146] = 9.3848855839489662 + lats[1147] = 9.3145868155540921 + lats[1148] = 9.2442880471586619 + lats[1149] = 9.1739892787626829 + lats[1150] = 9.1036905103661585 + lats[1151] = 9.0333917419690941 + lats[1152] = 8.963092973571495 + lats[1153] = 8.8927942051733631 + lats[1154] = 8.8224954367747017 + lats[1155] = 8.7521966683755217 + lats[1156] = 8.6818978999758194 + lats[1157] = 8.6115991315756055 + lats[1158] = 8.5413003631748801 + lats[1159] = 8.4710015947736537 + lats[1160] = 8.4007028263719228 + lats[1161] = 8.3304040579696963 + lats[1162] = 8.2601052895669778 + lats[1163] = 8.1898065211637725 + lats[1164] = 8.1195077527600841 + lats[1165] = 8.049208984355916 + lats[1166] = 7.9789102159512737 + lats[1167] = 7.9086114475461606 + lats[1168] = 7.8383126791405831 + lats[1169] = 7.7680139107345463 + lats[1170] = 7.6977151423280494 + lats[1171] = 7.6274163739210996 + lats[1172] = 7.557117605513703 + lats[1173] = 7.4868188371058624 + lats[1174] = 7.4165200686975803 + lats[1175] = 7.3462213002888648 + lats[1176] = 7.2759225318797176 + lats[1177] = 7.2056237634701441 + lats[1178] = 7.1353249950601469 + lats[1179] = 7.0650262266497315 + lats[1180] = 6.994727458238903 + lats[1181] = 6.924428689827665 + lats[1182] = 6.8541299214160212 + lats[1183] = 6.7838311530039768 + lats[1184] = 6.7135323845915353 + lats[1185] = 6.6432336161787013 + lats[1186] = 6.5729348477654792 + lats[1187] = 6.5026360793518734 + lats[1188] = 6.4323373109378874 + lats[1189] = 6.3620385425235257 + lats[1190] = 6.2917397741087928 + lats[1191] = 6.2214410056936931 + lats[1192] = 6.151142237278231 + lats[1193] = 6.0808434688624091 + lats[1194] = 6.0105447004462347 + lats[1195] = 5.9402459320297085 + lats[1196] = 5.869947163612836 + lats[1197] = 5.7996483951956233 + lats[1198] = 5.729349626778073 + lats[1199] = 5.6590508583601888 + lats[1200] = 5.5887520899419751 + lats[1201] = 5.5184533215234373 + lats[1202] = 5.4481545531045787 + lats[1203] = 5.3778557846854023 + lats[1204] = 5.3075570162659149 + lats[1205] = 5.2372582478461194 + lats[1206] = 5.1669594794260192 + lats[1207] = 5.0966607110056197 + lats[1208] = 5.0263619425849244 + lats[1209] = 4.9560631741639369 + lats[1210] = 4.8857644057426626 + lats[1211] = 4.8154656373211049 + lats[1212] = 4.7451668688992683 + lats[1213] = 4.6748681004771564 + lats[1214] = 4.6045693320547736 + lats[1215] = 4.5342705636321252 + lats[1216] = 4.4639717952092139 + lats[1217] = 4.3936730267860451 + lats[1218] = 4.3233742583626205 + lats[1219] = 4.2530754899389471 + lats[1220] = 4.1827767215150269 + lats[1221] = 4.1124779530908659 + lats[1222] = 4.0421791846664661 + lats[1223] = 3.9718804162418326 + lats[1224] = 3.90158164781697 + lats[1225] = 3.8312828793918823 + lats[1226] = 3.7609841109665734 + lats[1227] = 3.6906853425410477 + lats[1228] = 3.6203865741153085 + lats[1229] = 3.5500878056893601 + lats[1230] = 3.4797890372632065 + lats[1231] = 3.4094902688368531 + lats[1232] = 3.339191500410303 + lats[1233] = 3.2688927319835597 + lats[1234] = 3.1985939635566285 + lats[1235] = 3.1282951951295126 + lats[1236] = 3.0579964267022164 + lats[1237] = 2.9876976582747439 + lats[1238] = 2.9173988898470999 + lats[1239] = 2.8471001214192873 + lats[1240] = 2.7768013529913107 + lats[1241] = 2.7065025845631743 + lats[1242] = 2.6362038161348824 + lats[1243] = 2.5659050477064382 + lats[1244] = 2.4956062792778466 + lats[1245] = 2.4253075108491116 + lats[1246] = 2.3550087424202366 + lats[1247] = 2.2847099739912267 + lats[1248] = 2.2144112055620848 + lats[1249] = 2.1441124371328155 + lats[1250] = 2.0738136687034232 + lats[1251] = 2.0035149002739114 + lats[1252] = 1.9332161318442849 + lats[1253] = 1.8629173634145471 + lats[1254] = 1.792618594984702 + lats[1255] = 1.7223198265547539 + lats[1256] = 1.6520210581247066 + lats[1257] = 1.5817222896945646 + lats[1258] = 1.5114235212643317 + lats[1259] = 1.4411247528340119 + lats[1260] = 1.3708259844036093 + lats[1261] = 1.300527215973128 + lats[1262] = 1.2302284475425722 + lats[1263] = 1.1599296791119456 + lats[1264] = 1.0896309106812523 + lats[1265] = 1.0193321422504964 + lats[1266] = 0.949033373819682 + lats[1267] = 0.87873460538881287 + lats[1268] = 0.80843583695789356 + lats[1269] = 0.73813706852692773 + lats[1270] = 0.66783830009591949 + lats[1271] = 0.59753953166487306 + lats[1272] = 0.52724076323379232 + lats[1273] = 0.45694199480268116 + lats[1274] = 0.3866432263715438 + lats[1275] = 0.31634445794038429 + lats[1276] = 0.24604568950920663 + lats[1277] = 0.17574692107801482 + lats[1278] = 0.10544815264681295 + lats[1279] = 0.035149384215604956 + lats[1280] = -0.035149384215604956 + lats[1281] = -0.10544815264681295 + lats[1282] = -0.17574692107801482 + lats[1283] = -0.24604568950920663 + lats[1284] = -0.31634445794038429 + lats[1285] = -0.3866432263715438 + lats[1286] = -0.45694199480268116 + lats[1287] = -0.52724076323379232 + lats[1288] = -0.59753953166487306 + lats[1289] = -0.66783830009591949 + lats[1290] = -0.73813706852692773 + lats[1291] = -0.80843583695789356 + lats[1292] = -0.87873460538881287 + lats[1293] = -0.949033373819682 + lats[1294] = -1.0193321422504964 + lats[1295] = -1.0896309106812523 + lats[1296] = -1.1599296791119456 + lats[1297] = -1.2302284475425722 + lats[1298] = -1.300527215973128 + lats[1299] = -1.3708259844036093 + lats[1300] = -1.4411247528340119 + lats[1301] = -1.5114235212643317 + lats[1302] = -1.5817222896945646 + lats[1303] = -1.6520210581247066 + lats[1304] = -1.7223198265547539 + lats[1305] = -1.792618594984702 + lats[1306] = -1.8629173634145471 + lats[1307] = -1.9332161318442849 + lats[1308] = -2.0035149002739114 + lats[1309] = -2.0738136687034232 + lats[1310] = -2.1441124371328155 + lats[1311] = -2.2144112055620848 + lats[1312] = -2.2847099739912267 + lats[1313] = -2.3550087424202366 + lats[1314] = -2.4253075108491116 + lats[1315] = -2.4956062792778466 + lats[1316] = -2.5659050477064382 + lats[1317] = -2.6362038161348824 + lats[1318] = -2.7065025845631743 + lats[1319] = -2.7768013529913107 + lats[1320] = -2.8471001214192873 + lats[1321] = -2.9173988898470999 + lats[1322] = -2.9876976582747439 + lats[1323] = -3.0579964267022164 + lats[1324] = -3.1282951951295126 + lats[1325] = -3.1985939635566285 + lats[1326] = -3.2688927319835597 + lats[1327] = -3.339191500410303 + lats[1328] = -3.4094902688368531 + lats[1329] = -3.4797890372632065 + lats[1330] = -3.5500878056893601 + lats[1331] = -3.6203865741153085 + lats[1332] = -3.6906853425410477 + lats[1333] = -3.7609841109665734 + lats[1334] = -3.8312828793918823 + lats[1335] = -3.90158164781697 + lats[1336] = -3.9718804162418326 + lats[1337] = -4.0421791846664661 + lats[1338] = -4.1124779530908659 + lats[1339] = -4.1827767215150269 + lats[1340] = -4.2530754899389471 + lats[1341] = -4.3233742583626205 + lats[1342] = -4.3936730267860451 + lats[1343] = -4.4639717952092139 + lats[1344] = -4.5342705636321252 + lats[1345] = -4.6045693320547736 + lats[1346] = -4.6748681004771564 + lats[1347] = -4.7451668688992683 + lats[1348] = -4.8154656373211049 + lats[1349] = -4.8857644057426626 + lats[1350] = -4.9560631741639369 + lats[1351] = -5.0263619425849244 + lats[1352] = -5.0966607110056197 + lats[1353] = -5.1669594794260192 + lats[1354] = -5.2372582478461194 + lats[1355] = -5.3075570162659149 + lats[1356] = -5.3778557846854023 + lats[1357] = -5.4481545531045787 + lats[1358] = -5.5184533215234373 + lats[1359] = -5.5887520899419751 + lats[1360] = -5.6590508583601888 + lats[1361] = -5.729349626778073 + lats[1362] = -5.7996483951956233 + lats[1363] = -5.869947163612836 + lats[1364] = -5.9402459320297085 + lats[1365] = -6.0105447004462347 + lats[1366] = -6.0808434688624091 + lats[1367] = -6.151142237278231 + lats[1368] = -6.2214410056936931 + lats[1369] = -6.2917397741087928 + lats[1370] = -6.3620385425235257 + lats[1371] = -6.4323373109378874 + lats[1372] = -6.5026360793518734 + lats[1373] = -6.5729348477654792 + lats[1374] = -6.6432336161787013 + lats[1375] = -6.7135323845915353 + lats[1376] = -6.7838311530039768 + lats[1377] = -6.8541299214160212 + lats[1378] = -6.924428689827665 + lats[1379] = -6.994727458238903 + lats[1380] = -7.0650262266497315 + lats[1381] = -7.1353249950601469 + lats[1382] = -7.2056237634701441 + lats[1383] = -7.2759225318797176 + lats[1384] = -7.3462213002888648 + lats[1385] = -7.4165200686975803 + lats[1386] = -7.4868188371058624 + lats[1387] = -7.557117605513703 + lats[1388] = -7.6274163739210996 + lats[1389] = -7.6977151423280494 + lats[1390] = -7.7680139107345463 + lats[1391] = -7.8383126791405831 + lats[1392] = -7.9086114475461606 + lats[1393] = -7.9789102159512737 + lats[1394] = -8.049208984355916 + lats[1395] = -8.1195077527600841 + lats[1396] = -8.1898065211637725 + lats[1397] = -8.2601052895669778 + lats[1398] = -8.3304040579696963 + lats[1399] = -8.4007028263719228 + lats[1400] = -8.4710015947736537 + lats[1401] = -8.5413003631748801 + lats[1402] = -8.6115991315756055 + lats[1403] = -8.6818978999758194 + lats[1404] = -8.7521966683755217 + lats[1405] = -8.8224954367747017 + lats[1406] = -8.8927942051733631 + lats[1407] = -8.963092973571495 + lats[1408] = -9.0333917419690941 + lats[1409] = -9.1036905103661585 + lats[1410] = -9.1739892787626829 + lats[1411] = -9.2442880471586619 + lats[1412] = -9.3145868155540921 + lats[1413] = -9.3848855839489662 + lats[1414] = -9.4551843523432826 + lats[1415] = -9.5254831207370376 + lats[1416] = -9.5957818891302242 + lats[1417] = -9.6660806575228388 + lats[1418] = -9.7363794259148779 + lats[1419] = -9.8066781943063344 + lats[1420] = -9.8769769626972046 + lats[1421] = -9.9472757310874869 + lats[1422] = -10.017574499477174 + lats[1423] = -10.087873267866264 + lats[1424] = -10.158172036254747 + lats[1425] = -10.228470804642624 + lats[1426] = -10.298769573029887 + lats[1427] = -10.369068341416533 + lats[1428] = -10.439367109802557 + lats[1429] = -10.509665878187954 + lats[1430] = -10.579964646572719 + lats[1431] = -10.65026341495685 + lats[1432] = -10.720562183340341 + lats[1433] = -10.790860951723188 + lats[1434] = -10.861159720105382 + lats[1435] = -10.931458488486923 + lats[1436] = -11.001757256867807 + lats[1437] = -11.072056025248026 + lats[1438] = -11.142354793627575 + lats[1439] = -11.212653562006453 + lats[1440] = -11.282952330384653 + lats[1441] = -11.35325109876217 + lats[1442] = -11.423549867139002 + lats[1443] = -11.493848635515141 + lats[1444] = -11.564147403890583 + lats[1445] = -11.634446172265324 + lats[1446] = -11.704744940639358 + lats[1447] = -11.775043709012685 + lats[1448] = -11.845342477385294 + lats[1449] = -11.915641245757183 + lats[1450] = -11.985940014128348 + lats[1451] = -12.056238782498781 + lats[1452] = -12.126537550868482 + lats[1453] = -12.196836319237443 + lats[1454] = -12.267135087605659 + lats[1455] = -12.337433855973126 + lats[1456] = -12.407732624339841 + lats[1457] = -12.478031392705796 + lats[1458] = -12.548330161070988 + lats[1459] = -12.618628929435411 + lats[1460] = -12.688927697799061 + lats[1461] = -12.759226466161934 + lats[1462] = -12.829525234524022 + lats[1463] = -12.899824002885323 + lats[1464] = -12.970122771245832 + lats[1465] = -13.040421539605545 + lats[1466] = -13.110720307964451 + lats[1467] = -13.181019076322551 + lats[1468] = -13.251317844679837 + lats[1469] = -13.32161661303631 + lats[1470] = -13.391915381391959 + lats[1471] = -13.46221414974678 + lats[1472] = -13.532512918100766 + lats[1473] = -13.602811686453919 + lats[1474] = -13.673110454806226 + lats[1475] = -13.743409223157688 + lats[1476] = -13.813707991508297 + lats[1477] = -13.884006759858046 + lats[1478] = -13.954305528206934 + lats[1479] = -14.024604296554955 + lats[1480] = -14.0949030649021 + lats[1481] = -14.165201833248371 + lats[1482] = -14.23550060159376 + lats[1483] = -14.305799369938256 + lats[1484] = -14.376098138281863 + lats[1485] = -14.446396906624567 + lats[1486] = -14.516695674966371 + lats[1487] = -14.586994443307265 + lats[1488] = -14.657293211647247 + lats[1489] = -14.727591979986309 + lats[1490] = -14.797890748324447 + lats[1491] = -14.868189516661655 + lats[1492] = -14.938488284997929 + lats[1493] = -15.008787053333259 + lats[1494] = -15.07908582166765 + lats[1495] = -15.149384590001089 + lats[1496] = -15.219683358333569 + lats[1497] = -15.289982126665089 + lats[1498] = -15.360280894995643 + lats[1499] = -15.430579663325226 + lats[1500] = -15.500878431653829 + lats[1501] = -15.571177199981456 + lats[1502] = -15.641475968308091 + lats[1503] = -15.711774736633735 + lats[1504] = -15.78207350495838 + lats[1505] = -15.852372273282016 + lats[1506] = -15.922671041604652 + lats[1507] = -15.992969809926265 + lats[1508] = -16.063268578246863 + lats[1509] = -16.133567346566434 + lats[1510] = -16.203866114884974 + lats[1511] = -16.274164883202477 + lats[1512] = -16.344463651518936 + lats[1513] = -16.41476241983435 + lats[1514] = -16.485061188148713 + lats[1515] = -16.555359956462013 + lats[1516] = -16.625658724774254 + lats[1517] = -16.69595749308542 + lats[1518] = -16.766256261395515 + lats[1519] = -16.836555029704527 + lats[1520] = -16.906853798012452 + lats[1521] = -16.977152566319283 + lats[1522] = -17.04745133462502 + lats[1523] = -17.117750102929655 + lats[1524] = -17.188048871233182 + lats[1525] = -17.258347639535586 + lats[1526] = -17.328646407836878 + lats[1527] = -17.39894517613704 + lats[1528] = -17.469243944436066 + lats[1529] = -17.539542712733962 + lats[1530] = -17.60984148103071 + lats[1531] = -17.680140249326314 + lats[1532] = -17.75043901762076 + lats[1533] = -17.820737785914044 + lats[1534] = -17.89103655420616 + lats[1535] = -17.96133532249711 + lats[1536] = -18.031634090786874 + lats[1537] = -18.101932859075458 + lats[1538] = -18.172231627362851 + lats[1539] = -18.242530395649048 + lats[1540] = -18.312829163934047 + lats[1541] = -18.383127932217832 + lats[1542] = -18.453426700500408 + lats[1543] = -18.523725468781763 + lats[1544] = -18.594024237061891 + lats[1545] = -18.664323005340787 + lats[1546] = -18.734621773618446 + lats[1547] = -18.804920541894862 + lats[1548] = -18.875219310170031 + lats[1549] = -18.945518078443939 + lats[1550] = -19.015816846716586 + lats[1551] = -19.086115614987968 + lats[1552] = -19.15641438325807 + lats[1553] = -19.226713151526898 + lats[1554] = -19.297011919794439 + lats[1555] = -19.367310688060684 + lats[1556] = -19.437609456325632 + lats[1557] = -19.507908224589269 + lats[1558] = -19.578206992851602 + lats[1559] = -19.648505761112613 + lats[1560] = -19.718804529372303 + lats[1561] = -19.789103297630657 + lats[1562] = -19.859402065887682 + lats[1563] = -19.929700834143357 + lats[1564] = -19.999999602397686 + lats[1565] = -20.070298370650661 + lats[1566] = -20.140597138902272 + lats[1567] = -20.210895907152516 + lats[1568] = -20.28119467540138 + lats[1569] = -20.35149344364887 + lats[1570] = -20.421792211894967 + lats[1571] = -20.492090980139672 + lats[1572] = -20.562389748382977 + lats[1573] = -20.632688516624874 + lats[1574] = -20.702987284865355 + lats[1575] = -20.773286053104417 + lats[1576] = -20.843584821342048 + lats[1577] = -20.913883589578251 + lats[1578] = -20.984182357813012 + lats[1579] = -21.054481126046323 + lats[1580] = -21.124779894278181 + lats[1581] = -21.195078662508585 + lats[1582] = -21.265377430737512 + lats[1583] = -21.335676198964972 + lats[1584] = -21.40597496719095 + lats[1585] = -21.47627373541544 + lats[1586] = -21.546572503638437 + lats[1587] = -21.616871271859928 + lats[1588] = -21.687170040079913 + lats[1589] = -21.757468808298391 + lats[1590] = -21.827767576515338 + lats[1591] = -21.898066344730758 + lats[1592] = -21.968365112944642 + lats[1593] = -22.038663881156989 + lats[1594] = -22.108962649367779 + lats[1595] = -22.179261417577013 + lats[1596] = -22.249560185784691 + lats[1597] = -22.319858953990789 + lats[1598] = -22.390157722195315 + lats[1599] = -22.460456490398254 + lats[1600] = -22.530755258599601 + lats[1601] = -22.60105402679935 + lats[1602] = -22.671352794997489 + lats[1603] = -22.741651563194019 + lats[1604] = -22.811950331388925 + lats[1605] = -22.882249099582204 + lats[1606] = -22.952547867773848 + lats[1607] = -23.022846635963852 + lats[1608] = -23.0931454041522 + lats[1609] = -23.163444172338895 + lats[1610] = -23.233742940523921 + lats[1611] = -23.304041708707278 + lats[1612] = -23.374340476888957 + lats[1613] = -23.444639245068949 + lats[1614] = -23.514938013247242 + lats[1615] = -23.585236781423838 + lats[1616] = -23.655535549598721 + lats[1617] = -23.725834317771888 + lats[1618] = -23.796133085943328 + lats[1619] = -23.866431854113038 + lats[1620] = -23.936730622281004 + lats[1621] = -24.007029390447226 + lats[1622] = -24.077328158611696 + lats[1623] = -24.1476269267744 + lats[1624] = -24.217925694935328 + lats[1625] = -24.288224463094483 + lats[1626] = -24.358523231251851 + lats[1627] = -24.428821999407425 + lats[1628] = -24.499120767561195 + lats[1629] = -24.569419535713152 + lats[1630] = -24.639718303863294 + lats[1631] = -24.710017072011613 + lats[1632] = -24.780315840158096 + lats[1633] = -24.850614608302738 + lats[1634] = -24.920913376445526 + lats[1635] = -24.991212144586456 + lats[1636] = -25.061510912725527 + lats[1637] = -25.13180968086272 + lats[1638] = -25.202108448998025 + lats[1639] = -25.272407217131445 + lats[1640] = -25.342705985262967 + lats[1641] = -25.413004753392578 + lats[1642] = -25.483303521520277 + lats[1643] = -25.553602289646051 + lats[1644] = -25.623901057769892 + lats[1645] = -25.694199825891793 + lats[1646] = -25.764498594011751 + lats[1647] = -25.834797362129745 + lats[1648] = -25.90509613024577 + lats[1649] = -25.975394898359827 + lats[1650] = -26.045693666471902 + lats[1651] = -26.115992434581983 + lats[1652] = -26.186291202690064 + lats[1653] = -26.256589970796135 + lats[1654] = -26.326888738900195 + lats[1655] = -26.397187507002222 + lats[1656] = -26.467486275102218 + lats[1657] = -26.53778504320017 + lats[1658] = -26.608083811296069 + lats[1659] = -26.678382579389908 + lats[1660] = -26.748681347481678 + lats[1661] = -26.818980115571364 + lats[1662] = -26.889278883658971 + lats[1663] = -26.959577651744471 + lats[1664] = -27.029876419827872 + lats[1665] = -27.100175187909159 + lats[1666] = -27.170473955988321 + lats[1667] = -27.240772724065348 + lats[1668] = -27.311071492140236 + lats[1669] = -27.381370260212968 + lats[1670] = -27.451669028283543 + lats[1671] = -27.521967796351948 + lats[1672] = -27.592266564418171 + lats[1673] = -27.662565332482213 + lats[1674] = -27.732864100544052 + lats[1675] = -27.803162868603682 + lats[1676] = -27.873461636661098 + lats[1677] = -27.94376040471629 + lats[1678] = -28.014059172769244 + lats[1679] = -28.084357940819952 + lats[1680] = -28.154656708868405 + lats[1681] = -28.224955476914594 + lats[1682] = -28.29525424495851 + lats[1683] = -28.365553013000145 + lats[1684] = -28.435851781039485 + lats[1685] = -28.506150549076519 + lats[1686] = -28.576449317111244 + lats[1687] = -28.646748085143642 + lats[1688] = -28.717046853173709 + lats[1689] = -28.787345621201432 + lats[1690] = -28.857644389226806 + lats[1691] = -28.927943157249814 + lats[1692] = -28.998241925270449 + lats[1693] = -29.068540693288696 + lats[1694] = -29.138839461304556 + lats[1695] = -29.209138229318015 + lats[1696] = -29.279436997329057 + lats[1697] = -29.349735765337677 + lats[1698] = -29.420034533343859 + lats[1699] = -29.490333301347597 + lats[1700] = -29.560632069348884 + lats[1701] = -29.630930837347698 + lats[1702] = -29.701229605344039 + lats[1703] = -29.771528373337894 + lats[1704] = -29.841827141329258 + lats[1705] = -29.91212590931811 + lats[1706] = -29.98242467730444 + lats[1707] = -30.052723445288244 + lats[1708] = -30.123022213269511 + lats[1709] = -30.19332098124822 + lats[1710] = -30.263619749224372 + lats[1711] = -30.333918517197947 + lats[1712] = -30.404217285168947 + lats[1713] = -30.47451605313735 + lats[1714] = -30.544814821103138 + lats[1715] = -30.615113589066322 + lats[1716] = -30.685412357026873 + lats[1717] = -30.755711124984781 + lats[1718] = -30.826009892940046 + lats[1719] = -30.896308660892647 + lats[1720] = -30.966607428842572 + lats[1721] = -31.036906196789811 + lats[1722] = -31.107204964734358 + lats[1723] = -31.177503732676204 + lats[1724] = -31.247802500615318 + lats[1725] = -31.318101268551715 + lats[1726] = -31.388400036485361 + lats[1727] = -31.458698804416255 + lats[1728] = -31.528997572344384 + lats[1729] = -31.599296340269738 + lats[1730] = -31.669595108192297 + lats[1731] = -31.739893876112063 + lats[1732] = -31.810192644029012 + lats[1733] = -31.880491411943137 + lats[1734] = -31.950790179854422 + lats[1735] = -32.021088947762863 + lats[1736] = -32.091387715668439 + lats[1737] = -32.161686483571145 + lats[1738] = -32.231985251470959 + lats[1739] = -32.302284019367875 + lats[1740] = -32.372582787261891 + lats[1741] = -32.442881555152965 + lats[1742] = -32.513180323041112 + lats[1743] = -32.583479090926325 + lats[1744] = -32.653777858808567 + lats[1745] = -32.724076626687825 + lats[1746] = -32.794375394564113 + lats[1747] = -32.864674162437396 + lats[1748] = -32.934972930307666 + lats[1749] = -33.005271698174909 + lats[1750] = -33.075570466039117 + lats[1751] = -33.145869233900278 + lats[1752] = -33.216168001758369 + lats[1753] = -33.286466769613391 + lats[1754] = -33.356765537465314 + lats[1755] = -33.42706430531414 + lats[1756] = -33.497363073159853 + lats[1757] = -33.567661841002426 + lats[1758] = -33.637960608841851 + lats[1759] = -33.708259376678136 + lats[1760] = -33.778558144511237 + lats[1761] = -33.848856912341155 + lats[1762] = -33.919155680167876 + lats[1763] = -33.989454447991392 + lats[1764] = -34.059753215811682 + lats[1765] = -34.130051983628725 + lats[1766] = -34.200350751442521 + lats[1767] = -34.270649519253041 + lats[1768] = -34.340948287060286 + lats[1769] = -34.411247054864234 + lats[1770] = -34.481545822664863 + lats[1771] = -34.551844590462188 + lats[1772] = -34.622143358256153 + lats[1773] = -34.692442126046771 + lats[1774] = -34.762740893834028 + lats[1775] = -34.833039661617903 + lats[1776] = -34.903338429398374 + lats[1777] = -34.973637197175435 + lats[1778] = -35.043935964949064 + lats[1779] = -35.114234732719261 + lats[1780] = -35.184533500486005 + lats[1781] = -35.254832268249267 + lats[1782] = -35.325131036009047 + lats[1783] = -35.395429803765317 + lats[1784] = -35.465728571518085 + lats[1785] = -35.536027339267314 + lats[1786] = -35.606326107012997 + lats[1787] = -35.676624874755113 + lats[1788] = -35.746923642493655 + lats[1789] = -35.817222410228595 + lats[1790] = -35.887521177959933 + lats[1791] = -35.957819945687639 + lats[1792] = -36.028118713411708 + lats[1793] = -36.098417481132117 + lats[1794] = -36.16871624884886 + lats[1795] = -36.239015016561908 + lats[1796] = -36.309313784271254 + lats[1797] = -36.379612551976876 + lats[1798] = -36.449911319678755 + lats[1799] = -36.520210087376888 + lats[1800] = -36.590508855071242 + lats[1801] = -36.660807622761808 + lats[1802] = -36.731106390448581 + lats[1803] = -36.801405158131523 + lats[1804] = -36.871703925810628 + lats[1805] = -36.942002693485883 + lats[1806] = -37.012301461157264 + lats[1807] = -37.082600228824752 + lats[1808] = -37.152898996488332 + lats[1809] = -37.223197764147997 + lats[1810] = -37.293496531803719 + lats[1811] = -37.363795299455489 + lats[1812] = -37.434094067103274 + lats[1813] = -37.504392834747065 + lats[1814] = -37.574691602386856 + lats[1815] = -37.644990370022605 + lats[1816] = -37.715289137654317 + lats[1817] = -37.785587905281965 + lats[1818] = -37.855886672905527 + lats[1819] = -37.926185440524989 + lats[1820] = -37.99648420814033 + lats[1821] = -38.066782975751536 + lats[1822] = -38.137081743358586 + lats[1823] = -38.20738051096145 + lats[1824] = -38.277679278560143 + lats[1825] = -38.347978046154608 + lats[1826] = -38.418276813744846 + lats[1827] = -38.488575581330842 + lats[1828] = -38.558874348912568 + lats[1829] = -38.629173116490001 + lats[1830] = -38.699471884063136 + lats[1831] = -38.769770651631937 + lats[1832] = -38.840069419196389 + lats[1833] = -38.910368186756479 + lats[1834] = -38.980666954312184 + lats[1835] = -39.050965721863491 + lats[1836] = -39.121264489410365 + lats[1837] = -39.191563256952804 + lats[1838] = -39.261862024490775 + lats[1839] = -39.332160792024254 + lats[1840] = -39.402459559553229 + lats[1841] = -39.472758327077692 + lats[1842] = -39.543057094597607 + lats[1843] = -39.613355862112947 + lats[1844] = -39.683654629623703 + lats[1845] = -39.753953397129855 + lats[1846] = -39.824252164631375 + lats[1847] = -39.894550932128247 + lats[1848] = -39.964849699620437 + lats[1849] = -40.035148467107952 + lats[1850] = -40.105447234590748 + lats[1851] = -40.175746002068806 + lats[1852] = -40.246044769542102 + lats[1853] = -40.316343537010617 + lats[1854] = -40.386642304474343 + lats[1855] = -40.456941071933244 + lats[1856] = -40.527239839387299 + lats[1857] = -40.597538606836487 + lats[1858] = -40.667837374280786 + lats[1859] = -40.738136141720176 + lats[1860] = -40.808434909154634 + lats[1861] = -40.878733676584126 + lats[1862] = -40.949032444008644 + lats[1863] = -41.01933121142816 + lats[1864] = -41.089629978842645 + lats[1865] = -41.159928746252085 + lats[1866] = -41.230227513656445 + lats[1867] = -41.300526281055724 + lats[1868] = -41.370825048449873 + lats[1869] = -41.441123815838885 + lats[1870] = -41.511422583222718 + lats[1871] = -41.581721350601363 + lats[1872] = -41.6520201179748 + lats[1873] = -41.722318885343 + lats[1874] = -41.792617652705921 + lats[1875] = -41.862916420063563 + lats[1876] = -41.933215187415882 + lats[1877] = -42.003513954762873 + lats[1878] = -42.073812722104492 + lats[1879] = -42.144111489440725 + lats[1880] = -42.214410256771551 + lats[1881] = -42.284709024096927 + lats[1882] = -42.355007791416853 + lats[1883] = -42.425306558731272 + lats[1884] = -42.495605326040177 + lats[1885] = -42.565904093343548 + lats[1886] = -42.63620286064134 + lats[1887] = -42.706501627933541 + lats[1888] = -42.776800395220121 + lats[1889] = -42.847099162501053 + lats[1890] = -42.917397929776307 + lats[1891] = -42.987696697045862 + lats[1892] = -43.057995464309691 + lats[1893] = -43.128294231567757 + lats[1894] = -43.19859299882004 + lats[1895] = -43.26889176606651 + lats[1896] = -43.339190533307139 + lats[1897] = -43.409489300541907 + lats[1898] = -43.479788067770777 + lats[1899] = -43.550086834993728 + lats[1900] = -43.620385602210717 + lats[1901] = -43.690684369421732 + lats[1902] = -43.760983136626741 + lats[1903] = -43.831281903825705 + lats[1904] = -43.9015806710186 + lats[1905] = -43.971879438205391 + lats[1906] = -44.042178205386072 + lats[1907] = -44.112476972560586 + lats[1908] = -44.182775739728925 + lats[1909] = -44.253074506891046 + lats[1910] = -44.323373274046915 + lats[1911] = -44.39367204119651 + lats[1912] = -44.463970808339802 + lats[1913] = -44.534269575476756 + lats[1914] = -44.604568342607337 + lats[1915] = -44.674867109731515 + lats[1916] = -44.745165876849271 + lats[1917] = -44.81546464396056 + lats[1918] = -44.885763411065362 + lats[1919] = -44.956062178163634 + lats[1920] = -45.026360945255341 + lats[1921] = -45.096659712340461 + lats[1922] = -45.166958479418959 + lats[1923] = -45.237257246490813 + lats[1924] = -45.30755601355596 + lats[1925] = -45.377854780614399 + lats[1926] = -45.448153547666081 + lats[1927] = -45.51845231471097 + lats[1928] = -45.588751081749038 + lats[1929] = -45.659049848780263 + lats[1930] = -45.729348615804589 + lats[1931] = -45.799647382821995 + lats[1932] = -45.869946149832437 + lats[1933] = -45.94024491683588 + lats[1934] = -46.01054368383231 + lats[1935] = -46.080842450821663 + lats[1936] = -46.151141217803925 + lats[1937] = -46.221439984779053 + lats[1938] = -46.291738751747012 + lats[1939] = -46.362037518707766 + lats[1940] = -46.432336285661272 + lats[1941] = -46.502635052607502 + lats[1942] = -46.572933819546414 + lats[1943] = -46.643232586477971 + lats[1944] = -46.713531353402139 + lats[1945] = -46.783830120318882 + lats[1946] = -46.85412888722815 + lats[1947] = -46.924427654129929 + lats[1948] = -46.994726421024154 + lats[1949] = -47.065025187910805 + lats[1950] = -47.13532395478984 + lats[1951] = -47.205622721661214 + lats[1952] = -47.275921488524894 + lats[1953] = -47.346220255380835 + lats[1954] = -47.416519022228997 + lats[1955] = -47.486817789069342 + lats[1956] = -47.557116555901828 + lats[1957] = -47.627415322726435 + lats[1958] = -47.697714089543084 + lats[1959] = -47.76801285635176 + lats[1960] = -47.838311623152421 + lats[1961] = -47.908610389945018 + lats[1962] = -47.978909156729507 + lats[1963] = -48.049207923505868 + lats[1964] = -48.119506690274015 + lats[1965] = -48.189805457033941 + lats[1966] = -48.260104223785596 + lats[1967] = -48.330402990528938 + lats[1968] = -48.400701757263917 + lats[1969] = -48.47100052399049 + lats[1970] = -48.541299290708608 + lats[1971] = -48.611598057418242 + lats[1972] = -48.681896824119335 + lats[1973] = -48.752195590811837 + lats[1974] = -48.822494357495721 + lats[1975] = -48.892793124170929 + lats[1976] = -48.963091890837418 + lats[1977] = -49.03339065749514 + lats[1978] = -49.103689424144044 + lats[1979] = -49.173988190784094 + lats[1980] = -49.244286957415234 + lats[1981] = -49.314585724037435 + lats[1982] = -49.384884490650613 + lats[1983] = -49.455183257254745 + lats[1984] = -49.525482023849783 + lats[1985] = -49.595780790435676 + lats[1986] = -49.66607955701236 + lats[1987] = -49.736378323579807 + lats[1988] = -49.80667709013796 + lats[1989] = -49.876975856686762 + lats[1990] = -49.947274623226157 + lats[1991] = -50.017573389756123 + lats[1992] = -50.087872156276575 + lats[1993] = -50.158170922787484 + lats[1994] = -50.228469689288779 + lats[1995] = -50.298768455780426 + lats[1996] = -50.369067222262359 + lats[1997] = -50.439365988734544 + lats[1998] = -50.509664755196901 + lats[1999] = -50.579963521649397 + lats[2000] = -50.650262288091959 + lats[2001] = -50.720561054524559 + lats[2002] = -50.790859820947119 + lats[2003] = -50.86115858735959 + lats[2004] = -50.931457353761914 + lats[2005] = -51.001756120154049 + lats[2006] = -51.072054886535909 + lats[2007] = -51.14235365290746 + lats[2008] = -51.21265241926865 + lats[2009] = -51.282951185619417 + lats[2010] = -51.353249951959683 + lats[2011] = -51.423548718289396 + lats[2012] = -51.493847484608516 + lats[2013] = -51.56414625091697 + lats[2014] = -51.634445017214695 + lats[2015] = -51.704743783501634 + lats[2016] = -51.775042549777737 + lats[2017] = -51.845341316042933 + lats[2018] = -51.915640082297152 + lats[2019] = -51.985938848540336 + lats[2020] = -52.056237614772435 + lats[2021] = -52.126536380993372 + lats[2022] = -52.196835147203096 + lats[2023] = -52.26713391340153 + lats[2024] = -52.337432679588609 + lats[2025] = -52.407731445764284 + lats[2026] = -52.478030211928477 + lats[2027] = -52.548328978081123 + lats[2028] = -52.618627744222159 + lats[2029] = -52.688926510351514 + lats[2030] = -52.759225276469131 + lats[2031] = -52.829524042574917 + lats[2032] = -52.899822808668837 + lats[2033] = -52.970121574750792 + lats[2034] = -53.040420340820731 + lats[2035] = -53.110719106878584 + lats[2036] = -53.181017872924265 + lats[2037] = -53.251316638957725 + lats[2038] = -53.321615404978871 + lats[2039] = -53.391914170987633 + lats[2040] = -53.462212936983953 + lats[2041] = -53.53251170296776 + lats[2042] = -53.602810468938962 + lats[2043] = -53.673109234897495 + lats[2044] = -53.743408000843282 + lats[2045] = -53.813706766776235 + lats[2046] = -53.884005532696307 + lats[2047] = -53.954304298603383 + lats[2048] = -54.024603064497434 + lats[2049] = -54.094901830378333 + lats[2050] = -54.165200596246031 + lats[2051] = -54.235499362100448 + lats[2052] = -54.305798127941479 + lats[2053] = -54.376096893769081 + lats[2054] = -54.446395659583146 + lats[2055] = -54.516694425383605 + lats[2056] = -54.586993191170357 + lats[2057] = -54.657291956943347 + lats[2058] = -54.727590722702473 + lats[2059] = -54.797889488447652 + lats[2060] = -54.868188254178797 + lats[2061] = -54.938487019895831 + lats[2062] = -55.008785785598668 + lats[2063] = -55.07908455128721 + lats[2064] = -55.149383316961377 + lats[2065] = -55.219682082621084 + lats[2066] = -55.289980848266232 + lats[2067] = -55.360279613896743 + lats[2068] = -55.430578379512511 + lats[2069] = -55.500877145113449 + lats[2070] = -55.571175910699488 + lats[2071] = -55.641474676270505 + lats[2072] = -55.711773441826416 + lats[2073] = -55.782072207367136 + lats[2074] = -55.852370972892551 + lats[2075] = -55.922669738402583 + lats[2076] = -55.992968503897131 + lats[2077] = -56.063267269376091 + lats[2078] = -56.133566034839362 + lats[2079] = -56.203864800286865 + lats[2080] = -56.274163565718467 + lats[2081] = -56.34446233113411 + lats[2082] = -56.41476109653366 + lats[2083] = -56.485059861917016 + lats[2084] = -56.555358627284086 + lats[2085] = -56.625657392634771 + lats[2086] = -56.695956157968951 + lats[2087] = -56.766254923286517 + lats[2088] = -56.836553688587379 + lats[2089] = -56.90685245387143 + lats[2090] = -56.977151219138541 + lats[2091] = -57.047449984388614 + lats[2092] = -57.117748749621541 + lats[2093] = -57.188047514837208 + lats[2094] = -57.258346280035504 + lats[2095] = -57.328645045216312 + lats[2096] = -57.398943810379521 + lats[2097] = -57.469242575525016 + lats[2098] = -57.539541340652676 + lats[2099] = -57.60984010576238 + lats[2100] = -57.680138870854037 + lats[2101] = -57.75043763592749 + lats[2102] = -57.820736400982646 + lats[2103] = -57.891035166019364 + lats[2104] = -57.961333931037537 + lats[2105] = -58.031632696037022 + lats[2106] = -58.101931461017728 + lats[2107] = -58.172230225979497 + lats[2108] = -58.242528990922203 + lats[2109] = -58.312827755845746 + lats[2110] = -58.383126520749968 + lats[2111] = -58.453425285634758 + lats[2112] = -58.523724050499972 + lats[2113] = -58.594022815345468 + lats[2114] = -58.664321580171141 + lats[2115] = -58.73462034497684 + lats[2116] = -58.804919109762423 + lats[2117] = -58.875217874527763 + lats[2118] = -58.945516639272725 + lats[2119] = -59.015815403997145 + lats[2120] = -59.086114168700909 + lats[2121] = -59.156412933383855 + lats[2122] = -59.226711698045854 + lats[2123] = -59.29701046268675 + lats[2124] = -59.3673092273064 + lats[2125] = -59.43760799190467 + lats[2126] = -59.507906756481383 + lats[2127] = -59.578205521036402 + lats[2128] = -59.64850428556958 + lats[2129] = -59.718803050080759 + lats[2130] = -59.78910181456979 + lats[2131] = -59.859400579036503 + lats[2132] = -59.929699343480763 + lats[2133] = -59.999998107902378 + lats[2134] = -60.070296872301235 + lats[2135] = -60.140595636677112 + lats[2136] = -60.21089440102989 + lats[2137] = -60.28119316535939 + lats[2138] = -60.35149192966545 + lats[2139] = -60.421790693947884 + lats[2140] = -60.492089458206543 + lats[2141] = -60.562388222441243 + lats[2142] = -60.632686986651805 + lats[2143] = -60.702985750838074 + lats[2144] = -60.773284514999872 + lats[2145] = -60.843583279137007 + lats[2146] = -60.913882043249295 + lats[2147] = -60.984180807336578 + lats[2148] = -61.054479571398652 + lats[2149] = -61.124778335435344 + lats[2150] = -61.195077099446451 + lats[2151] = -61.265375863431785 + lats[2152] = -61.335674627391185 + lats[2153] = -61.405973391324409 + lats[2154] = -61.476272155231321 + lats[2155] = -61.546570919111666 + lats[2156] = -61.616869682965287 + lats[2157] = -61.687168446791986 + lats[2158] = -61.757467210591535 + lats[2159] = -61.827765974363729 + lats[2160] = -61.898064738108381 + lats[2161] = -61.968363501825259 + lats[2162] = -62.038662265514176 + lats[2163] = -62.108961029174914 + lats[2164] = -62.179259792807258 + lats[2165] = -62.249558556410982 + lats[2166] = -62.319857319985871 + lats[2167] = -62.3901560835317 + lats[2168] = -62.460454847048261 + lats[2169] = -62.530753610535321 + lats[2170] = -62.60105237399263 + lats[2171] = -62.67135113741999 + lats[2172] = -62.741649900817137 + lats[2173] = -62.811948664183866 + lats[2174] = -62.882247427519928 + lats[2175] = -62.952546190825068 + lats[2176] = -63.022844954099064 + lats[2177] = -63.093143717341647 + lats[2178] = -63.163442480552604 + lats[2179] = -63.23374124373165 + lats[2180] = -63.304040006878537 + lats[2181] = -63.374338769993031 + lats[2182] = -63.444637533074854 + lats[2183] = -63.514936296123757 + lats[2184] = -63.585235059139464 + lats[2185] = -63.655533822121711 + lats[2186] = -63.725832585070251 + lats[2187] = -63.796131347984762 + lats[2188] = -63.866430110865004 + lats[2189] = -63.93672887371072 + lats[2190] = -64.00702763652157 + lats[2191] = -64.07732639929732 + lats[2192] = -64.147625162037642 + lats[2193] = -64.21792392474228 + lats[2194] = -64.288222687410922 + lats[2195] = -64.358521450043284 + lats[2196] = -64.428820212639039 + lats[2197] = -64.499118975197902 + lats[2198] = -64.569417737719576 + lats[2199] = -64.639716500203733 + lats[2200] = -64.710015262650074 + lats[2201] = -64.780314025058246 + lats[2202] = -64.850612787427963 + lats[2203] = -64.920911549758912 + lats[2204] = -64.991210312050711 + lats[2205] = -65.061509074303089 + lats[2206] = -65.131807836515677 + lats[2207] = -65.202106598688133 + lats[2208] = -65.272405360820116 + lats[2209] = -65.342704122911286 + lats[2210] = -65.413002884961315 + lats[2211] = -65.483301646969792 + lats[2212] = -65.553600408936404 + lats[2213] = -65.623899170860767 + lats[2214] = -65.694197932742526 + lats[2215] = -65.764496694581283 + lats[2216] = -65.834795456376696 + lats[2217] = -65.905094218128355 + lats[2218] = -65.975392979835888 + lats[2219] = -66.045691741498899 + lats[2220] = -66.115990503117033 + lats[2221] = -66.186289264689833 + lats[2222] = -66.256588026216932 + lats[2223] = -66.326886787697887 + lats[2224] = -66.397185549132331 + lats[2225] = -66.467484310519808 + lats[2226] = -66.537783071859891 + lats[2227] = -66.608081833152212 + lats[2228] = -66.678380594396273 + lats[2229] = -66.748679355591662 + lats[2230] = -66.818978116737924 + lats[2231] = -66.889276877834618 + lats[2232] = -66.95957563888129 + lats[2233] = -67.029874399877471 + lats[2234] = -67.100173160822706 + lats[2235] = -67.170471921716526 + lats[2236] = -67.240770682558434 + lats[2237] = -67.311069443347961 + lats[2238] = -67.381368204084609 + lats[2239] = -67.451666964767895 + lats[2240] = -67.521965725397308 + lats[2241] = -67.592264485972336 + lats[2242] = -67.662563246492482 + lats[2243] = -67.732862006957205 + lats[2244] = -67.803160767365966 + lats[2245] = -67.873459527718282 + lats[2246] = -67.943758288013555 + lats[2247] = -68.014057048251274 + lats[2248] = -68.084355808430871 + lats[2249] = -68.154654568551791 + lats[2250] = -68.224953328613438 + lats[2251] = -68.295252088615257 + lats[2252] = -68.365550848556666 + lats[2253] = -68.435849608437067 + lats[2254] = -68.506148368255865 + lats[2255] = -68.576447128012447 + lats[2256] = -68.646745887706189 + lats[2257] = -68.717044647336493 + lats[2258] = -68.787343406902693 + lats[2259] = -68.85764216640419 + lats[2260] = -68.927940925840304 + lats[2261] = -68.998239685210365 + lats[2262] = -69.068538444513763 + lats[2263] = -69.138837203749759 + lats[2264] = -69.209135962917699 + lats[2265] = -69.279434722016902 + lats[2266] = -69.349733481046613 + lats[2267] = -69.420032240006194 + lats[2268] = -69.490330998894862 + lats[2269] = -69.560629757711908 + lats[2270] = -69.630928516456592 + lats[2271] = -69.701227275128161 + lats[2272] = -69.771526033725834 + lats[2273] = -69.841824792248843 + lats[2274] = -69.912123550696421 + lats[2275] = -69.982422309067744 + lats[2276] = -70.052721067362043 + lats[2277] = -70.123019825578467 + lats[2278] = -70.193318583716191 + lats[2279] = -70.263617341774406 + lats[2280] = -70.333916099752187 + lats[2281] = -70.404214857648739 + lats[2282] = -70.474513615463138 + lats[2283] = -70.544812373194532 + lats[2284] = -70.615111130841967 + lats[2285] = -70.685409888404578 + lats[2286] = -70.755708645881384 + lats[2287] = -70.826007403271475 + lats[2288] = -70.896306160573886 + lats[2289] = -70.966604917787635 + lats[2290] = -71.036903674911756 + lats[2291] = -71.107202431945211 + lats[2292] = -71.177501188887007 + lats[2293] = -71.247799945736105 + lats[2294] = -71.318098702491469 + lats[2295] = -71.388397459152031 + lats[2296] = -71.458696215716685 + lats[2297] = -71.528994972184378 + lats[2298] = -71.599293728553988 + lats[2299] = -71.669592484824364 + lats[2300] = -71.739891240994368 + lats[2301] = -71.810189997062835 + lats[2302] = -71.880488753028587 + lats[2303] = -71.950787508890414 + lats[2304] = -72.02108626464711 + lats[2305] = -72.091385020297409 + lats[2306] = -72.161683775840089 + lats[2307] = -72.231982531273843 + lats[2308] = -72.302281286597392 + lats[2309] = -72.3725800418094 + lats[2310] = -72.442878796908545 + lats[2311] = -72.513177551893421 + lats[2312] = -72.583476306762691 + lats[2313] = -72.653775061514935 + lats[2314] = -72.724073816148703 + lats[2315] = -72.794372570662574 + lats[2316] = -72.864671325055056 + lats[2317] = -72.934970079324657 + lats[2318] = -73.005268833469799 + lats[2319] = -73.075567587489019 + lats[2320] = -73.145866341380668 + lats[2321] = -73.216165095143182 + lats[2322] = -73.2864638487749 + lats[2323] = -73.356762602274188 + lats[2324] = -73.427061355639339 + lats[2325] = -73.497360108868662 + lats[2326] = -73.567658861960396 + lats[2327] = -73.637957614912779 + lats[2328] = -73.70825636772399 + lats[2329] = -73.778555120392184 + lats[2330] = -73.848853872915541 + lats[2331] = -73.919152625292114 + lats[2332] = -73.98945137751997 + lats[2333] = -74.059750129597163 + lats[2334] = -74.13004888152166 + lats[2335] = -74.200347633291472 + lats[2336] = -74.270646384904481 + lats[2337] = -74.340945136358584 + lats[2338] = -74.411243887651622 + lats[2339] = -74.481542638781434 + lats[2340] = -74.551841389745761 + lats[2341] = -74.622140140542356 + lats[2342] = -74.692438891168877 + lats[2343] = -74.762737641622991 + lats[2344] = -74.833036391902269 + lats[2345] = -74.903335142004323 + lats[2346] = -74.973633891926625 + lats[2347] = -75.043932641666672 + lats[2348] = -75.114231391221821 + lats[2349] = -75.184530140589501 + lats[2350] = -75.254828889766983 + lats[2351] = -75.325127638751567 + lats[2352] = -75.395426387540439 + lats[2353] = -75.465725136130786 + lats[2354] = -75.536023884519707 + lats[2355] = -75.60632263270422 + lats[2356] = -75.67662138068134 + lats[2357] = -75.746920128447996 + lats[2358] = -75.81721887600105 + lats[2359] = -75.887517623337317 + lats[2360] = -75.957816370453543 + lats[2361] = -76.028115117346374 + lats[2362] = -76.098413864012443 + lats[2363] = -76.16871261044831 + lats[2364] = -76.239011356650423 + lats[2365] = -76.3093101026152 + lats[2366] = -76.379608848338933 + lats[2367] = -76.449907593817869 + lats[2368] = -76.520206339048215 + lats[2369] = -76.59050508402602 + lats[2370] = -76.660803828747362 + lats[2371] = -76.731102573208048 + lats[2372] = -76.801401317404 + lats[2373] = -76.871700061330955 + lats[2374] = -76.941998804984564 + lats[2375] = -77.012297548360323 + lats[2376] = -77.082596291453768 + lats[2377] = -77.15289503426024 + lats[2378] = -77.22319377677502 + lats[2379] = -77.293492518993247 + lats[2380] = -77.363791260909963 + lats[2381] = -77.434090002520122 + lats[2382] = -77.504388743818524 + lats[2383] = -77.574687484799924 + lats[2384] = -77.644986225458879 + lats[2385] = -77.71528496578982 + lats[2386] = -77.785583705787161 + lats[2387] = -77.855882445445019 + lats[2388] = -77.926181184757539 + lats[2389] = -77.996479923718596 + lats[2390] = -78.066778662322022 + lats[2391] = -78.137077400561424 + lats[2392] = -78.207376138430348 + lats[2393] = -78.277674875922045 + lats[2394] = -78.347973613029708 + lats[2395] = -78.418272349746417 + lats[2396] = -78.488571086064923 + lats[2397] = -78.558869821977908 + lats[2398] = -78.629168557477882 + lats[2399] = -78.699467292557102 + lats[2400] = -78.769766027207638 + lats[2401] = -78.840064761421445 + lats[2402] = -78.910363495190211 + lats[2403] = -78.980662228505423 + lats[2404] = -79.050960961358285 + lats[2405] = -79.121259693739859 + lats[2406] = -79.191558425640977 + lats[2407] = -79.261857157052191 + lats[2408] = -79.332155887963822 + lats[2409] = -79.402454618365894 + lats[2410] = -79.472753348248219 + lats[2411] = -79.543052077600308 + lats[2412] = -79.61335080641139 + lats[2413] = -79.683649534670437 + lats[2414] = -79.753948262366038 + lats[2415] = -79.824246989486554 + lats[2416] = -79.894545716019948 + lats[2417] = -79.9648444419539 + lats[2418] = -80.035143167275749 + lats[2419] = -80.105441891972376 + lats[2420] = -80.175740616030438 + lats[2421] = -80.246039339436052 + lats[2422] = -80.316338062175078 + lats[2423] = -80.386636784232863 + lats[2424] = -80.456935505594302 + lats[2425] = -80.527234226243991 + lats[2426] = -80.59753294616587 + lats[2427] = -80.667831665343556 + lats[2428] = -80.73813038376008 + lats[2429] = -80.808429101397948 + lats[2430] = -80.878727818239184 + lats[2431] = -80.949026534265244 + lats[2432] = -81.019325249456955 + lats[2433] = -81.089623963794551 + lats[2434] = -81.159922677257711 + lats[2435] = -81.230221389825374 + lats[2436] = -81.300520101475826 + lats[2437] = -81.370818812186627 + lats[2438] = -81.441117521934686 + lats[2439] = -81.511416230696042 + lats[2440] = -81.581714938445955 + lats[2441] = -81.652013645158945 + lats[2442] = -81.722312350808508 + lats[2443] = -81.792611055367345 + lats[2444] = -81.862909758807191 + lats[2445] = -81.933208461098829 + lats[2446] = -82.003507162211946 + lats[2447] = -82.073805862115165 + lats[2448] = -82.144104560776 + lats[2449] = -82.214403258160871 + lats[2450] = -82.284701954234833 + lats[2451] = -82.355000648961692 + lats[2452] = -82.425299342304029 + lats[2453] = -82.495598034222837 + lats[2454] = -82.56589672467787 + lats[2455] = -82.63619541362705 + lats[2456] = -82.706494101026948 + lats[2457] = -82.77679278683226 + lats[2458] = -82.84709147099602 + lats[2459] = -82.917390153469313 + lats[2460] = -82.987688834201322 + lats[2461] = -83.057987513139125 + lats[2462] = -83.128286190227698 + lats[2463] = -83.198584865409657 + lats[2464] = -83.268883538625232 + lats[2465] = -83.339182209812321 + lats[2466] = -83.409480878905782 + lats[2467] = -83.479779545838113 + lats[2468] = -83.550078210538487 + lats[2469] = -83.620376872933264 + lats[2470] = -83.690675532945292 + lats[2471] = -83.760974190494011 + lats[2472] = -83.831272845495249 + lats[2473] = -83.901571497860914 + lats[2474] = -83.971870147498763 + lats[2475] = -84.042168794312317 + lats[2476] = -84.112467438200326 + lats[2477] = -84.18276607905679 + lats[2478] = -84.253064716770425 + lats[2479] = -84.323363351224444 + lats[2480] = -84.393661982296322 + lats[2481] = -84.463960609857125 + lats[2482] = -84.534259233771479 + lats[2483] = -84.604557853896708 + lats[2484] = -84.674856470082915 + lats[2485] = -84.745155082171991 + lats[2486] = -84.81545368999717 + lats[2487] = -84.885752293382765 + lats[2488] = -84.95605089214304 + lats[2489] = -85.026349486081983 + lats[2490] = -85.09664807499216 + lats[2491] = -85.16694665865414 + lats[2492] = -85.237245236835548 + lats[2493] = -85.307543809290152 + lats[2494] = -85.377842375756586 + lats[2495] = -85.448140935957483 + lats[2496] = -85.518439489597966 + lats[2497] = -85.588738036364362 + lats[2498] = -85.659036575922883 + lats[2499] = -85.729335107917464 + lats[2500] = -85.799633631968391 + lats[2501] = -85.869932147670127 + lats[2502] = -85.940230654588888 + lats[2503] = -86.010529152260403 + lats[2504] = -86.080827640187209 + lats[2505] = -86.151126117835304 + lats[2506] = -86.221424584631109 + lats[2507] = -86.291723039957418 + lats[2508] = -86.362021483149363 + lats[2509] = -86.432319913489792 + lats[2510] = -86.502618330203831 + lats[2511] = -86.572916732453024 + lats[2512] = -86.643215119328573 + lats[2513] = -86.713513489844246 + lats[2514] = -86.783811842927179 + lats[2515] = -86.854110177408927 + lats[2516] = -86.924408492014166 + lats[2517] = -86.994706785348129 + lats[2518] = -87.065005055882821 + lats[2519] = -87.135303301939786 + lats[2520] = -87.205601521672108 + lats[2521] = -87.275899713041966 + lats[2522] = -87.346197873795816 + lats[2523] = -87.416496001434894 + lats[2524] = -87.486794093180748 + lats[2525] = -87.557092145935584 + lats[2526] = -87.627390156234085 + lats[2527] = -87.697688120188062 + lats[2528] = -87.767986033419561 + lats[2529] = -87.838283890981543 + lats[2530] = -87.908581687261687 + lats[2531] = -87.978879415867283 + lats[2532] = -88.049177069484486 + lats[2533] = -88.119474639706425 + lats[2534] = -88.189772116820762 + lats[2535] = -88.26006948954614 + lats[2536] = -88.330366744702559 + lats[2537] = -88.40066386679355 + lats[2538] = -88.470960837474877 + lats[2539] = -88.541257634868515 + lats[2540] = -88.611554232668382 + lats[2541] = -88.681850598961759 + lats[2542] = -88.752146694650691 + lats[2543] = -88.822442471310097 + lats[2544] = -88.892737868230952 + lats[2545] = -88.96303280826325 + lats[2546] = -89.033327191845927 + lats[2547] = -89.103620888238879 + lats[2548] = -89.173913722284126 + lats[2549] = -89.24420545380525 + lats[2550] = -89.314495744374256 + lats[2551] = -89.3847841013921 + lats[2552] = -89.45506977912261 + lats[2553] = -89.525351592371393 + lats[2554] = -89.595627537554492 + lats[2555] = -89.6658939412157 + lats[2556] = -89.736143271609578 + lats[2557] = -89.806357319542244 + lats[2558] = -89.876478353332288 + lats[2559] = -89.946187715665616 + return lats + + def get_precomputed_values_N1280_new(self): + lats = np.empty([1280*2]) lats[0] = 89.946187715665616 lats[1] = 89.876478353332288 lats[2] = 89.806357319542244 @@ -2952,6 +5523,7 @@ def axes_idx_to_octahedral_idx(self, first_idx, second_idx): # NOTE: OR somehow cache this for a given first_idx and then only modify the axis idx for second_idx when the # first_idx changes # time1 = time.time() + # octa_idx = self._first_idx_map[first_idx-1] + second_idx octa_idx = self._first_idx_map[first_idx-1] + second_idx # octa_idx = 0 # if first_idx == 1: @@ -2983,6 +5555,7 @@ def create_first_idx_map(self): first_idx_list = {} idx = 0 for i in range(2*self._resolution): + # first_idx_list[i] = idx first_idx_list[i] = idx if i <= self._resolution - 1: idx += 20 + 4 * i @@ -3020,21 +5593,32 @@ def unmap_first_val_to_start_line_idx(self, first_val): def unmap(self, first_val, second_val): time1 = time.time() - first_axis_vals = self._first_axis_vals + # first_axis_vals = self._first_axis_vals + # inv_first_axis_vals = self._inv_first_axis_vals tol = 1e-10 # first_val = [val for val in first_axis_vals if first_val - tol < val < first_val + tol][0] # first_idx = first_axis_vals.index(first_val) + 1 # first_idx = len(first_axis_vals) - bisect.bisect_left(first_axis_vals[::-1], first_val - tol) - first_idx = bisect_left_cmp(first_axis_vals, first_val - tol, cmp=lambda x, y: x > y) + 1 - second_axis_vals = self.second_axis_vals(first_val) + # first_idx = bisect_left_cmp(first_axis_vals, first_val - tol, cmp=lambda x, y: x > y) + 1 + first_idx = bisect.bisect_left(self._inv_first_axis_vals, - (first_val - tol)) + # print(inv_first_axis_vals) + # print(first_val) + # first_idx = inv_first_axis_vals[first_val] + # first_idx = np.searchsorted(-first_axis_vals, - (first_val - tol), side="right") + if first_val not in self.treated_first_vals: + second_axis_vals = self.second_axis_vals(first_val) + self.treated_first_vals[first_val] = second_axis_vals + else: + second_axis_vals = self.treated_first_vals[first_val] # second_val = [val for val in second_axis_vals if second_val - tol < val < second_val + tol][0] # second_idx = second_axis_vals.index(second_val) second_idx = bisect.bisect_left(second_axis_vals, second_val - tol) - print("TIME SPENT DOING VAL TO IDX") - print(time.time() - time1) + # second_idx = np.searchsorted(second_axis_vals, second_val - tol) + # print("TIME SPENT DOING VAL TO IDX") + # print(time.time() - time1) octahedral_index = self.axes_idx_to_octahedral_idx(first_idx, second_idx) - print("OCTAHEDRAL UNMAP TIME") - print(time.time() - time1) + # print("OCTAHEDRAL UNMAP TIME ") + # print(time.time() - time1) return octahedral_index From a898711ae58f6290292a05352a327e8c9e8b55b9 Mon Sep 17 00:00:00 2001 From: Mathilde Leuridan Date: Thu, 19 Oct 2023 14:55:51 +0200 Subject: [PATCH 09/37] optimise second idx search --- .../transformations/datacube_mappers.py | 2713 +---------------- 1 file changed, 93 insertions(+), 2620 deletions(-) diff --git a/polytope/datacube/transformations/datacube_mappers.py b/polytope/datacube/transformations/datacube_mappers.py index 40870f1ac..a26a0df6f 100644 --- a/polytope/datacube/transformations/datacube_mappers.py +++ b/polytope/datacube/transformations/datacube_mappers.py @@ -253,10 +253,11 @@ def __init__(self, base_axis, mapped_axes, resolution): self._base_axis = base_axis self._resolution = resolution self._first_axis_vals = self.first_axis_vals() - self._inv_first_axis_vals = self._first_axis_vals[::-1] + # self._inv_first_axis_vals = self._first_axis_vals[::-1] # self._inv_first_axis_vals = {v:k for k,v in self._first_axis_vals.items()} self._first_idx_map = self.create_first_idx_map() - self.treated_first_vals = dict() + self._second_axis_spacing = dict() + # self.treated_first_vals = dict() def gauss_first_guess(self): i = 0 @@ -2888,2570 +2889,6 @@ def get_precomputed_values_N1280(self): lats[2559] = -89.946187715665616 return lats - def get_precomputed_values_N1280_new(self): - lats = np.empty([1280*2]) - lats[0] = 89.946187715665616 - lats[1] = 89.876478353332288 - lats[2] = 89.806357319542244 - lats[3] = 89.736143271609578 - lats[4] = 89.6658939412157 - lats[5] = 89.595627537554492 - lats[6] = 89.525351592371393 - lats[7] = 89.45506977912261 - lats[8] = 89.3847841013921 - lats[9] = 89.314495744374256 - lats[10] = 89.24420545380525 - lats[11] = 89.173913722284126 - lats[12] = 89.103620888238879 - lats[13] = 89.033327191845927 - lats[14] = 88.96303280826325 - lats[15] = 88.892737868230952 - lats[16] = 88.822442471310097 - lats[17] = 88.752146694650691 - lats[18] = 88.681850598961759 - lats[19] = 88.611554232668382 - lats[20] = 88.541257634868515 - lats[21] = 88.470960837474877 - lats[22] = 88.40066386679355 - lats[23] = 88.330366744702559 - lats[24] = 88.26006948954614 - lats[25] = 88.189772116820762 - lats[26] = 88.119474639706425 - lats[27] = 88.049177069484486 - lats[28] = 87.978879415867283 - lats[29] = 87.908581687261687 - lats[30] = 87.838283890981543 - lats[31] = 87.767986033419561 - lats[32] = 87.697688120188062 - lats[33] = 87.627390156234085 - lats[34] = 87.557092145935584 - lats[35] = 87.486794093180748 - lats[36] = 87.416496001434894 - lats[37] = 87.346197873795816 - lats[38] = 87.275899713041966 - lats[39] = 87.205601521672108 - lats[40] = 87.135303301939786 - lats[41] = 87.065005055882821 - lats[42] = 86.994706785348129 - lats[43] = 86.924408492014166 - lats[44] = 86.854110177408927 - lats[45] = 86.783811842927179 - lats[46] = 86.713513489844246 - lats[47] = 86.643215119328573 - lats[48] = 86.572916732453024 - lats[49] = 86.502618330203831 - lats[50] = 86.432319913489792 - lats[51] = 86.362021483149363 - lats[52] = 86.291723039957418 - lats[53] = 86.221424584631109 - lats[54] = 86.151126117835304 - lats[55] = 86.080827640187209 - lats[56] = 86.010529152260403 - lats[57] = 85.940230654588888 - lats[58] = 85.869932147670127 - lats[59] = 85.799633631968391 - lats[60] = 85.729335107917464 - lats[61] = 85.659036575922883 - lats[62] = 85.588738036364362 - lats[63] = 85.518439489597966 - lats[64] = 85.448140935957483 - lats[65] = 85.377842375756586 - lats[66] = 85.307543809290152 - lats[67] = 85.237245236835548 - lats[68] = 85.16694665865414 - lats[69] = 85.09664807499216 - lats[70] = 85.026349486081983 - lats[71] = 84.95605089214304 - lats[72] = 84.885752293382765 - lats[73] = 84.81545368999717 - lats[74] = 84.745155082171991 - lats[75] = 84.674856470082915 - lats[76] = 84.604557853896708 - lats[77] = 84.534259233771479 - lats[78] = 84.463960609857125 - lats[79] = 84.393661982296322 - lats[80] = 84.323363351224444 - lats[81] = 84.253064716770425 - lats[82] = 84.18276607905679 - lats[83] = 84.112467438200326 - lats[84] = 84.042168794312317 - lats[85] = 83.971870147498763 - lats[86] = 83.901571497860914 - lats[87] = 83.831272845495249 - lats[88] = 83.760974190494011 - lats[89] = 83.690675532945292 - lats[90] = 83.620376872933264 - lats[91] = 83.550078210538487 - lats[92] = 83.479779545838113 - lats[93] = 83.409480878905782 - lats[94] = 83.339182209812321 - lats[95] = 83.268883538625232 - lats[96] = 83.198584865409657 - lats[97] = 83.128286190227698 - lats[98] = 83.057987513139125 - lats[99] = 82.987688834201322 - lats[100] = 82.917390153469313 - lats[101] = 82.84709147099602 - lats[102] = 82.77679278683226 - lats[103] = 82.706494101026948 - lats[104] = 82.63619541362705 - lats[105] = 82.56589672467787 - lats[106] = 82.495598034222837 - lats[107] = 82.425299342304029 - lats[108] = 82.355000648961692 - lats[109] = 82.284701954234833 - lats[110] = 82.214403258160871 - lats[111] = 82.144104560776 - lats[112] = 82.073805862115165 - lats[113] = 82.003507162211946 - lats[114] = 81.933208461098829 - lats[115] = 81.862909758807191 - lats[116] = 81.792611055367345 - lats[117] = 81.722312350808508 - lats[118] = 81.652013645158945 - lats[119] = 81.581714938445955 - lats[120] = 81.511416230696042 - lats[121] = 81.441117521934686 - lats[122] = 81.370818812186627 - lats[123] = 81.300520101475826 - lats[124] = 81.230221389825374 - lats[125] = 81.159922677257711 - lats[126] = 81.089623963794551 - lats[127] = 81.019325249456955 - lats[128] = 80.949026534265244 - lats[129] = 80.878727818239184 - lats[130] = 80.808429101397948 - lats[131] = 80.73813038376008 - lats[132] = 80.667831665343556 - lats[133] = 80.59753294616587 - lats[134] = 80.527234226243991 - lats[135] = 80.456935505594302 - lats[136] = 80.386636784232863 - lats[137] = 80.316338062175078 - lats[138] = 80.246039339436052 - lats[139] = 80.175740616030438 - lats[140] = 80.105441891972376 - lats[141] = 80.035143167275749 - lats[142] = 79.9648444419539 - lats[143] = 79.894545716019948 - lats[144] = 79.824246989486554 - lats[145] = 79.753948262366038 - lats[146] = 79.683649534670437 - lats[147] = 79.61335080641139 - lats[148] = 79.543052077600308 - lats[149] = 79.472753348248219 - lats[150] = 79.402454618365894 - lats[151] = 79.332155887963822 - lats[152] = 79.261857157052191 - lats[153] = 79.191558425640977 - lats[154] = 79.121259693739859 - lats[155] = 79.050960961358285 - lats[156] = 78.980662228505423 - lats[157] = 78.910363495190211 - lats[158] = 78.840064761421445 - lats[159] = 78.769766027207638 - lats[160] = 78.699467292557102 - lats[161] = 78.629168557477882 - lats[162] = 78.558869821977908 - lats[163] = 78.488571086064923 - lats[164] = 78.418272349746417 - lats[165] = 78.347973613029708 - lats[166] = 78.277674875922045 - lats[167] = 78.207376138430348 - lats[168] = 78.137077400561424 - lats[169] = 78.066778662322022 - lats[170] = 77.996479923718596 - lats[171] = 77.926181184757539 - lats[172] = 77.855882445445019 - lats[173] = 77.785583705787161 - lats[174] = 77.71528496578982 - lats[175] = 77.644986225458879 - lats[176] = 77.574687484799924 - lats[177] = 77.504388743818524 - lats[178] = 77.434090002520122 - lats[179] = 77.363791260909963 - lats[180] = 77.293492518993247 - lats[181] = 77.22319377677502 - lats[182] = 77.15289503426024 - lats[183] = 77.082596291453768 - lats[184] = 77.012297548360323 - lats[185] = 76.941998804984564 - lats[186] = 76.871700061330955 - lats[187] = 76.801401317404 - lats[188] = 76.731102573208048 - lats[189] = 76.660803828747362 - lats[190] = 76.59050508402602 - lats[191] = 76.520206339048215 - lats[192] = 76.449907593817869 - lats[193] = 76.379608848338933 - lats[194] = 76.3093101026152 - lats[195] = 76.239011356650423 - lats[196] = 76.16871261044831 - lats[197] = 76.098413864012443 - lats[198] = 76.028115117346374 - lats[199] = 75.957816370453543 - lats[200] = 75.887517623337317 - lats[201] = 75.81721887600105 - lats[202] = 75.746920128447996 - lats[203] = 75.67662138068134 - lats[204] = 75.60632263270422 - lats[205] = 75.536023884519707 - lats[206] = 75.465725136130786 - lats[207] = 75.395426387540439 - lats[208] = 75.325127638751567 - lats[209] = 75.254828889766983 - lats[210] = 75.184530140589501 - lats[211] = 75.114231391221821 - lats[212] = 75.043932641666672 - lats[213] = 74.973633891926625 - lats[214] = 74.903335142004323 - lats[215] = 74.833036391902269 - lats[216] = 74.762737641622991 - lats[217] = 74.692438891168877 - lats[218] = 74.622140140542356 - lats[219] = 74.551841389745761 - lats[220] = 74.481542638781434 - lats[221] = 74.411243887651622 - lats[222] = 74.340945136358584 - lats[223] = 74.270646384904481 - lats[224] = 74.200347633291472 - lats[225] = 74.13004888152166 - lats[226] = 74.059750129597163 - lats[227] = 73.98945137751997 - lats[228] = 73.919152625292114 - lats[229] = 73.848853872915541 - lats[230] = 73.778555120392184 - lats[231] = 73.70825636772399 - lats[232] = 73.637957614912779 - lats[233] = 73.567658861960396 - lats[234] = 73.497360108868662 - lats[235] = 73.427061355639339 - lats[236] = 73.356762602274188 - lats[237] = 73.2864638487749 - lats[238] = 73.216165095143182 - lats[239] = 73.145866341380668 - lats[240] = 73.075567587489019 - lats[241] = 73.005268833469799 - lats[242] = 72.934970079324657 - lats[243] = 72.864671325055056 - lats[244] = 72.794372570662574 - lats[245] = 72.724073816148703 - lats[246] = 72.653775061514935 - lats[247] = 72.583476306762691 - lats[248] = 72.513177551893421 - lats[249] = 72.442878796908545 - lats[250] = 72.3725800418094 - lats[251] = 72.302281286597392 - lats[252] = 72.231982531273843 - lats[253] = 72.161683775840089 - lats[254] = 72.091385020297409 - lats[255] = 72.02108626464711 - lats[256] = 71.950787508890414 - lats[257] = 71.880488753028587 - lats[258] = 71.810189997062835 - lats[259] = 71.739891240994368 - lats[260] = 71.669592484824364 - lats[261] = 71.599293728553988 - lats[262] = 71.528994972184378 - lats[263] = 71.458696215716685 - lats[264] = 71.388397459152031 - lats[265] = 71.318098702491469 - lats[266] = 71.247799945736105 - lats[267] = 71.177501188887007 - lats[268] = 71.107202431945211 - lats[269] = 71.036903674911756 - lats[270] = 70.966604917787635 - lats[271] = 70.896306160573886 - lats[272] = 70.826007403271475 - lats[273] = 70.755708645881384 - lats[274] = 70.685409888404578 - lats[275] = 70.615111130841967 - lats[276] = 70.544812373194532 - lats[277] = 70.474513615463138 - lats[278] = 70.404214857648739 - lats[279] = 70.333916099752187 - lats[280] = 70.263617341774406 - lats[281] = 70.193318583716191 - lats[282] = 70.123019825578467 - lats[283] = 70.052721067362043 - lats[284] = 69.982422309067744 - lats[285] = 69.912123550696421 - lats[286] = 69.841824792248843 - lats[287] = 69.771526033725834 - lats[288] = 69.701227275128161 - lats[289] = 69.630928516456592 - lats[290] = 69.560629757711908 - lats[291] = 69.490330998894862 - lats[292] = 69.420032240006194 - lats[293] = 69.349733481046613 - lats[294] = 69.279434722016902 - lats[295] = 69.209135962917699 - lats[296] = 69.138837203749759 - lats[297] = 69.068538444513763 - lats[298] = 68.998239685210365 - lats[299] = 68.927940925840304 - lats[300] = 68.85764216640419 - lats[301] = 68.787343406902693 - lats[302] = 68.717044647336493 - lats[303] = 68.646745887706189 - lats[304] = 68.576447128012447 - lats[305] = 68.506148368255865 - lats[306] = 68.435849608437067 - lats[307] = 68.365550848556666 - lats[308] = 68.295252088615257 - lats[309] = 68.224953328613438 - lats[310] = 68.154654568551791 - lats[311] = 68.084355808430871 - lats[312] = 68.014057048251274 - lats[313] = 67.943758288013555 - lats[314] = 67.873459527718282 - lats[315] = 67.803160767365966 - lats[316] = 67.732862006957205 - lats[317] = 67.662563246492482 - lats[318] = 67.592264485972336 - lats[319] = 67.521965725397308 - lats[320] = 67.451666964767895 - lats[321] = 67.381368204084609 - lats[322] = 67.311069443347961 - lats[323] = 67.240770682558434 - lats[324] = 67.170471921716526 - lats[325] = 67.100173160822706 - lats[326] = 67.029874399877471 - lats[327] = 66.95957563888129 - lats[328] = 66.889276877834618 - lats[329] = 66.818978116737924 - lats[330] = 66.748679355591662 - lats[331] = 66.678380594396273 - lats[332] = 66.608081833152212 - lats[333] = 66.537783071859891 - lats[334] = 66.467484310519808 - lats[335] = 66.397185549132331 - lats[336] = 66.326886787697887 - lats[337] = 66.256588026216932 - lats[338] = 66.186289264689833 - lats[339] = 66.115990503117033 - lats[340] = 66.045691741498899 - lats[341] = 65.975392979835888 - lats[342] = 65.905094218128355 - lats[343] = 65.834795456376696 - lats[344] = 65.764496694581283 - lats[345] = 65.694197932742526 - lats[346] = 65.623899170860767 - lats[347] = 65.553600408936404 - lats[348] = 65.483301646969792 - lats[349] = 65.413002884961315 - lats[350] = 65.342704122911286 - lats[351] = 65.272405360820116 - lats[352] = 65.202106598688133 - lats[353] = 65.131807836515677 - lats[354] = 65.061509074303089 - lats[355] = 64.991210312050711 - lats[356] = 64.920911549758912 - lats[357] = 64.850612787427963 - lats[358] = 64.780314025058246 - lats[359] = 64.710015262650074 - lats[360] = 64.639716500203733 - lats[361] = 64.569417737719576 - lats[362] = 64.499118975197902 - lats[363] = 64.428820212639039 - lats[364] = 64.358521450043284 - lats[365] = 64.288222687410922 - lats[366] = 64.21792392474228 - lats[367] = 64.147625162037642 - lats[368] = 64.07732639929732 - lats[369] = 64.00702763652157 - lats[370] = 63.93672887371072 - lats[371] = 63.866430110865004 - lats[372] = 63.796131347984762 - lats[373] = 63.725832585070251 - lats[374] = 63.655533822121711 - lats[375] = 63.585235059139464 - lats[376] = 63.514936296123757 - lats[377] = 63.444637533074854 - lats[378] = 63.374338769993031 - lats[379] = 63.304040006878537 - lats[380] = 63.23374124373165 - lats[381] = 63.163442480552604 - lats[382] = 63.093143717341647 - lats[383] = 63.022844954099064 - lats[384] = 62.952546190825068 - lats[385] = 62.882247427519928 - lats[386] = 62.811948664183866 - lats[387] = 62.741649900817137 - lats[388] = 62.67135113741999 - lats[389] = 62.60105237399263 - lats[390] = 62.530753610535321 - lats[391] = 62.460454847048261 - lats[392] = 62.3901560835317 - lats[393] = 62.319857319985871 - lats[394] = 62.249558556410982 - lats[395] = 62.179259792807258 - lats[396] = 62.108961029174914 - lats[397] = 62.038662265514176 - lats[398] = 61.968363501825259 - lats[399] = 61.898064738108381 - lats[400] = 61.827765974363729 - lats[401] = 61.757467210591535 - lats[402] = 61.687168446791986 - lats[403] = 61.616869682965287 - lats[404] = 61.546570919111666 - lats[405] = 61.476272155231321 - lats[406] = 61.405973391324409 - lats[407] = 61.335674627391185 - lats[408] = 61.265375863431785 - lats[409] = 61.195077099446451 - lats[410] = 61.124778335435344 - lats[411] = 61.054479571398652 - lats[412] = 60.984180807336578 - lats[413] = 60.913882043249295 - lats[414] = 60.843583279137007 - lats[415] = 60.773284514999872 - lats[416] = 60.702985750838074 - lats[417] = 60.632686986651805 - lats[418] = 60.562388222441243 - lats[419] = 60.492089458206543 - lats[420] = 60.421790693947884 - lats[421] = 60.35149192966545 - lats[422] = 60.28119316535939 - lats[423] = 60.21089440102989 - lats[424] = 60.140595636677112 - lats[425] = 60.070296872301235 - lats[426] = 59.999998107902378 - lats[427] = 59.929699343480763 - lats[428] = 59.859400579036503 - lats[429] = 59.78910181456979 - lats[430] = 59.718803050080759 - lats[431] = 59.64850428556958 - lats[432] = 59.578205521036402 - lats[433] = 59.507906756481383 - lats[434] = 59.43760799190467 - lats[435] = 59.3673092273064 - lats[436] = 59.29701046268675 - lats[437] = 59.226711698045854 - lats[438] = 59.156412933383855 - lats[439] = 59.086114168700909 - lats[440] = 59.015815403997145 - lats[441] = 58.945516639272725 - lats[442] = 58.875217874527763 - lats[443] = 58.804919109762423 - lats[444] = 58.73462034497684 - lats[445] = 58.664321580171141 - lats[446] = 58.594022815345468 - lats[447] = 58.523724050499972 - lats[448] = 58.453425285634758 - lats[449] = 58.383126520749968 - lats[450] = 58.312827755845746 - lats[451] = 58.242528990922203 - lats[452] = 58.172230225979497 - lats[453] = 58.101931461017728 - lats[454] = 58.031632696037022 - lats[455] = 57.961333931037537 - lats[456] = 57.891035166019364 - lats[457] = 57.820736400982646 - lats[458] = 57.75043763592749 - lats[459] = 57.680138870854037 - lats[460] = 57.60984010576238 - lats[461] = 57.539541340652676 - lats[462] = 57.469242575525016 - lats[463] = 57.398943810379521 - lats[464] = 57.328645045216312 - lats[465] = 57.258346280035504 - lats[466] = 57.188047514837208 - lats[467] = 57.117748749621541 - lats[468] = 57.047449984388614 - lats[469] = 56.977151219138541 - lats[470] = 56.90685245387143 - lats[471] = 56.836553688587379 - lats[472] = 56.766254923286517 - lats[473] = 56.695956157968951 - lats[474] = 56.625657392634771 - lats[475] = 56.555358627284086 - lats[476] = 56.485059861917016 - lats[477] = 56.41476109653366 - lats[478] = 56.34446233113411 - lats[479] = 56.274163565718467 - lats[480] = 56.203864800286865 - lats[481] = 56.133566034839362 - lats[482] = 56.063267269376091 - lats[483] = 55.992968503897131 - lats[484] = 55.922669738402583 - lats[485] = 55.852370972892551 - lats[486] = 55.782072207367136 - lats[487] = 55.711773441826416 - lats[488] = 55.641474676270505 - lats[489] = 55.571175910699488 - lats[490] = 55.500877145113449 - lats[491] = 55.430578379512511 - lats[492] = 55.360279613896743 - lats[493] = 55.289980848266232 - lats[494] = 55.219682082621084 - lats[495] = 55.149383316961377 - lats[496] = 55.07908455128721 - lats[497] = 55.008785785598668 - lats[498] = 54.938487019895831 - lats[499] = 54.868188254178797 - lats[500] = 54.797889488447652 - lats[501] = 54.727590722702473 - lats[502] = 54.657291956943347 - lats[503] = 54.586993191170357 - lats[504] = 54.516694425383605 - lats[505] = 54.446395659583146 - lats[506] = 54.376096893769081 - lats[507] = 54.305798127941479 - lats[508] = 54.235499362100448 - lats[509] = 54.165200596246031 - lats[510] = 54.094901830378333 - lats[511] = 54.024603064497434 - lats[512] = 53.954304298603383 - lats[513] = 53.884005532696307 - lats[514] = 53.813706766776235 - lats[515] = 53.743408000843282 - lats[516] = 53.673109234897495 - lats[517] = 53.602810468938962 - lats[518] = 53.53251170296776 - lats[519] = 53.462212936983953 - lats[520] = 53.391914170987633 - lats[521] = 53.321615404978871 - lats[522] = 53.251316638957725 - lats[523] = 53.181017872924265 - lats[524] = 53.110719106878584 - lats[525] = 53.040420340820731 - lats[526] = 52.970121574750792 - lats[527] = 52.899822808668837 - lats[528] = 52.829524042574917 - lats[529] = 52.759225276469131 - lats[530] = 52.688926510351514 - lats[531] = 52.618627744222159 - lats[532] = 52.548328978081123 - lats[533] = 52.478030211928477 - lats[534] = 52.407731445764284 - lats[535] = 52.337432679588609 - lats[536] = 52.26713391340153 - lats[537] = 52.196835147203096 - lats[538] = 52.126536380993372 - lats[539] = 52.056237614772435 - lats[540] = 51.985938848540336 - lats[541] = 51.915640082297152 - lats[542] = 51.845341316042933 - lats[543] = 51.775042549777737 - lats[544] = 51.704743783501634 - lats[545] = 51.634445017214695 - lats[546] = 51.56414625091697 - lats[547] = 51.493847484608516 - lats[548] = 51.423548718289396 - lats[549] = 51.353249951959683 - lats[550] = 51.282951185619417 - lats[551] = 51.21265241926865 - lats[552] = 51.14235365290746 - lats[553] = 51.072054886535909 - lats[554] = 51.001756120154049 - lats[555] = 50.931457353761914 - lats[556] = 50.86115858735959 - lats[557] = 50.790859820947119 - lats[558] = 50.720561054524559 - lats[559] = 50.650262288091959 - lats[560] = 50.579963521649397 - lats[561] = 50.509664755196901 - lats[562] = 50.439365988734544 - lats[563] = 50.369067222262359 - lats[564] = 50.298768455780426 - lats[565] = 50.228469689288779 - lats[566] = 50.158170922787484 - lats[567] = 50.087872156276575 - lats[568] = 50.017573389756123 - lats[569] = 49.947274623226157 - lats[570] = 49.876975856686762 - lats[571] = 49.80667709013796 - lats[572] = 49.736378323579807 - lats[573] = 49.66607955701236 - lats[574] = 49.595780790435676 - lats[575] = 49.525482023849783 - lats[576] = 49.455183257254745 - lats[577] = 49.384884490650613 - lats[578] = 49.314585724037435 - lats[579] = 49.244286957415234 - lats[580] = 49.173988190784094 - lats[581] = 49.103689424144044 - lats[582] = 49.03339065749514 - lats[583] = 48.963091890837418 - lats[584] = 48.892793124170929 - lats[585] = 48.822494357495721 - lats[586] = 48.752195590811837 - lats[587] = 48.681896824119335 - lats[588] = 48.611598057418242 - lats[589] = 48.541299290708608 - lats[590] = 48.47100052399049 - lats[591] = 48.400701757263917 - lats[592] = 48.330402990528938 - lats[593] = 48.260104223785596 - lats[594] = 48.189805457033941 - lats[595] = 48.119506690274015 - lats[596] = 48.049207923505868 - lats[597] = 47.978909156729507 - lats[598] = 47.908610389945018 - lats[599] = 47.838311623152421 - lats[600] = 47.76801285635176 - lats[601] = 47.697714089543084 - lats[602] = 47.627415322726435 - lats[603] = 47.557116555901828 - lats[604] = 47.486817789069342 - lats[605] = 47.416519022228997 - lats[606] = 47.346220255380835 - lats[607] = 47.275921488524894 - lats[608] = 47.205622721661214 - lats[609] = 47.13532395478984 - lats[610] = 47.065025187910805 - lats[611] = 46.994726421024154 - lats[612] = 46.924427654129929 - lats[613] = 46.85412888722815 - lats[614] = 46.783830120318882 - lats[615] = 46.713531353402139 - lats[616] = 46.643232586477971 - lats[617] = 46.572933819546414 - lats[618] = 46.502635052607502 - lats[619] = 46.432336285661272 - lats[620] = 46.362037518707766 - lats[621] = 46.291738751747012 - lats[622] = 46.221439984779053 - lats[623] = 46.151141217803925 - lats[624] = 46.080842450821663 - lats[625] = 46.01054368383231 - lats[626] = 45.94024491683588 - lats[627] = 45.869946149832437 - lats[628] = 45.799647382821995 - lats[629] = 45.729348615804589 - lats[630] = 45.659049848780263 - lats[631] = 45.588751081749038 - lats[632] = 45.51845231471097 - lats[633] = 45.448153547666081 - lats[634] = 45.377854780614399 - lats[635] = 45.30755601355596 - lats[636] = 45.237257246490813 - lats[637] = 45.166958479418959 - lats[638] = 45.096659712340461 - lats[639] = 45.026360945255341 - lats[640] = 44.956062178163634 - lats[641] = 44.885763411065362 - lats[642] = 44.81546464396056 - lats[643] = 44.745165876849271 - lats[644] = 44.674867109731515 - lats[645] = 44.604568342607337 - lats[646] = 44.534269575476756 - lats[647] = 44.463970808339802 - lats[648] = 44.39367204119651 - lats[649] = 44.323373274046915 - lats[650] = 44.253074506891046 - lats[651] = 44.182775739728925 - lats[652] = 44.112476972560586 - lats[653] = 44.042178205386072 - lats[654] = 43.971879438205391 - lats[655] = 43.9015806710186 - lats[656] = 43.831281903825705 - lats[657] = 43.760983136626741 - lats[658] = 43.690684369421732 - lats[659] = 43.620385602210717 - lats[660] = 43.550086834993728 - lats[661] = 43.479788067770777 - lats[662] = 43.409489300541907 - lats[663] = 43.339190533307139 - lats[664] = 43.26889176606651 - lats[665] = 43.19859299882004 - lats[666] = 43.128294231567757 - lats[667] = 43.057995464309691 - lats[668] = 42.987696697045862 - lats[669] = 42.917397929776307 - lats[670] = 42.847099162501053 - lats[671] = 42.776800395220121 - lats[672] = 42.706501627933541 - lats[673] = 42.63620286064134 - lats[674] = 42.565904093343548 - lats[675] = 42.495605326040177 - lats[676] = 42.425306558731272 - lats[677] = 42.355007791416853 - lats[678] = 42.284709024096927 - lats[679] = 42.214410256771551 - lats[680] = 42.144111489440725 - lats[681] = 42.073812722104492 - lats[682] = 42.003513954762873 - lats[683] = 41.933215187415882 - lats[684] = 41.862916420063563 - lats[685] = 41.792617652705921 - lats[686] = 41.722318885343 - lats[687] = 41.6520201179748 - lats[688] = 41.581721350601363 - lats[689] = 41.511422583222718 - lats[690] = 41.441123815838885 - lats[691] = 41.370825048449873 - lats[692] = 41.300526281055724 - lats[693] = 41.230227513656445 - lats[694] = 41.159928746252085 - lats[695] = 41.089629978842645 - lats[696] = 41.01933121142816 - lats[697] = 40.949032444008644 - lats[698] = 40.878733676584126 - lats[699] = 40.808434909154634 - lats[700] = 40.738136141720176 - lats[701] = 40.667837374280786 - lats[702] = 40.597538606836487 - lats[703] = 40.527239839387299 - lats[704] = 40.456941071933244 - lats[705] = 40.386642304474343 - lats[706] = 40.316343537010617 - lats[707] = 40.246044769542102 - lats[708] = 40.175746002068806 - lats[709] = 40.105447234590748 - lats[710] = 40.035148467107952 - lats[711] = 39.964849699620437 - lats[712] = 39.894550932128247 - lats[713] = 39.824252164631375 - lats[714] = 39.753953397129855 - lats[715] = 39.683654629623703 - lats[716] = 39.613355862112947 - lats[717] = 39.543057094597607 - lats[718] = 39.472758327077692 - lats[719] = 39.402459559553229 - lats[720] = 39.332160792024254 - lats[721] = 39.261862024490775 - lats[722] = 39.191563256952804 - lats[723] = 39.121264489410365 - lats[724] = 39.050965721863491 - lats[725] = 38.980666954312184 - lats[726] = 38.910368186756479 - lats[727] = 38.840069419196389 - lats[728] = 38.769770651631937 - lats[729] = 38.699471884063136 - lats[730] = 38.629173116490001 - lats[731] = 38.558874348912568 - lats[732] = 38.488575581330842 - lats[733] = 38.418276813744846 - lats[734] = 38.347978046154608 - lats[735] = 38.277679278560143 - lats[736] = 38.20738051096145 - lats[737] = 38.137081743358586 - lats[738] = 38.066782975751536 - lats[739] = 37.99648420814033 - lats[740] = 37.926185440524989 - lats[741] = 37.855886672905527 - lats[742] = 37.785587905281965 - lats[743] = 37.715289137654317 - lats[744] = 37.644990370022605 - lats[745] = 37.574691602386856 - lats[746] = 37.504392834747065 - lats[747] = 37.434094067103274 - lats[748] = 37.363795299455489 - lats[749] = 37.293496531803719 - lats[750] = 37.223197764147997 - lats[751] = 37.152898996488332 - lats[752] = 37.082600228824752 - lats[753] = 37.012301461157264 - lats[754] = 36.942002693485883 - lats[755] = 36.871703925810628 - lats[756] = 36.801405158131523 - lats[757] = 36.731106390448581 - lats[758] = 36.660807622761808 - lats[759] = 36.590508855071242 - lats[760] = 36.520210087376888 - lats[761] = 36.449911319678755 - lats[762] = 36.379612551976876 - lats[763] = 36.309313784271254 - lats[764] = 36.239015016561908 - lats[765] = 36.16871624884886 - lats[766] = 36.098417481132117 - lats[767] = 36.028118713411708 - lats[768] = 35.957819945687639 - lats[769] = 35.887521177959933 - lats[770] = 35.817222410228595 - lats[771] = 35.746923642493655 - lats[772] = 35.676624874755113 - lats[773] = 35.606326107012997 - lats[774] = 35.536027339267314 - lats[775] = 35.465728571518085 - lats[776] = 35.395429803765317 - lats[777] = 35.325131036009047 - lats[778] = 35.254832268249267 - lats[779] = 35.184533500486005 - lats[780] = 35.114234732719261 - lats[781] = 35.043935964949064 - lats[782] = 34.973637197175435 - lats[783] = 34.903338429398374 - lats[784] = 34.833039661617903 - lats[785] = 34.762740893834028 - lats[786] = 34.692442126046771 - lats[787] = 34.622143358256153 - lats[788] = 34.551844590462188 - lats[789] = 34.481545822664863 - lats[790] = 34.411247054864234 - lats[791] = 34.340948287060286 - lats[792] = 34.270649519253041 - lats[793] = 34.200350751442521 - lats[794] = 34.130051983628725 - lats[795] = 34.059753215811682 - lats[796] = 33.989454447991392 - lats[797] = 33.919155680167876 - lats[798] = 33.848856912341155 - lats[799] = 33.778558144511237 - lats[800] = 33.708259376678136 - lats[801] = 33.637960608841851 - lats[802] = 33.567661841002426 - lats[803] = 33.497363073159853 - lats[804] = 33.42706430531414 - lats[805] = 33.356765537465314 - lats[806] = 33.286466769613391 - lats[807] = 33.216168001758369 - lats[808] = 33.145869233900278 - lats[809] = 33.075570466039117 - lats[810] = 33.005271698174909 - lats[811] = 32.934972930307666 - lats[812] = 32.864674162437396 - lats[813] = 32.794375394564113 - lats[814] = 32.724076626687825 - lats[815] = 32.653777858808567 - lats[816] = 32.583479090926325 - lats[817] = 32.513180323041112 - lats[818] = 32.442881555152965 - lats[819] = 32.372582787261891 - lats[820] = 32.302284019367875 - lats[821] = 32.231985251470959 - lats[822] = 32.161686483571145 - lats[823] = 32.091387715668439 - lats[824] = 32.021088947762863 - lats[825] = 31.950790179854422 - lats[826] = 31.880491411943137 - lats[827] = 31.810192644029012 - lats[828] = 31.739893876112063 - lats[829] = 31.669595108192297 - lats[830] = 31.599296340269738 - lats[831] = 31.528997572344384 - lats[832] = 31.458698804416255 - lats[833] = 31.388400036485361 - lats[834] = 31.318101268551715 - lats[835] = 31.247802500615318 - lats[836] = 31.177503732676204 - lats[837] = 31.107204964734358 - lats[838] = 31.036906196789811 - lats[839] = 30.966607428842572 - lats[840] = 30.896308660892647 - lats[841] = 30.826009892940046 - lats[842] = 30.755711124984781 - lats[843] = 30.685412357026873 - lats[844] = 30.615113589066322 - lats[845] = 30.544814821103138 - lats[846] = 30.47451605313735 - lats[847] = 30.404217285168947 - lats[848] = 30.333918517197947 - lats[849] = 30.263619749224372 - lats[850] = 30.19332098124822 - lats[851] = 30.123022213269511 - lats[852] = 30.052723445288244 - lats[853] = 29.98242467730444 - lats[854] = 29.91212590931811 - lats[855] = 29.841827141329258 - lats[856] = 29.771528373337894 - lats[857] = 29.701229605344039 - lats[858] = 29.630930837347698 - lats[859] = 29.560632069348884 - lats[860] = 29.490333301347597 - lats[861] = 29.420034533343859 - lats[862] = 29.349735765337677 - lats[863] = 29.279436997329057 - lats[864] = 29.209138229318015 - lats[865] = 29.138839461304556 - lats[866] = 29.068540693288696 - lats[867] = 28.998241925270449 - lats[868] = 28.927943157249814 - lats[869] = 28.857644389226806 - lats[870] = 28.787345621201432 - lats[871] = 28.717046853173709 - lats[872] = 28.646748085143642 - lats[873] = 28.576449317111244 - lats[874] = 28.506150549076519 - lats[875] = 28.435851781039485 - lats[876] = 28.365553013000145 - lats[877] = 28.29525424495851 - lats[878] = 28.224955476914594 - lats[879] = 28.154656708868405 - lats[880] = 28.084357940819952 - lats[881] = 28.014059172769244 - lats[882] = 27.94376040471629 - lats[883] = 27.873461636661098 - lats[884] = 27.803162868603682 - lats[885] = 27.732864100544052 - lats[886] = 27.662565332482213 - lats[887] = 27.592266564418171 - lats[888] = 27.521967796351948 - lats[889] = 27.451669028283543 - lats[890] = 27.381370260212968 - lats[891] = 27.311071492140236 - lats[892] = 27.240772724065348 - lats[893] = 27.170473955988321 - lats[894] = 27.100175187909159 - lats[895] = 27.029876419827872 - lats[896] = 26.959577651744471 - lats[897] = 26.889278883658971 - lats[898] = 26.818980115571364 - lats[899] = 26.748681347481678 - lats[900] = 26.678382579389908 - lats[901] = 26.608083811296069 - lats[902] = 26.53778504320017 - lats[903] = 26.467486275102218 - lats[904] = 26.397187507002222 - lats[905] = 26.326888738900195 - lats[906] = 26.256589970796135 - lats[907] = 26.186291202690064 - lats[908] = 26.115992434581983 - lats[909] = 26.045693666471902 - lats[910] = 25.975394898359827 - lats[911] = 25.90509613024577 - lats[912] = 25.834797362129745 - lats[913] = 25.764498594011751 - lats[914] = 25.694199825891793 - lats[915] = 25.623901057769892 - lats[916] = 25.553602289646051 - lats[917] = 25.483303521520277 - lats[918] = 25.413004753392578 - lats[919] = 25.342705985262967 - lats[920] = 25.272407217131445 - lats[921] = 25.202108448998025 - lats[922] = 25.13180968086272 - lats[923] = 25.061510912725527 - lats[924] = 24.991212144586456 - lats[925] = 24.920913376445526 - lats[926] = 24.850614608302738 - lats[927] = 24.780315840158096 - lats[928] = 24.710017072011613 - lats[929] = 24.639718303863294 - lats[930] = 24.569419535713152 - lats[931] = 24.499120767561195 - lats[932] = 24.428821999407425 - lats[933] = 24.358523231251851 - lats[934] = 24.288224463094483 - lats[935] = 24.217925694935328 - lats[936] = 24.1476269267744 - lats[937] = 24.077328158611696 - lats[938] = 24.007029390447226 - lats[939] = 23.936730622281004 - lats[940] = 23.866431854113038 - lats[941] = 23.796133085943328 - lats[942] = 23.725834317771888 - lats[943] = 23.655535549598721 - lats[944] = 23.585236781423838 - lats[945] = 23.514938013247242 - lats[946] = 23.444639245068949 - lats[947] = 23.374340476888957 - lats[948] = 23.304041708707278 - lats[949] = 23.233742940523921 - lats[950] = 23.163444172338895 - lats[951] = 23.0931454041522 - lats[952] = 23.022846635963852 - lats[953] = 22.952547867773848 - lats[954] = 22.882249099582204 - lats[955] = 22.811950331388925 - lats[956] = 22.741651563194019 - lats[957] = 22.671352794997489 - lats[958] = 22.60105402679935 - lats[959] = 22.530755258599601 - lats[960] = 22.460456490398254 - lats[961] = 22.390157722195315 - lats[962] = 22.319858953990789 - lats[963] = 22.249560185784691 - lats[964] = 22.179261417577013 - lats[965] = 22.108962649367779 - lats[966] = 22.038663881156989 - lats[967] = 21.968365112944642 - lats[968] = 21.898066344730758 - lats[969] = 21.827767576515338 - lats[970] = 21.757468808298391 - lats[971] = 21.687170040079913 - lats[972] = 21.616871271859928 - lats[973] = 21.546572503638437 - lats[974] = 21.47627373541544 - lats[975] = 21.40597496719095 - lats[976] = 21.335676198964972 - lats[977] = 21.265377430737512 - lats[978] = 21.195078662508585 - lats[979] = 21.124779894278181 - lats[980] = 21.054481126046323 - lats[981] = 20.984182357813012 - lats[982] = 20.913883589578251 - lats[983] = 20.843584821342048 - lats[984] = 20.773286053104417 - lats[985] = 20.702987284865355 - lats[986] = 20.632688516624874 - lats[987] = 20.562389748382977 - lats[988] = 20.492090980139672 - lats[989] = 20.421792211894967 - lats[990] = 20.35149344364887 - lats[991] = 20.28119467540138 - lats[992] = 20.210895907152516 - lats[993] = 20.140597138902272 - lats[994] = 20.070298370650661 - lats[995] = 19.999999602397686 - lats[996] = 19.929700834143357 - lats[997] = 19.859402065887682 - lats[998] = 19.789103297630657 - lats[999] = 19.718804529372303 - lats[1000] = 19.648505761112613 - lats[1001] = 19.578206992851602 - lats[1002] = 19.507908224589269 - lats[1003] = 19.437609456325632 - lats[1004] = 19.367310688060684 - lats[1005] = 19.297011919794439 - lats[1006] = 19.226713151526898 - lats[1007] = 19.15641438325807 - lats[1008] = 19.086115614987968 - lats[1009] = 19.015816846716586 - lats[1010] = 18.945518078443939 - lats[1011] = 18.875219310170031 - lats[1012] = 18.804920541894862 - lats[1013] = 18.734621773618446 - lats[1014] = 18.664323005340787 - lats[1015] = 18.594024237061891 - lats[1016] = 18.523725468781763 - lats[1017] = 18.453426700500408 - lats[1018] = 18.383127932217832 - lats[1019] = 18.312829163934047 - lats[1020] = 18.242530395649048 - lats[1021] = 18.172231627362851 - lats[1022] = 18.101932859075458 - lats[1023] = 18.031634090786874 - lats[1024] = 17.96133532249711 - lats[1025] = 17.89103655420616 - lats[1026] = 17.820737785914044 - lats[1027] = 17.75043901762076 - lats[1028] = 17.680140249326314 - lats[1029] = 17.60984148103071 - lats[1030] = 17.539542712733962 - lats[1031] = 17.469243944436066 - lats[1032] = 17.39894517613704 - lats[1033] = 17.328646407836878 - lats[1034] = 17.258347639535586 - lats[1035] = 17.188048871233182 - lats[1036] = 17.117750102929655 - lats[1037] = 17.04745133462502 - lats[1038] = 16.977152566319283 - lats[1039] = 16.906853798012452 - lats[1040] = 16.836555029704527 - lats[1041] = 16.766256261395515 - lats[1042] = 16.69595749308542 - lats[1043] = 16.625658724774254 - lats[1044] = 16.555359956462013 - lats[1045] = 16.485061188148713 - lats[1046] = 16.41476241983435 - lats[1047] = 16.344463651518936 - lats[1048] = 16.274164883202477 - lats[1049] = 16.203866114884974 - lats[1050] = 16.133567346566434 - lats[1051] = 16.063268578246863 - lats[1052] = 15.992969809926265 - lats[1053] = 15.922671041604652 - lats[1054] = 15.852372273282016 - lats[1055] = 15.78207350495838 - lats[1056] = 15.711774736633735 - lats[1057] = 15.641475968308091 - lats[1058] = 15.571177199981456 - lats[1059] = 15.500878431653829 - lats[1060] = 15.430579663325226 - lats[1061] = 15.360280894995643 - lats[1062] = 15.289982126665089 - lats[1063] = 15.219683358333569 - lats[1064] = 15.149384590001089 - lats[1065] = 15.07908582166765 - lats[1066] = 15.008787053333259 - lats[1067] = 14.938488284997929 - lats[1068] = 14.868189516661655 - lats[1069] = 14.797890748324447 - lats[1070] = 14.727591979986309 - lats[1071] = 14.657293211647247 - lats[1072] = 14.586994443307265 - lats[1073] = 14.516695674966371 - lats[1074] = 14.446396906624567 - lats[1075] = 14.376098138281863 - lats[1076] = 14.305799369938256 - lats[1077] = 14.23550060159376 - lats[1078] = 14.165201833248371 - lats[1079] = 14.0949030649021 - lats[1080] = 14.024604296554955 - lats[1081] = 13.954305528206934 - lats[1082] = 13.884006759858046 - lats[1083] = 13.813707991508297 - lats[1084] = 13.743409223157688 - lats[1085] = 13.673110454806226 - lats[1086] = 13.602811686453919 - lats[1087] = 13.532512918100766 - lats[1088] = 13.46221414974678 - lats[1089] = 13.391915381391959 - lats[1090] = 13.32161661303631 - lats[1091] = 13.251317844679837 - lats[1092] = 13.181019076322551 - lats[1093] = 13.110720307964451 - lats[1094] = 13.040421539605545 - lats[1095] = 12.970122771245832 - lats[1096] = 12.899824002885323 - lats[1097] = 12.829525234524022 - lats[1098] = 12.759226466161934 - lats[1099] = 12.688927697799061 - lats[1100] = 12.618628929435411 - lats[1101] = 12.548330161070988 - lats[1102] = 12.478031392705796 - lats[1103] = 12.407732624339841 - lats[1104] = 12.337433855973126 - lats[1105] = 12.267135087605659 - lats[1106] = 12.196836319237443 - lats[1107] = 12.126537550868482 - lats[1108] = 12.056238782498781 - lats[1109] = 11.985940014128348 - lats[1110] = 11.915641245757183 - lats[1111] = 11.845342477385294 - lats[1112] = 11.775043709012685 - lats[1113] = 11.704744940639358 - lats[1114] = 11.634446172265324 - lats[1115] = 11.564147403890583 - lats[1116] = 11.493848635515141 - lats[1117] = 11.423549867139002 - lats[1118] = 11.35325109876217 - lats[1119] = 11.282952330384653 - lats[1120] = 11.212653562006453 - lats[1121] = 11.142354793627575 - lats[1122] = 11.072056025248026 - lats[1123] = 11.001757256867807 - lats[1124] = 10.931458488486923 - lats[1125] = 10.861159720105382 - lats[1126] = 10.790860951723188 - lats[1127] = 10.720562183340341 - lats[1128] = 10.65026341495685 - lats[1129] = 10.579964646572719 - lats[1130] = 10.509665878187954 - lats[1131] = 10.439367109802557 - lats[1132] = 10.369068341416533 - lats[1133] = 10.298769573029887 - lats[1134] = 10.228470804642624 - lats[1135] = 10.158172036254747 - lats[1136] = 10.087873267866264 - lats[1137] = 10.017574499477174 - lats[1138] = 9.9472757310874869 - lats[1139] = 9.8769769626972046 - lats[1140] = 9.8066781943063344 - lats[1141] = 9.7363794259148779 - lats[1142] = 9.6660806575228388 - lats[1143] = 9.5957818891302242 - lats[1144] = 9.5254831207370376 - lats[1145] = 9.4551843523432826 - lats[1146] = 9.3848855839489662 - lats[1147] = 9.3145868155540921 - lats[1148] = 9.2442880471586619 - lats[1149] = 9.1739892787626829 - lats[1150] = 9.1036905103661585 - lats[1151] = 9.0333917419690941 - lats[1152] = 8.963092973571495 - lats[1153] = 8.8927942051733631 - lats[1154] = 8.8224954367747017 - lats[1155] = 8.7521966683755217 - lats[1156] = 8.6818978999758194 - lats[1157] = 8.6115991315756055 - lats[1158] = 8.5413003631748801 - lats[1159] = 8.4710015947736537 - lats[1160] = 8.4007028263719228 - lats[1161] = 8.3304040579696963 - lats[1162] = 8.2601052895669778 - lats[1163] = 8.1898065211637725 - lats[1164] = 8.1195077527600841 - lats[1165] = 8.049208984355916 - lats[1166] = 7.9789102159512737 - lats[1167] = 7.9086114475461606 - lats[1168] = 7.8383126791405831 - lats[1169] = 7.7680139107345463 - lats[1170] = 7.6977151423280494 - lats[1171] = 7.6274163739210996 - lats[1172] = 7.557117605513703 - lats[1173] = 7.4868188371058624 - lats[1174] = 7.4165200686975803 - lats[1175] = 7.3462213002888648 - lats[1176] = 7.2759225318797176 - lats[1177] = 7.2056237634701441 - lats[1178] = 7.1353249950601469 - lats[1179] = 7.0650262266497315 - lats[1180] = 6.994727458238903 - lats[1181] = 6.924428689827665 - lats[1182] = 6.8541299214160212 - lats[1183] = 6.7838311530039768 - lats[1184] = 6.7135323845915353 - lats[1185] = 6.6432336161787013 - lats[1186] = 6.5729348477654792 - lats[1187] = 6.5026360793518734 - lats[1188] = 6.4323373109378874 - lats[1189] = 6.3620385425235257 - lats[1190] = 6.2917397741087928 - lats[1191] = 6.2214410056936931 - lats[1192] = 6.151142237278231 - lats[1193] = 6.0808434688624091 - lats[1194] = 6.0105447004462347 - lats[1195] = 5.9402459320297085 - lats[1196] = 5.869947163612836 - lats[1197] = 5.7996483951956233 - lats[1198] = 5.729349626778073 - lats[1199] = 5.6590508583601888 - lats[1200] = 5.5887520899419751 - lats[1201] = 5.5184533215234373 - lats[1202] = 5.4481545531045787 - lats[1203] = 5.3778557846854023 - lats[1204] = 5.3075570162659149 - lats[1205] = 5.2372582478461194 - lats[1206] = 5.1669594794260192 - lats[1207] = 5.0966607110056197 - lats[1208] = 5.0263619425849244 - lats[1209] = 4.9560631741639369 - lats[1210] = 4.8857644057426626 - lats[1211] = 4.8154656373211049 - lats[1212] = 4.7451668688992683 - lats[1213] = 4.6748681004771564 - lats[1214] = 4.6045693320547736 - lats[1215] = 4.5342705636321252 - lats[1216] = 4.4639717952092139 - lats[1217] = 4.3936730267860451 - lats[1218] = 4.3233742583626205 - lats[1219] = 4.2530754899389471 - lats[1220] = 4.1827767215150269 - lats[1221] = 4.1124779530908659 - lats[1222] = 4.0421791846664661 - lats[1223] = 3.9718804162418326 - lats[1224] = 3.90158164781697 - lats[1225] = 3.8312828793918823 - lats[1226] = 3.7609841109665734 - lats[1227] = 3.6906853425410477 - lats[1228] = 3.6203865741153085 - lats[1229] = 3.5500878056893601 - lats[1230] = 3.4797890372632065 - lats[1231] = 3.4094902688368531 - lats[1232] = 3.339191500410303 - lats[1233] = 3.2688927319835597 - lats[1234] = 3.1985939635566285 - lats[1235] = 3.1282951951295126 - lats[1236] = 3.0579964267022164 - lats[1237] = 2.9876976582747439 - lats[1238] = 2.9173988898470999 - lats[1239] = 2.8471001214192873 - lats[1240] = 2.7768013529913107 - lats[1241] = 2.7065025845631743 - lats[1242] = 2.6362038161348824 - lats[1243] = 2.5659050477064382 - lats[1244] = 2.4956062792778466 - lats[1245] = 2.4253075108491116 - lats[1246] = 2.3550087424202366 - lats[1247] = 2.2847099739912267 - lats[1248] = 2.2144112055620848 - lats[1249] = 2.1441124371328155 - lats[1250] = 2.0738136687034232 - lats[1251] = 2.0035149002739114 - lats[1252] = 1.9332161318442849 - lats[1253] = 1.8629173634145471 - lats[1254] = 1.792618594984702 - lats[1255] = 1.7223198265547539 - lats[1256] = 1.6520210581247066 - lats[1257] = 1.5817222896945646 - lats[1258] = 1.5114235212643317 - lats[1259] = 1.4411247528340119 - lats[1260] = 1.3708259844036093 - lats[1261] = 1.300527215973128 - lats[1262] = 1.2302284475425722 - lats[1263] = 1.1599296791119456 - lats[1264] = 1.0896309106812523 - lats[1265] = 1.0193321422504964 - lats[1266] = 0.949033373819682 - lats[1267] = 0.87873460538881287 - lats[1268] = 0.80843583695789356 - lats[1269] = 0.73813706852692773 - lats[1270] = 0.66783830009591949 - lats[1271] = 0.59753953166487306 - lats[1272] = 0.52724076323379232 - lats[1273] = 0.45694199480268116 - lats[1274] = 0.3866432263715438 - lats[1275] = 0.31634445794038429 - lats[1276] = 0.24604568950920663 - lats[1277] = 0.17574692107801482 - lats[1278] = 0.10544815264681295 - lats[1279] = 0.035149384215604956 - lats[1280] = -0.035149384215604956 - lats[1281] = -0.10544815264681295 - lats[1282] = -0.17574692107801482 - lats[1283] = -0.24604568950920663 - lats[1284] = -0.31634445794038429 - lats[1285] = -0.3866432263715438 - lats[1286] = -0.45694199480268116 - lats[1287] = -0.52724076323379232 - lats[1288] = -0.59753953166487306 - lats[1289] = -0.66783830009591949 - lats[1290] = -0.73813706852692773 - lats[1291] = -0.80843583695789356 - lats[1292] = -0.87873460538881287 - lats[1293] = -0.949033373819682 - lats[1294] = -1.0193321422504964 - lats[1295] = -1.0896309106812523 - lats[1296] = -1.1599296791119456 - lats[1297] = -1.2302284475425722 - lats[1298] = -1.300527215973128 - lats[1299] = -1.3708259844036093 - lats[1300] = -1.4411247528340119 - lats[1301] = -1.5114235212643317 - lats[1302] = -1.5817222896945646 - lats[1303] = -1.6520210581247066 - lats[1304] = -1.7223198265547539 - lats[1305] = -1.792618594984702 - lats[1306] = -1.8629173634145471 - lats[1307] = -1.9332161318442849 - lats[1308] = -2.0035149002739114 - lats[1309] = -2.0738136687034232 - lats[1310] = -2.1441124371328155 - lats[1311] = -2.2144112055620848 - lats[1312] = -2.2847099739912267 - lats[1313] = -2.3550087424202366 - lats[1314] = -2.4253075108491116 - lats[1315] = -2.4956062792778466 - lats[1316] = -2.5659050477064382 - lats[1317] = -2.6362038161348824 - lats[1318] = -2.7065025845631743 - lats[1319] = -2.7768013529913107 - lats[1320] = -2.8471001214192873 - lats[1321] = -2.9173988898470999 - lats[1322] = -2.9876976582747439 - lats[1323] = -3.0579964267022164 - lats[1324] = -3.1282951951295126 - lats[1325] = -3.1985939635566285 - lats[1326] = -3.2688927319835597 - lats[1327] = -3.339191500410303 - lats[1328] = -3.4094902688368531 - lats[1329] = -3.4797890372632065 - lats[1330] = -3.5500878056893601 - lats[1331] = -3.6203865741153085 - lats[1332] = -3.6906853425410477 - lats[1333] = -3.7609841109665734 - lats[1334] = -3.8312828793918823 - lats[1335] = -3.90158164781697 - lats[1336] = -3.9718804162418326 - lats[1337] = -4.0421791846664661 - lats[1338] = -4.1124779530908659 - lats[1339] = -4.1827767215150269 - lats[1340] = -4.2530754899389471 - lats[1341] = -4.3233742583626205 - lats[1342] = -4.3936730267860451 - lats[1343] = -4.4639717952092139 - lats[1344] = -4.5342705636321252 - lats[1345] = -4.6045693320547736 - lats[1346] = -4.6748681004771564 - lats[1347] = -4.7451668688992683 - lats[1348] = -4.8154656373211049 - lats[1349] = -4.8857644057426626 - lats[1350] = -4.9560631741639369 - lats[1351] = -5.0263619425849244 - lats[1352] = -5.0966607110056197 - lats[1353] = -5.1669594794260192 - lats[1354] = -5.2372582478461194 - lats[1355] = -5.3075570162659149 - lats[1356] = -5.3778557846854023 - lats[1357] = -5.4481545531045787 - lats[1358] = -5.5184533215234373 - lats[1359] = -5.5887520899419751 - lats[1360] = -5.6590508583601888 - lats[1361] = -5.729349626778073 - lats[1362] = -5.7996483951956233 - lats[1363] = -5.869947163612836 - lats[1364] = -5.9402459320297085 - lats[1365] = -6.0105447004462347 - lats[1366] = -6.0808434688624091 - lats[1367] = -6.151142237278231 - lats[1368] = -6.2214410056936931 - lats[1369] = -6.2917397741087928 - lats[1370] = -6.3620385425235257 - lats[1371] = -6.4323373109378874 - lats[1372] = -6.5026360793518734 - lats[1373] = -6.5729348477654792 - lats[1374] = -6.6432336161787013 - lats[1375] = -6.7135323845915353 - lats[1376] = -6.7838311530039768 - lats[1377] = -6.8541299214160212 - lats[1378] = -6.924428689827665 - lats[1379] = -6.994727458238903 - lats[1380] = -7.0650262266497315 - lats[1381] = -7.1353249950601469 - lats[1382] = -7.2056237634701441 - lats[1383] = -7.2759225318797176 - lats[1384] = -7.3462213002888648 - lats[1385] = -7.4165200686975803 - lats[1386] = -7.4868188371058624 - lats[1387] = -7.557117605513703 - lats[1388] = -7.6274163739210996 - lats[1389] = -7.6977151423280494 - lats[1390] = -7.7680139107345463 - lats[1391] = -7.8383126791405831 - lats[1392] = -7.9086114475461606 - lats[1393] = -7.9789102159512737 - lats[1394] = -8.049208984355916 - lats[1395] = -8.1195077527600841 - lats[1396] = -8.1898065211637725 - lats[1397] = -8.2601052895669778 - lats[1398] = -8.3304040579696963 - lats[1399] = -8.4007028263719228 - lats[1400] = -8.4710015947736537 - lats[1401] = -8.5413003631748801 - lats[1402] = -8.6115991315756055 - lats[1403] = -8.6818978999758194 - lats[1404] = -8.7521966683755217 - lats[1405] = -8.8224954367747017 - lats[1406] = -8.8927942051733631 - lats[1407] = -8.963092973571495 - lats[1408] = -9.0333917419690941 - lats[1409] = -9.1036905103661585 - lats[1410] = -9.1739892787626829 - lats[1411] = -9.2442880471586619 - lats[1412] = -9.3145868155540921 - lats[1413] = -9.3848855839489662 - lats[1414] = -9.4551843523432826 - lats[1415] = -9.5254831207370376 - lats[1416] = -9.5957818891302242 - lats[1417] = -9.6660806575228388 - lats[1418] = -9.7363794259148779 - lats[1419] = -9.8066781943063344 - lats[1420] = -9.8769769626972046 - lats[1421] = -9.9472757310874869 - lats[1422] = -10.017574499477174 - lats[1423] = -10.087873267866264 - lats[1424] = -10.158172036254747 - lats[1425] = -10.228470804642624 - lats[1426] = -10.298769573029887 - lats[1427] = -10.369068341416533 - lats[1428] = -10.439367109802557 - lats[1429] = -10.509665878187954 - lats[1430] = -10.579964646572719 - lats[1431] = -10.65026341495685 - lats[1432] = -10.720562183340341 - lats[1433] = -10.790860951723188 - lats[1434] = -10.861159720105382 - lats[1435] = -10.931458488486923 - lats[1436] = -11.001757256867807 - lats[1437] = -11.072056025248026 - lats[1438] = -11.142354793627575 - lats[1439] = -11.212653562006453 - lats[1440] = -11.282952330384653 - lats[1441] = -11.35325109876217 - lats[1442] = -11.423549867139002 - lats[1443] = -11.493848635515141 - lats[1444] = -11.564147403890583 - lats[1445] = -11.634446172265324 - lats[1446] = -11.704744940639358 - lats[1447] = -11.775043709012685 - lats[1448] = -11.845342477385294 - lats[1449] = -11.915641245757183 - lats[1450] = -11.985940014128348 - lats[1451] = -12.056238782498781 - lats[1452] = -12.126537550868482 - lats[1453] = -12.196836319237443 - lats[1454] = -12.267135087605659 - lats[1455] = -12.337433855973126 - lats[1456] = -12.407732624339841 - lats[1457] = -12.478031392705796 - lats[1458] = -12.548330161070988 - lats[1459] = -12.618628929435411 - lats[1460] = -12.688927697799061 - lats[1461] = -12.759226466161934 - lats[1462] = -12.829525234524022 - lats[1463] = -12.899824002885323 - lats[1464] = -12.970122771245832 - lats[1465] = -13.040421539605545 - lats[1466] = -13.110720307964451 - lats[1467] = -13.181019076322551 - lats[1468] = -13.251317844679837 - lats[1469] = -13.32161661303631 - lats[1470] = -13.391915381391959 - lats[1471] = -13.46221414974678 - lats[1472] = -13.532512918100766 - lats[1473] = -13.602811686453919 - lats[1474] = -13.673110454806226 - lats[1475] = -13.743409223157688 - lats[1476] = -13.813707991508297 - lats[1477] = -13.884006759858046 - lats[1478] = -13.954305528206934 - lats[1479] = -14.024604296554955 - lats[1480] = -14.0949030649021 - lats[1481] = -14.165201833248371 - lats[1482] = -14.23550060159376 - lats[1483] = -14.305799369938256 - lats[1484] = -14.376098138281863 - lats[1485] = -14.446396906624567 - lats[1486] = -14.516695674966371 - lats[1487] = -14.586994443307265 - lats[1488] = -14.657293211647247 - lats[1489] = -14.727591979986309 - lats[1490] = -14.797890748324447 - lats[1491] = -14.868189516661655 - lats[1492] = -14.938488284997929 - lats[1493] = -15.008787053333259 - lats[1494] = -15.07908582166765 - lats[1495] = -15.149384590001089 - lats[1496] = -15.219683358333569 - lats[1497] = -15.289982126665089 - lats[1498] = -15.360280894995643 - lats[1499] = -15.430579663325226 - lats[1500] = -15.500878431653829 - lats[1501] = -15.571177199981456 - lats[1502] = -15.641475968308091 - lats[1503] = -15.711774736633735 - lats[1504] = -15.78207350495838 - lats[1505] = -15.852372273282016 - lats[1506] = -15.922671041604652 - lats[1507] = -15.992969809926265 - lats[1508] = -16.063268578246863 - lats[1509] = -16.133567346566434 - lats[1510] = -16.203866114884974 - lats[1511] = -16.274164883202477 - lats[1512] = -16.344463651518936 - lats[1513] = -16.41476241983435 - lats[1514] = -16.485061188148713 - lats[1515] = -16.555359956462013 - lats[1516] = -16.625658724774254 - lats[1517] = -16.69595749308542 - lats[1518] = -16.766256261395515 - lats[1519] = -16.836555029704527 - lats[1520] = -16.906853798012452 - lats[1521] = -16.977152566319283 - lats[1522] = -17.04745133462502 - lats[1523] = -17.117750102929655 - lats[1524] = -17.188048871233182 - lats[1525] = -17.258347639535586 - lats[1526] = -17.328646407836878 - lats[1527] = -17.39894517613704 - lats[1528] = -17.469243944436066 - lats[1529] = -17.539542712733962 - lats[1530] = -17.60984148103071 - lats[1531] = -17.680140249326314 - lats[1532] = -17.75043901762076 - lats[1533] = -17.820737785914044 - lats[1534] = -17.89103655420616 - lats[1535] = -17.96133532249711 - lats[1536] = -18.031634090786874 - lats[1537] = -18.101932859075458 - lats[1538] = -18.172231627362851 - lats[1539] = -18.242530395649048 - lats[1540] = -18.312829163934047 - lats[1541] = -18.383127932217832 - lats[1542] = -18.453426700500408 - lats[1543] = -18.523725468781763 - lats[1544] = -18.594024237061891 - lats[1545] = -18.664323005340787 - lats[1546] = -18.734621773618446 - lats[1547] = -18.804920541894862 - lats[1548] = -18.875219310170031 - lats[1549] = -18.945518078443939 - lats[1550] = -19.015816846716586 - lats[1551] = -19.086115614987968 - lats[1552] = -19.15641438325807 - lats[1553] = -19.226713151526898 - lats[1554] = -19.297011919794439 - lats[1555] = -19.367310688060684 - lats[1556] = -19.437609456325632 - lats[1557] = -19.507908224589269 - lats[1558] = -19.578206992851602 - lats[1559] = -19.648505761112613 - lats[1560] = -19.718804529372303 - lats[1561] = -19.789103297630657 - lats[1562] = -19.859402065887682 - lats[1563] = -19.929700834143357 - lats[1564] = -19.999999602397686 - lats[1565] = -20.070298370650661 - lats[1566] = -20.140597138902272 - lats[1567] = -20.210895907152516 - lats[1568] = -20.28119467540138 - lats[1569] = -20.35149344364887 - lats[1570] = -20.421792211894967 - lats[1571] = -20.492090980139672 - lats[1572] = -20.562389748382977 - lats[1573] = -20.632688516624874 - lats[1574] = -20.702987284865355 - lats[1575] = -20.773286053104417 - lats[1576] = -20.843584821342048 - lats[1577] = -20.913883589578251 - lats[1578] = -20.984182357813012 - lats[1579] = -21.054481126046323 - lats[1580] = -21.124779894278181 - lats[1581] = -21.195078662508585 - lats[1582] = -21.265377430737512 - lats[1583] = -21.335676198964972 - lats[1584] = -21.40597496719095 - lats[1585] = -21.47627373541544 - lats[1586] = -21.546572503638437 - lats[1587] = -21.616871271859928 - lats[1588] = -21.687170040079913 - lats[1589] = -21.757468808298391 - lats[1590] = -21.827767576515338 - lats[1591] = -21.898066344730758 - lats[1592] = -21.968365112944642 - lats[1593] = -22.038663881156989 - lats[1594] = -22.108962649367779 - lats[1595] = -22.179261417577013 - lats[1596] = -22.249560185784691 - lats[1597] = -22.319858953990789 - lats[1598] = -22.390157722195315 - lats[1599] = -22.460456490398254 - lats[1600] = -22.530755258599601 - lats[1601] = -22.60105402679935 - lats[1602] = -22.671352794997489 - lats[1603] = -22.741651563194019 - lats[1604] = -22.811950331388925 - lats[1605] = -22.882249099582204 - lats[1606] = -22.952547867773848 - lats[1607] = -23.022846635963852 - lats[1608] = -23.0931454041522 - lats[1609] = -23.163444172338895 - lats[1610] = -23.233742940523921 - lats[1611] = -23.304041708707278 - lats[1612] = -23.374340476888957 - lats[1613] = -23.444639245068949 - lats[1614] = -23.514938013247242 - lats[1615] = -23.585236781423838 - lats[1616] = -23.655535549598721 - lats[1617] = -23.725834317771888 - lats[1618] = -23.796133085943328 - lats[1619] = -23.866431854113038 - lats[1620] = -23.936730622281004 - lats[1621] = -24.007029390447226 - lats[1622] = -24.077328158611696 - lats[1623] = -24.1476269267744 - lats[1624] = -24.217925694935328 - lats[1625] = -24.288224463094483 - lats[1626] = -24.358523231251851 - lats[1627] = -24.428821999407425 - lats[1628] = -24.499120767561195 - lats[1629] = -24.569419535713152 - lats[1630] = -24.639718303863294 - lats[1631] = -24.710017072011613 - lats[1632] = -24.780315840158096 - lats[1633] = -24.850614608302738 - lats[1634] = -24.920913376445526 - lats[1635] = -24.991212144586456 - lats[1636] = -25.061510912725527 - lats[1637] = -25.13180968086272 - lats[1638] = -25.202108448998025 - lats[1639] = -25.272407217131445 - lats[1640] = -25.342705985262967 - lats[1641] = -25.413004753392578 - lats[1642] = -25.483303521520277 - lats[1643] = -25.553602289646051 - lats[1644] = -25.623901057769892 - lats[1645] = -25.694199825891793 - lats[1646] = -25.764498594011751 - lats[1647] = -25.834797362129745 - lats[1648] = -25.90509613024577 - lats[1649] = -25.975394898359827 - lats[1650] = -26.045693666471902 - lats[1651] = -26.115992434581983 - lats[1652] = -26.186291202690064 - lats[1653] = -26.256589970796135 - lats[1654] = -26.326888738900195 - lats[1655] = -26.397187507002222 - lats[1656] = -26.467486275102218 - lats[1657] = -26.53778504320017 - lats[1658] = -26.608083811296069 - lats[1659] = -26.678382579389908 - lats[1660] = -26.748681347481678 - lats[1661] = -26.818980115571364 - lats[1662] = -26.889278883658971 - lats[1663] = -26.959577651744471 - lats[1664] = -27.029876419827872 - lats[1665] = -27.100175187909159 - lats[1666] = -27.170473955988321 - lats[1667] = -27.240772724065348 - lats[1668] = -27.311071492140236 - lats[1669] = -27.381370260212968 - lats[1670] = -27.451669028283543 - lats[1671] = -27.521967796351948 - lats[1672] = -27.592266564418171 - lats[1673] = -27.662565332482213 - lats[1674] = -27.732864100544052 - lats[1675] = -27.803162868603682 - lats[1676] = -27.873461636661098 - lats[1677] = -27.94376040471629 - lats[1678] = -28.014059172769244 - lats[1679] = -28.084357940819952 - lats[1680] = -28.154656708868405 - lats[1681] = -28.224955476914594 - lats[1682] = -28.29525424495851 - lats[1683] = -28.365553013000145 - lats[1684] = -28.435851781039485 - lats[1685] = -28.506150549076519 - lats[1686] = -28.576449317111244 - lats[1687] = -28.646748085143642 - lats[1688] = -28.717046853173709 - lats[1689] = -28.787345621201432 - lats[1690] = -28.857644389226806 - lats[1691] = -28.927943157249814 - lats[1692] = -28.998241925270449 - lats[1693] = -29.068540693288696 - lats[1694] = -29.138839461304556 - lats[1695] = -29.209138229318015 - lats[1696] = -29.279436997329057 - lats[1697] = -29.349735765337677 - lats[1698] = -29.420034533343859 - lats[1699] = -29.490333301347597 - lats[1700] = -29.560632069348884 - lats[1701] = -29.630930837347698 - lats[1702] = -29.701229605344039 - lats[1703] = -29.771528373337894 - lats[1704] = -29.841827141329258 - lats[1705] = -29.91212590931811 - lats[1706] = -29.98242467730444 - lats[1707] = -30.052723445288244 - lats[1708] = -30.123022213269511 - lats[1709] = -30.19332098124822 - lats[1710] = -30.263619749224372 - lats[1711] = -30.333918517197947 - lats[1712] = -30.404217285168947 - lats[1713] = -30.47451605313735 - lats[1714] = -30.544814821103138 - lats[1715] = -30.615113589066322 - lats[1716] = -30.685412357026873 - lats[1717] = -30.755711124984781 - lats[1718] = -30.826009892940046 - lats[1719] = -30.896308660892647 - lats[1720] = -30.966607428842572 - lats[1721] = -31.036906196789811 - lats[1722] = -31.107204964734358 - lats[1723] = -31.177503732676204 - lats[1724] = -31.247802500615318 - lats[1725] = -31.318101268551715 - lats[1726] = -31.388400036485361 - lats[1727] = -31.458698804416255 - lats[1728] = -31.528997572344384 - lats[1729] = -31.599296340269738 - lats[1730] = -31.669595108192297 - lats[1731] = -31.739893876112063 - lats[1732] = -31.810192644029012 - lats[1733] = -31.880491411943137 - lats[1734] = -31.950790179854422 - lats[1735] = -32.021088947762863 - lats[1736] = -32.091387715668439 - lats[1737] = -32.161686483571145 - lats[1738] = -32.231985251470959 - lats[1739] = -32.302284019367875 - lats[1740] = -32.372582787261891 - lats[1741] = -32.442881555152965 - lats[1742] = -32.513180323041112 - lats[1743] = -32.583479090926325 - lats[1744] = -32.653777858808567 - lats[1745] = -32.724076626687825 - lats[1746] = -32.794375394564113 - lats[1747] = -32.864674162437396 - lats[1748] = -32.934972930307666 - lats[1749] = -33.005271698174909 - lats[1750] = -33.075570466039117 - lats[1751] = -33.145869233900278 - lats[1752] = -33.216168001758369 - lats[1753] = -33.286466769613391 - lats[1754] = -33.356765537465314 - lats[1755] = -33.42706430531414 - lats[1756] = -33.497363073159853 - lats[1757] = -33.567661841002426 - lats[1758] = -33.637960608841851 - lats[1759] = -33.708259376678136 - lats[1760] = -33.778558144511237 - lats[1761] = -33.848856912341155 - lats[1762] = -33.919155680167876 - lats[1763] = -33.989454447991392 - lats[1764] = -34.059753215811682 - lats[1765] = -34.130051983628725 - lats[1766] = -34.200350751442521 - lats[1767] = -34.270649519253041 - lats[1768] = -34.340948287060286 - lats[1769] = -34.411247054864234 - lats[1770] = -34.481545822664863 - lats[1771] = -34.551844590462188 - lats[1772] = -34.622143358256153 - lats[1773] = -34.692442126046771 - lats[1774] = -34.762740893834028 - lats[1775] = -34.833039661617903 - lats[1776] = -34.903338429398374 - lats[1777] = -34.973637197175435 - lats[1778] = -35.043935964949064 - lats[1779] = -35.114234732719261 - lats[1780] = -35.184533500486005 - lats[1781] = -35.254832268249267 - lats[1782] = -35.325131036009047 - lats[1783] = -35.395429803765317 - lats[1784] = -35.465728571518085 - lats[1785] = -35.536027339267314 - lats[1786] = -35.606326107012997 - lats[1787] = -35.676624874755113 - lats[1788] = -35.746923642493655 - lats[1789] = -35.817222410228595 - lats[1790] = -35.887521177959933 - lats[1791] = -35.957819945687639 - lats[1792] = -36.028118713411708 - lats[1793] = -36.098417481132117 - lats[1794] = -36.16871624884886 - lats[1795] = -36.239015016561908 - lats[1796] = -36.309313784271254 - lats[1797] = -36.379612551976876 - lats[1798] = -36.449911319678755 - lats[1799] = -36.520210087376888 - lats[1800] = -36.590508855071242 - lats[1801] = -36.660807622761808 - lats[1802] = -36.731106390448581 - lats[1803] = -36.801405158131523 - lats[1804] = -36.871703925810628 - lats[1805] = -36.942002693485883 - lats[1806] = -37.012301461157264 - lats[1807] = -37.082600228824752 - lats[1808] = -37.152898996488332 - lats[1809] = -37.223197764147997 - lats[1810] = -37.293496531803719 - lats[1811] = -37.363795299455489 - lats[1812] = -37.434094067103274 - lats[1813] = -37.504392834747065 - lats[1814] = -37.574691602386856 - lats[1815] = -37.644990370022605 - lats[1816] = -37.715289137654317 - lats[1817] = -37.785587905281965 - lats[1818] = -37.855886672905527 - lats[1819] = -37.926185440524989 - lats[1820] = -37.99648420814033 - lats[1821] = -38.066782975751536 - lats[1822] = -38.137081743358586 - lats[1823] = -38.20738051096145 - lats[1824] = -38.277679278560143 - lats[1825] = -38.347978046154608 - lats[1826] = -38.418276813744846 - lats[1827] = -38.488575581330842 - lats[1828] = -38.558874348912568 - lats[1829] = -38.629173116490001 - lats[1830] = -38.699471884063136 - lats[1831] = -38.769770651631937 - lats[1832] = -38.840069419196389 - lats[1833] = -38.910368186756479 - lats[1834] = -38.980666954312184 - lats[1835] = -39.050965721863491 - lats[1836] = -39.121264489410365 - lats[1837] = -39.191563256952804 - lats[1838] = -39.261862024490775 - lats[1839] = -39.332160792024254 - lats[1840] = -39.402459559553229 - lats[1841] = -39.472758327077692 - lats[1842] = -39.543057094597607 - lats[1843] = -39.613355862112947 - lats[1844] = -39.683654629623703 - lats[1845] = -39.753953397129855 - lats[1846] = -39.824252164631375 - lats[1847] = -39.894550932128247 - lats[1848] = -39.964849699620437 - lats[1849] = -40.035148467107952 - lats[1850] = -40.105447234590748 - lats[1851] = -40.175746002068806 - lats[1852] = -40.246044769542102 - lats[1853] = -40.316343537010617 - lats[1854] = -40.386642304474343 - lats[1855] = -40.456941071933244 - lats[1856] = -40.527239839387299 - lats[1857] = -40.597538606836487 - lats[1858] = -40.667837374280786 - lats[1859] = -40.738136141720176 - lats[1860] = -40.808434909154634 - lats[1861] = -40.878733676584126 - lats[1862] = -40.949032444008644 - lats[1863] = -41.01933121142816 - lats[1864] = -41.089629978842645 - lats[1865] = -41.159928746252085 - lats[1866] = -41.230227513656445 - lats[1867] = -41.300526281055724 - lats[1868] = -41.370825048449873 - lats[1869] = -41.441123815838885 - lats[1870] = -41.511422583222718 - lats[1871] = -41.581721350601363 - lats[1872] = -41.6520201179748 - lats[1873] = -41.722318885343 - lats[1874] = -41.792617652705921 - lats[1875] = -41.862916420063563 - lats[1876] = -41.933215187415882 - lats[1877] = -42.003513954762873 - lats[1878] = -42.073812722104492 - lats[1879] = -42.144111489440725 - lats[1880] = -42.214410256771551 - lats[1881] = -42.284709024096927 - lats[1882] = -42.355007791416853 - lats[1883] = -42.425306558731272 - lats[1884] = -42.495605326040177 - lats[1885] = -42.565904093343548 - lats[1886] = -42.63620286064134 - lats[1887] = -42.706501627933541 - lats[1888] = -42.776800395220121 - lats[1889] = -42.847099162501053 - lats[1890] = -42.917397929776307 - lats[1891] = -42.987696697045862 - lats[1892] = -43.057995464309691 - lats[1893] = -43.128294231567757 - lats[1894] = -43.19859299882004 - lats[1895] = -43.26889176606651 - lats[1896] = -43.339190533307139 - lats[1897] = -43.409489300541907 - lats[1898] = -43.479788067770777 - lats[1899] = -43.550086834993728 - lats[1900] = -43.620385602210717 - lats[1901] = -43.690684369421732 - lats[1902] = -43.760983136626741 - lats[1903] = -43.831281903825705 - lats[1904] = -43.9015806710186 - lats[1905] = -43.971879438205391 - lats[1906] = -44.042178205386072 - lats[1907] = -44.112476972560586 - lats[1908] = -44.182775739728925 - lats[1909] = -44.253074506891046 - lats[1910] = -44.323373274046915 - lats[1911] = -44.39367204119651 - lats[1912] = -44.463970808339802 - lats[1913] = -44.534269575476756 - lats[1914] = -44.604568342607337 - lats[1915] = -44.674867109731515 - lats[1916] = -44.745165876849271 - lats[1917] = -44.81546464396056 - lats[1918] = -44.885763411065362 - lats[1919] = -44.956062178163634 - lats[1920] = -45.026360945255341 - lats[1921] = -45.096659712340461 - lats[1922] = -45.166958479418959 - lats[1923] = -45.237257246490813 - lats[1924] = -45.30755601355596 - lats[1925] = -45.377854780614399 - lats[1926] = -45.448153547666081 - lats[1927] = -45.51845231471097 - lats[1928] = -45.588751081749038 - lats[1929] = -45.659049848780263 - lats[1930] = -45.729348615804589 - lats[1931] = -45.799647382821995 - lats[1932] = -45.869946149832437 - lats[1933] = -45.94024491683588 - lats[1934] = -46.01054368383231 - lats[1935] = -46.080842450821663 - lats[1936] = -46.151141217803925 - lats[1937] = -46.221439984779053 - lats[1938] = -46.291738751747012 - lats[1939] = -46.362037518707766 - lats[1940] = -46.432336285661272 - lats[1941] = -46.502635052607502 - lats[1942] = -46.572933819546414 - lats[1943] = -46.643232586477971 - lats[1944] = -46.713531353402139 - lats[1945] = -46.783830120318882 - lats[1946] = -46.85412888722815 - lats[1947] = -46.924427654129929 - lats[1948] = -46.994726421024154 - lats[1949] = -47.065025187910805 - lats[1950] = -47.13532395478984 - lats[1951] = -47.205622721661214 - lats[1952] = -47.275921488524894 - lats[1953] = -47.346220255380835 - lats[1954] = -47.416519022228997 - lats[1955] = -47.486817789069342 - lats[1956] = -47.557116555901828 - lats[1957] = -47.627415322726435 - lats[1958] = -47.697714089543084 - lats[1959] = -47.76801285635176 - lats[1960] = -47.838311623152421 - lats[1961] = -47.908610389945018 - lats[1962] = -47.978909156729507 - lats[1963] = -48.049207923505868 - lats[1964] = -48.119506690274015 - lats[1965] = -48.189805457033941 - lats[1966] = -48.260104223785596 - lats[1967] = -48.330402990528938 - lats[1968] = -48.400701757263917 - lats[1969] = -48.47100052399049 - lats[1970] = -48.541299290708608 - lats[1971] = -48.611598057418242 - lats[1972] = -48.681896824119335 - lats[1973] = -48.752195590811837 - lats[1974] = -48.822494357495721 - lats[1975] = -48.892793124170929 - lats[1976] = -48.963091890837418 - lats[1977] = -49.03339065749514 - lats[1978] = -49.103689424144044 - lats[1979] = -49.173988190784094 - lats[1980] = -49.244286957415234 - lats[1981] = -49.314585724037435 - lats[1982] = -49.384884490650613 - lats[1983] = -49.455183257254745 - lats[1984] = -49.525482023849783 - lats[1985] = -49.595780790435676 - lats[1986] = -49.66607955701236 - lats[1987] = -49.736378323579807 - lats[1988] = -49.80667709013796 - lats[1989] = -49.876975856686762 - lats[1990] = -49.947274623226157 - lats[1991] = -50.017573389756123 - lats[1992] = -50.087872156276575 - lats[1993] = -50.158170922787484 - lats[1994] = -50.228469689288779 - lats[1995] = -50.298768455780426 - lats[1996] = -50.369067222262359 - lats[1997] = -50.439365988734544 - lats[1998] = -50.509664755196901 - lats[1999] = -50.579963521649397 - lats[2000] = -50.650262288091959 - lats[2001] = -50.720561054524559 - lats[2002] = -50.790859820947119 - lats[2003] = -50.86115858735959 - lats[2004] = -50.931457353761914 - lats[2005] = -51.001756120154049 - lats[2006] = -51.072054886535909 - lats[2007] = -51.14235365290746 - lats[2008] = -51.21265241926865 - lats[2009] = -51.282951185619417 - lats[2010] = -51.353249951959683 - lats[2011] = -51.423548718289396 - lats[2012] = -51.493847484608516 - lats[2013] = -51.56414625091697 - lats[2014] = -51.634445017214695 - lats[2015] = -51.704743783501634 - lats[2016] = -51.775042549777737 - lats[2017] = -51.845341316042933 - lats[2018] = -51.915640082297152 - lats[2019] = -51.985938848540336 - lats[2020] = -52.056237614772435 - lats[2021] = -52.126536380993372 - lats[2022] = -52.196835147203096 - lats[2023] = -52.26713391340153 - lats[2024] = -52.337432679588609 - lats[2025] = -52.407731445764284 - lats[2026] = -52.478030211928477 - lats[2027] = -52.548328978081123 - lats[2028] = -52.618627744222159 - lats[2029] = -52.688926510351514 - lats[2030] = -52.759225276469131 - lats[2031] = -52.829524042574917 - lats[2032] = -52.899822808668837 - lats[2033] = -52.970121574750792 - lats[2034] = -53.040420340820731 - lats[2035] = -53.110719106878584 - lats[2036] = -53.181017872924265 - lats[2037] = -53.251316638957725 - lats[2038] = -53.321615404978871 - lats[2039] = -53.391914170987633 - lats[2040] = -53.462212936983953 - lats[2041] = -53.53251170296776 - lats[2042] = -53.602810468938962 - lats[2043] = -53.673109234897495 - lats[2044] = -53.743408000843282 - lats[2045] = -53.813706766776235 - lats[2046] = -53.884005532696307 - lats[2047] = -53.954304298603383 - lats[2048] = -54.024603064497434 - lats[2049] = -54.094901830378333 - lats[2050] = -54.165200596246031 - lats[2051] = -54.235499362100448 - lats[2052] = -54.305798127941479 - lats[2053] = -54.376096893769081 - lats[2054] = -54.446395659583146 - lats[2055] = -54.516694425383605 - lats[2056] = -54.586993191170357 - lats[2057] = -54.657291956943347 - lats[2058] = -54.727590722702473 - lats[2059] = -54.797889488447652 - lats[2060] = -54.868188254178797 - lats[2061] = -54.938487019895831 - lats[2062] = -55.008785785598668 - lats[2063] = -55.07908455128721 - lats[2064] = -55.149383316961377 - lats[2065] = -55.219682082621084 - lats[2066] = -55.289980848266232 - lats[2067] = -55.360279613896743 - lats[2068] = -55.430578379512511 - lats[2069] = -55.500877145113449 - lats[2070] = -55.571175910699488 - lats[2071] = -55.641474676270505 - lats[2072] = -55.711773441826416 - lats[2073] = -55.782072207367136 - lats[2074] = -55.852370972892551 - lats[2075] = -55.922669738402583 - lats[2076] = -55.992968503897131 - lats[2077] = -56.063267269376091 - lats[2078] = -56.133566034839362 - lats[2079] = -56.203864800286865 - lats[2080] = -56.274163565718467 - lats[2081] = -56.34446233113411 - lats[2082] = -56.41476109653366 - lats[2083] = -56.485059861917016 - lats[2084] = -56.555358627284086 - lats[2085] = -56.625657392634771 - lats[2086] = -56.695956157968951 - lats[2087] = -56.766254923286517 - lats[2088] = -56.836553688587379 - lats[2089] = -56.90685245387143 - lats[2090] = -56.977151219138541 - lats[2091] = -57.047449984388614 - lats[2092] = -57.117748749621541 - lats[2093] = -57.188047514837208 - lats[2094] = -57.258346280035504 - lats[2095] = -57.328645045216312 - lats[2096] = -57.398943810379521 - lats[2097] = -57.469242575525016 - lats[2098] = -57.539541340652676 - lats[2099] = -57.60984010576238 - lats[2100] = -57.680138870854037 - lats[2101] = -57.75043763592749 - lats[2102] = -57.820736400982646 - lats[2103] = -57.891035166019364 - lats[2104] = -57.961333931037537 - lats[2105] = -58.031632696037022 - lats[2106] = -58.101931461017728 - lats[2107] = -58.172230225979497 - lats[2108] = -58.242528990922203 - lats[2109] = -58.312827755845746 - lats[2110] = -58.383126520749968 - lats[2111] = -58.453425285634758 - lats[2112] = -58.523724050499972 - lats[2113] = -58.594022815345468 - lats[2114] = -58.664321580171141 - lats[2115] = -58.73462034497684 - lats[2116] = -58.804919109762423 - lats[2117] = -58.875217874527763 - lats[2118] = -58.945516639272725 - lats[2119] = -59.015815403997145 - lats[2120] = -59.086114168700909 - lats[2121] = -59.156412933383855 - lats[2122] = -59.226711698045854 - lats[2123] = -59.29701046268675 - lats[2124] = -59.3673092273064 - lats[2125] = -59.43760799190467 - lats[2126] = -59.507906756481383 - lats[2127] = -59.578205521036402 - lats[2128] = -59.64850428556958 - lats[2129] = -59.718803050080759 - lats[2130] = -59.78910181456979 - lats[2131] = -59.859400579036503 - lats[2132] = -59.929699343480763 - lats[2133] = -59.999998107902378 - lats[2134] = -60.070296872301235 - lats[2135] = -60.140595636677112 - lats[2136] = -60.21089440102989 - lats[2137] = -60.28119316535939 - lats[2138] = -60.35149192966545 - lats[2139] = -60.421790693947884 - lats[2140] = -60.492089458206543 - lats[2141] = -60.562388222441243 - lats[2142] = -60.632686986651805 - lats[2143] = -60.702985750838074 - lats[2144] = -60.773284514999872 - lats[2145] = -60.843583279137007 - lats[2146] = -60.913882043249295 - lats[2147] = -60.984180807336578 - lats[2148] = -61.054479571398652 - lats[2149] = -61.124778335435344 - lats[2150] = -61.195077099446451 - lats[2151] = -61.265375863431785 - lats[2152] = -61.335674627391185 - lats[2153] = -61.405973391324409 - lats[2154] = -61.476272155231321 - lats[2155] = -61.546570919111666 - lats[2156] = -61.616869682965287 - lats[2157] = -61.687168446791986 - lats[2158] = -61.757467210591535 - lats[2159] = -61.827765974363729 - lats[2160] = -61.898064738108381 - lats[2161] = -61.968363501825259 - lats[2162] = -62.038662265514176 - lats[2163] = -62.108961029174914 - lats[2164] = -62.179259792807258 - lats[2165] = -62.249558556410982 - lats[2166] = -62.319857319985871 - lats[2167] = -62.3901560835317 - lats[2168] = -62.460454847048261 - lats[2169] = -62.530753610535321 - lats[2170] = -62.60105237399263 - lats[2171] = -62.67135113741999 - lats[2172] = -62.741649900817137 - lats[2173] = -62.811948664183866 - lats[2174] = -62.882247427519928 - lats[2175] = -62.952546190825068 - lats[2176] = -63.022844954099064 - lats[2177] = -63.093143717341647 - lats[2178] = -63.163442480552604 - lats[2179] = -63.23374124373165 - lats[2180] = -63.304040006878537 - lats[2181] = -63.374338769993031 - lats[2182] = -63.444637533074854 - lats[2183] = -63.514936296123757 - lats[2184] = -63.585235059139464 - lats[2185] = -63.655533822121711 - lats[2186] = -63.725832585070251 - lats[2187] = -63.796131347984762 - lats[2188] = -63.866430110865004 - lats[2189] = -63.93672887371072 - lats[2190] = -64.00702763652157 - lats[2191] = -64.07732639929732 - lats[2192] = -64.147625162037642 - lats[2193] = -64.21792392474228 - lats[2194] = -64.288222687410922 - lats[2195] = -64.358521450043284 - lats[2196] = -64.428820212639039 - lats[2197] = -64.499118975197902 - lats[2198] = -64.569417737719576 - lats[2199] = -64.639716500203733 - lats[2200] = -64.710015262650074 - lats[2201] = -64.780314025058246 - lats[2202] = -64.850612787427963 - lats[2203] = -64.920911549758912 - lats[2204] = -64.991210312050711 - lats[2205] = -65.061509074303089 - lats[2206] = -65.131807836515677 - lats[2207] = -65.202106598688133 - lats[2208] = -65.272405360820116 - lats[2209] = -65.342704122911286 - lats[2210] = -65.413002884961315 - lats[2211] = -65.483301646969792 - lats[2212] = -65.553600408936404 - lats[2213] = -65.623899170860767 - lats[2214] = -65.694197932742526 - lats[2215] = -65.764496694581283 - lats[2216] = -65.834795456376696 - lats[2217] = -65.905094218128355 - lats[2218] = -65.975392979835888 - lats[2219] = -66.045691741498899 - lats[2220] = -66.115990503117033 - lats[2221] = -66.186289264689833 - lats[2222] = -66.256588026216932 - lats[2223] = -66.326886787697887 - lats[2224] = -66.397185549132331 - lats[2225] = -66.467484310519808 - lats[2226] = -66.537783071859891 - lats[2227] = -66.608081833152212 - lats[2228] = -66.678380594396273 - lats[2229] = -66.748679355591662 - lats[2230] = -66.818978116737924 - lats[2231] = -66.889276877834618 - lats[2232] = -66.95957563888129 - lats[2233] = -67.029874399877471 - lats[2234] = -67.100173160822706 - lats[2235] = -67.170471921716526 - lats[2236] = -67.240770682558434 - lats[2237] = -67.311069443347961 - lats[2238] = -67.381368204084609 - lats[2239] = -67.451666964767895 - lats[2240] = -67.521965725397308 - lats[2241] = -67.592264485972336 - lats[2242] = -67.662563246492482 - lats[2243] = -67.732862006957205 - lats[2244] = -67.803160767365966 - lats[2245] = -67.873459527718282 - lats[2246] = -67.943758288013555 - lats[2247] = -68.014057048251274 - lats[2248] = -68.084355808430871 - lats[2249] = -68.154654568551791 - lats[2250] = -68.224953328613438 - lats[2251] = -68.295252088615257 - lats[2252] = -68.365550848556666 - lats[2253] = -68.435849608437067 - lats[2254] = -68.506148368255865 - lats[2255] = -68.576447128012447 - lats[2256] = -68.646745887706189 - lats[2257] = -68.717044647336493 - lats[2258] = -68.787343406902693 - lats[2259] = -68.85764216640419 - lats[2260] = -68.927940925840304 - lats[2261] = -68.998239685210365 - lats[2262] = -69.068538444513763 - lats[2263] = -69.138837203749759 - lats[2264] = -69.209135962917699 - lats[2265] = -69.279434722016902 - lats[2266] = -69.349733481046613 - lats[2267] = -69.420032240006194 - lats[2268] = -69.490330998894862 - lats[2269] = -69.560629757711908 - lats[2270] = -69.630928516456592 - lats[2271] = -69.701227275128161 - lats[2272] = -69.771526033725834 - lats[2273] = -69.841824792248843 - lats[2274] = -69.912123550696421 - lats[2275] = -69.982422309067744 - lats[2276] = -70.052721067362043 - lats[2277] = -70.123019825578467 - lats[2278] = -70.193318583716191 - lats[2279] = -70.263617341774406 - lats[2280] = -70.333916099752187 - lats[2281] = -70.404214857648739 - lats[2282] = -70.474513615463138 - lats[2283] = -70.544812373194532 - lats[2284] = -70.615111130841967 - lats[2285] = -70.685409888404578 - lats[2286] = -70.755708645881384 - lats[2287] = -70.826007403271475 - lats[2288] = -70.896306160573886 - lats[2289] = -70.966604917787635 - lats[2290] = -71.036903674911756 - lats[2291] = -71.107202431945211 - lats[2292] = -71.177501188887007 - lats[2293] = -71.247799945736105 - lats[2294] = -71.318098702491469 - lats[2295] = -71.388397459152031 - lats[2296] = -71.458696215716685 - lats[2297] = -71.528994972184378 - lats[2298] = -71.599293728553988 - lats[2299] = -71.669592484824364 - lats[2300] = -71.739891240994368 - lats[2301] = -71.810189997062835 - lats[2302] = -71.880488753028587 - lats[2303] = -71.950787508890414 - lats[2304] = -72.02108626464711 - lats[2305] = -72.091385020297409 - lats[2306] = -72.161683775840089 - lats[2307] = -72.231982531273843 - lats[2308] = -72.302281286597392 - lats[2309] = -72.3725800418094 - lats[2310] = -72.442878796908545 - lats[2311] = -72.513177551893421 - lats[2312] = -72.583476306762691 - lats[2313] = -72.653775061514935 - lats[2314] = -72.724073816148703 - lats[2315] = -72.794372570662574 - lats[2316] = -72.864671325055056 - lats[2317] = -72.934970079324657 - lats[2318] = -73.005268833469799 - lats[2319] = -73.075567587489019 - lats[2320] = -73.145866341380668 - lats[2321] = -73.216165095143182 - lats[2322] = -73.2864638487749 - lats[2323] = -73.356762602274188 - lats[2324] = -73.427061355639339 - lats[2325] = -73.497360108868662 - lats[2326] = -73.567658861960396 - lats[2327] = -73.637957614912779 - lats[2328] = -73.70825636772399 - lats[2329] = -73.778555120392184 - lats[2330] = -73.848853872915541 - lats[2331] = -73.919152625292114 - lats[2332] = -73.98945137751997 - lats[2333] = -74.059750129597163 - lats[2334] = -74.13004888152166 - lats[2335] = -74.200347633291472 - lats[2336] = -74.270646384904481 - lats[2337] = -74.340945136358584 - lats[2338] = -74.411243887651622 - lats[2339] = -74.481542638781434 - lats[2340] = -74.551841389745761 - lats[2341] = -74.622140140542356 - lats[2342] = -74.692438891168877 - lats[2343] = -74.762737641622991 - lats[2344] = -74.833036391902269 - lats[2345] = -74.903335142004323 - lats[2346] = -74.973633891926625 - lats[2347] = -75.043932641666672 - lats[2348] = -75.114231391221821 - lats[2349] = -75.184530140589501 - lats[2350] = -75.254828889766983 - lats[2351] = -75.325127638751567 - lats[2352] = -75.395426387540439 - lats[2353] = -75.465725136130786 - lats[2354] = -75.536023884519707 - lats[2355] = -75.60632263270422 - lats[2356] = -75.67662138068134 - lats[2357] = -75.746920128447996 - lats[2358] = -75.81721887600105 - lats[2359] = -75.887517623337317 - lats[2360] = -75.957816370453543 - lats[2361] = -76.028115117346374 - lats[2362] = -76.098413864012443 - lats[2363] = -76.16871261044831 - lats[2364] = -76.239011356650423 - lats[2365] = -76.3093101026152 - lats[2366] = -76.379608848338933 - lats[2367] = -76.449907593817869 - lats[2368] = -76.520206339048215 - lats[2369] = -76.59050508402602 - lats[2370] = -76.660803828747362 - lats[2371] = -76.731102573208048 - lats[2372] = -76.801401317404 - lats[2373] = -76.871700061330955 - lats[2374] = -76.941998804984564 - lats[2375] = -77.012297548360323 - lats[2376] = -77.082596291453768 - lats[2377] = -77.15289503426024 - lats[2378] = -77.22319377677502 - lats[2379] = -77.293492518993247 - lats[2380] = -77.363791260909963 - lats[2381] = -77.434090002520122 - lats[2382] = -77.504388743818524 - lats[2383] = -77.574687484799924 - lats[2384] = -77.644986225458879 - lats[2385] = -77.71528496578982 - lats[2386] = -77.785583705787161 - lats[2387] = -77.855882445445019 - lats[2388] = -77.926181184757539 - lats[2389] = -77.996479923718596 - lats[2390] = -78.066778662322022 - lats[2391] = -78.137077400561424 - lats[2392] = -78.207376138430348 - lats[2393] = -78.277674875922045 - lats[2394] = -78.347973613029708 - lats[2395] = -78.418272349746417 - lats[2396] = -78.488571086064923 - lats[2397] = -78.558869821977908 - lats[2398] = -78.629168557477882 - lats[2399] = -78.699467292557102 - lats[2400] = -78.769766027207638 - lats[2401] = -78.840064761421445 - lats[2402] = -78.910363495190211 - lats[2403] = -78.980662228505423 - lats[2404] = -79.050960961358285 - lats[2405] = -79.121259693739859 - lats[2406] = -79.191558425640977 - lats[2407] = -79.261857157052191 - lats[2408] = -79.332155887963822 - lats[2409] = -79.402454618365894 - lats[2410] = -79.472753348248219 - lats[2411] = -79.543052077600308 - lats[2412] = -79.61335080641139 - lats[2413] = -79.683649534670437 - lats[2414] = -79.753948262366038 - lats[2415] = -79.824246989486554 - lats[2416] = -79.894545716019948 - lats[2417] = -79.9648444419539 - lats[2418] = -80.035143167275749 - lats[2419] = -80.105441891972376 - lats[2420] = -80.175740616030438 - lats[2421] = -80.246039339436052 - lats[2422] = -80.316338062175078 - lats[2423] = -80.386636784232863 - lats[2424] = -80.456935505594302 - lats[2425] = -80.527234226243991 - lats[2426] = -80.59753294616587 - lats[2427] = -80.667831665343556 - lats[2428] = -80.73813038376008 - lats[2429] = -80.808429101397948 - lats[2430] = -80.878727818239184 - lats[2431] = -80.949026534265244 - lats[2432] = -81.019325249456955 - lats[2433] = -81.089623963794551 - lats[2434] = -81.159922677257711 - lats[2435] = -81.230221389825374 - lats[2436] = -81.300520101475826 - lats[2437] = -81.370818812186627 - lats[2438] = -81.441117521934686 - lats[2439] = -81.511416230696042 - lats[2440] = -81.581714938445955 - lats[2441] = -81.652013645158945 - lats[2442] = -81.722312350808508 - lats[2443] = -81.792611055367345 - lats[2444] = -81.862909758807191 - lats[2445] = -81.933208461098829 - lats[2446] = -82.003507162211946 - lats[2447] = -82.073805862115165 - lats[2448] = -82.144104560776 - lats[2449] = -82.214403258160871 - lats[2450] = -82.284701954234833 - lats[2451] = -82.355000648961692 - lats[2452] = -82.425299342304029 - lats[2453] = -82.495598034222837 - lats[2454] = -82.56589672467787 - lats[2455] = -82.63619541362705 - lats[2456] = -82.706494101026948 - lats[2457] = -82.77679278683226 - lats[2458] = -82.84709147099602 - lats[2459] = -82.917390153469313 - lats[2460] = -82.987688834201322 - lats[2461] = -83.057987513139125 - lats[2462] = -83.128286190227698 - lats[2463] = -83.198584865409657 - lats[2464] = -83.268883538625232 - lats[2465] = -83.339182209812321 - lats[2466] = -83.409480878905782 - lats[2467] = -83.479779545838113 - lats[2468] = -83.550078210538487 - lats[2469] = -83.620376872933264 - lats[2470] = -83.690675532945292 - lats[2471] = -83.760974190494011 - lats[2472] = -83.831272845495249 - lats[2473] = -83.901571497860914 - lats[2474] = -83.971870147498763 - lats[2475] = -84.042168794312317 - lats[2476] = -84.112467438200326 - lats[2477] = -84.18276607905679 - lats[2478] = -84.253064716770425 - lats[2479] = -84.323363351224444 - lats[2480] = -84.393661982296322 - lats[2481] = -84.463960609857125 - lats[2482] = -84.534259233771479 - lats[2483] = -84.604557853896708 - lats[2484] = -84.674856470082915 - lats[2485] = -84.745155082171991 - lats[2486] = -84.81545368999717 - lats[2487] = -84.885752293382765 - lats[2488] = -84.95605089214304 - lats[2489] = -85.026349486081983 - lats[2490] = -85.09664807499216 - lats[2491] = -85.16694665865414 - lats[2492] = -85.237245236835548 - lats[2493] = -85.307543809290152 - lats[2494] = -85.377842375756586 - lats[2495] = -85.448140935957483 - lats[2496] = -85.518439489597966 - lats[2497] = -85.588738036364362 - lats[2498] = -85.659036575922883 - lats[2499] = -85.729335107917464 - lats[2500] = -85.799633631968391 - lats[2501] = -85.869932147670127 - lats[2502] = -85.940230654588888 - lats[2503] = -86.010529152260403 - lats[2504] = -86.080827640187209 - lats[2505] = -86.151126117835304 - lats[2506] = -86.221424584631109 - lats[2507] = -86.291723039957418 - lats[2508] = -86.362021483149363 - lats[2509] = -86.432319913489792 - lats[2510] = -86.502618330203831 - lats[2511] = -86.572916732453024 - lats[2512] = -86.643215119328573 - lats[2513] = -86.713513489844246 - lats[2514] = -86.783811842927179 - lats[2515] = -86.854110177408927 - lats[2516] = -86.924408492014166 - lats[2517] = -86.994706785348129 - lats[2518] = -87.065005055882821 - lats[2519] = -87.135303301939786 - lats[2520] = -87.205601521672108 - lats[2521] = -87.275899713041966 - lats[2522] = -87.346197873795816 - lats[2523] = -87.416496001434894 - lats[2524] = -87.486794093180748 - lats[2525] = -87.557092145935584 - lats[2526] = -87.627390156234085 - lats[2527] = -87.697688120188062 - lats[2528] = -87.767986033419561 - lats[2529] = -87.838283890981543 - lats[2530] = -87.908581687261687 - lats[2531] = -87.978879415867283 - lats[2532] = -88.049177069484486 - lats[2533] = -88.119474639706425 - lats[2534] = -88.189772116820762 - lats[2535] = -88.26006948954614 - lats[2536] = -88.330366744702559 - lats[2537] = -88.40066386679355 - lats[2538] = -88.470960837474877 - lats[2539] = -88.541257634868515 - lats[2540] = -88.611554232668382 - lats[2541] = -88.681850598961759 - lats[2542] = -88.752146694650691 - lats[2543] = -88.822442471310097 - lats[2544] = -88.892737868230952 - lats[2545] = -88.96303280826325 - lats[2546] = -89.033327191845927 - lats[2547] = -89.103620888238879 - lats[2548] = -89.173913722284126 - lats[2549] = -89.24420545380525 - lats[2550] = -89.314495744374256 - lats[2551] = -89.3847841013921 - lats[2552] = -89.45506977912261 - lats[2553] = -89.525351592371393 - lats[2554] = -89.595627537554492 - lats[2555] = -89.6658939412157 - lats[2556] = -89.736143271609578 - lats[2557] = -89.806357319542244 - lats[2558] = -89.876478353332288 - lats[2559] = -89.946187715665616 - return lats - def first_axis_vals(self): if self._resolution == 1280: return self.get_precomputed_values_N1280() @@ -5502,16 +2939,40 @@ def second_axis_vals(self, first_val): second_axis_vals = [i * second_axis_spacing for i in range(npoints)] return second_axis_vals + def second_axis_spacing(self, first_val): + first_axis_vals = self._first_axis_vals + tol = 1e-10 + # first_val = [val for val in first_axis_vals if first_val - tol < val < first_val + tol][0] + # first_idx = first_axis_vals.index(first_val) + _first_idx = bisect_left_cmp(first_axis_vals, first_val - tol, cmp=lambda x, y: x > y) + first_idx = _first_idx + if first_idx >= self._resolution: + first_idx = (2 * self._resolution) - 1 - first_idx + first_idx = first_idx + 1 + npoints = 4 * first_idx + 16 + second_axis_spacing = 360 / npoints + return (second_axis_spacing, _first_idx + 1) + def map_second_axis(self, first_val, lower, upper): - second_axis_vals = self.second_axis_vals(first_val) - # NOTE: here this seems faster than the bisect.bisect? - # return_vals = [val for val in second_axis_vals if lower <= val <= upper] - start_idx = bisect_left_cmp(second_axis_vals, lower, cmp=lambda x, y: x < y) + 1 - end_idx = bisect_right_cmp(second_axis_vals, upper, cmp=lambda x, y: x < y) + 1 - return_vals = second_axis_vals[start_idx:end_idx] - # start_idx = bisect.bisect_left(second_axis_vals, lower) - # end_idx = bisect.bisect_right(second_axis_vals, upper) + second_axis_spacing, first_idx = self.second_axis_spacing(first_val) + # if first_val not in self._second_axis_spacing: + # (second_axis_spacing, first_idx) = self.second_axis_spacing(first_val) + # self._second_axis_spacing[first_val] = (second_axis_spacing, first_idx) + # else: + # (second_axis_spacing, first_idx) = self._second_axis_spacing[first_val] + start_idx = int(lower/second_axis_spacing) + end_idx = int(upper/second_axis_spacing) + 1 + return_vals = [i * second_axis_spacing for i in range(start_idx, end_idx)] + + # second_axis_vals = self.second_axis_vals(first_val) + # # NOTE: here this seems faster than the bisect.bisect? + # # return_vals = [val for val in second_axis_vals if lower <= val <= upper] + # start_idx = bisect_left_cmp(second_axis_vals, lower, cmp=lambda x, y: x < y) + 1 + # end_idx = bisect_right_cmp(second_axis_vals, upper, cmp=lambda x, y: x < y) + 1 # return_vals = second_axis_vals[start_idx:end_idx] + # # start_idx = bisect.bisect_left(second_axis_vals, lower) + # # end_idx = bisect.bisect_right(second_axis_vals, upper) + # # return_vals = second_axis_vals[start_idx:end_idx] return return_vals def axes_idx_to_octahedral_idx(self, first_idx, second_idx): @@ -5544,11 +3005,11 @@ def axes_idx_to_octahedral_idx(self, first_idx, second_idx): # print(time.time() - time1) return octa_idx - def find_second_idx(self, first_val, second_val): - tol = 1e-10 - second_axis_vals = self.second_axis_vals(first_val) - second_idx = bisect.bisect_left(second_axis_vals, second_val - tol) - return second_idx + # def find_second_idx(self, first_val, second_val): + # tol = 1e-10 + # second_axis_vals = self.second_axis_vals(first_val) + # second_idx = bisect.bisect_left(second_axis_vals, second_val - tol) + # return second_idx def create_first_idx_map(self): # first_idx_list = [0] * (2*self._resolution) @@ -5568,55 +3029,67 @@ def create_first_idx_map(self): idx += 16 + 4 * (self._resolution - i) return first_idx_list - def unmap_first_val_to_start_line_idx(self, first_val): - first_axis_vals = self._first_axis_vals - tol = 1e-10 - # first_val = [val for val in first_axis_vals if first_val - tol < val < first_val + tol][0] - # first_idx = first_axis_vals.index(first_val) + 1 - # first_idx = len(first_axis_vals) - bisect.bisect_left(first_axis_vals[::-1], first_val - tol) - first_idx = bisect_left_cmp(first_axis_vals, first_val - tol, cmp=lambda x, y: x > y) + 1 - octa_idx = 0 - if first_idx == 1: - return octa_idx - else: - for i in range(first_idx - 1): - if i <= self._resolution - 1: - octa_idx += 20 + 4 * i - else: - i = i - self._resolution + 1 - if i == 1: - octa_idx += 16 + 4 * self._resolution - else: - i = i - 1 - octa_idx += 16 + 4 * (self._resolution - i) - return octa_idx + # def unmap_first_val_to_start_line_idx(self, first_val): + # first_axis_vals = self._first_axis_vals + # tol = 1e-10 + # # first_val = [val for val in first_axis_vals if first_val - tol < val < first_val + tol][0] + # # first_idx = first_axis_vals.index(first_val) + 1 + # # first_idx = len(first_axis_vals) - bisect.bisect_left(first_axis_vals[::-1], first_val - tol) + # first_idx = bisect_left_cmp(first_axis_vals, first_val - tol, cmp=lambda x, y: x > y) + 1 + # octa_idx = 0 + # if first_idx == 1: + # return octa_idx + # else: + # for i in range(first_idx - 1): + # if i <= self._resolution - 1: + # octa_idx += 20 + 4 * i + # else: + # i = i - self._resolution + 1 + # if i == 1: + # octa_idx += 16 + 4 * self._resolution + # else: + # i = i - 1 + # octa_idx += 16 + 4 * (self._resolution - i) + # return octa_idx + + def find_second_axis_idx(self, first_val, second_val): + (second_axis_spacing, first_idx) = self.second_axis_spacing(first_val) + # if first_val not in self._second_axis_spacing: + # (second_axis_spacing, first_idx) = self.second_axis_spacing(first_val) + # self._second_axis_spacing[first_val] = (second_axis_spacing, first_idx) + # else: + # (second_axis_spacing, first_idx) = self._second_axis_spacing[first_val] + second_idx = int(second_val/second_axis_spacing) + return (first_idx, second_idx) def unmap(self, first_val, second_val): - time1 = time.time() + # time1 = time.time() # first_axis_vals = self._first_axis_vals # inv_first_axis_vals = self._inv_first_axis_vals - tol = 1e-10 - # first_val = [val for val in first_axis_vals if first_val - tol < val < first_val + tol][0] - # first_idx = first_axis_vals.index(first_val) + 1 - # first_idx = len(first_axis_vals) - bisect.bisect_left(first_axis_vals[::-1], first_val - tol) - # first_idx = bisect_left_cmp(first_axis_vals, first_val - tol, cmp=lambda x, y: x > y) + 1 - first_idx = bisect.bisect_left(self._inv_first_axis_vals, - (first_val - tol)) - # print(inv_first_axis_vals) - # print(first_val) - # first_idx = inv_first_axis_vals[first_val] - # first_idx = np.searchsorted(-first_axis_vals, - (first_val - tol), side="right") - if first_val not in self.treated_first_vals: - second_axis_vals = self.second_axis_vals(first_val) - self.treated_first_vals[first_val] = second_axis_vals - else: - second_axis_vals = self.treated_first_vals[first_val] - # second_val = [val for val in second_axis_vals if second_val - tol < val < second_val + tol][0] - # second_idx = second_axis_vals.index(second_val) - second_idx = bisect.bisect_left(second_axis_vals, second_val - tol) + # tol = 1e-10 + # # first_val = [val for val in first_axis_vals if first_val - tol < val < first_val + tol][0] + # # first_idx = first_axis_vals.index(first_val) + 1 + # # first_idx = len(first_axis_vals) - bisect.bisect_left(first_axis_vals[::-1], first_val - tol) + # # first_idx = bisect_left_cmp(first_axis_vals, first_val - tol, cmp=lambda x, y: x > y) + 1 + # first_idx = bisect.bisect_left(self._inv_first_axis_vals, - (first_val - tol)) + # # print(inv_first_axis_vals) + # # print(first_val) + # # first_idx = inv_first_axis_vals[first_val] + # # first_idx = np.searchsorted(-first_axis_vals, - (first_val - tol), side="right") + # if first_val not in self.treated_first_vals: + # second_axis_vals = self.second_axis_vals(first_val) + # self.treated_first_vals[first_val] = second_axis_vals + # else: + # second_axis_vals = self.treated_first_vals[first_val] + # # second_val = [val for val in second_axis_vals if second_val - tol < val < second_val + tol][0] + # # second_idx = second_axis_vals.index(second_val) + # second_idx = bisect.bisect_left(second_axis_vals, second_val - tol) + (first_idx, second_idx) = self.find_second_axis_idx(first_val, second_val) # second_idx = np.searchsorted(second_axis_vals, second_val - tol) # print("TIME SPENT DOING VAL TO IDX") # print(time.time() - time1) octahedral_index = self.axes_idx_to_octahedral_idx(first_idx, second_idx) + # octahedral_index = int(octahedral_index) # print("OCTAHEDRAL UNMAP TIME ") # print(time.time() - time1) return octahedral_index From 9faf711f483a9b539b5f03da2b783276266ff66b Mon Sep 17 00:00:00 2001 From: Mathilde Leuridan Date: Thu, 19 Oct 2023 16:52:27 +0200 Subject: [PATCH 10/37] optimise small bits --- polytope/datacube/backends/FDB_datacube.py | 18 +++++++++++++----- polytope/datacube/index_tree.py | 1 + .../transformations/datacube_merger.py | 18 ++++++++++++++++-- polytope/engine/hullslicer.py | 1 + 4 files changed, 31 insertions(+), 7 deletions(-) diff --git a/polytope/datacube/backends/FDB_datacube.py b/polytope/datacube/backends/FDB_datacube.py index 61404cd6f..ba119d9a6 100644 --- a/polytope/datacube/backends/FDB_datacube.py +++ b/polytope/datacube/backends/FDB_datacube.py @@ -8,7 +8,7 @@ def update_fdb_dataarray(fdb_dataarray): - fdb_dataarray["values"] = [0.0] + fdb_dataarray["values"] = [] return fdb_dataarray @@ -32,7 +32,6 @@ def __init__(self, config={}, axis_options={}): fdb_dataarray = self.fdb.axes(partial_request).as_dict() dataarray = update_fdb_dataarray(fdb_dataarray) self.dataarray = dataarray - for name, values in dataarray.items(): values.sort() options = axis_options.get(name, {}) @@ -48,11 +47,17 @@ def __init__(self, config={}, axis_options={}): self._check_and_add_axes(options, name, val) def get(self, requests: IndexTree): + # NOTE: this will do all the transformation unmappings for all the points + # It doesn't use the tree structure of the result to do the unmapping transformations anymore time0 = time.time() time_changing_path = 0 accumulated_fdb_time = 0 + time_change_path = 0 for r in requests.leaves: + time5 = time.time() + # NOTE: Accumulated time in flatten is 0.14s... could be better? path = r.flatten() + time_change_path += time.time() - time5 path = self.remap_path(path) if len(path.items()) == self.axis_counter: # first, find the grid mapper transform @@ -88,6 +93,8 @@ def get(self, requests: IndexTree): print(accumulated_fdb_time) print("GET TIME") print(time.time() - time0) + print("TIME FLATTEN PATH AND CHANGE PATH") + print(time_change_path) print("TIME CHANGING PATH") print(time_changing_path) @@ -99,6 +106,7 @@ def select(self, path, unmapped_path): return self.dataarray def ax_vals(self, name): - for _name, values in self.dataarray.items(): - if _name == name: - return values + # for _name, values in self.dataarray.items(): + # if _name == name: + # return values + return self.dataarray.get(name, None) diff --git a/polytope/datacube/index_tree.py b/polytope/datacube/index_tree.py index b7a37aff5..20f82f1c2 100644 --- a/polytope/datacube/index_tree.py +++ b/polytope/datacube/index_tree.py @@ -33,6 +33,7 @@ def __init__(self, axis=root, value=None): @property def leaves(self): + # TODO: could store ancestors directly in leaves? leaves = [] self._collect_leaf_nodes(leaves) return leaves diff --git a/polytope/datacube/transformations/datacube_merger.py b/polytope/datacube/transformations/datacube_merger.py index e8ff67145..288875135 100644 --- a/polytope/datacube/transformations/datacube_merger.py +++ b/polytope/datacube/transformations/datacube_merger.py @@ -1,5 +1,6 @@ import numpy as np import pandas as pd +import time from .datacube_transformations import DatacubeAxisTransformation @@ -16,19 +17,29 @@ def blocked_axes(self): return [self._second_axis] def merged_values(self, datacube): + # time1 = time.time() first_ax_vals = datacube.ax_vals(self.name) second_ax_name = self._second_axis second_ax_vals = datacube.ax_vals(second_ax_name) linkers = self._linkers merged_values = [] - for first_val in first_ax_vals: - for second_val in second_ax_vals: + # merged_values = np.empty(len(first_ax_vals)*len(second_ax_vals)) + # for first_val in first_ax_vals: + for i in range(len(first_ax_vals)): + first_val = first_ax_vals[i] + # for second_val in second_ax_vals: + for j in range(len(second_ax_vals)): + second_val = second_ax_vals[j] # TODO: check that the first and second val are strings val_to_add = pd.to_datetime(first_val + linkers[0] + second_val + linkers[1]) val_to_add = val_to_add.to_numpy() val_to_add = val_to_add.astype("datetime64[s]") merged_values.append(val_to_add) + # print(val_to_add) + # merged_values[i*len(second_ax_vals) + j] = val_to_add merged_values = np.array(merged_values) + # print("MERGED VALUES TIME") + # print(time.time() - time1) return merged_values def transformation_axes_final(self): @@ -38,6 +49,7 @@ def generate_final_transformation(self): return self def unmerge(self, merged_val): + # time1 = time.time() merged_val = str(merged_val) first_idx = merged_val.find(self._linkers[0]) first_val = merged_val[:first_idx] @@ -48,6 +60,8 @@ def unmerge(self, merged_val): # TODO: maybe replacing like this is too specific to time/dates? first_val = str(first_val).replace("-", "") second_val = second_val.replace(":", "") + # print("UNMERGE TIME") + # print(time.time() - time1) return (first_val, second_val) def change_val_type(self, axis_name, values): diff --git a/polytope/engine/hullslicer.py b/polytope/engine/hullslicer.py index f39f8b0c0..7b386cae8 100644 --- a/polytope/engine/hullslicer.py +++ b/polytope/engine/hullslicer.py @@ -2,6 +2,7 @@ from copy import copy from itertools import chain from typing import List +import time import scipy.spatial From fb079544348904116a79d4d754fa670edd5df95e Mon Sep 17 00:00:00 2001 From: Mathilde Leuridan Date: Fri, 20 Oct 2023 13:36:26 +0200 Subject: [PATCH 11/37] calculate leaves' ancestors while finding leaves optimisation --- polytope/datacube/backends/FDB_datacube.py | 5 ++-- polytope/datacube/index_tree.py | 29 +++++++++++++++++++++- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/polytope/datacube/backends/FDB_datacube.py b/polytope/datacube/backends/FDB_datacube.py index ba119d9a6..fcecda8cc 100644 --- a/polytope/datacube/backends/FDB_datacube.py +++ b/polytope/datacube/backends/FDB_datacube.py @@ -53,10 +53,11 @@ def get(self, requests: IndexTree): time_changing_path = 0 accumulated_fdb_time = 0 time_change_path = 0 - for r in requests.leaves: + for r in requests.leaves_with_ancestors: time5 = time.time() # NOTE: Accumulated time in flatten is 0.14s... could be better? - path = r.flatten() + path = r.flatten_with_ancestors() + # path = r.flatten() time_change_path += time.time() - time5 path = self.remap_path(path) if len(path.items()) == self.axis_counter: diff --git a/polytope/datacube/index_tree.py b/polytope/datacube/index_tree.py index 20f82f1c2..9054cd0c5 100644 --- a/polytope/datacube/index_tree.py +++ b/polytope/datacube/index_tree.py @@ -30,18 +30,38 @@ def __init__(self, axis=root, value=None): self._parent = None self.result = None self.axis = axis + self.ancestors = [] @property def leaves(self): - # TODO: could store ancestors directly in leaves? leaves = [] self._collect_leaf_nodes(leaves) return leaves + @property + def leaves_with_ancestors(self): + # TODO: could store ancestors directly in leaves? Change here + leaves = [] + self._collect_leaf_nodes(leaves) + return leaves + + def _collect_leaf_nodes_old(self, leaves): + if len(self.children) == 0: + leaves.append(self) + for n in self.children: + n._collect_leaf_nodes(leaves) + def _collect_leaf_nodes(self, leaves): + # NOTE: leaves_and_ancestors is going to be a list of tuples, where first entry is leaf and second entry is a + # list of its ancestors if len(self.children) == 0: leaves.append(self) + self.ancestors.append(self) for n in self.children: + for ancestor in self.ancestors: + n.ancestors.append(ancestor) + if self.axis != IndexTree.root: + n.ancestors.append(self) n._collect_leaf_nodes(leaves) def __setitem__(self, key, value): @@ -165,6 +185,13 @@ def flatten(self): path[ancestor.axis.name] = ancestor.value return path + def flatten_with_ancestors(self): + path = DatacubePath() + ancestors = self.ancestors + for ancestor in ancestors: + path[ancestor.axis.name] = ancestor.value + return path + def get_ancestors(self): ancestors = [] current_node = self From 03f5b17aaf29c498355a489dda6a36af03265119 Mon Sep 17 00:00:00 2001 From: Mathilde Leuridan Date: Fri, 20 Oct 2023 15:14:38 +0200 Subject: [PATCH 12/37] small optimisation --- polytope/engine/hullslicer.py | 9 +++++---- polytope/polytope.py | 4 ++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/polytope/engine/hullslicer.py b/polytope/engine/hullslicer.py index 7b386cae8..1975f75b8 100644 --- a/polytope/engine/hullslicer.py +++ b/polytope/engine/hullslicer.py @@ -20,7 +20,7 @@ def __init__(self): pass def _unique_continuous_points(self, p: ConvexPolytope, datacube: Datacube): - for i, ax in enumerate(p.axes()): + for i, ax in enumerate(p._axes): mapper = datacube.get_mapper(ax) if isinstance(mapper, UnsliceableDatacubeAxis): break @@ -31,7 +31,7 @@ def _unique_continuous_points(self, p: ConvexPolytope, datacube: Datacube): unique(p.points) def _build_unsliceable_child(self, polytope, ax, node, datacube, lower, next_nodes): - if polytope.axes() != [ax.name]: + if polytope._axes != [ax.name]: raise UnsliceableShapeError(ax) path = node.flatten() if datacube.has_index(path, ax, lower): @@ -56,7 +56,8 @@ def _build_sliceable_child(self, polytope, ax, node, datacube, lower, upper, nex # store the native type remapped_val = value if ax.is_cyclic: - remapped_val = (ax.remap([value, value])[0][0] + ax.remap([value, value])[0][1]) / 2 + remapped_val_interm = ax.remap([value, value])[0] + remapped_val = (remapped_val_interm[0] + remapped_val_interm[1]) / 2 remapped_val = round(remapped_val, int(-math.log10(ax.tol))) child = node.create_child(ax, remapped_val) child["unsliced_polytopes"] = copy(node["unsliced_polytopes"]) @@ -67,7 +68,7 @@ def _build_sliceable_child(self, polytope, ax, node, datacube, lower, upper, nex def _build_branch(self, ax, node, datacube, next_nodes): for polytope in node["unsliced_polytopes"]: - if ax.name in polytope.axes(): + if ax.name in polytope._axes: lower, upper = polytope.extents(ax.name) # here, first check if the axis is an unsliceable axis and directly build node if it is if isinstance(ax, UnsliceableDatacubeAxis): diff --git a/polytope/polytope.py b/polytope/polytope.py index 5e8fc7133..8dea584d5 100644 --- a/polytope/polytope.py +++ b/polytope/polytope.py @@ -1,4 +1,5 @@ from typing import List +import time from .shapes import ConvexPolytope from .utility.exceptions import AxisOverdefinedError @@ -44,6 +45,9 @@ def slice(self, polytopes: List[ConvexPolytope]): def retrieve(self, request: Request, method="standard"): """Higher-level API which takes a request and uses it to slice the datacube""" + print("TIME IN POLYTOPE EXTRACT") + time0 = time.time() request_tree = self.engine.extract(self.datacube, request.polytopes()) + print(time.time() - time0) self.datacube.get(request_tree) return request_tree From 517591985aa55cd8807a6e9b89c48f44d4523f97 Mon Sep 17 00:00:00 2001 From: Mathilde Leuridan Date: Fri, 20 Oct 2023 15:23:14 +0200 Subject: [PATCH 13/37] store slice_axis_idx in hullslicer --- polytope/engine/hullslicer.py | 18 +++++++++--------- polytope/shapes.py | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/polytope/engine/hullslicer.py b/polytope/engine/hullslicer.py index 1975f75b8..00db17bbb 100644 --- a/polytope/engine/hullslicer.py +++ b/polytope/engine/hullslicer.py @@ -30,7 +30,7 @@ def _unique_continuous_points(self, p: ConvexPolytope, datacube: Datacube): # Remove duplicate points unique(p.points) - def _build_unsliceable_child(self, polytope, ax, node, datacube, lower, next_nodes): + def _build_unsliceable_child(self, polytope, ax, node, datacube, lower, next_nodes, slice_axis_idx): if polytope._axes != [ax.name]: raise UnsliceableShapeError(ax) path = node.flatten() @@ -43,7 +43,7 @@ def _build_unsliceable_child(self, polytope, ax, node, datacube, lower, next_nod # raise a value not found error raise ValueError() - def _build_sliceable_child(self, polytope, ax, node, datacube, lower, upper, next_nodes): + def _build_sliceable_child(self, polytope, ax, node, datacube, lower, upper, next_nodes, slice_axis_idx): tol = ax.tol lower = ax.from_float(lower - tol) upper = ax.from_float(upper + tol) @@ -52,7 +52,7 @@ def _build_sliceable_child(self, polytope, ax, node, datacube, lower, upper, nex for value in datacube.get_indices(flattened, ax, lower, upper, method): # convert to float for slicing fvalue = ax.to_float(value) - new_polytope = slice(polytope, ax.name, fvalue) + new_polytope = slice(polytope, ax.name, fvalue, slice_axis_idx) # store the native type remapped_val = value if ax.is_cyclic: @@ -69,12 +69,12 @@ def _build_sliceable_child(self, polytope, ax, node, datacube, lower, upper, nex def _build_branch(self, ax, node, datacube, next_nodes): for polytope in node["unsliced_polytopes"]: if ax.name in polytope._axes: - lower, upper = polytope.extents(ax.name) + lower, upper, slice_axis_idx = polytope.extents(ax.name) # here, first check if the axis is an unsliceable axis and directly build node if it is if isinstance(ax, UnsliceableDatacubeAxis): - self._build_unsliceable_child(polytope, ax, node, datacube, lower, next_nodes) + self._build_unsliceable_child(polytope, ax, node, datacube, lower, next_nodes, slice_axis_idx) else: - self._build_sliceable_child(polytope, ax, node, datacube, lower, upper, next_nodes) + self._build_sliceable_child(polytope, ax, node, datacube, lower, upper, next_nodes, slice_axis_idx) del node["unsliced_polytopes"] def extract(self, datacube: Datacube, polytopes: List[ConvexPolytope]): @@ -129,8 +129,8 @@ def _reduce_dimension(intersects, slice_axis_idx): return temp_intersects -def slice(polytope: ConvexPolytope, axis, value): - slice_axis_idx = polytope._axes.index(axis) +def slice(polytope: ConvexPolytope, axis, value, slice_axis_idx): + # slice_axis_idx = polytope._axes.index(axis) if len(polytope.points[0]) == 1: # Note that in this case, we do not need to do linear interpolation so we can save time @@ -147,7 +147,7 @@ def slice(polytope: ConvexPolytope, axis, value): # Reduce dimension of intersection points, removing slice axis intersects = _reduce_dimension(intersects, slice_axis_idx) - axes = [ax for ax in polytope.axes() if ax != axis] + axes = [ax for ax in polytope._axes if ax != axis] if len(intersects) < len(intersects[0]) + 1: return ConvexPolytope(axes, intersects) diff --git a/polytope/shapes.py b/polytope/shapes.py index 94562abc5..59ac39fd0 100644 --- a/polytope/shapes.py +++ b/polytope/shapes.py @@ -33,7 +33,7 @@ def extents(self, axis): axis_values = [point[slice_axis_idx] for point in self.points] lower = min(axis_values) upper = max(axis_values) - return (lower, upper) + return (lower, upper, slice_axis_idx) def __str__(self): return f"Polytope in {self.axes} with points {self.points}" From fb2b1104fb78b6265db7974af7e1fc00aebd341f Mon Sep 17 00:00:00 2001 From: Mathilde Leuridan Date: Tue, 24 Oct 2023 11:56:09 +0200 Subject: [PATCH 14/37] try to make faster --- polytope/datacube/backends/FDB_datacube.py | 15 +++++++++++++ polytope/engine/hullslicer.py | 25 ++++++++++++++++++---- polytope/utility/combinatorics.py | 2 +- 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/polytope/datacube/backends/FDB_datacube.py b/polytope/datacube/backends/FDB_datacube.py index fcecda8cc..7e3f5ecc2 100644 --- a/polytope/datacube/backends/FDB_datacube.py +++ b/polytope/datacube/backends/FDB_datacube.py @@ -53,6 +53,9 @@ def get(self, requests: IndexTree): time_changing_path = 0 accumulated_fdb_time = 0 time_change_path = 0 + time_removing_branch = 0 + time_is_nan = 0 + interm_time = 0 for r in requests.leaves_with_ancestors: time5 = time.time() # NOTE: Accumulated time in flatten is 0.14s... could be better? @@ -70,6 +73,7 @@ def get(self, requests: IndexTree): axis = self._axes[key] (path, unmapped_path) = axis.unmap_total_path_to_datacube(path, unmapped_path) time_changing_path += time.time() - time2 + time8 = time.time() path = self.fit_path(path) # merge path and unmapped path into a single path path.update(unmapped_path) @@ -80,16 +84,21 @@ def get(self, requests: IndexTree): fdb_request_key = path fdb_requests = [(fdb_request_key, [(fdb_request_val, fdb_request_val + 1)])] + interm_time += time.time() - time8 # need to request data from the fdb time1 = time.time() subxarray = self.fdb.extract(fdb_requests) accumulated_fdb_time += time.time() - time1 subxarray_output_tuple = subxarray[0][0] output_value = subxarray_output_tuple[0][0][0] + time7 = time.time() if not math.isnan(output_value): r.result = output_value + time_is_nan += time.time() - time7 else: + time6 = time.time() r.remove_branch() + time_removing_branch += time.time() - time6 print("FDB TIME") print(accumulated_fdb_time) print("GET TIME") @@ -98,6 +107,12 @@ def get(self, requests: IndexTree): print(time_change_path) print("TIME CHANGING PATH") print(time_changing_path) + print("TIME REMOVING BRANCHES") + print(time_removing_branch) + print("TIME IS NAN") + print(time_is_nan) + print("INTERM TIME") + print(interm_time) def datacube_natural_indexes(self, axis, subarray): indexes = subarray[axis.name] diff --git a/polytope/engine/hullslicer.py b/polytope/engine/hullslicer.py index 00db17bbb..158f09273 100644 --- a/polytope/engine/hullslicer.py +++ b/polytope/engine/hullslicer.py @@ -1,6 +1,6 @@ import math from copy import copy -from itertools import chain +from itertools import chain, product from typing import List import time @@ -9,7 +9,7 @@ from ..datacube.backends.datacube import Datacube, IndexTree from ..datacube.datacube_axis import UnsliceableDatacubeAxis from ..shapes import ConvexPolytope -from ..utility.combinatorics import argmax, argmin, group, product, unique +from ..utility.combinatorics import argmax, argmin, group, tensor_product, unique from ..utility.exceptions import UnsliceableShapeError from ..utility.geometry import lerp from .engine import Engine @@ -85,7 +85,7 @@ def extract(self, datacube: Datacube, polytopes: List[ConvexPolytope]): groups, input_axes = group(polytopes) datacube.validate(input_axes) request = IndexTree() - combinations = product(groups) + combinations = tensor_product(groups) for c in combinations: r = IndexTree() @@ -103,6 +103,12 @@ def extract(self, datacube: Datacube, polytopes: List[ConvexPolytope]): def _find_intersects(polytope, slice_axis_idx, value): intersects = [] # Find all points above and below slice axis + # above_slice, below_slice = [], [] + # for p in polytope.points: + # if p[slice_axis_idx] >= value: + # above_slice.append(p) + # if p[slice_axis_idx] <= value: + # below_slice.append(p) above_slice = [p for p in polytope.points if p[slice_axis_idx] >= value] below_slice = [p for p in polytope.points if p[slice_axis_idx] <= value] @@ -118,6 +124,16 @@ def _find_intersects(polytope, slice_axis_idx, value): interp_coeff = (value - b[slice_axis_idx]) / (a[slice_axis_idx] - b[slice_axis_idx]) intersect = lerp(a, b, interp_coeff) intersects.append(intersect) + # for (a, b) in product(above_slice, below_slice): + # # edge is incident with slice plane, don't need these points + # if a[slice_axis_idx] == b[slice_axis_idx]: + # intersects.append(b) + # continue + + # # Linearly interpolate all coordinates of two points (a,b) of the polytope + # interp_coeff = (value - b[slice_axis_idx]) / (a[slice_axis_idx] - b[slice_axis_idx]) + # intersect = lerp(a, b, interp_coeff) + # intersects.append(intersect) return intersects @@ -164,7 +180,8 @@ def slice(polytope: ConvexPolytope, axis, value, slice_axis_idx): vertices = hull.vertices except scipy.spatial.qhull.QhullError as e: - if "input is less than" or "simplex is flat" in str(e): + # if "input is less than" or "simplex is flat" in str(e): + if "less than" or "flat" in str(e): return ConvexPolytope(axes, intersects) # Sliced result is simply the convex hull return ConvexPolytope(axes, [intersects[i] for i in vertices]) diff --git a/polytope/utility/combinatorics.py b/polytope/utility/combinatorics.py index 1a4a24a5b..9dc641084 100644 --- a/polytope/utility/combinatorics.py +++ b/polytope/utility/combinatorics.py @@ -18,7 +18,7 @@ def group(polytopes: List[ConvexPolytope]): return groups, concatenation -def product(groups): +def tensor_product(groups): # Compute the tensor product of polytope groups return list(itertools.product(*groups.values())) From 722d0f087819656b44486f1431c1e615d9d83ffa Mon Sep 17 00:00:00 2001 From: Mathilde Leuridan Date: Tue, 24 Oct 2023 13:38:21 +0200 Subject: [PATCH 15/37] add a null transformation and see effect on performance --- performance/fdb_performance.py | 5 +++ polytope/datacube/datacube_axis.py | 39 +++++++++++++++++++ .../datacube_null_transformation.py | 19 +++++++++ .../datacube_transformations.py | 3 ++ 4 files changed, 66 insertions(+) create mode 100644 polytope/datacube/transformations/datacube_null_transformation.py diff --git a/performance/fdb_performance.py b/performance/fdb_performance.py index 9bcac25b7..d4fd0ac5a 100644 --- a/performance/fdb_performance.py +++ b/performance/fdb_performance.py @@ -20,6 +20,11 @@ def setup_method(self, method): }, "date": {"transformation": {"merge": {"with": "time", "linkers": [" ", "00"]}}}, "step": {"transformation": {"type_change": "int"}}, + # "latitude": {"transformation": {"null": []}}, + # "longitude": {"transformation": {"null": []}}, + # "class": {"transformation": {"null": []}}, + # "param": {"transformation": {"null": []}}, + # "stream": {"transformation": {"null": []}}, } self.config = {"class": "od", "expver": "0001", "levtype": "sfc", "step": 0} self.fdbdatacube = FDBDatacube(self.config, axis_options=self.options) diff --git a/polytope/datacube/datacube_axis.py b/polytope/datacube/datacube_axis.py index 07edd8d40..0efbefa9b 100644 --- a/polytope/datacube/datacube_axis.py +++ b/polytope/datacube/datacube_axis.py @@ -559,6 +559,45 @@ def remap(range): return cls +def null(cls): + + if cls.type_change: + old_find_indexes = cls.find_indexes + + def find_indexes(path, datacube): + return old_find_indexes(path, datacube) + + old_unmap_total_path_to_datacube = cls.unmap_total_path_to_datacube + + def unmap_total_path_to_datacube(path, unmapped_path): + return old_unmap_total_path_to_datacube(path, unmapped_path) + + def unmap_to_datacube(path, unmapped_path): + return (path, unmapped_path) + + def remap_to_requested(path, unmapped_path): + return (path, unmapped_path) + + def find_indices_between(index_ranges, low, up, datacube, method=None): + indexes_between_ranges = [] + for indexes in index_ranges: + indexes_between = [i for i in indexes if low <= i <= up] + indexes_between_ranges.append(indexes_between) + return indexes_between_ranges + + def remap(range): + return [range] + + cls.remap = remap + cls.find_indexes = find_indexes + cls.unmap_to_datacube = unmap_to_datacube + cls.remap_to_requested = remap_to_requested + cls.find_indices_between = find_indices_between + cls.unmap_total_path_to_datacube = unmap_total_path_to_datacube + + return cls + + class DatacubeAxis(ABC): is_cyclic = False has_mapper = False diff --git a/polytope/datacube/transformations/datacube_null_transformation.py b/polytope/datacube/transformations/datacube_null_transformation.py new file mode 100644 index 000000000..ef026428c --- /dev/null +++ b/polytope/datacube/transformations/datacube_null_transformation.py @@ -0,0 +1,19 @@ +from .datacube_transformations import DatacubeAxisTransformation + + +class DatacubeNullTransformation(DatacubeAxisTransformation): + def __init__(self, name, mapper_options): + self.name = name + self.transformation_options = mapper_options + + def generate_final_transformation(self): + return self + + def transformation_axes_final(self): + return [self.name] + + def change_val_type(self, axis_name, values): + return values + + def blocked_axes(self): + return [] diff --git a/polytope/datacube/transformations/datacube_transformations.py b/polytope/datacube/transformations/datacube_transformations.py index f4ce357a9..900ad16b6 100644 --- a/polytope/datacube/transformations/datacube_transformations.py +++ b/polytope/datacube/transformations/datacube_transformations.py @@ -50,6 +50,7 @@ def change_val_type(self, axis_name, values): "merge": "DatacubeAxisMerger", "reverse": "DatacubeAxisReverse", "type_change": "DatacubeAxisTypeChange", + "null": "DatacubeNullTransformation", } _type_to_transformation_file_lookup = { @@ -58,6 +59,7 @@ def change_val_type(self, axis_name, values): "merge": "merger", "reverse": "reverse", "type_change": "type_change", + "null": "null_transformation", } has_transform = { @@ -66,4 +68,5 @@ def change_val_type(self, axis_name, values): "merge": "has_merger", "reverse": "reorder", "type_change": "type_change", + "null": "null", } From a225c41cc005f105f67fa0c0c2f59d4582d95d86 Mon Sep 17 00:00:00 2001 From: Mathilde Leuridan Date: Wed, 25 Oct 2023 13:32:27 +0200 Subject: [PATCH 16/37] small optimisation --- polytope/datacube/backends/datacube.py | 1 + polytope/datacube/backends/xarray.py | 2 + polytope/datacube/datacube_axis.py | 62 +++++++++++++------ .../transformations/datacube_mappers.py | 11 ++-- .../transformations/datacube_merger.py | 4 +- tests/test_combinatorics.py | 4 +- tests/test_datacube_axes_init.py | 6 +- tests/test_hull_slicer.py | 16 ++--- 8 files changed, 69 insertions(+), 37 deletions(-) diff --git a/polytope/datacube/backends/datacube.py b/polytope/datacube/backends/datacube.py index f6ffb041f..c9e8854b6 100644 --- a/polytope/datacube/backends/datacube.py +++ b/polytope/datacube/backends/datacube.py @@ -39,6 +39,7 @@ def _create_axes(self, name, values, transformation_type_key, transformation_opt self.blocked_axes.append(blocked_axis) for axis_name in final_axis_names: self.complete_axes.append(axis_name) + self.fake_axes.append(axis_name) # if axis does not yet exist, create it # first need to change the values so that we have right type diff --git a/polytope/datacube/backends/xarray.py b/polytope/datacube/backends/xarray.py index 321f0f644..18ec06aa2 100644 --- a/polytope/datacube/backends/xarray.py +++ b/polytope/datacube/backends/xarray.py @@ -66,6 +66,8 @@ def get(self, requests: IndexTree): r.remove_branch() def datacube_natural_indexes(self, axis, subarray): + # if axis.name in self.fake_axes: + # indexes = subarray[axis.name].values if axis.name in self.complete_axes: indexes = next(iter(subarray.xindexes.values())).to_pandas_index() else: diff --git a/polytope/datacube/datacube_axis.py b/polytope/datacube/datacube_axis.py index 0efbefa9b..2505c6f09 100644 --- a/polytope/datacube/datacube_axis.py +++ b/polytope/datacube/datacube_axis.py @@ -2,6 +2,7 @@ from copy import deepcopy from typing import Any, List import time +import bisect import numpy as np import pandas as pd @@ -249,8 +250,14 @@ def unmap_total_path_to_datacube(path, unmapped_path): if cls.name == transformation._mapped_axes()[0]: # axis = cls.name # if we are on the first axis, then need to add the first val to unmapped_path - first_val = path.get(cls.name, None) - path.pop(cls.name, None) + # if cls.name in path: + # first_val = path.get(cls.name, None) + # path.pop(cls.name, None) + first_val = path[cls.name] + del path[cls.name] + # else: + # first_val = None + if unmapped_path is None: unmapped_path[cls.name] = first_val elif cls.name not in unmapped_path: @@ -262,11 +269,14 @@ def unmap_total_path_to_datacube(path, unmapped_path): # axis = cls.name # print("TIME time handling path") # time2 = time.time() - second_val = path.get(cls.name, None) - path.pop(cls.name, None) + # second_val = path.get(cls.name, None) + # path.pop(cls.name, None) + second_val = path[cls.name] + del path[cls.name] first_val = unmapped_path.get(transformation._mapped_axes()[0], None) unmapped_path.pop(transformation._mapped_axes()[0], None) + # del unmapped_path[transformation._mapped_axes()[0]] # print(time.time() - time2) # NOTE: here we first calculate the starting idx of the first_val grid line # and then append the second_idx to get the final unmapped_idx @@ -279,11 +289,11 @@ def unmap_total_path_to_datacube(path, unmapped_path): if first_val is None: first_val = path.get(transformation._mapped_axes()[0], None) path.pop(transformation._mapped_axes()[0], None) - if second_val is not None: + # if second_val is not None: # time4 = time.time() # unmapped_idx = first_line_idx + second_idx - unmapped_idx = transformation.unmap(first_val, second_val) - unmapped_path[transformation.old_axis] = unmapped_idx + unmapped_idx = transformation.unmap(first_val, second_val) + unmapped_path[transformation.old_axis] = unmapped_idx # print(time.time() - time4) # time3 = time.time() # print("MAPPER UNMAP TIME") @@ -313,6 +323,10 @@ def find_indices_between(index_ranges, low, up, datacube, method=None): indexes_between = idxs[start:end] indexes_between_ranges.append(indexes_between) else: + # lower_idx = bisect.bisect_left(idxs, low) + # upper_idx = bisect.bisect_right(idxs, up) + # indexes_between = idxs[lower_idx: upper_idx] + # print(indexes_between) indexes_between = [i for i in idxs if low <= i <= up] indexes_between_ranges.append(indexes_between) return indexes_between_ranges @@ -337,12 +351,14 @@ def merge(cls): if cls.has_merger: + cls_name = cls.name + def find_indexes(path, datacube): # first, find the relevant transformation object that is a mapping in the cls.transformation dico for transform in cls.transformations: if isinstance(transform, DatacubeAxisMerger): transformation = transform - if cls.name == transformation._first_axis: + if cls_name == transformation._first_axis: return transformation.merged_values(datacube) old_unmap_total_path_to_datacube = cls.unmap_total_path_to_datacube @@ -352,10 +368,11 @@ def unmap_total_path_to_datacube(path, unmapped_path): for transform in cls.transformations: if isinstance(transform, DatacubeAxisMerger): transformation = transform - if cls.name == transformation._first_axis: - old_val = path.get(cls.name, None) + if cls_name == transformation._first_axis: + # old_val = path.get(cls.name, None) + old_val = path[cls_name] (first_val, second_val) = transformation.unmerge(old_val) - path.pop(cls.name, None) + # path.pop(cls.name, None) path[transformation._first_axis] = first_val path[transformation._second_axis] = second_val return (path, unmapped_path) @@ -367,10 +384,10 @@ def unmap_to_datacube(path, unmapped_path): for transform in cls.transformations: if isinstance(transform, DatacubeAxisMerger): transformation = transform - if cls.name == transformation._first_axis: - old_val = path.get(cls.name, None) + if cls_name == transformation._first_axis: + old_val = path.get(cls_name, None) (first_val, second_val) = transformation.unmerge(old_val) - path.pop(cls.name, None) + path.pop(cls_name, None) path[transformation._first_axis] = first_val path[transformation._second_axis] = second_val return (path, unmapped_path) @@ -384,7 +401,7 @@ def find_indices_between(index_ranges, low, up, datacube, method=None): for transform in cls.transformations: if isinstance(transform, DatacubeAxisMerger): transformation = transform - if cls.name in transformation._mapped_axes(): + if cls_name in transformation._mapped_axes(): for indexes in index_ranges: if method == "surrounding": start = indexes.index(low) @@ -394,7 +411,10 @@ def find_indices_between(index_ranges, low, up, datacube, method=None): indexes_between = indexes[start:end] indexes_between_ranges.append(indexes_between) else: - indexes_between = [i for i in indexes if low <= i <= up] + lower_idx = bisect.bisect_left(indexes, low) + upper_idx = bisect.bisect_right(indexes, up) + indexes_between = indexes[lower_idx: upper_idx] + # indexes_between = [i for i in indexes if low <= i <= up] indexes_between_ranges.append(indexes_between) return indexes_between_ranges @@ -466,7 +486,10 @@ def find_indices_between(index_ranges, low, up, datacube, method=None): indexes_between = indexes[start:end] indexes_between_ranges.append(indexes_between) else: - indexes_between = [i for i in indexes if low <= i <= up] + # indexes_between = [i for i in indexes if low <= i <= up] + lower_idx = bisect.bisect_left(indexes, low) + upper_idx = bisect.bisect_right(indexes, up) + indexes_between = indexes[lower_idx: upper_idx] indexes_between_ranges.append(indexes_between) return indexes_between_ranges @@ -542,7 +565,10 @@ def find_indices_between(index_ranges, low, up, datacube, method=None): indexes_between = indexes[start:end] indexes_between_ranges.append(indexes_between) else: - indexes_between = [i for i in indexes if low <= i <= up] + # indexes_between = [i for i in indexes if low <= i <= up] + lower_idx = bisect.bisect_left(indexes, low) + upper_idx = bisect.bisect_right(indexes, up) + indexes_between = indexes[lower_idx: upper_idx] indexes_between_ranges.append(indexes_between) return indexes_between_ranges diff --git a/polytope/datacube/transformations/datacube_mappers.py b/polytope/datacube/transformations/datacube_mappers.py index a26a0df6f..ec4b7d70b 100644 --- a/polytope/datacube/transformations/datacube_mappers.py +++ b/polytope/datacube/transformations/datacube_mappers.py @@ -3,10 +3,6 @@ from importlib import import_module from ...utility.list_tools import bisect_left_cmp, bisect_right_cmp import bisect -import time -import array -import numpy as np -from sortedcontainers import SortedDict, SortedList from .datacube_transformations import DatacubeAxisTransformation @@ -21,6 +17,7 @@ def __init__(self, name, mapper_options): self.grid_axes = mapper_options["axes"] self.old_axis = name self._final_transformation = self.generate_final_transformation() + self._final_mapped_axes = self._final_transformation._mapped_axes def generate_final_transformation(self): map_type = _type_to_datacube_mapper_lookup[self.grid_type] @@ -34,7 +31,8 @@ def blocked_axes(self): def transformation_axes_final(self): # final_transformation = self.generate_final_transformation() - final_axes = self._final_transformation._mapped_axes + # final_axes = self._final_transformation._mapped_axes + final_axes = self._final_mapped_axes return final_axes # Needs to also implement its own methods @@ -46,7 +44,8 @@ def change_val_type(self, axis_name, values): def _mapped_axes(self): # NOTE: Each of the mapper method needs to call it's sub mapper method # final_transformation = self.generate_final_transformation() - final_axes = self._final_transformation._mapped_axes + # final_axes = self._final_transformation._mapped_axes + final_axes = self._final_mapped_axes return final_axes def _base_axis(self): diff --git a/polytope/datacube/transformations/datacube_merger.py b/polytope/datacube/transformations/datacube_merger.py index 288875135..4326d202b 100644 --- a/polytope/datacube/transformations/datacube_merger.py +++ b/polytope/datacube/transformations/datacube_merger.py @@ -1,6 +1,6 @@ import numpy as np import pandas as pd -import time +# import time from .datacube_transformations import DatacubeAxisTransformation @@ -31,7 +31,7 @@ def merged_values(self, datacube): for j in range(len(second_ax_vals)): second_val = second_ax_vals[j] # TODO: check that the first and second val are strings - val_to_add = pd.to_datetime(first_val + linkers[0] + second_val + linkers[1]) + val_to_add = pd.to_datetime("".join([first_val, linkers[0], second_val, linkers[1]])) val_to_add = val_to_add.to_numpy() val_to_add = val_to_add.astype("datetime64[s]") merged_values.append(val_to_add) diff --git a/tests/test_combinatorics.py b/tests/test_combinatorics.py index fab2fb2ca..980ad8e2c 100644 --- a/tests/test_combinatorics.py +++ b/tests/test_combinatorics.py @@ -2,7 +2,7 @@ import pytest from polytope import ConvexPolytope -from polytope.utility.combinatorics import group, product, validate_axes +from polytope.utility.combinatorics import group, tensor_product, validate_axes from polytope.utility.exceptions import ( AxisNotFoundError, AxisOverdefinedError, @@ -28,7 +28,7 @@ def test_group_and_product(self): assert len(groups[("a", "b")]) == 4 assert len(all_axes) == 4 - combinations = product(groups) + combinations = tensor_product(groups) assert len(combinations) == 4 for c in combinations: diff --git a/tests/test_datacube_axes_init.py b/tests/test_datacube_axes_init.py index 9089de0c7..248b59ff4 100644 --- a/tests/test_datacube_axes_init.py +++ b/tests/test_datacube_axes_init.py @@ -23,7 +23,8 @@ def setup_method(self, method): "transformation": { "mapper": {"type": "octahedral", "resolution": 1280, "axes": ["latitude", "longitude"]} } - } + }, + # "latitude": {"transformation": {"reverse": {True}}}, } self.slicer = HullSlicer() self.API = Polytope(datacube=latlon_array, engine=self.slicer, axis_options=self.options) @@ -35,7 +36,8 @@ def test_created_axes(self): assert self.datacube._axes["longitude"].has_mapper assert isinstance(self.datacube._axes["longitude"], FloatDatacubeAxis) assert not ("values" in self.datacube._axes.keys()) - assert self.datacube._axes["latitude"].find_indexes({}, self.datacube)[:5] == [ + print(list(self.datacube._axes["latitude"].find_indexes({}, self.datacube)[:5])) + assert list(self.datacube._axes["latitude"].find_indexes({}, self.datacube)[:5]) == [ 89.94618771566562, 89.87647835333229, 89.80635731954224, diff --git a/tests/test_hull_slicer.py b/tests/test_hull_slicer.py index 4e9404e23..e733612f7 100644 --- a/tests/test_hull_slicer.py +++ b/tests/test_hull_slicer.py @@ -20,38 +20,40 @@ def construct_nd_cube(self, dimension, lower=-1, upper=1): def test_3D(self): p3 = self.construct_nd_cube(3) print(p3) - p2 = polytope.engine.hullslicer.slice(p3, "c", 0.5) + p2 = polytope.engine.hullslicer.slice(p3, "c", 0.5, 2) print(p2) - p1 = polytope.engine.hullslicer.slice(p2, "b", 0.5) + p1 = polytope.engine.hullslicer.slice(p2, "b", 0.5, 1) print(p1) + @pytest.mark.skip(reason="This is too slow.") def test_4D(self): p = self.construct_nd_cube(4) print(p) while len(p.axes()) > 1: - p = polytope.engine.hullslicer.slice(p, p._axes[-1], 0.5) + p = polytope.engine.hullslicer.slice(p, p._axes[-1], 0.5, -1) print(p) + @pytest.mark.skip(reason="This is too slow.") def test_ND(self): with benchmark("4D"): p = self.construct_nd_cube(4) while len(p.axes()) > 1: - p = polytope.engine.hullslicer.slice(p, p._axes[-1], 0.5) + p = polytope.engine.hullslicer.slice(p, p._axes[-1], 0.5, -1) with benchmark("5D"): p = self.construct_nd_cube(5) while len(p.axes()) > 1: - p = polytope.engine.hullslicer.slice(p, p._axes[-1], 0.5) + p = polytope.engine.hullslicer.slice(p, p._axes[-1], 0.5, -1) with benchmark("6D"): p = self.construct_nd_cube(6) while len(p.axes()) > 1: - p = polytope.engine.hullslicer.slice(p, p._axes[-1], 0.5) + p = polytope.engine.hullslicer.slice(p, p._axes[-1], 0.5, -1) with benchmark("7D"): p = self.construct_nd_cube(7) while len(p.axes()) > 1: - p = polytope.engine.hullslicer.slice(p, p._axes[-1], 0.5) + p = polytope.engine.hullslicer.slice(p, p._axes[-1], 0.5, -1) # QHull is not performant above 7D as per its documentation # with benchmark("8D"): From dd5c2498052501bd48f2a499a558dfefea2712f4 Mon Sep 17 00:00:00 2001 From: Mathilde Leuridan Date: Thu, 26 Oct 2023 10:01:14 +0200 Subject: [PATCH 17/37] small optimisations --- polytope/datacube/backends/FDB_datacube.py | 9 +- polytope/datacube/backends/datacube.py | 1 + polytope/datacube/backends/xarray.py | 2 +- polytope/datacube/datacube_axis.py | 85 +++++++++---------- .../transformations/datacube_mappers.py | 7 +- 5 files changed, 52 insertions(+), 52 deletions(-) diff --git a/polytope/datacube/backends/FDB_datacube.py b/polytope/datacube/backends/FDB_datacube.py index 7e3f5ecc2..d25029e3d 100644 --- a/polytope/datacube/backends/FDB_datacube.py +++ b/polytope/datacube/backends/FDB_datacube.py @@ -49,20 +49,19 @@ def __init__(self, config={}, axis_options={}): def get(self, requests: IndexTree): # NOTE: this will do all the transformation unmappings for all the points # It doesn't use the tree structure of the result to do the unmapping transformations anymore - time0 = time.time() time_changing_path = 0 accumulated_fdb_time = 0 time_change_path = 0 - time_removing_branch = 0 time_is_nan = 0 interm_time = 0 + time0 = time.time() for r in requests.leaves_with_ancestors: time5 = time.time() # NOTE: Accumulated time in flatten is 0.14s... could be better? path = r.flatten_with_ancestors() # path = r.flatten() time_change_path += time.time() - time5 - path = self.remap_path(path) + # path = self.remap_path(path) if len(path.items()) == self.axis_counter: # first, find the grid mapper transform @@ -96,9 +95,7 @@ def get(self, requests: IndexTree): r.result = output_value time_is_nan += time.time() - time7 else: - time6 = time.time() r.remove_branch() - time_removing_branch += time.time() - time6 print("FDB TIME") print(accumulated_fdb_time) print("GET TIME") @@ -107,8 +104,6 @@ def get(self, requests: IndexTree): print(time_change_path) print("TIME CHANGING PATH") print(time_changing_path) - print("TIME REMOVING BRANCHES") - print(time_removing_branch) print("TIME IS NAN") print(time_is_nan) print("INTERM TIME") diff --git a/polytope/datacube/backends/datacube.py b/polytope/datacube/backends/datacube.py index c9e8854b6..b9bf40d54 100644 --- a/polytope/datacube/backends/datacube.py +++ b/polytope/datacube/backends/datacube.py @@ -2,6 +2,7 @@ import math from abc import ABC, abstractmethod from typing import Any +import time import xarray as xr diff --git a/polytope/datacube/backends/xarray.py b/polytope/datacube/backends/xarray.py index 18ec06aa2..fdb7f087e 100644 --- a/polytope/datacube/backends/xarray.py +++ b/polytope/datacube/backends/xarray.py @@ -48,7 +48,7 @@ def __init__(self, dataarray: xr.DataArray, axis_options={}): def get(self, requests: IndexTree): for r in requests.leaves: path = r.flatten() - path = self.remap_path(path) + # path = self.remap_path(path) if len(path.items()) == self.axis_counter: # first, find the grid mapper transform unmapped_path = {} diff --git a/polytope/datacube/datacube_axis.py b/polytope/datacube/datacube_axis.py index 2505c6f09..87181888e 100644 --- a/polytope/datacube/datacube_axis.py +++ b/polytope/datacube/datacube_axis.py @@ -3,6 +3,7 @@ from typing import Any, List import time import bisect +from ..utility.list_tools import bisect_left_cmp, bisect_right_cmp import numpy as np import pandas as pd @@ -213,28 +214,27 @@ def unmap_to_datacube(path, unmapped_path): (path, unmapped_path) = old_unmap_to_datacube(path, unmapped_path) for transform in cls.transformations: if isinstance(transform, DatacubeMapper): - transformation = transform - if cls.name == transformation._mapped_axes()[0]: + if cls.name == transform._mapped_axes()[0]: # if we are on the first axis, then need to add the first val to unmapped_path first_val = path.get(cls.name, None) path.pop(cls.name, None) if cls.name not in unmapped_path: # if for some reason, the unmapped_path already has the first axis val, then don't update unmapped_path[cls.name] = first_val - if cls.name == transformation._mapped_axes()[1]: + if cls.name == transform._mapped_axes()[1]: # if we are on the second axis, then the val of the first axis is stored # inside unmapped_path so can get it from there second_val = path.get(cls.name, None) path.pop(cls.name, None) - first_val = unmapped_path.get(transformation._mapped_axes()[0], None) - unmapped_path.pop(transformation._mapped_axes()[0], None) + first_val = unmapped_path.get(transform._mapped_axes()[0], None) + unmapped_path.pop(transform._mapped_axes()[0], None) # if the first_val was not in the unmapped_path, then it's still in path if first_val is None: - first_val = path.get(transformation._mapped_axes()[0], None) - path.pop(transformation._mapped_axes()[0], None) + first_val = path.get(transform._mapped_axes()[0], None) + path.pop(transform._mapped_axes()[0], None) if first_val is not None and second_val is not None: - unmapped_idx = transformation.unmap(first_val, second_val) - unmapped_path[transformation.old_axis] = unmapped_idx + unmapped_idx = transform.unmap(first_val, second_val) + unmapped_path[transform.old_axis] = unmapped_idx return (path, unmapped_path) old_unmap_total_path_to_datacube = cls.unmap_total_path_to_datacube @@ -246,13 +246,9 @@ def unmap_total_path_to_datacube(path, unmapped_path): for transform in cls.transformations: if isinstance(transform, DatacubeMapper): # time2 = time.time() - transformation = transform - if cls.name == transformation._mapped_axes()[0]: + if cls.name == transform._mapped_axes()[0]: # axis = cls.name # if we are on the first axis, then need to add the first val to unmapped_path - # if cls.name in path: - # first_val = path.get(cls.name, None) - # path.pop(cls.name, None) first_val = path[cls.name] del path[cls.name] # else: @@ -263,7 +259,7 @@ def unmap_total_path_to_datacube(path, unmapped_path): elif cls.name not in unmapped_path: # if for some reason, the unmapped_path already has the first axis val, then don't update unmapped_path[cls.name] = first_val - if cls.name == transformation._mapped_axes()[1]: + if cls.name == transform._mapped_axes()[1]: # if we are on the second axis, then the val of the first axis is stored # inside unmapped_path so can get it from there # axis = cls.name @@ -273,30 +269,25 @@ def unmap_total_path_to_datacube(path, unmapped_path): # path.pop(cls.name, None) second_val = path[cls.name] del path[cls.name] - first_val = unmapped_path.get(transformation._mapped_axes()[0], None) + first_val = unmapped_path.get(transform._mapped_axes()[0], None) - unmapped_path.pop(transformation._mapped_axes()[0], None) + unmapped_path.pop(transform._mapped_axes()[0], None) # del unmapped_path[transformation._mapped_axes()[0]] # print(time.time() - time2) # NOTE: here we first calculate the starting idx of the first_val grid line # and then append the second_idx to get the final unmapped_idx # To do this, also need to find second_idx from second_val... - # second_idx = transformation.find_second_idx(first_val, second_val) - # first_line_idx = transformation.unmap_first_val_to_start_line_idx(first_val) # if the first_val was not in the unmapped_path, then it's still in path # print("AAAAAND TIME TAKEN DOING UNMAP") if first_val is None: - first_val = path.get(transformation._mapped_axes()[0], None) - path.pop(transformation._mapped_axes()[0], None) - # if second_val is not None: - # time4 = time.time() - # unmapped_idx = first_line_idx + second_idx - unmapped_idx = transformation.unmap(first_val, second_val) - unmapped_path[transformation.old_axis] = unmapped_idx - # print(time.time() - time4) + first_val = path.get(transform._mapped_axes()[0], None) + path.pop(transform._mapped_axes()[0], None) + unmapped_idx = transform.unmap(first_val, second_val) + unmapped_path[transform.old_axis] = unmapped_idx # time3 = time.time() # print("MAPPER UNMAP TIME") + # print(time.time() - time1) # print(time3 - time1) # print("AXIS THIS IS FOR") # print(axis) @@ -323,11 +314,17 @@ def find_indices_between(index_ranges, low, up, datacube, method=None): indexes_between = idxs[start:end] indexes_between_ranges.append(indexes_between) else: - # lower_idx = bisect.bisect_left(idxs, low) - # upper_idx = bisect.bisect_right(idxs, up) - # indexes_between = idxs[lower_idx: upper_idx] - # print(indexes_between) - indexes_between = [i for i in idxs if low <= i <= up] + axis_reversed = transform._axis_reversed[cls.name] + if not axis_reversed: + lower_idx = bisect.bisect_left(idxs, low) + upper_idx = bisect.bisect_right(idxs, up) + indexes_between = idxs[lower_idx: upper_idx] + else: + # TODO: do the custom bisect + end_idx = bisect_left_cmp(idxs, low, cmp=lambda x, y: x > y) + 1 + start_idx = bisect_right_cmp(idxs, up, cmp=lambda x, y: x > y) + indexes_between = idxs[start_idx:end_idx] + # indexes_between = [i for i in idxs if low <= i <= up] indexes_between_ranges.append(indexes_between) return indexes_between_ranges @@ -351,30 +348,29 @@ def merge(cls): if cls.has_merger: - cls_name = cls.name - def find_indexes(path, datacube): # first, find the relevant transformation object that is a mapping in the cls.transformation dico for transform in cls.transformations: if isinstance(transform, DatacubeAxisMerger): transformation = transform - if cls_name == transformation._first_axis: + if cls.name == transformation._first_axis: return transformation.merged_values(datacube) old_unmap_total_path_to_datacube = cls.unmap_total_path_to_datacube def unmap_total_path_to_datacube(path, unmapped_path): + # time1 = time.time() (path, unmapped_path) = old_unmap_total_path_to_datacube(path, unmapped_path) for transform in cls.transformations: if isinstance(transform, DatacubeAxisMerger): transformation = transform - if cls_name == transformation._first_axis: - # old_val = path.get(cls.name, None) - old_val = path[cls_name] + if cls.name == transformation._first_axis: + old_val = path[cls.name] (first_val, second_val) = transformation.unmerge(old_val) - # path.pop(cls.name, None) path[transformation._first_axis] = first_val path[transformation._second_axis] = second_val + # print("UNMAPPER TIME INSIDE MERGE") + # print(time.time() - time1) return (path, unmapped_path) old_unmap_to_datacube = cls.unmap_to_datacube @@ -384,10 +380,10 @@ def unmap_to_datacube(path, unmapped_path): for transform in cls.transformations: if isinstance(transform, DatacubeAxisMerger): transformation = transform - if cls_name == transformation._first_axis: - old_val = path.get(cls_name, None) + if cls.name == transformation._first_axis: + old_val = path.get(cls.name, None) (first_val, second_val) = transformation.unmerge(old_val) - path.pop(cls_name, None) + path.pop(cls.name, None) path[transformation._first_axis] = first_val path[transformation._second_axis] = second_val return (path, unmapped_path) @@ -401,7 +397,7 @@ def find_indices_between(index_ranges, low, up, datacube, method=None): for transform in cls.transformations: if isinstance(transform, DatacubeAxisMerger): transformation = transform - if cls_name in transformation._mapped_axes(): + if cls.name in transformation._mapped_axes(): for indexes in index_ranges: if method == "surrounding": start = indexes.index(low) @@ -522,6 +518,7 @@ def find_indexes(path, datacube): old_unmap_total_path_to_datacube = cls.unmap_total_path_to_datacube def unmap_total_path_to_datacube(path, unmapped_path): + # time1 = time.time() (path, unmapped_path) = old_unmap_total_path_to_datacube(path, unmapped_path) for transform in cls.transformations: if isinstance(transform, DatacubeAxisTypeChange): @@ -532,6 +529,8 @@ def unmap_total_path_to_datacube(path, unmapped_path): if cls.name in path: path.pop(cls.name, None) unmapped_path[cls.name] = unchanged_val + # print("UNMAPPER TIME INSIDE TYPE_CHANGE") + # print(time.time() - time1) return (path, unmapped_path) def unmap_to_datacube(path, unmapped_path): diff --git a/polytope/datacube/transformations/datacube_mappers.py b/polytope/datacube/transformations/datacube_mappers.py index ec4b7d70b..947920e4e 100644 --- a/polytope/datacube/transformations/datacube_mappers.py +++ b/polytope/datacube/transformations/datacube_mappers.py @@ -18,6 +18,7 @@ def __init__(self, name, mapper_options): self.old_axis = name self._final_transformation = self.generate_final_transformation() self._final_mapped_axes = self._final_transformation._mapped_axes + self._axis_reversed = self._final_transformation._axis_reversed def generate_final_transformation(self): map_type = _type_to_datacube_mapper_lookup[self.grid_type] @@ -87,6 +88,7 @@ def __init__(self, base_axis, mapped_axes, resolution): self._base_axis = base_axis self._resolution = resolution self.deg_increment = 90 / self._resolution + self._axis_reversed = {mapped_axes[0]: True, mapped_axes[1]: False} def first_axis_vals(self): first_ax_vals = [-90 + i * self.deg_increment for i in range(2 * self._resolution)] @@ -137,6 +139,7 @@ def __init__(self, base_axis, mapped_axes, resolution): self._mapped_axes = mapped_axes self._base_axis = base_axis self._resolution = resolution + self._axis_reversed = {mapped_axes[0]: True, mapped_axes[1]: False} def first_axis_vals(self): rad2deg = 180 / math.pi @@ -255,8 +258,10 @@ def __init__(self, base_axis, mapped_axes, resolution): # self._inv_first_axis_vals = self._first_axis_vals[::-1] # self._inv_first_axis_vals = {v:k for k,v in self._first_axis_vals.items()} self._first_idx_map = self.create_first_idx_map() - self._second_axis_spacing = dict() + # self._second_axis_spacing = dict() + self._second_axis_spacing = {} # self.treated_first_vals = dict() + self._axis_reversed = {mapped_axes[0]: True, mapped_axes[1]: False} def gauss_first_guess(self): i = 0 From b32ff76996436908802e09d45435ec82744afc2e Mon Sep 17 00:00:00 2001 From: Mathilde Leuridan Date: Fri, 27 Oct 2023 12:57:27 +0200 Subject: [PATCH 18/37] make new recursive get --- polytope/datacube/backends/FDB_datacube.py | 58 ++++++++++++++++- polytope/datacube/backends/datacube.py | 2 + polytope/datacube/datacube_axis.py | 64 +++++++++++++++++++ .../transformations/datacube_cyclic.py | 3 + .../transformations/datacube_mappers.py | 3 + .../transformations/datacube_merger.py | 3 + .../datacube_null_transformation.py | 3 + .../transformations/datacube_reverse.py | 3 + .../transformations/datacube_type_change.py | 3 + 9 files changed, 141 insertions(+), 1 deletion(-) diff --git a/polytope/datacube/backends/FDB_datacube.py b/polytope/datacube/backends/FDB_datacube.py index d25029e3d..7fdff8e8c 100644 --- a/polytope/datacube/backends/FDB_datacube.py +++ b/polytope/datacube/backends/FDB_datacube.py @@ -22,6 +22,7 @@ def __init__(self, config={}, axis_options={}): self.non_complete_axes = [] self.complete_axes = [] self.blocked_axes = [] + self.unwanted_axes = [] self.transformation = None self.fake_axes = [] @@ -46,7 +47,7 @@ def __init__(self, config={}, axis_options={}): val = self._axes[name].type self._check_and_add_axes(options, name, val) - def get(self, requests: IndexTree): + def get_old(self, requests: IndexTree): # NOTE: this will do all the transformation unmappings for all the points # It doesn't use the tree structure of the result to do the unmapping transformations anymore time_changing_path = 0 @@ -109,6 +110,61 @@ def get(self, requests: IndexTree): print("INTERM TIME") print(interm_time) + def remove_unwanted_axes(self, leaf_path): + for axis in self.unwanted_axes: + leaf_path.pop(axis) + return leaf_path + + def get(self, requests: IndexTree, leaf_path={}): + # NOTE: this will do all the transformation unmappings for all the points + # It doesn't use the tree structure of the result to do the unmapping transformations anymore + + # SECOND when request node is root, go to its children + # if requests.is_root(): + if requests.axis.name == "root": + if len(requests.children) == 0: + pass + else: + for c in requests.children: + self.get(c) + + # FIRST if request node has no children, we have a leaf so need to assign fdb values to it + # of course, before assigning results, we need to remap this last key too + else: + if len(requests.children) == 0: + # remap this last key + key_value_path = {requests.axis.name: requests.value} + ax = self._axes[requests.axis.name] + (key_value_path, leaf_path) = ax.unmap_path_key(key_value_path, leaf_path) + leaf_path.update(key_value_path) + leaf_path_copy = deepcopy(leaf_path) + leaf_path_copy = self.remove_unwanted_axes(leaf_path_copy) + # print("FINAL LEAF PATH") + # print(leaf_path) + output_value = self.find_fdb_values(leaf_path_copy) + if not math.isnan(output_value): + requests.result = output_value + + # THIRD TODO: otherwise remap the path for this key and iterate again over children + # NOTE: how do we remap for keys that are inside a mapping for multiple axes? + else: + key_value_path = {requests.axis.name: requests.value} + ax = self._axes[requests.axis.name] + (key_value_path, leaf_path) = ax.unmap_path_key(key_value_path, leaf_path) + leaf_path.update(key_value_path) + for c in requests.children: + self.get(c, leaf_path) + + def find_fdb_values(self, path): + fdb_request_val = path["values"] + path.pop("values") + fdb_request_key = path + fdb_requests = [(fdb_request_key, [(fdb_request_val, fdb_request_val + 1)])] + subxarray = self.fdb.extract(fdb_requests) + subxarray_output_tuple = subxarray[0][0] + output_value = subxarray_output_tuple[0][0][0] + return output_value + def datacube_natural_indexes(self, axis, subarray): indexes = subarray[axis.name] return indexes diff --git a/polytope/datacube/backends/datacube.py b/polytope/datacube/backends/datacube.py index b9bf40d54..a31bb947b 100644 --- a/polytope/datacube/backends/datacube.py +++ b/polytope/datacube/backends/datacube.py @@ -38,6 +38,8 @@ def _create_axes(self, name, values, transformation_type_key, transformation_opt ) for blocked_axis in transformation.blocked_axes(): self.blocked_axes.append(blocked_axis) + for unwanted_axis in transformation.unwanted_axes(): + self.unwanted_axes.append(unwanted_axis) for axis_name in final_axis_names: self.complete_axes.append(axis_name) self.fake_axes.append(axis_name) diff --git a/polytope/datacube/datacube_axis.py b/polytope/datacube/datacube_axis.py index 87181888e..a09798862 100644 --- a/polytope/datacube/datacube_axis.py +++ b/polytope/datacube/datacube_axis.py @@ -134,6 +134,18 @@ def unmap_total_path_to_datacube(path, unmapped_path): print("CYCLIC UNMAP TIME") print(time.time() - time1) return (path, unmapped_path) + + old_unmap_path_key = cls.unmap_path_key + + def unmap_path_key(key_value_path, leaf_path): + value = key_value_path[cls.name] + for transform in cls.transformations: + if isinstance(transform, DatacubeAxisCyclic): + if cls.name == transform.name: + new_val = _remap_val_to_axis_range(value) + key_value_path[cls.name] = new_val + key_value_path, leaf_path = old_unmap_path_key(key_value_path, leaf_path) + return (key_value_path, leaf_path) old_unmap_to_datacube = cls.unmap_to_datacube @@ -188,6 +200,7 @@ def offset(range): cls.unmap_to_datacube = unmap_to_datacube cls.unmap_total_path_to_datacube = unmap_total_path_to_datacube cls.find_indices_between = find_indices_between + cls.unmap_path_key = unmap_path_key return cls @@ -294,6 +307,25 @@ def unmap_total_path_to_datacube(path, unmapped_path): # print("MAPPER TIME ONCE CHOSEN THE MAPPING") # print(time3 - time2) return (path, unmapped_path) + + old_unmap_path_key = cls.unmap_path_key + + def unmap_path_key(key_value_path, leaf_path): + key_value_path, leaf_path = old_unmap_path_key(key_value_path, leaf_path) + value = key_value_path[cls.name] + # print(cls.name) + # print(key_value_path) + for transform in cls.transformations: + if isinstance(transform, DatacubeMapper): + # if cls.name == transform._mapped_axes()[0]: + # unmapping_path[cls.name] = value + if cls.name == transform._mapped_axes()[1]: + first_val = leaf_path[transform._mapped_axes()[0]] + unmapped_idx = transform.unmap(first_val, value) + # leaf_path.pop(transform._mapped_axes()[0]) + key_value_path.pop(cls.name) + key_value_path[transform.old_axis] = unmapped_idx + return (key_value_path, leaf_path) def remap_to_requested(path, unmapped_path): return (path, unmapped_path) @@ -339,6 +371,7 @@ def remap(range): cls.remap_to_requested = remap_to_requested cls.find_indices_between = find_indices_between cls.unmap_total_path_to_datacube = unmap_total_path_to_datacube + cls.unmap_path_key = unmap_path_key return cls @@ -372,6 +405,20 @@ def unmap_total_path_to_datacube(path, unmapped_path): # print("UNMAPPER TIME INSIDE MERGE") # print(time.time() - time1) return (path, unmapped_path) + + old_unmap_path_key = cls.unmap_path_key + + def unmap_path_key(key_value_path, leaf_path): + key_value_path, leaf_path = old_unmap_path_key(key_value_path, leaf_path) + new_key_value_path = {} + value = key_value_path[cls.name] + for transform in cls.transformations: + if isinstance(transform, DatacubeAxisMerger): + if cls.name == transform._first_axis: + (first_val, second_val) = transform.unmerge(value) + new_key_value_path[transform._first_axis] = first_val + new_key_value_path[transform._second_axis] = second_val + return (new_key_value_path, leaf_path) old_unmap_to_datacube = cls.unmap_to_datacube @@ -423,6 +470,7 @@ def remap(range): cls.remap_to_requested = remap_to_requested cls.find_indices_between = find_indices_between cls.unmap_total_path_to_datacube = unmap_total_path_to_datacube + cls.unmap_path_key = unmap_path_key return cls @@ -533,6 +581,18 @@ def unmap_total_path_to_datacube(path, unmapped_path): # print(time.time() - time1) return (path, unmapped_path) + old_unmap_path_key = cls.unmap_path_key + + def unmap_path_key(key_value_path, leaf_path): + key_value_path, leaf_path = old_unmap_path_key(key_value_path, leaf_path) + value = key_value_path[cls.name] + for transform in cls.transformations: + if isinstance(transform, DatacubeAxisTypeChange): + if cls.name == transform.name: + unchanged_val = transform.make_str(value) + key_value_path[cls.name] = unchanged_val + return (key_value_path, leaf_path) + def unmap_to_datacube(path, unmapped_path): for transform in cls.transformations: if isinstance(transform, DatacubeAxisTypeChange): @@ -580,6 +640,7 @@ def remap(range): cls.remap_to_requested = remap_to_requested cls.find_indices_between = find_indices_between cls.unmap_total_path_to_datacube = unmap_total_path_to_datacube + cls.unmap_path_key = unmap_path_key return cls @@ -677,6 +738,9 @@ def offset(self, value): def unmap_total_path_to_datacube(self, path, unmapped_path): return (path, unmapped_path) + def unmap_path_key(self, key_value_path, leaf_path): + return (key_value_path, leaf_path) + def remap_to_requeest(path, unmapped_path): return (path, unmapped_path) diff --git a/polytope/datacube/transformations/datacube_cyclic.py b/polytope/datacube/transformations/datacube_cyclic.py index a48dedf3d..284a2f6ad 100644 --- a/polytope/datacube/transformations/datacube_cyclic.py +++ b/polytope/datacube/transformations/datacube_cyclic.py @@ -20,3 +20,6 @@ def change_val_type(self, axis_name, values): def blocked_axes(self): return [] + + def unwanted_axes(self): + return [] diff --git a/polytope/datacube/transformations/datacube_mappers.py b/polytope/datacube/transformations/datacube_mappers.py index 947920e4e..f9a55a7ef 100644 --- a/polytope/datacube/transformations/datacube_mappers.py +++ b/polytope/datacube/transformations/datacube_mappers.py @@ -30,6 +30,9 @@ def generate_final_transformation(self): def blocked_axes(self): return [] + def unwanted_axes(self): + return [self._final_mapped_axes[0]] + def transformation_axes_final(self): # final_transformation = self.generate_final_transformation() # final_axes = self._final_transformation._mapped_axes diff --git a/polytope/datacube/transformations/datacube_merger.py b/polytope/datacube/transformations/datacube_merger.py index 4326d202b..48250b20e 100644 --- a/polytope/datacube/transformations/datacube_merger.py +++ b/polytope/datacube/transformations/datacube_merger.py @@ -15,6 +15,9 @@ def __init__(self, name, merge_options): def blocked_axes(self): return [self._second_axis] + + def unwanted_axes(self): + return [] def merged_values(self, datacube): # time1 = time.time() diff --git a/polytope/datacube/transformations/datacube_null_transformation.py b/polytope/datacube/transformations/datacube_null_transformation.py index ef026428c..26f9ffaa4 100644 --- a/polytope/datacube/transformations/datacube_null_transformation.py +++ b/polytope/datacube/transformations/datacube_null_transformation.py @@ -17,3 +17,6 @@ def change_val_type(self, axis_name, values): def blocked_axes(self): return [] + + def unwanted_axes(self): + return [] diff --git a/polytope/datacube/transformations/datacube_reverse.py b/polytope/datacube/transformations/datacube_reverse.py index bda03c4a0..f0b1415b5 100644 --- a/polytope/datacube/transformations/datacube_reverse.py +++ b/polytope/datacube/transformations/datacube_reverse.py @@ -17,3 +17,6 @@ def change_val_type(self, axis_name, values): def blocked_axes(self): return [] + + def unwanted_axes(self): + return [] diff --git a/polytope/datacube/transformations/datacube_type_change.py b/polytope/datacube/transformations/datacube_type_change.py index 0f4cedd21..dde8ee346 100644 --- a/polytope/datacube/transformations/datacube_type_change.py +++ b/polytope/datacube/transformations/datacube_type_change.py @@ -34,6 +34,9 @@ def make_str(self, value): def blocked_axes(self): return [] + + def unwanted_axes(self): + return [] class TypeChangeStrToInt(DatacubeAxisTypeChange): From 0deab2efdcd8b5a836f3b3f37c6dbc79b95f85c5 Mon Sep 17 00:00:00 2001 From: Mathilde Leuridan Date: Mon, 30 Oct 2023 09:20:55 +0100 Subject: [PATCH 19/37] time recursive get function --- polytope/datacube/backends/FDB_datacube.py | 3 +++ polytope/polytope.py | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/polytope/datacube/backends/FDB_datacube.py b/polytope/datacube/backends/FDB_datacube.py index 7fdff8e8c..76130bf0a 100644 --- a/polytope/datacube/backends/FDB_datacube.py +++ b/polytope/datacube/backends/FDB_datacube.py @@ -25,6 +25,7 @@ def __init__(self, config={}, axis_options={}): self.unwanted_axes = [] self.transformation = None self.fake_axes = [] + self.time_fdb = 0 partial_request = config # Find values in the level 3 FDB datacube @@ -141,7 +142,9 @@ def get(self, requests: IndexTree, leaf_path={}): leaf_path_copy = self.remove_unwanted_axes(leaf_path_copy) # print("FINAL LEAF PATH") # print(leaf_path) + time0 = time.time() output_value = self.find_fdb_values(leaf_path_copy) + self.time_fdb += time.time() - time0 if not math.isnan(output_value): requests.result = output_value diff --git a/polytope/polytope.py b/polytope/polytope.py index 8dea584d5..4e6a93645 100644 --- a/polytope/polytope.py +++ b/polytope/polytope.py @@ -49,5 +49,10 @@ def retrieve(self, request: Request, method="standard"): time0 = time.time() request_tree = self.engine.extract(self.datacube, request.polytopes()) print(time.time() - time0) + print("TIME INSIDE OF GET") + time1 = time.time() self.datacube.get(request_tree) + print(time.time() - time1) + print("TIME INSIDE FDB") + print(self.datacube.time_fdb) return request_tree From 9a3f3bc5fa10defe1df6c811b0a753fc1878baaf Mon Sep 17 00:00:00 2001 From: Mathilde Leuridan Date: Mon, 30 Oct 2023 14:23:59 +0100 Subject: [PATCH 20/37] add scalability_plot --- performance/fdb_performance.py | 3 +- performance/fdb_scalability_plot.py | 12 ++++++++ polytope/datacube/backends/FDB_datacube.py | 33 +++++++++++++++------- polytope/datacube/backends/xarray.py | 3 ++ polytope/polytope.py | 4 +++ 5 files changed, 44 insertions(+), 11 deletions(-) create mode 100644 performance/fdb_scalability_plot.py diff --git a/performance/fdb_performance.py b/performance/fdb_performance.py index d4fd0ac5a..37b3cb500 100644 --- a/performance/fdb_performance.py +++ b/performance/fdb_performance.py @@ -49,4 +49,5 @@ def test_fdb_datacube(self): time1 = time.time() result = self.API.retrieve(request) print(time.time() - time1) - assert len(result.leaves) == 19226 + print(len(result.leaves)) + # assert len(result.leaves) == 19226 diff --git a/performance/fdb_scalability_plot.py b/performance/fdb_scalability_plot.py new file mode 100644 index 000000000..a5c7bcb4f --- /dev/null +++ b/performance/fdb_scalability_plot.py @@ -0,0 +1,12 @@ +import matplotlib.pyplot as plt + +fdb_time = [7.6377081871032715 - 7.558288812637329, 73.57192325592041 - 72.99611115455627, 733.2706120014191 - 727.7059993743896, 4808.3157522678375 - 4770.814565420151] +num_extracted_points = [1986, 19226, 191543, 1267134] + +# for the 1.3M points, we used 100 latitudes too...., maybe that's why it's not as linear... + +# plt.xscale("log") +plt.plot(num_extracted_points, fdb_time, marker="o") +plt.xlabel("Number of extracted points") +plt.ylabel("Polytope extraction time (in s)") +plt.show() diff --git a/polytope/datacube/backends/FDB_datacube.py b/polytope/datacube/backends/FDB_datacube.py index 76130bf0a..72b6c719c 100644 --- a/polytope/datacube/backends/FDB_datacube.py +++ b/polytope/datacube/backends/FDB_datacube.py @@ -26,6 +26,8 @@ def __init__(self, config={}, axis_options={}): self.transformation = None self.fake_axes = [] self.time_fdb = 0 + self.time_unmap_key = 0 + self.other_time = 0 partial_request = config # Find values in the level 3 FDB datacube @@ -132,29 +134,38 @@ def get(self, requests: IndexTree, leaf_path={}): # FIRST if request node has no children, we have a leaf so need to assign fdb values to it # of course, before assigning results, we need to remap this last key too else: + key_value_path = {requests.axis.name: requests.value} + # ax = self._axes[requests.axis.name] + ax = requests.axis + time1 = time.time() + (key_value_path, leaf_path) = ax.unmap_path_key(key_value_path, leaf_path) + self.time_unmap_key += time.time() - time1 + leaf_path.update(key_value_path) if len(requests.children) == 0: # remap this last key - key_value_path = {requests.axis.name: requests.value} - ax = self._axes[requests.axis.name] - (key_value_path, leaf_path) = ax.unmap_path_key(key_value_path, leaf_path) - leaf_path.update(key_value_path) + # key_value_path = {requests.axis.name: requests.value} + # ax = self._axes[requests.axis.name] + # (key_value_path, leaf_path) = ax.unmap_path_key(key_value_path, leaf_path) + # leaf_path.update(key_value_path) + time2 = time.time() leaf_path_copy = deepcopy(leaf_path) + self.other_time += time.time() - time2 leaf_path_copy = self.remove_unwanted_axes(leaf_path_copy) # print("FINAL LEAF PATH") # print(leaf_path) - time0 = time.time() + # time0 = time.time() output_value = self.find_fdb_values(leaf_path_copy) - self.time_fdb += time.time() - time0 + # self.time_fdb += time.time() - time0 if not math.isnan(output_value): requests.result = output_value # THIRD TODO: otherwise remap the path for this key and iterate again over children # NOTE: how do we remap for keys that are inside a mapping for multiple axes? else: - key_value_path = {requests.axis.name: requests.value} - ax = self._axes[requests.axis.name] - (key_value_path, leaf_path) = ax.unmap_path_key(key_value_path, leaf_path) - leaf_path.update(key_value_path) + # key_value_path = {requests.axis.name: requests.value} + # ax = self._axes[requests.axis.name] + # (key_value_path, leaf_path) = ax.unmap_path_key(key_value_path, leaf_path) + # leaf_path.update(key_value_path) for c in requests.children: self.get(c, leaf_path) @@ -163,7 +174,9 @@ def find_fdb_values(self, path): path.pop("values") fdb_request_key = path fdb_requests = [(fdb_request_key, [(fdb_request_val, fdb_request_val + 1)])] + time0 = time.time() subxarray = self.fdb.extract(fdb_requests) + self.time_fdb += time.time() - time0 subxarray_output_tuple = subxarray[0][0] output_value = subxarray_output_tuple[0][0][0] return output_value diff --git a/polytope/datacube/backends/xarray.py b/polytope/datacube/backends/xarray.py index fdb7f087e..84a4b793b 100644 --- a/polytope/datacube/backends/xarray.py +++ b/polytope/datacube/backends/xarray.py @@ -20,6 +20,9 @@ def __init__(self, dataarray: xr.DataArray, axis_options={}): self.blocked_axes = [] self.transformation = None self.fake_axes = [] + self.time_fdb = 0 + self.time_unmap_key = 0 + self.unwanted_axes = [] for name, values in dataarray.coords.variables.items(): if name in dataarray.dims: options = axis_options.get(name, {}) diff --git a/polytope/polytope.py b/polytope/polytope.py index 4e6a93645..1f20beef3 100644 --- a/polytope/polytope.py +++ b/polytope/polytope.py @@ -55,4 +55,8 @@ def retrieve(self, request: Request, method="standard"): print(time.time() - time1) print("TIME INSIDE FDB") print(self.datacube.time_fdb) + print("TIME UNMAP KEY") + print(self.datacube.time_unmap_key) + print("TIME SPENT REMOVE UNNECESSARY PATH KEYS") + print(self.datacube.other_time) return request_tree From f2aa886e53fcd818c60a29bfe0772df9776550b7 Mon Sep 17 00:00:00 2001 From: Mathilde Leuridan Date: Thu, 2 Nov 2023 11:22:50 +0100 Subject: [PATCH 21/37] retrieve ranges of longitudes from FDB --- polytope/datacube/backends/FDB_datacube.py | 235 +++++++++++++++--- polytope/datacube/datacube_axis.py | 131 ++++++++++ .../transformations/datacube_mappers.py | 6 +- 3 files changed, 335 insertions(+), 37 deletions(-) diff --git a/polytope/datacube/backends/FDB_datacube.py b/polytope/datacube/backends/FDB_datacube.py index 72b6c719c..f95ddd146 100644 --- a/polytope/datacube/backends/FDB_datacube.py +++ b/polytope/datacube/backends/FDB_datacube.py @@ -28,6 +28,10 @@ def __init__(self, config={}, axis_options={}): self.time_fdb = 0 self.time_unmap_key = 0 self.other_time = 0 + self.final_path = {"class" : 0, "date": 0, "domain": 0, "expver": 0, "levtype": 0, "param": 0, + "step" : 0, "stream": 0, "time": 0, "type": 0, "values": 0} + # self.unwanted_path = {"latitude": 0} + self.unwanted_path = {} partial_request = config # Find values in the level 3 FDB datacube @@ -118,12 +122,8 @@ def remove_unwanted_axes(self, leaf_path): leaf_path.pop(axis) return leaf_path - def get(self, requests: IndexTree, leaf_path={}): - # NOTE: this will do all the transformation unmappings for all the points - # It doesn't use the tree structure of the result to do the unmapping transformations anymore - - # SECOND when request node is root, go to its children - # if requests.is_root(): + def older_get(self, requests: IndexTree, leaf_path={}): + # First when request node is root, go to its children if requests.axis.name == "root": if len(requests.children) == 0: pass @@ -131,55 +131,218 @@ def get(self, requests: IndexTree, leaf_path={}): for c in requests.children: self.get(c) - # FIRST if request node has no children, we have a leaf so need to assign fdb values to it - # of course, before assigning results, we need to remap this last key too + # Second if request node has no children, we have a leaf so need to assign fdb values to it else: + # time2 = time.time() key_value_path = {requests.axis.name: requests.value} - # ax = self._axes[requests.axis.name] + # self.other_time += time.time() - time2 ax = requests.axis time1 = time.time() - (key_value_path, leaf_path) = ax.unmap_path_key(key_value_path, leaf_path) + # (key_value_path, leaf_path) = ax.unmap_path_key(key_value_path, leaf_path) + (key_value_path, leaf_path, self.unwanted_path) = ax.n_unmap_path_key(key_value_path, leaf_path, self.unwanted_path) self.time_unmap_key += time.time() - time1 - leaf_path.update(key_value_path) + time2 = time.time() + leaf_path |= key_value_path + self.other_time += time.time() - time2 if len(requests.children) == 0: # remap this last key - # key_value_path = {requests.axis.name: requests.value} - # ax = self._axes[requests.axis.name] - # (key_value_path, leaf_path) = ax.unmap_path_key(key_value_path, leaf_path) - # leaf_path.update(key_value_path) - time2 = time.time() - leaf_path_copy = deepcopy(leaf_path) - self.other_time += time.time() - time2 - leaf_path_copy = self.remove_unwanted_axes(leaf_path_copy) - # print("FINAL LEAF PATH") - # print(leaf_path) - # time0 = time.time() - output_value = self.find_fdb_values(leaf_path_copy) - # self.time_fdb += time.time() - time0 + output_value = self.find_fdb_values(leaf_path) if not math.isnan(output_value): requests.result = output_value - # THIRD TODO: otherwise remap the path for this key and iterate again over children - # NOTE: how do we remap for keys that are inside a mapping for multiple axes? + # THIRD otherwise remap the path for this key and iterate again over children + else: + for c in requests.children: + self.get(c, leaf_path) + + def get(self, requests: IndexTree, leaf_path={}): + # First when request node is root, go to its children + if requests.axis.name == "root": + if len(requests.children) == 0: + pass + else: + for c in requests.children: + self.get(c) + + # Second if request node has no children, we have a leaf so need to assign fdb values to it + else: + # time2 = time.time() + key_value_path = {requests.axis.name: requests.value} + # self.other_time += time.time() - time2 + ax = requests.axis + time1 = time.time() + # (key_value_path, leaf_path) = ax.unmap_path_key(key_value_path, leaf_path) + (key_value_path, leaf_path, self.unwanted_path) = ax.n_unmap_path_key(key_value_path, leaf_path, self.unwanted_path) + self.time_unmap_key += time.time() - time1 + time2 = time.time() + leaf_path |= key_value_path + self.other_time += time.time() - time2 + if len(requests.children[0].children) == 0: + # remap this last key + self.get_last_layer_before_leaf(requests, leaf_path) + + # THIRD otherwise remap the path for this key and iterate again over children else: - # key_value_path = {requests.axis.name: requests.value} - # ax = self._axes[requests.axis.name] - # (key_value_path, leaf_path) = ax.unmap_path_key(key_value_path, leaf_path) - # leaf_path.update(key_value_path) for c in requests.children: self.get(c, leaf_path) + # def get_last_layer_before_leaf(self, requests, leaf_path={}): + # range_length = 1 + # current_start_idx = None + # fdb_range_nodes = [IndexTree.root] * 200 + # for c in requests.children: + # # now c are the leaves of the initial tree + # key_value_path = {c.axis.name: c.value} + # print(key_value_path) + # ax = c.axis + # (key_value_path, leaf_path, self.unwanted_path) = ax.n_unmap_path_key(key_value_path, leaf_path, self.unwanted_path) + # leaf_path |= key_value_path + # last_idx = key_value_path["values"] + # if current_start_idx is None: + # current_start_idx = last_idx + # else: + # if last_idx == current_start_idx + 1: + # range_length += 1 + # fdb_range_nodes[range_length-1] = c + # else: + # # here, we jump to another range, so we first extract the old values from the fdb, and then we reset range_length etc... + # self.give_fdb_val_to_node(leaf_path, range_length, current_start_idx, fdb_range_nodes) + # key_value_path = {c.axis.name: c.value} + # ax = c.axis + # (key_value_path, leaf_path, self.unwanted_path) = ax.n_unmap_path_key(key_value_path, leaf_path, self.unwanted_path) + # leaf_path |= key_value_path + # current_start_idx = key_value_path["values"] + # range_length = 1 + # fdb_range_nodes = [c] * 200 + # # need to extract the last ranges + # self.give_fdb_val_to_node(leaf_path, range_length, current_start_idx, fdb_range_nodes) + + def get_last_layer_before_leaf(self, requests, leaf_path={}): + range_length = 1 + current_start_idx = None + fdb_range_nodes = [IndexTree.root] * 200 + for c in requests.children: + # now c are the leaves of the initial tree + key_value_path = {c.axis.name: c.value} + # print(key_value_path) + ax = c.axis + (key_value_path, leaf_path, self.unwanted_path) = ax.n_unmap_path_key(key_value_path, leaf_path, self.unwanted_path) + leaf_path |= key_value_path + last_idx = key_value_path["values"] + if current_start_idx is None: + current_start_idx = last_idx + fdb_range_nodes[range_length-1] = c + else: + # if last_idx == current_start_idx + 1: + # print((last_idx, current_start_idx+range_length)) + if last_idx == current_start_idx + range_length: + range_length += 1 + fdb_range_nodes[range_length-1] = c + else: + # here, we jump to another range, so we first extract the old values from the fdb, and then we reset range_length etc... + # print(range_length) + # print(current_start_idx) + self.give_fdb_val_to_node(leaf_path, range_length, current_start_idx, fdb_range_nodes) + key_value_path = {c.axis.name: c.value} + ax = c.axis + (key_value_path, leaf_path, self.unwanted_path) = ax.n_unmap_path_key(key_value_path, leaf_path, self.unwanted_path) + leaf_path |= key_value_path + current_start_idx = key_value_path["values"] + range_length = 1 + fdb_range_nodes = [IndexTree.root] * 200 + # need to extract the last ranges + self.give_fdb_val_to_node(leaf_path, range_length, current_start_idx, fdb_range_nodes) + + def give_fdb_val_to_node(self, leaf_path, range_length, current_start_idx, fdb_range_nodes): + output_values = self.new_find_fdb_values(leaf_path, range_length, current_start_idx) + for i in range(len(fdb_range_nodes[:range_length])): + n = fdb_range_nodes[i] + n.result = output_values[i] + + # def get_last_layer_before_leaf(self, requests, leaf_path={}): + # range_lengths = [[1]*200]*200 + # current_start_idx = [[None]*200]*200 + # fdb_range_nodes = [[[IndexTree.root] * 200]*200]*200 + # requests_length = len(requests.children) + # j=0 + # # for c in requests.children: + # for i in range(len(requests.children)): + # c = requests.children[i] + # # now c are the leaves of the initial tree + # key_value_path = {c.axis.name: c.value} + # ax = c.axis + # (key_value_path, leaf_path, self.unwanted_path) = ax.n_unmap_path_key(key_value_path, leaf_path, self.unwanted_path) + # leaf_path |= key_value_path + # last_idx = key_value_path["values"] + # # print(last_idx) + # if current_start_idx[i][j] is None: + # current_start_idx[i][j] = last_idx + # # print("HERE") + # else: + # if last_idx == current_start_idx[i][j] + 1: + # range_lengths[i][j] += 1 + # fdb_range_nodes[i][j][range_lengths[i][j]-1] = c + # else: + # # here, we jump to another range, so we first extract the old values from the fdb, and then we reset range_length etc... + # # self.give_fdb_val_to_node(leaf_path, range_lengths, current_start_idx, fdb_range_nodes, requests_length) + # key_value_path = {c.axis.name: c.value} + # ax = c.axis + # (key_value_path, leaf_path, self.unwanted_path) = ax.n_unmap_path_key(key_value_path, leaf_path, self.unwanted_path) + # j += 1 + # leaf_path |= key_value_path + # current_start_idx[i][j] = key_value_path["values"] + # range_lengths[i][j] = 1 + # fdb_range_nodes[i][j] = [c] * 200 + # # need to extract the last ranges + # self.give_fdb_val_to_node(leaf_path, range_lengths, current_start_idx, fdb_range_nodes, requests_length) + + # def give_fdb_val_to_node(self, leaf_path, range_lengths, current_start_idx, fdb_range_nodes, requests_length): + # # print("RANGE LENGTHS") + # # print(range_lengths) + # # print("CURRENT START IDX") + # # print(current_start_idx) + # # TODO: change this to accommodate for several requests at once + # output_values = self.new_find_fdb_values(leaf_path, range_lengths, current_start_idx, requests_length) + # for j in range(requests_length): + # for i in range(range_lengths[j]): + # n = fdb_range_nodes[j][i] + # n.result = output_values[j][i] # TODO: is this true?? + def find_fdb_values(self, path): - fdb_request_val = path["values"] - path.pop("values") - fdb_request_key = path - fdb_requests = [(fdb_request_key, [(fdb_request_val, fdb_request_val + 1)])] + fdb_request_val = path.pop("values") + fdb_requests = [(path, [(fdb_request_val, fdb_request_val + 1)])] time0 = time.time() subxarray = self.fdb.extract(fdb_requests) self.time_fdb += time.time() - time0 - subxarray_output_tuple = subxarray[0][0] - output_value = subxarray_output_tuple[0][0][0] + output_value = subxarray[0][0][0][0][0] return output_value + + def new_find_fdb_values(self, path, range_length, current_start_idx): + fdb_request_val = path.pop("values") + # print((current_start_idx, current_start_idx + range_length + 1)) + fdb_requests = [(path, [(current_start_idx, current_start_idx + range_length + 1)])] + # fdb_requests = [(path, new_reqs)] + time0 = time.time() + subxarray = self.fdb.extract(fdb_requests) + self.time_fdb += time.time() - time0 + # output_value = subxarray[0][0][0][0][0] + output_values = subxarray[0][0][0][0] + return output_values + + # def new_find_fdb_values(self, path, range_lengths, current_start_idx, requests_length): + # fdb_request_val = path.pop("values") + # fdb_requests = [(path, [])] + # for j in range(requests_length): + # current_request_ranges = (current_start_idx[j], current_start_idx[j] + range_lengths[j]+1) + # # print(current_request_ranges) + # # fdb_requests = [(path, [(current_start_idx, current_start_idx + range_length + 1)])] + # fdb_requests[0][1].append(current_request_ranges) + # time0 = time.time() + # subxarray = self.fdb.extract(fdb_requests) + # self.time_fdb += time.time() - time0 + # # output_value = subxarray[0][0][0][0][0] + # output_values = subxarray[0][0][0] + # return output_values def datacube_natural_indexes(self, axis, subarray): indexes = subarray[axis.name] diff --git a/polytope/datacube/datacube_axis.py b/polytope/datacube/datacube_axis.py index a09798862..197e59a78 100644 --- a/polytope/datacube/datacube_axis.py +++ b/polytope/datacube/datacube_axis.py @@ -146,6 +146,30 @@ def unmap_path_key(key_value_path, leaf_path): key_value_path[cls.name] = new_val key_value_path, leaf_path = old_unmap_path_key(key_value_path, leaf_path) return (key_value_path, leaf_path) + + old_n_unmap_path_key = cls.n_unmap_path_key + + def n_unmap_path_key(key_value_path, leaf_path, unwanted_path): + value = key_value_path[cls.name] + for transform in cls.transformations: + if isinstance(transform, DatacubeAxisCyclic): + if cls.name == transform.name: + new_val = _remap_val_to_axis_range(value) + key_value_path[cls.name] = new_val + key_value_path, leaf_path, unwanted_path = old_n_unmap_path_key(key_value_path, leaf_path, unwanted_path) + return (key_value_path, leaf_path, unwanted_path) + + old_new_unmap_path_key = cls.new_unmap_path_key + + def new_unmap_path_key(key_value_path, unwanted_path, final_path): + value = key_value_path[cls.name] + for transform in cls.transformations: + if isinstance(transform, DatacubeAxisCyclic): + if cls.name == transform.name: + new_val = _remap_val_to_axis_range(value) + key_value_path[cls.name] = new_val + key_value_path, unwanted_path, final_path = old_new_unmap_path_key(key_value_path, unwanted_path, final_path) + return (key_value_path, unwanted_path, final_path) old_unmap_to_datacube = cls.unmap_to_datacube @@ -201,6 +225,8 @@ def offset(range): cls.unmap_total_path_to_datacube = unmap_total_path_to_datacube cls.find_indices_between = find_indices_between cls.unmap_path_key = unmap_path_key + cls.new_unmap_path_key = new_unmap_path_key + cls.n_unmap_path_key = n_unmap_path_key return cls @@ -326,6 +352,46 @@ def unmap_path_key(key_value_path, leaf_path): key_value_path.pop(cls.name) key_value_path[transform.old_axis] = unmapped_idx return (key_value_path, leaf_path) + + old_n_unmap_path_key = cls.n_unmap_path_key + + def n_unmap_path_key(key_value_path, leaf_path, unwanted_path): + key_value_path, leaf_path, unwanted_path = old_n_unmap_path_key(key_value_path, leaf_path, unwanted_path) + value = key_value_path[cls.name] + for transform in cls.transformations: + if isinstance(transform, DatacubeMapper): + if cls.name == transform._mapped_axes()[0]: + unwanted_val = key_value_path[transform._mapped_axes()[0]] + unwanted_path[cls.name] = unwanted_val + # leaf_path.pop(transform._mapped_axes()[0]) + if cls.name == transform._mapped_axes()[1]: + # first_val = leaf_path[transform._mapped_axes()[0]] + first_val = unwanted_path[transform._mapped_axes()[0]] + unmapped_idx = transform.unmap(first_val, value) + leaf_path.pop(transform._mapped_axes()[0], None) + key_value_path.pop(cls.name) + key_value_path[transform.old_axis] = unmapped_idx + return (key_value_path, leaf_path, unwanted_path) + + old_new_unmap_path_key = cls.new_unmap_path_key + + def new_unmap_path_key(key_value_path, unwanted_path, final_path): + # NOTE: think this doesn't work recursively because we update the final path already, which is sort of duplicated from the key-value_path... + key_value_path, unwanted_path, final_path = old_new_unmap_path_key(key_value_path, unwanted_path, final_path) + value = key_value_path[cls.name] + for transform in cls.transformations: + if isinstance(transform, DatacubeMapper): + if cls.name == transform._mapped_axes()[0]: + unwanted_val = key_value_path[transform._mapped_axes()[0]] + unwanted_path[cls.name] = unwanted_val + if cls.name == transform._mapped_axes()[1]: + # first_val = leaf_path[transform._mapped_axes()[0]] + first_val = unwanted_path[transform._mapped_axes()[0]] + unmapped_idx = transform.unmap(first_val, value) + # key_value_path.pop(cls.name) + # key_value_path[transform.old_axis] = unmapped_idx + final_path[transform.old_axis] = unmapped_idx + return (key_value_path, unwanted_path, final_path) def remap_to_requested(path, unmapped_path): return (path, unmapped_path) @@ -372,6 +438,8 @@ def remap(range): cls.find_indices_between = find_indices_between cls.unmap_total_path_to_datacube = unmap_total_path_to_datacube cls.unmap_path_key = unmap_path_key + cls.new_unmap_path_key = new_unmap_path_key + cls.n_unmap_path_key = n_unmap_path_key return cls @@ -419,6 +487,36 @@ def unmap_path_key(key_value_path, leaf_path): new_key_value_path[transform._first_axis] = first_val new_key_value_path[transform._second_axis] = second_val return (new_key_value_path, leaf_path) + + old_n_unmap_path_key = cls.n_unmap_path_key + + def n_unmap_path_key(key_value_path, leaf_path, unwanted_path): + key_value_path, leaf_path, unwanted_path = old_n_unmap_path_key(key_value_path, leaf_path, unwanted_path) + new_key_value_path = {} + value = key_value_path[cls.name] + for transform in cls.transformations: + if isinstance(transform, DatacubeAxisMerger): + if cls.name == transform._first_axis: + (first_val, second_val) = transform.unmerge(value) + new_key_value_path[transform._first_axis] = first_val + new_key_value_path[transform._second_axis] = second_val + return (new_key_value_path, leaf_path, unwanted_path) + + old_new_unmap_path_key = cls.new_unmap_path_key + + def new_unmap_path_key(key_value_path, unwanted_path, final_path): + key_value_path, unwanted_path, final_path = old_new_unmap_path_key(key_value_path, unwanted_path, final_path) + # new_key_value_path = {} + value = key_value_path[cls.name] + for transform in cls.transformations: + if isinstance(transform, DatacubeAxisMerger): + if cls.name == transform._first_axis: + (first_val, second_val) = transform.unmerge(value) + # new_key_value_path[transform._first_axis] = first_val + final_path[transform._first_axis] = first_val + # new_key_value_path[transform._second_axis] = second_val + final_path[transform._second_axis] = second_val + return (key_value_path, unwanted_path, final_path) old_unmap_to_datacube = cls.unmap_to_datacube @@ -471,6 +569,8 @@ def remap(range): cls.find_indices_between = find_indices_between cls.unmap_total_path_to_datacube = unmap_total_path_to_datacube cls.unmap_path_key = unmap_path_key + cls.new_unmap_path_key = new_unmap_path_key + cls.n_unmap_path_key = n_unmap_path_key return cls @@ -592,6 +692,30 @@ def unmap_path_key(key_value_path, leaf_path): unchanged_val = transform.make_str(value) key_value_path[cls.name] = unchanged_val return (key_value_path, leaf_path) + + old_n_unmap_path_key = cls.n_unmap_path_key + + def n_unmap_path_key(key_value_path, leaf_path, unwanted_path): + key_value_path, leaf_path, unwanted_path = old_n_unmap_path_key(key_value_path, leaf_path, unwanted_path) + value = key_value_path[cls.name] + for transform in cls.transformations: + if isinstance(transform, DatacubeAxisTypeChange): + if cls.name == transform.name: + unchanged_val = transform.make_str(value) + key_value_path[cls.name] = unchanged_val + return (key_value_path, leaf_path, unwanted_path) + + old_new_unmap_path_key = cls.new_unmap_path_key + + def new_unmap_path_key(key_value_path, unwanted_path, final_path): + key_value_path, unwanted_path, final_path = old_new_unmap_path_key(key_value_path, unwanted_path, final_path) + value = key_value_path[cls.name] + for transform in cls.transformations: + if isinstance(transform, DatacubeAxisTypeChange): + if cls.name == transform.name: + unchanged_val = transform.make_str(value) + key_value_path[cls.name] = unchanged_val + return (key_value_path, unwanted_path, final_path) def unmap_to_datacube(path, unmapped_path): for transform in cls.transformations: @@ -641,6 +765,7 @@ def remap(range): cls.find_indices_between = find_indices_between cls.unmap_total_path_to_datacube = unmap_total_path_to_datacube cls.unmap_path_key = unmap_path_key + cls.n_unmap_path_key = n_unmap_path_key return cls @@ -740,6 +865,12 @@ def unmap_total_path_to_datacube(self, path, unmapped_path): def unmap_path_key(self, key_value_path, leaf_path): return (key_value_path, leaf_path) + + def n_unmap_path_key(self, key_value_path, leaf_path, unwanted_path): + return (key_value_path, leaf_path, unwanted_path) + + def new_unmap_path_key(self, key_value_path, leaf_path, unwanted_path): + return (key_value_path, leaf_path, unwanted_path) def remap_to_requeest(path, unmapped_path): return (path, unmapped_path) diff --git a/polytope/datacube/transformations/datacube_mappers.py b/polytope/datacube/transformations/datacube_mappers.py index f9a55a7ef..07a53336d 100644 --- a/polytope/datacube/transformations/datacube_mappers.py +++ b/polytope/datacube/transformations/datacube_mappers.py @@ -3066,7 +3066,11 @@ def find_second_axis_idx(self, first_val, second_val): # self._second_axis_spacing[first_val] = (second_axis_spacing, first_idx) # else: # (second_axis_spacing, first_idx) = self._second_axis_spacing[first_val] - second_idx = int(second_val/second_axis_spacing) + tol = 1e-8 + if second_val/second_axis_spacing > int(second_val/second_axis_spacing) + 1 - tol: + second_idx = int(second_val/second_axis_spacing) + 1 + else: + second_idx = int(second_val/second_axis_spacing) return (first_idx, second_idx) def unmap(self, first_val, second_val): From 245d0b4f0c3cb1e0c0916fd54eab54939bb4f2cc Mon Sep 17 00:00:00 2001 From: Mathilde Leuridan Date: Tue, 7 Nov 2023 10:27:46 +0000 Subject: [PATCH 22/37] make latlon requests to the fdb in a single path --- performance/fdb_performance.py | 4 + polytope/datacube/backends/FDB_datacube.py | 150 ++++++++++++++++++--- polytope/datacube/backends/xarray.py | 1 + polytope/datacube/datacube_axis.py | 4 +- polytope/polytope.py | 24 ++-- 5 files changed, 154 insertions(+), 29 deletions(-) diff --git a/performance/fdb_performance.py b/performance/fdb_performance.py index 37b3cb500..48853b231 100644 --- a/performance/fdb_performance.py +++ b/performance/fdb_performance.py @@ -45,9 +45,13 @@ def test_fdb_datacube(self): Select("stream", ["oper"]), Select("type", ["an"]), Box(["latitude", "longitude"], [0, 0], [10, 10]), + # Box(["latitude", "longitude"], [0, 0], [0.2, 0.2]), ) time1 = time.time() result = self.API.retrieve(request) + print("ENTIRE TIME") print(time.time() - time1) + print("FDB TIME") + print(self.fdbdatacube.time_fdb) print(len(result.leaves)) # assert len(result.leaves) == 19226 diff --git a/polytope/datacube/backends/FDB_datacube.py b/polytope/datacube/backends/FDB_datacube.py index f95ddd146..cde83b521 100644 --- a/polytope/datacube/backends/FDB_datacube.py +++ b/polytope/datacube/backends/FDB_datacube.py @@ -155,7 +155,7 @@ def older_get(self, requests: IndexTree, leaf_path={}): for c in requests.children: self.get(c, leaf_path) - def get(self, requests: IndexTree, leaf_path={}): + def lon_get(self, requests: IndexTree, leaf_path={}): # First when request node is root, go to its children if requests.axis.name == "root": if len(requests.children) == 0: @@ -186,6 +186,37 @@ def get(self, requests: IndexTree, leaf_path={}): for c in requests.children: self.get(c, leaf_path) + def get(self, requests: IndexTree, leaf_path={}): + # First when request node is root, go to its children + if requests.axis.name == "root": + if len(requests.children) == 0: + pass + else: + for c in requests.children: + self.get(c) + + # Second if request node has no children, we have a leaf so need to assign fdb values to it + else: + # time2 = time.time() + key_value_path = {requests.axis.name: requests.value} + # self.other_time += time.time() - time2 + ax = requests.axis + time1 = time.time() + # (key_value_path, leaf_path) = ax.unmap_path_key(key_value_path, leaf_path) + (key_value_path, leaf_path, self.unwanted_path) = ax.n_unmap_path_key(key_value_path, leaf_path, self.unwanted_path) + self.time_unmap_key += time.time() - time1 + time2 = time.time() + leaf_path |= key_value_path + self.other_time += time.time() - time2 + if len(requests.children[0].children[0].children) == 0: + # remap this last key + self.handle_last_before_last_layer(requests, leaf_path) + + # THIRD otherwise remap the path for this key and iterate again over children + else: + for c in requests.children: + self.get(c, leaf_path) + # def get_last_layer_before_leaf(self, requests, leaf_path={}): # range_length = 1 # current_start_idx = None @@ -217,41 +248,86 @@ def get(self, requests: IndexTree, leaf_path={}): # # need to extract the last ranges # self.give_fdb_val_to_node(leaf_path, range_length, current_start_idx, fdb_range_nodes) - def get_last_layer_before_leaf(self, requests, leaf_path={}): - range_length = 1 - current_start_idx = None - fdb_range_nodes = [IndexTree.root] * 200 + def handle_last_before_last_layer(self, requests, leaf_path={}): + range_lengths = [[1]*200]*200 + current_start_idxs = [[None]*200]*200 + fdb_node_ranges = [[[IndexTree.root]*200]*200]*200 + lat_length = len(requests.children) + # requests.pprint() + for i in range(len(requests.children)): + lat_child = requests.children[i] + range_length = deepcopy(range_lengths[i]) + current_start_idx = deepcopy(current_start_idxs[i]) + fdb_range_nodes = deepcopy(fdb_node_ranges[i]) + key_value_path = {lat_child.axis.name: lat_child.value} + # print(key_value_path) + ax = lat_child.axis + (key_value_path, leaf_path, self.unwanted_path) = ax.n_unmap_path_key(key_value_path, leaf_path, self.unwanted_path) + leaf_path |= key_value_path + # leaf_path.pop("values", None) + (range_lengths[i], + current_start_idxs[i], + fdb_node_ranges[i]) = self.get_last_last_layer_before_leaf(lat_child, + leaf_path, + range_length, + current_start_idx, + fdb_range_nodes) + # print(current_start_idxs[i]) + # print(lat_length) + # TODO: now call get_last_last_layer_before_layer on lat_child and add the range_lengths etc to the big array + # TODO: fetch data from fdb using big arrays + self.new_give_fdb_val_to_node(leaf_path, range_lengths, current_start_idxs, fdb_node_ranges, lat_length) + + def get_last_last_layer_before_leaf(self, requests, leaf_path, range_l, current_idx, fdb_range_n): + i = 0 + # range_length = range_l[i] + # current_start_idx = current_idx[i] + # fdb_range_nodes = fdb_range_n[i] + # TODO: need to build the range_lengths etc ranges... for c in requests.children: # now c are the leaves of the initial tree key_value_path = {c.axis.name: c.value} # print(key_value_path) + # print(key_value_path) ax = c.axis (key_value_path, leaf_path, self.unwanted_path) = ax.n_unmap_path_key(key_value_path, leaf_path, self.unwanted_path) + # print(key_value_path) + # print(current_idx[i]) leaf_path |= key_value_path + # print("INSIDE SECOND FUNCTION") + # print(leaf_path) last_idx = key_value_path["values"] - if current_start_idx is None: - current_start_idx = last_idx - fdb_range_nodes[range_length-1] = c + if current_idx[i] is None: + current_idx[i] = last_idx + fdb_range_n[i][range_l[i]-1] = c else: # if last_idx == current_start_idx + 1: # print((last_idx, current_start_idx+range_length)) - if last_idx == current_start_idx + range_length: - range_length += 1 - fdb_range_nodes[range_length-1] = c + if last_idx == current_idx[i] + range_l[i]: + range_l[i] += 1 + fdb_range_n[i][range_l[i]-1] = c else: + # print(key_value_path) + # print(last_idx) + # print(current_idx[i] + range_l[i]) # here, we jump to another range, so we first extract the old values from the fdb, and then we reset range_length etc... # print(range_length) # print(current_start_idx) - self.give_fdb_val_to_node(leaf_path, range_length, current_start_idx, fdb_range_nodes) + # self.give_fdb_val_to_node(leaf_path, range_l[i], current_idx[i], fdb_range_n[i]) key_value_path = {c.axis.name: c.value} ax = c.axis (key_value_path, leaf_path, self.unwanted_path) = ax.n_unmap_path_key(key_value_path, leaf_path, self.unwanted_path) leaf_path |= key_value_path + i += 1 current_start_idx = key_value_path["values"] - range_length = 1 - fdb_range_nodes = [IndexTree.root] * 200 + current_idx[i] = current_start_idx + # range_length = 1 + # fdb_range_nodes = [IndexTree.root] * 200 # need to extract the last ranges - self.give_fdb_val_to_node(leaf_path, range_length, current_start_idx, fdb_range_nodes) + # print(range_l) + # print(current_idx) + return (range_l, current_idx, fdb_range_n) + # self.give_fdb_val_to_node(leaf_path, range_length, current_start_idx, fdb_range_nodes) def give_fdb_val_to_node(self, leaf_path, range_length, current_start_idx, fdb_range_nodes): output_values = self.new_find_fdb_values(leaf_path, range_length, current_start_idx) @@ -308,6 +384,22 @@ def give_fdb_val_to_node(self, leaf_path, range_length, current_start_idx, fdb_r # n = fdb_range_nodes[j][i] # n.result = output_values[j][i] # TODO: is this true?? + def new_give_fdb_val_to_node(self, leaf_path, range_lengths, current_start_idx, fdb_range_nodes, lat_length): + # TODO: change this to accommodate for several requests at once + output_values = self.newest_find_fdb_values(leaf_path, range_lengths, current_start_idx, lat_length) + for j in range(lat_length - 1): + for i in range(len(range_lengths[j])): + if current_start_idx[j][i] is not None: + for k in range(range_lengths[j][i]): + # print(output_values) + n = fdb_range_nodes[j][i][k] + # print("NOW") + # print(i) + # print(j) + # print(k) + # print(output_values[j][0][0][i][k]) + n.result = output_values[j][0][0][i][k] # TODO: is this true?? + def find_fdb_values(self, path): fdb_request_val = path.pop("values") fdb_requests = [(path, [(fdb_request_val, fdb_request_val + 1)])] @@ -344,6 +436,34 @@ def new_find_fdb_values(self, path, range_length, current_start_idx): # output_values = subxarray[0][0][0] # return output_values + def newest_find_fdb_values(self, path, range_lengths, current_start_idx, lat_length): + fdb_request_val = path.pop("values") + # fdb_requests = [(path, [])] + # fdb_requests = list(zip([path]*lat_length, [[]]*lat_length)) + fdb_requests = [] + # print(fdb_requests) + for i in range(lat_length): + # fdb_requests[i][1] = [] + interm_request_ranges = [] + for j in range(200): + if current_start_idx[i][j] is not None: + current_request_ranges = (current_start_idx[i][j], current_start_idx[i][j] + range_lengths[i][j]) + # print(current_request_ranges) + # fdb_requests = [(path, [(current_start_idx, current_start_idx + range_length + 1)])] + # print(current_request_ranges) + interm_request_ranges.append(current_request_ranges) + fdb_requests.append(tuple((path, interm_request_ranges))) + print(fdb_requests) + # print(fdb_requests) + # print("TIME EXTRACT") + time0 = time.time() + subxarray = self.fdb.extract(fdb_requests) + self.time_fdb += time.time() - time0 + # output_value = subxarray[0][0][0][0][0] + # print(subxarray) + output_values = subxarray + return output_values + def datacube_natural_indexes(self, axis, subarray): indexes = subarray[axis.name] return indexes diff --git a/polytope/datacube/backends/xarray.py b/polytope/datacube/backends/xarray.py index 84a4b793b..3a2dd83cd 100644 --- a/polytope/datacube/backends/xarray.py +++ b/polytope/datacube/backends/xarray.py @@ -21,6 +21,7 @@ def __init__(self, dataarray: xr.DataArray, axis_options={}): self.transformation = None self.fake_axes = [] self.time_fdb = 0 + self.other_time = 0 self.time_unmap_key = 0 self.unwanted_axes = [] for name, values in dataarray.coords.variables.items(): diff --git a/polytope/datacube/datacube_axis.py b/polytope/datacube/datacube_axis.py index 197e59a78..090e0e326 100644 --- a/polytope/datacube/datacube_axis.py +++ b/polytope/datacube/datacube_axis.py @@ -131,8 +131,8 @@ def unmap_total_path_to_datacube(path, unmapped_path): new_val = _remap_val_to_axis_range(old_val) path[cls.name] = new_val (path, unmapped_path) = old_unmap_total_path_to_datacube(path, unmapped_path) - print("CYCLIC UNMAP TIME") - print(time.time() - time1) + # print("CYCLIC UNMAP TIME") + # print(time.time() - time1) return (path, unmapped_path) old_unmap_path_key = cls.unmap_path_key diff --git a/polytope/polytope.py b/polytope/polytope.py index 1f20beef3..dcd46f407 100644 --- a/polytope/polytope.py +++ b/polytope/polytope.py @@ -45,18 +45,18 @@ def slice(self, polytopes: List[ConvexPolytope]): def retrieve(self, request: Request, method="standard"): """Higher-level API which takes a request and uses it to slice the datacube""" - print("TIME IN POLYTOPE EXTRACT") - time0 = time.time() + # print("TIME IN POLYTOPE EXTRACT") + # time0 = time.time() request_tree = self.engine.extract(self.datacube, request.polytopes()) - print(time.time() - time0) - print("TIME INSIDE OF GET") - time1 = time.time() + # print(time.time() - time0) + # print("TIME INSIDE OF GET") + # time1 = time.time() self.datacube.get(request_tree) - print(time.time() - time1) - print("TIME INSIDE FDB") - print(self.datacube.time_fdb) - print("TIME UNMAP KEY") - print(self.datacube.time_unmap_key) - print("TIME SPENT REMOVE UNNECESSARY PATH KEYS") - print(self.datacube.other_time) + # print(time.time() - time1) + # print("TIME INSIDE FDB") + # print(self.datacube.time_fdb) + # print("TIME UNMAP KEY") + # print(self.datacube.time_unmap_key) + # print("TIME SPENT REMOVE UNNECESSARY PATH KEYS") + # print(self.datacube.other_time) return request_tree From 15de427d32fd363ab917077bd86de7c1ea4c2f93 Mon Sep 17 00:00:00 2001 From: Mathilde Leuridan Date: Wed, 8 Nov 2023 09:07:34 +0000 Subject: [PATCH 23/37] request only 1 request to pyfdb --- performance/fdb_performance_3D.py | 56 ++++++++++++++++++++++ polytope/datacube/backends/FDB_datacube.py | 52 ++++++++++++++------ 2 files changed, 93 insertions(+), 15 deletions(-) create mode 100644 performance/fdb_performance_3D.py diff --git a/performance/fdb_performance_3D.py b/performance/fdb_performance_3D.py new file mode 100644 index 000000000..11f6ed197 --- /dev/null +++ b/performance/fdb_performance_3D.py @@ -0,0 +1,56 @@ +import time + +import pandas as pd +import pytest + +from polytope.datacube.backends.FDB_datacube import FDBDatacube +from polytope.engine.hullslicer import HullSlicer +from polytope.polytope import Polytope, Request +from polytope.shapes import Box, Select, Span + + +class TestSlicingFDBDatacube: + def setup_method(self, method): + # Create a dataarray with 3 labelled axes using different index types + self.options = { + "values": { + "transformation": { + "mapper": {"type": "octahedral", "resolution": 1280, "axes": ["latitude", "longitude"]} + } + }, + "date": {"transformation": {"merge": {"with": "time", "linkers": [" ", "00"]}}}, + "step": {"transformation": {"type_change": "int"}}, + "levelist": {"transformation": {"type_change": "int"}}, + } + self.config = {"class": "od", "expver": "0001", "levtype": "sfc"} + self.fdbdatacube = FDBDatacube(self.config, axis_options=self.options) + # print(self.fdbdatacube) + self.slicer = HullSlicer() + self.API = Polytope(datacube=self.fdbdatacube, engine=self.slicer, axis_options=self.options) + + # Testing different shapes + # @pytest.mark.skip(reason="can't install fdb branch on CI") + def test_fdb_datacube(self): + request = Request( + # Select("step", [0]), + Span("step", 1, 15), + Select("levtype", ["sfc"]), + Select("date", [pd.Timestamp("20231102T000000")]), + Select("domain", ["g"]), + Select("expver", ["0001"]), + Select("param", ["167"]), + Select("class", ["od"]), + Select("stream", ["oper"]), + Select("type", ["fc"]), + Box(["latitude", "longitude"], [0, 0], [3, 5]), + # Span("levelist", 1, 15) + # Box(["latitude", "longitude"], [0, 0], [0.2, 0.2]), + ) + time1 = time.time() + result = self.API.retrieve(request) + print("ENTIRE TIME") + print(time.time() - time1) + print("FDB TIME") + print(self.fdbdatacube.time_fdb) + print(len(result.leaves)) + # assert len(result.leaves) == 19226 diff --git a/polytope/datacube/backends/FDB_datacube.py b/polytope/datacube/backends/FDB_datacube.py index cde83b521..3db63e7dd 100644 --- a/polytope/datacube/backends/FDB_datacube.py +++ b/polytope/datacube/backends/FDB_datacube.py @@ -386,19 +386,33 @@ def give_fdb_val_to_node(self, leaf_path, range_length, current_start_idx, fdb_r def new_give_fdb_val_to_node(self, leaf_path, range_lengths, current_start_idx, fdb_range_nodes, lat_length): # TODO: change this to accommodate for several requests at once - output_values = self.newest_find_fdb_values(leaf_path, range_lengths, current_start_idx, lat_length) - for j in range(lat_length - 1): + (output_values, original_indices) = self.newest_find_fdb_values(leaf_path, range_lengths, current_start_idx, lat_length) + new_fdb_range_nodes = [] + new_range_lengths = [] + for j in range(lat_length): for i in range(len(range_lengths[j])): if current_start_idx[j][i] is not None: - for k in range(range_lengths[j][i]): - # print(output_values) - n = fdb_range_nodes[j][i][k] - # print("NOW") - # print(i) - # print(j) - # print(k) - # print(output_values[j][0][0][i][k]) - n.result = output_values[j][0][0][i][k] # TODO: is this true?? + new_fdb_range_nodes.append(fdb_range_nodes[j][i]) + new_range_lengths.append(range_lengths[j][i]) + sorted_fdb_range_nodes = [new_fdb_range_nodes[i] for i in original_indices] + sorted_range_lengths = [new_range_lengths[i] for i in original_indices] + for i in range(len(sorted_fdb_range_nodes)): + for k in range(sorted_range_lengths[i]): + n = sorted_fdb_range_nodes[i][k] + n.result = output_values[0][0][0][i][k] + # for j in range(lat_length - 1): + # for i in range(len(range_lengths[j])): + # if current_start_idx[j][i] is not None: + # # TODO: need to use original_indices to unmap j and i to the right idxs + # for k in range(range_lengths[j][i]): + # # print(output_values) + # n = fdb_range_nodes[j][i][k] + # # print("NOW") + # # print(i) + # # print(j) + # # print(k) + # # print(output_values[j][0][0][i][k]) + # n.result = output_values[j][0][0][i][k] # TODO: is this true?? def find_fdb_values(self, path): fdb_request_val = path.pop("values") @@ -438,13 +452,15 @@ def new_find_fdb_values(self, path, range_length, current_start_idx): def newest_find_fdb_values(self, path, range_lengths, current_start_idx, lat_length): fdb_request_val = path.pop("values") + # print("NOW INSIDE NEWEST FIND FDB VAL") + # print(path) # fdb_requests = [(path, [])] # fdb_requests = list(zip([path]*lat_length, [[]]*lat_length)) fdb_requests = [] # print(fdb_requests) + interm_request_ranges = [] for i in range(lat_length): # fdb_requests[i][1] = [] - interm_request_ranges = [] for j in range(200): if current_start_idx[i][j] is not None: current_request_ranges = (current_start_idx[i][j], current_start_idx[i][j] + range_lengths[i][j]) @@ -452,17 +468,23 @@ def newest_find_fdb_values(self, path, range_lengths, current_start_idx, lat_len # fdb_requests = [(path, [(current_start_idx, current_start_idx + range_length + 1)])] # print(current_request_ranges) interm_request_ranges.append(current_request_ranges) - fdb_requests.append(tuple((path, interm_request_ranges))) - print(fdb_requests) + request_ranges_with_idx = list(enumerate(interm_request_ranges)) + sorted_list = sorted(request_ranges_with_idx, key=lambda x: x[1][0]) + sorted_request_ranges = [item[1] for item in sorted_list] + original_indices = [item[0] for item in sorted_list] + fdb_requests.append(tuple((path, sorted_request_ranges))) + # print(fdb_requests) # print(fdb_requests) # print("TIME EXTRACT") + # print(fdb_requests) time0 = time.time() subxarray = self.fdb.extract(fdb_requests) self.time_fdb += time.time() - time0 # output_value = subxarray[0][0][0][0][0] # print(subxarray) output_values = subxarray - return output_values + # output_values = [[[[[0]*1000]*1000]*1000]] + return (output_values, original_indices) def datacube_natural_indexes(self, axis, subarray): indexes = subarray[axis.name] From 56d978a0984d001be935ad94fcb15909bf0a21fd Mon Sep 17 00:00:00 2001 From: Mathilde Leuridan Date: Fri, 10 Nov 2023 11:14:20 +0000 Subject: [PATCH 24/37] clean up --- performance/fdb_performance.py | 8 -------- performance/fdb_performance_3D.py | 6 ------ performance/fdb_scalability_plot.py | 4 ++-- 3 files changed, 2 insertions(+), 16 deletions(-) diff --git a/performance/fdb_performance.py b/performance/fdb_performance.py index 48853b231..01d57b7c6 100644 --- a/performance/fdb_performance.py +++ b/performance/fdb_performance.py @@ -1,7 +1,6 @@ import time import pandas as pd -import pytest from polytope.datacube.backends.FDB_datacube import FDBDatacube from polytope.engine.hullslicer import HullSlicer @@ -20,11 +19,6 @@ def setup_method(self, method): }, "date": {"transformation": {"merge": {"with": "time", "linkers": [" ", "00"]}}}, "step": {"transformation": {"type_change": "int"}}, - # "latitude": {"transformation": {"null": []}}, - # "longitude": {"transformation": {"null": []}}, - # "class": {"transformation": {"null": []}}, - # "param": {"transformation": {"null": []}}, - # "stream": {"transformation": {"null": []}}, } self.config = {"class": "od", "expver": "0001", "levtype": "sfc", "step": 0} self.fdbdatacube = FDBDatacube(self.config, axis_options=self.options) @@ -45,7 +39,6 @@ def test_fdb_datacube(self): Select("stream", ["oper"]), Select("type", ["an"]), Box(["latitude", "longitude"], [0, 0], [10, 10]), - # Box(["latitude", "longitude"], [0, 0], [0.2, 0.2]), ) time1 = time.time() result = self.API.retrieve(request) @@ -54,4 +47,3 @@ def test_fdb_datacube(self): print("FDB TIME") print(self.fdbdatacube.time_fdb) print(len(result.leaves)) - # assert len(result.leaves) == 19226 diff --git a/performance/fdb_performance_3D.py b/performance/fdb_performance_3D.py index 11f6ed197..b2f4a2bbe 100644 --- a/performance/fdb_performance_3D.py +++ b/performance/fdb_performance_3D.py @@ -1,7 +1,6 @@ import time import pandas as pd -import pytest from polytope.datacube.backends.FDB_datacube import FDBDatacube from polytope.engine.hullslicer import HullSlicer @@ -24,7 +23,6 @@ def setup_method(self, method): } self.config = {"class": "od", "expver": "0001", "levtype": "sfc"} self.fdbdatacube = FDBDatacube(self.config, axis_options=self.options) - # print(self.fdbdatacube) self.slicer = HullSlicer() self.API = Polytope(datacube=self.fdbdatacube, engine=self.slicer, axis_options=self.options) @@ -32,7 +30,6 @@ def setup_method(self, method): # @pytest.mark.skip(reason="can't install fdb branch on CI") def test_fdb_datacube(self): request = Request( - # Select("step", [0]), Span("step", 1, 15), Select("levtype", ["sfc"]), Select("date", [pd.Timestamp("20231102T000000")]), @@ -43,8 +40,6 @@ def test_fdb_datacube(self): Select("stream", ["oper"]), Select("type", ["fc"]), Box(["latitude", "longitude"], [0, 0], [3, 5]), - # Span("levelist", 1, 15) - # Box(["latitude", "longitude"], [0, 0], [0.2, 0.2]), ) time1 = time.time() result = self.API.retrieve(request) @@ -53,4 +48,3 @@ def test_fdb_datacube(self): print("FDB TIME") print(self.fdbdatacube.time_fdb) print(len(result.leaves)) - # assert len(result.leaves) == 19226 diff --git a/performance/fdb_scalability_plot.py b/performance/fdb_scalability_plot.py index a5c7bcb4f..13f2bd9b7 100644 --- a/performance/fdb_scalability_plot.py +++ b/performance/fdb_scalability_plot.py @@ -1,11 +1,11 @@ import matplotlib.pyplot as plt -fdb_time = [7.6377081871032715 - 7.558288812637329, 73.57192325592041 - 72.99611115455627, 733.2706120014191 - 727.7059993743896, 4808.3157522678375 - 4770.814565420151] +fdb_time = [7.6377081871032715 - 7.558288812637329, 73.57192325592041 - 72.99611115455627, + 733.2706120014191 - 727.7059993743896, 4808.3157522678375 - 4770.814565420151] num_extracted_points = [1986, 19226, 191543, 1267134] # for the 1.3M points, we used 100 latitudes too...., maybe that's why it's not as linear... -# plt.xscale("log") plt.plot(num_extracted_points, fdb_time, marker="o") plt.xlabel("Number of extracted points") plt.ylabel("Polytope extraction time (in s)") From 7a7a2ace2fbece5dffea6ba944be6157cb057688 Mon Sep 17 00:00:00 2001 From: Mathilde Leuridan Date: Fri, 10 Nov 2023 12:02:52 +0000 Subject: [PATCH 25/37] clean up --- performance/fdb_performance.py | 2 - performance/fdb_performance_3D.py | 2 - polytope/datacube/backends/FDB_datacube.py | 361 +----------------- polytope/datacube/backends/datacube.py | 1 - polytope/datacube/backends/xarray.py | 3 - polytope/datacube/datacube_axis.py | 195 +--------- .../transformations/datacube_cyclic.py | 2 +- .../transformations/datacube_mappers.py | 119 +----- .../transformations/datacube_merger.py | 14 +- .../datacube_null_transformation.py | 2 +- .../transformations/datacube_reverse.py | 2 +- .../transformations/datacube_type_change.py | 5 +- polytope/engine/hullslicer.py | 21 +- polytope/polytope.py | 13 - requirements_example.txt | 1 + tests/data/era5-levels-members.grib | 3 + tests/data/foo.grib | 3 + tests/data/healpix.grib | 3 + 18 files changed, 38 insertions(+), 714 deletions(-) create mode 100644 requirements_example.txt create mode 100644 tests/data/era5-levels-members.grib create mode 100644 tests/data/foo.grib create mode 100644 tests/data/healpix.grib diff --git a/performance/fdb_performance.py b/performance/fdb_performance.py index 01d57b7c6..4ee8715be 100644 --- a/performance/fdb_performance.py +++ b/performance/fdb_performance.py @@ -44,6 +44,4 @@ def test_fdb_datacube(self): result = self.API.retrieve(request) print("ENTIRE TIME") print(time.time() - time1) - print("FDB TIME") - print(self.fdbdatacube.time_fdb) print(len(result.leaves)) diff --git a/performance/fdb_performance_3D.py b/performance/fdb_performance_3D.py index b2f4a2bbe..2cfec94cf 100644 --- a/performance/fdb_performance_3D.py +++ b/performance/fdb_performance_3D.py @@ -45,6 +45,4 @@ def test_fdb_datacube(self): result = self.API.retrieve(request) print("ENTIRE TIME") print(time.time() - time1) - print("FDB TIME") - print(self.fdbdatacube.time_fdb) print(len(result.leaves)) diff --git a/polytope/datacube/backends/FDB_datacube.py b/polytope/datacube/backends/FDB_datacube.py index 3db63e7dd..7326d6e4d 100644 --- a/polytope/datacube/backends/FDB_datacube.py +++ b/polytope/datacube/backends/FDB_datacube.py @@ -1,5 +1,3 @@ -import math -import time from copy import deepcopy import pyfdb @@ -25,12 +23,8 @@ def __init__(self, config={}, axis_options={}): self.unwanted_axes = [] self.transformation = None self.fake_axes = [] - self.time_fdb = 0 - self.time_unmap_key = 0 - self.other_time = 0 self.final_path = {"class" : 0, "date": 0, "domain": 0, "expver": 0, "levtype": 0, "param": 0, "step" : 0, "stream": 0, "time": 0, "type": 0, "values": 0} - # self.unwanted_path = {"latitude": 0} self.unwanted_path = {} partial_request = config @@ -54,138 +48,11 @@ def __init__(self, config={}, axis_options={}): val = self._axes[name].type self._check_and_add_axes(options, name, val) - def get_old(self, requests: IndexTree): - # NOTE: this will do all the transformation unmappings for all the points - # It doesn't use the tree structure of the result to do the unmapping transformations anymore - time_changing_path = 0 - accumulated_fdb_time = 0 - time_change_path = 0 - time_is_nan = 0 - interm_time = 0 - time0 = time.time() - for r in requests.leaves_with_ancestors: - time5 = time.time() - # NOTE: Accumulated time in flatten is 0.14s... could be better? - path = r.flatten_with_ancestors() - # path = r.flatten() - time_change_path += time.time() - time5 - # path = self.remap_path(path) - if len(path.items()) == self.axis_counter: - # first, find the grid mapper transform - - unmapped_path = {} - path_copy = deepcopy(path) - time2 = time.time() - for key in path_copy: - axis = self._axes[key] - (path, unmapped_path) = axis.unmap_total_path_to_datacube(path, unmapped_path) - time_changing_path += time.time() - time2 - time8 = time.time() - path = self.fit_path(path) - # merge path and unmapped path into a single path - path.update(unmapped_path) - - # fit request into something for pyfdb - fdb_request_val = path["values"] - path.pop("values") - fdb_request_key = path - - fdb_requests = [(fdb_request_key, [(fdb_request_val, fdb_request_val + 1)])] - interm_time += time.time() - time8 - # need to request data from the fdb - time1 = time.time() - subxarray = self.fdb.extract(fdb_requests) - accumulated_fdb_time += time.time() - time1 - subxarray_output_tuple = subxarray[0][0] - output_value = subxarray_output_tuple[0][0][0] - time7 = time.time() - if not math.isnan(output_value): - r.result = output_value - time_is_nan += time.time() - time7 - else: - r.remove_branch() - print("FDB TIME") - print(accumulated_fdb_time) - print("GET TIME") - print(time.time() - time0) - print("TIME FLATTEN PATH AND CHANGE PATH") - print(time_change_path) - print("TIME CHANGING PATH") - print(time_changing_path) - print("TIME IS NAN") - print(time_is_nan) - print("INTERM TIME") - print(interm_time) - def remove_unwanted_axes(self, leaf_path): for axis in self.unwanted_axes: leaf_path.pop(axis) return leaf_path - def older_get(self, requests: IndexTree, leaf_path={}): - # First when request node is root, go to its children - if requests.axis.name == "root": - if len(requests.children) == 0: - pass - else: - for c in requests.children: - self.get(c) - - # Second if request node has no children, we have a leaf so need to assign fdb values to it - else: - # time2 = time.time() - key_value_path = {requests.axis.name: requests.value} - # self.other_time += time.time() - time2 - ax = requests.axis - time1 = time.time() - # (key_value_path, leaf_path) = ax.unmap_path_key(key_value_path, leaf_path) - (key_value_path, leaf_path, self.unwanted_path) = ax.n_unmap_path_key(key_value_path, leaf_path, self.unwanted_path) - self.time_unmap_key += time.time() - time1 - time2 = time.time() - leaf_path |= key_value_path - self.other_time += time.time() - time2 - if len(requests.children) == 0: - # remap this last key - output_value = self.find_fdb_values(leaf_path) - if not math.isnan(output_value): - requests.result = output_value - - # THIRD otherwise remap the path for this key and iterate again over children - else: - for c in requests.children: - self.get(c, leaf_path) - - def lon_get(self, requests: IndexTree, leaf_path={}): - # First when request node is root, go to its children - if requests.axis.name == "root": - if len(requests.children) == 0: - pass - else: - for c in requests.children: - self.get(c) - - # Second if request node has no children, we have a leaf so need to assign fdb values to it - else: - # time2 = time.time() - key_value_path = {requests.axis.name: requests.value} - # self.other_time += time.time() - time2 - ax = requests.axis - time1 = time.time() - # (key_value_path, leaf_path) = ax.unmap_path_key(key_value_path, leaf_path) - (key_value_path, leaf_path, self.unwanted_path) = ax.n_unmap_path_key(key_value_path, leaf_path, self.unwanted_path) - self.time_unmap_key += time.time() - time1 - time2 = time.time() - leaf_path |= key_value_path - self.other_time += time.time() - time2 - if len(requests.children[0].children) == 0: - # remap this last key - self.get_last_layer_before_leaf(requests, leaf_path) - - # THIRD otherwise remap the path for this key and iterate again over children - else: - for c in requests.children: - self.get(c, leaf_path) - def get(self, requests: IndexTree, leaf_path={}): # First when request node is root, go to its children if requests.axis.name == "root": @@ -197,17 +64,11 @@ def get(self, requests: IndexTree, leaf_path={}): # Second if request node has no children, we have a leaf so need to assign fdb values to it else: - # time2 = time.time() key_value_path = {requests.axis.name: requests.value} - # self.other_time += time.time() - time2 ax = requests.axis - time1 = time.time() - # (key_value_path, leaf_path) = ax.unmap_path_key(key_value_path, leaf_path) - (key_value_path, leaf_path, self.unwanted_path) = ax.n_unmap_path_key(key_value_path, leaf_path, self.unwanted_path) - self.time_unmap_key += time.time() - time1 - time2 = time.time() + (key_value_path, leaf_path, self.unwanted_path) = ax.n_unmap_path_key(key_value_path, leaf_path, + self.unwanted_path) leaf_path |= key_value_path - self.other_time += time.time() - time2 if len(requests.children[0].children[0].children) == 0: # remap this last key self.handle_last_before_last_layer(requests, leaf_path) @@ -217,176 +78,58 @@ def get(self, requests: IndexTree, leaf_path={}): for c in requests.children: self.get(c, leaf_path) - # def get_last_layer_before_leaf(self, requests, leaf_path={}): - # range_length = 1 - # current_start_idx = None - # fdb_range_nodes = [IndexTree.root] * 200 - # for c in requests.children: - # # now c are the leaves of the initial tree - # key_value_path = {c.axis.name: c.value} - # print(key_value_path) - # ax = c.axis - # (key_value_path, leaf_path, self.unwanted_path) = ax.n_unmap_path_key(key_value_path, leaf_path, self.unwanted_path) - # leaf_path |= key_value_path - # last_idx = key_value_path["values"] - # if current_start_idx is None: - # current_start_idx = last_idx - # else: - # if last_idx == current_start_idx + 1: - # range_length += 1 - # fdb_range_nodes[range_length-1] = c - # else: - # # here, we jump to another range, so we first extract the old values from the fdb, and then we reset range_length etc... - # self.give_fdb_val_to_node(leaf_path, range_length, current_start_idx, fdb_range_nodes) - # key_value_path = {c.axis.name: c.value} - # ax = c.axis - # (key_value_path, leaf_path, self.unwanted_path) = ax.n_unmap_path_key(key_value_path, leaf_path, self.unwanted_path) - # leaf_path |= key_value_path - # current_start_idx = key_value_path["values"] - # range_length = 1 - # fdb_range_nodes = [c] * 200 - # # need to extract the last ranges - # self.give_fdb_val_to_node(leaf_path, range_length, current_start_idx, fdb_range_nodes) - def handle_last_before_last_layer(self, requests, leaf_path={}): range_lengths = [[1]*200]*200 current_start_idxs = [[None]*200]*200 fdb_node_ranges = [[[IndexTree.root]*200]*200]*200 lat_length = len(requests.children) - # requests.pprint() for i in range(len(requests.children)): lat_child = requests.children[i] range_length = deepcopy(range_lengths[i]) current_start_idx = deepcopy(current_start_idxs[i]) fdb_range_nodes = deepcopy(fdb_node_ranges[i]) key_value_path = {lat_child.axis.name: lat_child.value} - # print(key_value_path) ax = lat_child.axis - (key_value_path, leaf_path, self.unwanted_path) = ax.n_unmap_path_key(key_value_path, leaf_path, self.unwanted_path) + (key_value_path, leaf_path, self.unwanted_path) = ax.n_unmap_path_key(key_value_path, leaf_path, + self.unwanted_path) leaf_path |= key_value_path - # leaf_path.pop("values", None) (range_lengths[i], current_start_idxs[i], - fdb_node_ranges[i]) = self.get_last_last_layer_before_leaf(lat_child, - leaf_path, - range_length, - current_start_idx, - fdb_range_nodes) - # print(current_start_idxs[i]) - # print(lat_length) - # TODO: now call get_last_last_layer_before_layer on lat_child and add the range_lengths etc to the big array - # TODO: fetch data from fdb using big arrays - self.new_give_fdb_val_to_node(leaf_path, range_lengths, current_start_idxs, fdb_node_ranges, lat_length) + fdb_node_ranges[i]) = self.get_last_layer_before_leaf(lat_child, leaf_path, range_length, + current_start_idx, fdb_range_nodes) + self.give_fdb_val_to_node(leaf_path, range_lengths, current_start_idxs, fdb_node_ranges, lat_length) - def get_last_last_layer_before_leaf(self, requests, leaf_path, range_l, current_idx, fdb_range_n): + def get_last_layer_before_leaf(self, requests, leaf_path, range_l, current_idx, fdb_range_n): i = 0 - # range_length = range_l[i] - # current_start_idx = current_idx[i] - # fdb_range_nodes = fdb_range_n[i] - # TODO: need to build the range_lengths etc ranges... for c in requests.children: # now c are the leaves of the initial tree key_value_path = {c.axis.name: c.value} - # print(key_value_path) - # print(key_value_path) ax = c.axis - (key_value_path, leaf_path, self.unwanted_path) = ax.n_unmap_path_key(key_value_path, leaf_path, self.unwanted_path) - # print(key_value_path) - # print(current_idx[i]) + (key_value_path, leaf_path, self.unwanted_path) = ax.n_unmap_path_key(key_value_path, leaf_path, + self.unwanted_path) leaf_path |= key_value_path - # print("INSIDE SECOND FUNCTION") - # print(leaf_path) last_idx = key_value_path["values"] if current_idx[i] is None: current_idx[i] = last_idx fdb_range_n[i][range_l[i]-1] = c else: - # if last_idx == current_start_idx + 1: - # print((last_idx, current_start_idx+range_length)) if last_idx == current_idx[i] + range_l[i]: range_l[i] += 1 fdb_range_n[i][range_l[i]-1] = c else: - # print(key_value_path) - # print(last_idx) - # print(current_idx[i] + range_l[i]) - # here, we jump to another range, so we first extract the old values from the fdb, and then we reset range_length etc... - # print(range_length) - # print(current_start_idx) - # self.give_fdb_val_to_node(leaf_path, range_l[i], current_idx[i], fdb_range_n[i]) key_value_path = {c.axis.name: c.value} ax = c.axis - (key_value_path, leaf_path, self.unwanted_path) = ax.n_unmap_path_key(key_value_path, leaf_path, self.unwanted_path) + (key_value_path, leaf_path, self.unwanted_path) = ax.n_unmap_path_key(key_value_path, leaf_path, + self.unwanted_path) leaf_path |= key_value_path i += 1 current_start_idx = key_value_path["values"] current_idx[i] = current_start_idx - # range_length = 1 - # fdb_range_nodes = [IndexTree.root] * 200 - # need to extract the last ranges - # print(range_l) - # print(current_idx) return (range_l, current_idx, fdb_range_n) - # self.give_fdb_val_to_node(leaf_path, range_length, current_start_idx, fdb_range_nodes) - - def give_fdb_val_to_node(self, leaf_path, range_length, current_start_idx, fdb_range_nodes): - output_values = self.new_find_fdb_values(leaf_path, range_length, current_start_idx) - for i in range(len(fdb_range_nodes[:range_length])): - n = fdb_range_nodes[i] - n.result = output_values[i] - # def get_last_layer_before_leaf(self, requests, leaf_path={}): - # range_lengths = [[1]*200]*200 - # current_start_idx = [[None]*200]*200 - # fdb_range_nodes = [[[IndexTree.root] * 200]*200]*200 - # requests_length = len(requests.children) - # j=0 - # # for c in requests.children: - # for i in range(len(requests.children)): - # c = requests.children[i] - # # now c are the leaves of the initial tree - # key_value_path = {c.axis.name: c.value} - # ax = c.axis - # (key_value_path, leaf_path, self.unwanted_path) = ax.n_unmap_path_key(key_value_path, leaf_path, self.unwanted_path) - # leaf_path |= key_value_path - # last_idx = key_value_path["values"] - # # print(last_idx) - # if current_start_idx[i][j] is None: - # current_start_idx[i][j] = last_idx - # # print("HERE") - # else: - # if last_idx == current_start_idx[i][j] + 1: - # range_lengths[i][j] += 1 - # fdb_range_nodes[i][j][range_lengths[i][j]-1] = c - # else: - # # here, we jump to another range, so we first extract the old values from the fdb, and then we reset range_length etc... - # # self.give_fdb_val_to_node(leaf_path, range_lengths, current_start_idx, fdb_range_nodes, requests_length) - # key_value_path = {c.axis.name: c.value} - # ax = c.axis - # (key_value_path, leaf_path, self.unwanted_path) = ax.n_unmap_path_key(key_value_path, leaf_path, self.unwanted_path) - # j += 1 - # leaf_path |= key_value_path - # current_start_idx[i][j] = key_value_path["values"] - # range_lengths[i][j] = 1 - # fdb_range_nodes[i][j] = [c] * 200 - # # need to extract the last ranges - # self.give_fdb_val_to_node(leaf_path, range_lengths, current_start_idx, fdb_range_nodes, requests_length) - - # def give_fdb_val_to_node(self, leaf_path, range_lengths, current_start_idx, fdb_range_nodes, requests_length): - # # print("RANGE LENGTHS") - # # print(range_lengths) - # # print("CURRENT START IDX") - # # print(current_start_idx) - # # TODO: change this to accommodate for several requests at once - # output_values = self.new_find_fdb_values(leaf_path, range_lengths, current_start_idx, requests_length) - # for j in range(requests_length): - # for i in range(range_lengths[j]): - # n = fdb_range_nodes[j][i] - # n.result = output_values[j][i] # TODO: is this true?? - - def new_give_fdb_val_to_node(self, leaf_path, range_lengths, current_start_idx, fdb_range_nodes, lat_length): - # TODO: change this to accommodate for several requests at once - (output_values, original_indices) = self.newest_find_fdb_values(leaf_path, range_lengths, current_start_idx, lat_length) + def give_fdb_val_to_node(self, leaf_path, range_lengths, current_start_idx, fdb_range_nodes, lat_length): + (output_values, original_indices) = self.find_fdb_values(leaf_path, range_lengths, current_start_idx, + lat_length) new_fdb_range_nodes = [] new_range_lengths = [] for j in range(lat_length): @@ -400,90 +143,23 @@ def new_give_fdb_val_to_node(self, leaf_path, range_lengths, current_start_idx, for k in range(sorted_range_lengths[i]): n = sorted_fdb_range_nodes[i][k] n.result = output_values[0][0][0][i][k] - # for j in range(lat_length - 1): - # for i in range(len(range_lengths[j])): - # if current_start_idx[j][i] is not None: - # # TODO: need to use original_indices to unmap j and i to the right idxs - # for k in range(range_lengths[j][i]): - # # print(output_values) - # n = fdb_range_nodes[j][i][k] - # # print("NOW") - # # print(i) - # # print(j) - # # print(k) - # # print(output_values[j][0][0][i][k]) - # n.result = output_values[j][0][0][i][k] # TODO: is this true?? - - def find_fdb_values(self, path): - fdb_request_val = path.pop("values") - fdb_requests = [(path, [(fdb_request_val, fdb_request_val + 1)])] - time0 = time.time() - subxarray = self.fdb.extract(fdb_requests) - self.time_fdb += time.time() - time0 - output_value = subxarray[0][0][0][0][0] - return output_value - - def new_find_fdb_values(self, path, range_length, current_start_idx): - fdb_request_val = path.pop("values") - # print((current_start_idx, current_start_idx + range_length + 1)) - fdb_requests = [(path, [(current_start_idx, current_start_idx + range_length + 1)])] - # fdb_requests = [(path, new_reqs)] - time0 = time.time() - subxarray = self.fdb.extract(fdb_requests) - self.time_fdb += time.time() - time0 - # output_value = subxarray[0][0][0][0][0] - output_values = subxarray[0][0][0][0] - return output_values - - # def new_find_fdb_values(self, path, range_lengths, current_start_idx, requests_length): - # fdb_request_val = path.pop("values") - # fdb_requests = [(path, [])] - # for j in range(requests_length): - # current_request_ranges = (current_start_idx[j], current_start_idx[j] + range_lengths[j]+1) - # # print(current_request_ranges) - # # fdb_requests = [(path, [(current_start_idx, current_start_idx + range_length + 1)])] - # fdb_requests[0][1].append(current_request_ranges) - # time0 = time.time() - # subxarray = self.fdb.extract(fdb_requests) - # self.time_fdb += time.time() - time0 - # # output_value = subxarray[0][0][0][0][0] - # output_values = subxarray[0][0][0] - # return output_values - def newest_find_fdb_values(self, path, range_lengths, current_start_idx, lat_length): - fdb_request_val = path.pop("values") - # print("NOW INSIDE NEWEST FIND FDB VAL") - # print(path) - # fdb_requests = [(path, [])] - # fdb_requests = list(zip([path]*lat_length, [[]]*lat_length)) + def find_fdb_values(self, path, range_lengths, current_start_idx, lat_length): + path.pop("values") fdb_requests = [] - # print(fdb_requests) interm_request_ranges = [] for i in range(lat_length): - # fdb_requests[i][1] = [] for j in range(200): if current_start_idx[i][j] is not None: current_request_ranges = (current_start_idx[i][j], current_start_idx[i][j] + range_lengths[i][j]) - # print(current_request_ranges) - # fdb_requests = [(path, [(current_start_idx, current_start_idx + range_length + 1)])] - # print(current_request_ranges) interm_request_ranges.append(current_request_ranges) request_ranges_with_idx = list(enumerate(interm_request_ranges)) sorted_list = sorted(request_ranges_with_idx, key=lambda x: x[1][0]) sorted_request_ranges = [item[1] for item in sorted_list] original_indices = [item[0] for item in sorted_list] fdb_requests.append(tuple((path, sorted_request_ranges))) - # print(fdb_requests) - # print(fdb_requests) - # print("TIME EXTRACT") - # print(fdb_requests) - time0 = time.time() subxarray = self.fdb.extract(fdb_requests) - self.time_fdb += time.time() - time0 - # output_value = subxarray[0][0][0][0][0] - # print(subxarray) output_values = subxarray - # output_values = [[[[[0]*1000]*1000]*1000]] return (output_values, original_indices) def datacube_natural_indexes(self, axis, subarray): @@ -494,7 +170,4 @@ def select(self, path, unmapped_path): return self.dataarray def ax_vals(self, name): - # for _name, values in self.dataarray.items(): - # if _name == name: - # return values return self.dataarray.get(name, None) diff --git a/polytope/datacube/backends/datacube.py b/polytope/datacube/backends/datacube.py index a31bb947b..10b5a6613 100644 --- a/polytope/datacube/backends/datacube.py +++ b/polytope/datacube/backends/datacube.py @@ -2,7 +2,6 @@ import math from abc import ABC, abstractmethod from typing import Any -import time import xarray as xr diff --git a/polytope/datacube/backends/xarray.py b/polytope/datacube/backends/xarray.py index 3a2dd83cd..0d244764e 100644 --- a/polytope/datacube/backends/xarray.py +++ b/polytope/datacube/backends/xarray.py @@ -20,9 +20,6 @@ def __init__(self, dataarray: xr.DataArray, axis_options={}): self.blocked_axes = [] self.transformation = None self.fake_axes = [] - self.time_fdb = 0 - self.other_time = 0 - self.time_unmap_key = 0 self.unwanted_axes = [] for name, values in dataarray.coords.variables.items(): if name in dataarray.dims: diff --git a/polytope/datacube/datacube_axis.py b/polytope/datacube/datacube_axis.py index 090e0e326..57a971bcb 100644 --- a/polytope/datacube/datacube_axis.py +++ b/polytope/datacube/datacube_axis.py @@ -1,13 +1,13 @@ +import bisect from abc import ABC, abstractmethod from copy import deepcopy from typing import Any, List -import time -import bisect -from ..utility.list_tools import bisect_left_cmp, bisect_right_cmp import numpy as np import pandas as pd +from ..utility.list_tools import bisect_left_cmp, bisect_right_cmp + def cyclic(cls): if cls.is_cyclic: @@ -121,7 +121,6 @@ def find_indexes(path, datacube): old_unmap_total_path_to_datacube = cls.unmap_total_path_to_datacube def unmap_total_path_to_datacube(path, unmapped_path): - time1 = time.time() for transform in cls.transformations: if isinstance(transform, DatacubeAxisCyclic): transformation = transform @@ -131,22 +130,8 @@ def unmap_total_path_to_datacube(path, unmapped_path): new_val = _remap_val_to_axis_range(old_val) path[cls.name] = new_val (path, unmapped_path) = old_unmap_total_path_to_datacube(path, unmapped_path) - # print("CYCLIC UNMAP TIME") - # print(time.time() - time1) return (path, unmapped_path) - - old_unmap_path_key = cls.unmap_path_key - def unmap_path_key(key_value_path, leaf_path): - value = key_value_path[cls.name] - for transform in cls.transformations: - if isinstance(transform, DatacubeAxisCyclic): - if cls.name == transform.name: - new_val = _remap_val_to_axis_range(value) - key_value_path[cls.name] = new_val - key_value_path, leaf_path = old_unmap_path_key(key_value_path, leaf_path) - return (key_value_path, leaf_path) - old_n_unmap_path_key = cls.n_unmap_path_key def n_unmap_path_key(key_value_path, leaf_path, unwanted_path): @@ -158,18 +143,6 @@ def n_unmap_path_key(key_value_path, leaf_path, unwanted_path): key_value_path[cls.name] = new_val key_value_path, leaf_path, unwanted_path = old_n_unmap_path_key(key_value_path, leaf_path, unwanted_path) return (key_value_path, leaf_path, unwanted_path) - - old_new_unmap_path_key = cls.new_unmap_path_key - - def new_unmap_path_key(key_value_path, unwanted_path, final_path): - value = key_value_path[cls.name] - for transform in cls.transformations: - if isinstance(transform, DatacubeAxisCyclic): - if cls.name == transform.name: - new_val = _remap_val_to_axis_range(value) - key_value_path[cls.name] = new_val - key_value_path, unwanted_path, final_path = old_new_unmap_path_key(key_value_path, unwanted_path, final_path) - return (key_value_path, unwanted_path, final_path) old_unmap_to_datacube = cls.unmap_to_datacube @@ -224,8 +197,6 @@ def offset(range): cls.unmap_to_datacube = unmap_to_datacube cls.unmap_total_path_to_datacube = unmap_total_path_to_datacube cls.find_indices_between = find_indices_between - cls.unmap_path_key = unmap_path_key - cls.new_unmap_path_key = new_unmap_path_key cls.n_unmap_path_key = n_unmap_path_key return cls @@ -280,18 +251,13 @@ def unmap_to_datacube(path, unmapped_path): def unmap_total_path_to_datacube(path, unmapped_path): # TODO: to be faster, could just compute the first lat unmapped idx, and do +1 for each subsequent lat idx? - # time1 = time.time() (path, unmapped_path) = old_unmap_total_path_to_datacube(path, unmapped_path) for transform in cls.transformations: if isinstance(transform, DatacubeMapper): - # time2 = time.time() if cls.name == transform._mapped_axes()[0]: - # axis = cls.name # if we are on the first axis, then need to add the first val to unmapped_path first_val = path[cls.name] del path[cls.name] - # else: - # first_val = None if unmapped_path is None: unmapped_path[cls.name] = first_val @@ -301,58 +267,23 @@ def unmap_total_path_to_datacube(path, unmapped_path): if cls.name == transform._mapped_axes()[1]: # if we are on the second axis, then the val of the first axis is stored # inside unmapped_path so can get it from there - # axis = cls.name - # print("TIME time handling path") - # time2 = time.time() - # second_val = path.get(cls.name, None) - # path.pop(cls.name, None) second_val = path[cls.name] del path[cls.name] first_val = unmapped_path.get(transform._mapped_axes()[0], None) unmapped_path.pop(transform._mapped_axes()[0], None) - # del unmapped_path[transformation._mapped_axes()[0]] - # print(time.time() - time2) # NOTE: here we first calculate the starting idx of the first_val grid line # and then append the second_idx to get the final unmapped_idx # To do this, also need to find second_idx from second_val... # if the first_val was not in the unmapped_path, then it's still in path - # print("AAAAAND TIME TAKEN DOING UNMAP") if first_val is None: first_val = path.get(transform._mapped_axes()[0], None) path.pop(transform._mapped_axes()[0], None) unmapped_idx = transform.unmap(first_val, second_val) unmapped_path[transform.old_axis] = unmapped_idx - # time3 = time.time() - # print("MAPPER UNMAP TIME") - # print(time.time() - time1) - # print(time3 - time1) - # print("AXIS THIS IS FOR") - # print(axis) - # print("MAPPER TIME ONCE CHOSEN THE MAPPING") - # print(time3 - time2) return (path, unmapped_path) - - old_unmap_path_key = cls.unmap_path_key - def unmap_path_key(key_value_path, leaf_path): - key_value_path, leaf_path = old_unmap_path_key(key_value_path, leaf_path) - value = key_value_path[cls.name] - # print(cls.name) - # print(key_value_path) - for transform in cls.transformations: - if isinstance(transform, DatacubeMapper): - # if cls.name == transform._mapped_axes()[0]: - # unmapping_path[cls.name] = value - if cls.name == transform._mapped_axes()[1]: - first_val = leaf_path[transform._mapped_axes()[0]] - unmapped_idx = transform.unmap(first_val, value) - # leaf_path.pop(transform._mapped_axes()[0]) - key_value_path.pop(cls.name) - key_value_path[transform.old_axis] = unmapped_idx - return (key_value_path, leaf_path) - old_n_unmap_path_key = cls.n_unmap_path_key def n_unmap_path_key(key_value_path, leaf_path, unwanted_path): @@ -363,38 +294,13 @@ def n_unmap_path_key(key_value_path, leaf_path, unwanted_path): if cls.name == transform._mapped_axes()[0]: unwanted_val = key_value_path[transform._mapped_axes()[0]] unwanted_path[cls.name] = unwanted_val - # leaf_path.pop(transform._mapped_axes()[0]) if cls.name == transform._mapped_axes()[1]: - # first_val = leaf_path[transform._mapped_axes()[0]] first_val = unwanted_path[transform._mapped_axes()[0]] unmapped_idx = transform.unmap(first_val, value) leaf_path.pop(transform._mapped_axes()[0], None) key_value_path.pop(cls.name) key_value_path[transform.old_axis] = unmapped_idx return (key_value_path, leaf_path, unwanted_path) - - old_new_unmap_path_key = cls.new_unmap_path_key - - def new_unmap_path_key(key_value_path, unwanted_path, final_path): - # NOTE: think this doesn't work recursively because we update the final path already, which is sort of duplicated from the key-value_path... - key_value_path, unwanted_path, final_path = old_new_unmap_path_key(key_value_path, unwanted_path, final_path) - value = key_value_path[cls.name] - for transform in cls.transformations: - if isinstance(transform, DatacubeMapper): - if cls.name == transform._mapped_axes()[0]: - unwanted_val = key_value_path[transform._mapped_axes()[0]] - unwanted_path[cls.name] = unwanted_val - if cls.name == transform._mapped_axes()[1]: - # first_val = leaf_path[transform._mapped_axes()[0]] - first_val = unwanted_path[transform._mapped_axes()[0]] - unmapped_idx = transform.unmap(first_val, value) - # key_value_path.pop(cls.name) - # key_value_path[transform.old_axis] = unmapped_idx - final_path[transform.old_axis] = unmapped_idx - return (key_value_path, unwanted_path, final_path) - - def remap_to_requested(path, unmapped_path): - return (path, unmapped_path) def find_indices_between(index_ranges, low, up, datacube, method=None): # TODO: add method for snappping @@ -422,7 +328,6 @@ def find_indices_between(index_ranges, low, up, datacube, method=None): end_idx = bisect_left_cmp(idxs, low, cmp=lambda x, y: x > y) + 1 start_idx = bisect_right_cmp(idxs, up, cmp=lambda x, y: x > y) indexes_between = idxs[start_idx:end_idx] - # indexes_between = [i for i in idxs if low <= i <= up] indexes_between_ranges.append(indexes_between) return indexes_between_ranges @@ -434,11 +339,8 @@ def remap(range): cls.remap = remap cls.find_indexes = find_indexes cls.unmap_to_datacube = unmap_to_datacube - cls.remap_to_requested = remap_to_requested cls.find_indices_between = find_indices_between cls.unmap_total_path_to_datacube = unmap_total_path_to_datacube - cls.unmap_path_key = unmap_path_key - cls.new_unmap_path_key = new_unmap_path_key cls.n_unmap_path_key = n_unmap_path_key return cls @@ -460,7 +362,6 @@ def find_indexes(path, datacube): old_unmap_total_path_to_datacube = cls.unmap_total_path_to_datacube def unmap_total_path_to_datacube(path, unmapped_path): - # time1 = time.time() (path, unmapped_path) = old_unmap_total_path_to_datacube(path, unmapped_path) for transform in cls.transformations: if isinstance(transform, DatacubeAxisMerger): @@ -470,24 +371,8 @@ def unmap_total_path_to_datacube(path, unmapped_path): (first_val, second_val) = transformation.unmerge(old_val) path[transformation._first_axis] = first_val path[transformation._second_axis] = second_val - # print("UNMAPPER TIME INSIDE MERGE") - # print(time.time() - time1) return (path, unmapped_path) - - old_unmap_path_key = cls.unmap_path_key - def unmap_path_key(key_value_path, leaf_path): - key_value_path, leaf_path = old_unmap_path_key(key_value_path, leaf_path) - new_key_value_path = {} - value = key_value_path[cls.name] - for transform in cls.transformations: - if isinstance(transform, DatacubeAxisMerger): - if cls.name == transform._first_axis: - (first_val, second_val) = transform.unmerge(value) - new_key_value_path[transform._first_axis] = first_val - new_key_value_path[transform._second_axis] = second_val - return (new_key_value_path, leaf_path) - old_n_unmap_path_key = cls.n_unmap_path_key def n_unmap_path_key(key_value_path, leaf_path, unwanted_path): @@ -502,22 +387,6 @@ def n_unmap_path_key(key_value_path, leaf_path, unwanted_path): new_key_value_path[transform._second_axis] = second_val return (new_key_value_path, leaf_path, unwanted_path) - old_new_unmap_path_key = cls.new_unmap_path_key - - def new_unmap_path_key(key_value_path, unwanted_path, final_path): - key_value_path, unwanted_path, final_path = old_new_unmap_path_key(key_value_path, unwanted_path, final_path) - # new_key_value_path = {} - value = key_value_path[cls.name] - for transform in cls.transformations: - if isinstance(transform, DatacubeAxisMerger): - if cls.name == transform._first_axis: - (first_val, second_val) = transform.unmerge(value) - # new_key_value_path[transform._first_axis] = first_val - final_path[transform._first_axis] = first_val - # new_key_value_path[transform._second_axis] = second_val - final_path[transform._second_axis] = second_val - return (key_value_path, unwanted_path, final_path) - old_unmap_to_datacube = cls.unmap_to_datacube def unmap_to_datacube(path, unmapped_path): @@ -533,9 +402,6 @@ def unmap_to_datacube(path, unmapped_path): path[transformation._second_axis] = second_val return (path, unmapped_path) - def remap_to_requested(path, unmapped_path): - return (path, unmapped_path) - def find_indices_between(index_ranges, low, up, datacube, method=None): # TODO: add method for snappping indexes_between_ranges = [] @@ -555,7 +421,6 @@ def find_indices_between(index_ranges, low, up, datacube, method=None): lower_idx = bisect.bisect_left(indexes, low) upper_idx = bisect.bisect_right(indexes, up) indexes_between = indexes[lower_idx: upper_idx] - # indexes_between = [i for i in indexes if low <= i <= up] indexes_between_ranges.append(indexes_between) return indexes_between_ranges @@ -565,11 +430,8 @@ def remap(range): cls.remap = remap cls.find_indexes = find_indexes cls.unmap_to_datacube = unmap_to_datacube - cls.remap_to_requested = remap_to_requested cls.find_indices_between = find_indices_between cls.unmap_total_path_to_datacube = unmap_total_path_to_datacube - cls.unmap_path_key = unmap_path_key - cls.new_unmap_path_key = new_unmap_path_key cls.n_unmap_path_key = n_unmap_path_key return cls @@ -593,9 +455,6 @@ def find_indexes(path, datacube): def unmap_to_datacube(path, unmapped_path): return (path, unmapped_path) - def remap_to_requested(path, unmapped_path): - return (path, unmapped_path) - def find_indices_between(index_ranges, low, up, datacube, method=None): # TODO: add method for snappping indexes_between_ranges = [] @@ -630,7 +489,6 @@ def find_indices_between(index_ranges, low, up, datacube, method=None): indexes_between = indexes[start:end] indexes_between_ranges.append(indexes_between) else: - # indexes_between = [i for i in indexes if low <= i <= up] lower_idx = bisect.bisect_left(indexes, low) upper_idx = bisect.bisect_right(indexes, up) indexes_between = indexes[lower_idx: upper_idx] @@ -643,7 +501,6 @@ def remap(range): cls.remap = remap cls.find_indexes = find_indexes cls.unmap_to_datacube = unmap_to_datacube - cls.remap_to_requested = remap_to_requested cls.find_indices_between = find_indices_between return cls @@ -666,7 +523,6 @@ def find_indexes(path, datacube): old_unmap_total_path_to_datacube = cls.unmap_total_path_to_datacube def unmap_total_path_to_datacube(path, unmapped_path): - # time1 = time.time() (path, unmapped_path) = old_unmap_total_path_to_datacube(path, unmapped_path) for transform in cls.transformations: if isinstance(transform, DatacubeAxisTypeChange): @@ -677,22 +533,8 @@ def unmap_total_path_to_datacube(path, unmapped_path): if cls.name in path: path.pop(cls.name, None) unmapped_path[cls.name] = unchanged_val - # print("UNMAPPER TIME INSIDE TYPE_CHANGE") - # print(time.time() - time1) return (path, unmapped_path) - old_unmap_path_key = cls.unmap_path_key - - def unmap_path_key(key_value_path, leaf_path): - key_value_path, leaf_path = old_unmap_path_key(key_value_path, leaf_path) - value = key_value_path[cls.name] - for transform in cls.transformations: - if isinstance(transform, DatacubeAxisTypeChange): - if cls.name == transform.name: - unchanged_val = transform.make_str(value) - key_value_path[cls.name] = unchanged_val - return (key_value_path, leaf_path) - old_n_unmap_path_key = cls.n_unmap_path_key def n_unmap_path_key(key_value_path, leaf_path, unwanted_path): @@ -704,18 +546,6 @@ def n_unmap_path_key(key_value_path, leaf_path, unwanted_path): unchanged_val = transform.make_str(value) key_value_path[cls.name] = unchanged_val return (key_value_path, leaf_path, unwanted_path) - - old_new_unmap_path_key = cls.new_unmap_path_key - - def new_unmap_path_key(key_value_path, unwanted_path, final_path): - key_value_path, unwanted_path, final_path = old_new_unmap_path_key(key_value_path, unwanted_path, final_path) - value = key_value_path[cls.name] - for transform in cls.transformations: - if isinstance(transform, DatacubeAxisTypeChange): - if cls.name == transform.name: - unchanged_val = transform.make_str(value) - key_value_path[cls.name] = unchanged_val - return (key_value_path, unwanted_path, final_path) def unmap_to_datacube(path, unmapped_path): for transform in cls.transformations: @@ -729,9 +559,6 @@ def unmap_to_datacube(path, unmapped_path): unmapped_path[cls.name] = unchanged_val return (path, unmapped_path) - def remap_to_requested(path, unmapped_path): - return (path, unmapped_path) - def find_indices_between(index_ranges, low, up, datacube, method=None): # TODO: add method for snappping indexes_between_ranges = [] @@ -748,7 +575,6 @@ def find_indices_between(index_ranges, low, up, datacube, method=None): indexes_between = indexes[start:end] indexes_between_ranges.append(indexes_between) else: - # indexes_between = [i for i in indexes if low <= i <= up] lower_idx = bisect.bisect_left(indexes, low) upper_idx = bisect.bisect_right(indexes, up) indexes_between = indexes[lower_idx: upper_idx] @@ -761,10 +587,8 @@ def remap(range): cls.remap = remap cls.find_indexes = find_indexes cls.unmap_to_datacube = unmap_to_datacube - cls.remap_to_requested = remap_to_requested cls.find_indices_between = find_indices_between cls.unmap_total_path_to_datacube = unmap_total_path_to_datacube - cls.unmap_path_key = unmap_path_key cls.n_unmap_path_key = n_unmap_path_key return cls @@ -786,9 +610,6 @@ def unmap_total_path_to_datacube(path, unmapped_path): def unmap_to_datacube(path, unmapped_path): return (path, unmapped_path) - def remap_to_requested(path, unmapped_path): - return (path, unmapped_path) - def find_indices_between(index_ranges, low, up, datacube, method=None): indexes_between_ranges = [] for indexes in index_ranges: @@ -802,7 +623,6 @@ def remap(range): cls.remap = remap cls.find_indexes = find_indexes cls.unmap_to_datacube = unmap_to_datacube - cls.remap_to_requested = remap_to_requested cls.find_indices_between = find_indices_between cls.unmap_total_path_to_datacube = unmap_total_path_to_datacube @@ -863,17 +683,8 @@ def offset(self, value): def unmap_total_path_to_datacube(self, path, unmapped_path): return (path, unmapped_path) - def unmap_path_key(self, key_value_path, leaf_path): - return (key_value_path, leaf_path) - def n_unmap_path_key(self, key_value_path, leaf_path, unwanted_path): return (key_value_path, leaf_path, unwanted_path) - - def new_unmap_path_key(self, key_value_path, leaf_path, unwanted_path): - return (key_value_path, leaf_path, unwanted_path) - - def remap_to_requeest(path, unmapped_path): - return (path, unmapped_path) def find_indices_between(self, index_ranges, low, up, datacube, method=None): # TODO: add method for snappping diff --git a/polytope/datacube/transformations/datacube_cyclic.py b/polytope/datacube/transformations/datacube_cyclic.py index 284a2f6ad..802285c32 100644 --- a/polytope/datacube/transformations/datacube_cyclic.py +++ b/polytope/datacube/transformations/datacube_cyclic.py @@ -20,6 +20,6 @@ def change_val_type(self, axis_name, values): def blocked_axes(self): return [] - + def unwanted_axes(self): return [] diff --git a/polytope/datacube/transformations/datacube_mappers.py b/polytope/datacube/transformations/datacube_mappers.py index 07a53336d..fa6f4fd8c 100644 --- a/polytope/datacube/transformations/datacube_mappers.py +++ b/polytope/datacube/transformations/datacube_mappers.py @@ -1,9 +1,9 @@ +import bisect import math from copy import deepcopy from importlib import import_module -from ...utility.list_tools import bisect_left_cmp, bisect_right_cmp -import bisect +from ...utility.list_tools import bisect_left_cmp, bisect_right_cmp from .datacube_transformations import DatacubeAxisTransformation @@ -34,8 +34,6 @@ def unwanted_axes(self): return [self._final_mapped_axes[0]] def transformation_axes_final(self): - # final_transformation = self.generate_final_transformation() - # final_axes = self._final_transformation._mapped_axes final_axes = self._final_mapped_axes return final_axes @@ -47,8 +45,6 @@ def change_val_type(self, axis_name, values): def _mapped_axes(self): # NOTE: Each of the mapper method needs to call it's sub mapper method - # final_transformation = self.generate_final_transformation() - # final_axes = self._final_transformation._mapped_axes final_axes = self._final_mapped_axes return final_axes @@ -59,19 +55,15 @@ def _resolution(self): pass def first_axis_vals(self): - # final_transformation = self.generate_final_transformation() return self._final_transformation.first_axis_vals() def second_axis_vals(self, first_val): - # final_transformation = self.generate_final_transformation() return self._final_transformation.second_axis_vals(first_val) def map_first_axis(self, lower, upper): - # final_transformation = self.generate_final_transformation() return self._final_transformation.map_first_axis(lower, upper) def map_second_axis(self, first_val, lower, upper): - # final_transformation = self.generate_final_transformation() return self._final_transformation.map_second_axis(first_val, lower, upper) def find_second_idx(self, first_val, second_val): @@ -81,7 +73,6 @@ def unmap_first_val_to_start_line_idx(self, first_val): return self._final_transformation.unmap_first_val_to_start_line_idx(first_val) def unmap(self, first_val, second_val): - # final_transformation = self.generate_final_transformation() return self._final_transformation.unmap(first_val, second_val) @@ -258,12 +249,8 @@ def __init__(self, base_axis, mapped_axes, resolution): self._base_axis = base_axis self._resolution = resolution self._first_axis_vals = self.first_axis_vals() - # self._inv_first_axis_vals = self._first_axis_vals[::-1] - # self._inv_first_axis_vals = {v:k for k,v in self._first_axis_vals.items()} self._first_idx_map = self.create_first_idx_map() - # self._second_axis_spacing = dict() self._second_axis_spacing = {} - # self.treated_first_vals = dict() self._axis_reversed = {mapped_axes[0]: True, mapped_axes[1]: False} def gauss_first_guess(self): @@ -2926,7 +2913,6 @@ def first_axis_vals(self): def map_first_axis(self, lower, upper): axis_lines = self._first_axis_vals - # return_vals = [val for val in axis_lines if lower <= val <= upper] end_idx = bisect_left_cmp(axis_lines, lower, cmp=lambda x, y: x > y) + 1 start_idx = bisect_right_cmp(axis_lines, upper, cmp=lambda x, y: x > y) return_vals = axis_lines[start_idx:end_idx] @@ -2935,8 +2921,6 @@ def map_first_axis(self, lower, upper): def second_axis_vals(self, first_val): first_axis_vals = self._first_axis_vals tol = 1e-10 - # first_val = [val for val in first_axis_vals if first_val - tol < val < first_val + tol][0] - # first_idx = first_axis_vals.index(first_val) first_idx = bisect_left_cmp(first_axis_vals, first_val - tol, cmp=lambda x, y: x > y) if first_idx >= self._resolution: first_idx = (2 * self._resolution) - 1 - first_idx @@ -2949,8 +2933,6 @@ def second_axis_vals(self, first_val): def second_axis_spacing(self, first_val): first_axis_vals = self._first_axis_vals tol = 1e-10 - # first_val = [val for val in first_axis_vals if first_val - tol < val < first_val + tol][0] - # first_idx = first_axis_vals.index(first_val) _first_idx = bisect_left_cmp(first_axis_vals, first_val - tol, cmp=lambda x, y: x > y) first_idx = _first_idx if first_idx >= self._resolution: @@ -2962,24 +2944,9 @@ def second_axis_spacing(self, first_val): def map_second_axis(self, first_val, lower, upper): second_axis_spacing, first_idx = self.second_axis_spacing(first_val) - # if first_val not in self._second_axis_spacing: - # (second_axis_spacing, first_idx) = self.second_axis_spacing(first_val) - # self._second_axis_spacing[first_val] = (second_axis_spacing, first_idx) - # else: - # (second_axis_spacing, first_idx) = self._second_axis_spacing[first_val] start_idx = int(lower/second_axis_spacing) end_idx = int(upper/second_axis_spacing) + 1 return_vals = [i * second_axis_spacing for i in range(start_idx, end_idx)] - - # second_axis_vals = self.second_axis_vals(first_val) - # # NOTE: here this seems faster than the bisect.bisect? - # # return_vals = [val for val in second_axis_vals if lower <= val <= upper] - # start_idx = bisect_left_cmp(second_axis_vals, lower, cmp=lambda x, y: x < y) + 1 - # end_idx = bisect_right_cmp(second_axis_vals, upper, cmp=lambda x, y: x < y) + 1 - # return_vals = second_axis_vals[start_idx:end_idx] - # # start_idx = bisect.bisect_left(second_axis_vals, lower) - # # end_idx = bisect.bisect_right(second_axis_vals, upper) - # # return_vals = second_axis_vals[start_idx:end_idx] return return_vals def axes_idx_to_octahedral_idx(self, first_idx, second_idx): @@ -2990,40 +2957,13 @@ def axes_idx_to_octahedral_idx(self, first_idx, second_idx): # NOTE: OR somehow cache this for a given first_idx and then only modify the axis idx for second_idx when the # first_idx changes - # time1 = time.time() - # octa_idx = self._first_idx_map[first_idx-1] + second_idx octa_idx = self._first_idx_map[first_idx-1] + second_idx - # octa_idx = 0 - # if first_idx == 1: - # octa_idx = second_idx - # else: - # for i in range(first_idx - 1): - # if i <= self._resolution - 1: - # octa_idx += 20 + 4 * i - # else: - # i = i - self._resolution + 1 - # if i == 1: - # octa_idx += 16 + 4 * self._resolution - # else: - # i = i - 1 - # octa_idx += 16 + 4 * (self._resolution - i) - # octa_idx += second_idx - # print("TIME UNMAPPING TO OCT IDX") - # print(time.time() - time1) return octa_idx - # def find_second_idx(self, first_val, second_val): - # tol = 1e-10 - # second_axis_vals = self.second_axis_vals(first_val) - # second_idx = bisect.bisect_left(second_axis_vals, second_val - tol) - # return second_idx - def create_first_idx_map(self): - # first_idx_list = [0] * (2*self._resolution) first_idx_list = {} idx = 0 for i in range(2*self._resolution): - # first_idx_list[i] = idx first_idx_list[i] = idx if i <= self._resolution - 1: idx += 20 + 4 * i @@ -3036,36 +2976,8 @@ def create_first_idx_map(self): idx += 16 + 4 * (self._resolution - i) return first_idx_list - # def unmap_first_val_to_start_line_idx(self, first_val): - # first_axis_vals = self._first_axis_vals - # tol = 1e-10 - # # first_val = [val for val in first_axis_vals if first_val - tol < val < first_val + tol][0] - # # first_idx = first_axis_vals.index(first_val) + 1 - # # first_idx = len(first_axis_vals) - bisect.bisect_left(first_axis_vals[::-1], first_val - tol) - # first_idx = bisect_left_cmp(first_axis_vals, first_val - tol, cmp=lambda x, y: x > y) + 1 - # octa_idx = 0 - # if first_idx == 1: - # return octa_idx - # else: - # for i in range(first_idx - 1): - # if i <= self._resolution - 1: - # octa_idx += 20 + 4 * i - # else: - # i = i - self._resolution + 1 - # if i == 1: - # octa_idx += 16 + 4 * self._resolution - # else: - # i = i - 1 - # octa_idx += 16 + 4 * (self._resolution - i) - # return octa_idx - def find_second_axis_idx(self, first_val, second_val): (second_axis_spacing, first_idx) = self.second_axis_spacing(first_val) - # if first_val not in self._second_axis_spacing: - # (second_axis_spacing, first_idx) = self.second_axis_spacing(first_val) - # self._second_axis_spacing[first_val] = (second_axis_spacing, first_idx) - # else: - # (second_axis_spacing, first_idx) = self._second_axis_spacing[first_val] tol = 1e-8 if second_val/second_axis_spacing > int(second_val/second_axis_spacing) + 1 - tol: second_idx = int(second_val/second_axis_spacing) + 1 @@ -3074,35 +2986,8 @@ def find_second_axis_idx(self, first_val, second_val): return (first_idx, second_idx) def unmap(self, first_val, second_val): - # time1 = time.time() - # first_axis_vals = self._first_axis_vals - # inv_first_axis_vals = self._inv_first_axis_vals - # tol = 1e-10 - # # first_val = [val for val in first_axis_vals if first_val - tol < val < first_val + tol][0] - # # first_idx = first_axis_vals.index(first_val) + 1 - # # first_idx = len(first_axis_vals) - bisect.bisect_left(first_axis_vals[::-1], first_val - tol) - # # first_idx = bisect_left_cmp(first_axis_vals, first_val - tol, cmp=lambda x, y: x > y) + 1 - # first_idx = bisect.bisect_left(self._inv_first_axis_vals, - (first_val - tol)) - # # print(inv_first_axis_vals) - # # print(first_val) - # # first_idx = inv_first_axis_vals[first_val] - # # first_idx = np.searchsorted(-first_axis_vals, - (first_val - tol), side="right") - # if first_val not in self.treated_first_vals: - # second_axis_vals = self.second_axis_vals(first_val) - # self.treated_first_vals[first_val] = second_axis_vals - # else: - # second_axis_vals = self.treated_first_vals[first_val] - # # second_val = [val for val in second_axis_vals if second_val - tol < val < second_val + tol][0] - # # second_idx = second_axis_vals.index(second_val) - # second_idx = bisect.bisect_left(second_axis_vals, second_val - tol) (first_idx, second_idx) = self.find_second_axis_idx(first_val, second_val) - # second_idx = np.searchsorted(second_axis_vals, second_val - tol) - # print("TIME SPENT DOING VAL TO IDX") - # print(time.time() - time1) octahedral_index = self.axes_idx_to_octahedral_idx(first_idx, second_idx) - # octahedral_index = int(octahedral_index) - # print("OCTAHEDRAL UNMAP TIME ") - # print(time.time() - time1) return octahedral_index diff --git a/polytope/datacube/transformations/datacube_merger.py b/polytope/datacube/transformations/datacube_merger.py index 48250b20e..e91354c4f 100644 --- a/polytope/datacube/transformations/datacube_merger.py +++ b/polytope/datacube/transformations/datacube_merger.py @@ -1,6 +1,5 @@ import numpy as np import pandas as pd -# import time from .datacube_transformations import DatacubeAxisTransformation @@ -15,22 +14,18 @@ def __init__(self, name, merge_options): def blocked_axes(self): return [self._second_axis] - + def unwanted_axes(self): return [] def merged_values(self, datacube): - # time1 = time.time() first_ax_vals = datacube.ax_vals(self.name) second_ax_name = self._second_axis second_ax_vals = datacube.ax_vals(second_ax_name) linkers = self._linkers merged_values = [] - # merged_values = np.empty(len(first_ax_vals)*len(second_ax_vals)) - # for first_val in first_ax_vals: for i in range(len(first_ax_vals)): first_val = first_ax_vals[i] - # for second_val in second_ax_vals: for j in range(len(second_ax_vals)): second_val = second_ax_vals[j] # TODO: check that the first and second val are strings @@ -38,11 +33,7 @@ def merged_values(self, datacube): val_to_add = val_to_add.to_numpy() val_to_add = val_to_add.astype("datetime64[s]") merged_values.append(val_to_add) - # print(val_to_add) - # merged_values[i*len(second_ax_vals) + j] = val_to_add merged_values = np.array(merged_values) - # print("MERGED VALUES TIME") - # print(time.time() - time1) return merged_values def transformation_axes_final(self): @@ -52,7 +43,6 @@ def generate_final_transformation(self): return self def unmerge(self, merged_val): - # time1 = time.time() merged_val = str(merged_val) first_idx = merged_val.find(self._linkers[0]) first_val = merged_val[:first_idx] @@ -63,8 +53,6 @@ def unmerge(self, merged_val): # TODO: maybe replacing like this is too specific to time/dates? first_val = str(first_val).replace("-", "") second_val = second_val.replace(":", "") - # print("UNMERGE TIME") - # print(time.time() - time1) return (first_val, second_val) def change_val_type(self, axis_name, values): diff --git a/polytope/datacube/transformations/datacube_null_transformation.py b/polytope/datacube/transformations/datacube_null_transformation.py index 26f9ffaa4..55c94277e 100644 --- a/polytope/datacube/transformations/datacube_null_transformation.py +++ b/polytope/datacube/transformations/datacube_null_transformation.py @@ -17,6 +17,6 @@ def change_val_type(self, axis_name, values): def blocked_axes(self): return [] - + def unwanted_axes(self): return [] diff --git a/polytope/datacube/transformations/datacube_reverse.py b/polytope/datacube/transformations/datacube_reverse.py index f0b1415b5..6a556907a 100644 --- a/polytope/datacube/transformations/datacube_reverse.py +++ b/polytope/datacube/transformations/datacube_reverse.py @@ -17,6 +17,6 @@ def change_val_type(self, axis_name, values): def blocked_axes(self): return [] - + def unwanted_axes(self): return [] diff --git a/polytope/datacube/transformations/datacube_type_change.py b/polytope/datacube/transformations/datacube_type_change.py index dde8ee346..8dee75341 100644 --- a/polytope/datacube/transformations/datacube_type_change.py +++ b/polytope/datacube/transformations/datacube_type_change.py @@ -21,20 +21,17 @@ def generate_final_transformation(self): return transformation def transformation_axes_final(self): - # final_transformation = self.generate_final_transformation() return [self._final_transformation.axis_name] def change_val_type(self, axis_name, values): - # transformation = self.generate_final_transformation() return [self._final_transformation.transform_type(val) for val in values] def make_str(self, value): - # transformation = self.generate_final_transformation() return self._final_transformation.make_str(value) def blocked_axes(self): return [] - + def unwanted_axes(self): return [] diff --git a/polytope/engine/hullslicer.py b/polytope/engine/hullslicer.py index 158f09273..10c3bd5f4 100644 --- a/polytope/engine/hullslicer.py +++ b/polytope/engine/hullslicer.py @@ -1,8 +1,7 @@ import math from copy import copy -from itertools import chain, product +from itertools import chain from typing import List -import time import scipy.spatial @@ -103,12 +102,6 @@ def extract(self, datacube: Datacube, polytopes: List[ConvexPolytope]): def _find_intersects(polytope, slice_axis_idx, value): intersects = [] # Find all points above and below slice axis - # above_slice, below_slice = [], [] - # for p in polytope.points: - # if p[slice_axis_idx] >= value: - # above_slice.append(p) - # if p[slice_axis_idx] <= value: - # below_slice.append(p) above_slice = [p for p in polytope.points if p[slice_axis_idx] >= value] below_slice = [p for p in polytope.points if p[slice_axis_idx] <= value] @@ -124,16 +117,6 @@ def _find_intersects(polytope, slice_axis_idx, value): interp_coeff = (value - b[slice_axis_idx]) / (a[slice_axis_idx] - b[slice_axis_idx]) intersect = lerp(a, b, interp_coeff) intersects.append(intersect) - # for (a, b) in product(above_slice, below_slice): - # # edge is incident with slice plane, don't need these points - # if a[slice_axis_idx] == b[slice_axis_idx]: - # intersects.append(b) - # continue - - # # Linearly interpolate all coordinates of two points (a,b) of the polytope - # interp_coeff = (value - b[slice_axis_idx]) / (a[slice_axis_idx] - b[slice_axis_idx]) - # intersect = lerp(a, b, interp_coeff) - # intersects.append(intersect) return intersects @@ -146,7 +129,6 @@ def _reduce_dimension(intersects, slice_axis_idx): def slice(polytope: ConvexPolytope, axis, value, slice_axis_idx): - # slice_axis_idx = polytope._axes.index(axis) if len(polytope.points[0]) == 1: # Note that in this case, we do not need to do linear interpolation so we can save time @@ -180,7 +162,6 @@ def slice(polytope: ConvexPolytope, axis, value, slice_axis_idx): vertices = hull.vertices except scipy.spatial.qhull.QhullError as e: - # if "input is less than" or "simplex is flat" in str(e): if "less than" or "flat" in str(e): return ConvexPolytope(axes, intersects) # Sliced result is simply the convex hull diff --git a/polytope/polytope.py b/polytope/polytope.py index dcd46f407..5e8fc7133 100644 --- a/polytope/polytope.py +++ b/polytope/polytope.py @@ -1,5 +1,4 @@ from typing import List -import time from .shapes import ConvexPolytope from .utility.exceptions import AxisOverdefinedError @@ -45,18 +44,6 @@ def slice(self, polytopes: List[ConvexPolytope]): def retrieve(self, request: Request, method="standard"): """Higher-level API which takes a request and uses it to slice the datacube""" - # print("TIME IN POLYTOPE EXTRACT") - # time0 = time.time() request_tree = self.engine.extract(self.datacube, request.polytopes()) - # print(time.time() - time0) - # print("TIME INSIDE OF GET") - # time1 = time.time() self.datacube.get(request_tree) - # print(time.time() - time1) - # print("TIME INSIDE FDB") - # print(self.datacube.time_fdb) - # print("TIME UNMAP KEY") - # print(self.datacube.time_unmap_key) - # print("TIME SPENT REMOVE UNNECESSARY PATH KEYS") - # print(self.datacube.other_time) return request_tree diff --git a/requirements_example.txt b/requirements_example.txt new file mode 100644 index 000000000..19717dacf --- /dev/null +++ b/requirements_example.txt @@ -0,0 +1 @@ +cfgrib==0.9.10.3 \ No newline at end of file diff --git a/tests/data/era5-levels-members.grib b/tests/data/era5-levels-members.grib new file mode 100644 index 000000000..90d45deed --- /dev/null +++ b/tests/data/era5-levels-members.grib @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c144fde61ca5d53702bf6f212775ef2cc783bdd66b6865160bf597c1b35ed898 +size 2361600 diff --git a/tests/data/foo.grib b/tests/data/foo.grib new file mode 100644 index 000000000..9c5efa68b --- /dev/null +++ b/tests/data/foo.grib @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:12533bae9b3aa078a3298a82f289c7dbba6dbdb9a21e4e5e24e84b8695a75dee +size 26409360 diff --git a/tests/data/healpix.grib b/tests/data/healpix.grib new file mode 100644 index 000000000..693c98c12 --- /dev/null +++ b/tests/data/healpix.grib @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:df57790df280627b2883c01fa4b56986d9938ed69b7434fe09c4bede99d2895f +size 37030 From 2090029856d8214d20907cc4c813dd9ef4f35f74 Mon Sep 17 00:00:00 2001 From: Mathilde Leuridan Date: Fri, 10 Nov 2023 14:50:26 +0000 Subject: [PATCH 26/37] black --- performance/fdb_scalability_plot.py | 8 ++- polytope/datacube/backends/FDB_datacube.py | 57 ++++++++++++------- polytope/datacube/datacube_axis.py | 9 ++- .../transformations/datacube_mappers.py | 14 ++--- polytope/engine/hullslicer.py | 1 - tests/test_regular_grid.py | 10 ++-- 6 files changed, 57 insertions(+), 42 deletions(-) diff --git a/performance/fdb_scalability_plot.py b/performance/fdb_scalability_plot.py index 13f2bd9b7..7230fd47b 100644 --- a/performance/fdb_scalability_plot.py +++ b/performance/fdb_scalability_plot.py @@ -1,7 +1,11 @@ import matplotlib.pyplot as plt -fdb_time = [7.6377081871032715 - 7.558288812637329, 73.57192325592041 - 72.99611115455627, - 733.2706120014191 - 727.7059993743896, 4808.3157522678375 - 4770.814565420151] +fdb_time = [ + 7.6377081871032715 - 7.558288812637329, + 73.57192325592041 - 72.99611115455627, + 733.2706120014191 - 727.7059993743896, + 4808.3157522678375 - 4770.814565420151, +] num_extracted_points = [1986, 19226, 191543, 1267134] # for the 1.3M points, we used 100 latitudes too...., maybe that's why it's not as linear... diff --git a/polytope/datacube/backends/FDB_datacube.py b/polytope/datacube/backends/FDB_datacube.py index 7326d6e4d..70a867cf0 100644 --- a/polytope/datacube/backends/FDB_datacube.py +++ b/polytope/datacube/backends/FDB_datacube.py @@ -23,8 +23,19 @@ def __init__(self, config={}, axis_options={}): self.unwanted_axes = [] self.transformation = None self.fake_axes = [] - self.final_path = {"class" : 0, "date": 0, "domain": 0, "expver": 0, "levtype": 0, "param": 0, - "step" : 0, "stream": 0, "time": 0, "type": 0, "values": 0} + self.final_path = { + "class": 0, + "date": 0, + "domain": 0, + "expver": 0, + "levtype": 0, + "param": 0, + "step": 0, + "stream": 0, + "time": 0, + "type": 0, + "values": 0, + } self.unwanted_path = {} partial_request = config @@ -66,8 +77,9 @@ def get(self, requests: IndexTree, leaf_path={}): else: key_value_path = {requests.axis.name: requests.value} ax = requests.axis - (key_value_path, leaf_path, self.unwanted_path) = ax.n_unmap_path_key(key_value_path, leaf_path, - self.unwanted_path) + (key_value_path, leaf_path, self.unwanted_path) = ax.n_unmap_path_key( + key_value_path, leaf_path, self.unwanted_path + ) leaf_path |= key_value_path if len(requests.children[0].children[0].children) == 0: # remap this last key @@ -79,9 +91,9 @@ def get(self, requests: IndexTree, leaf_path={}): self.get(c, leaf_path) def handle_last_before_last_layer(self, requests, leaf_path={}): - range_lengths = [[1]*200]*200 - current_start_idxs = [[None]*200]*200 - fdb_node_ranges = [[[IndexTree.root]*200]*200]*200 + range_lengths = [[1] * 200] * 200 + current_start_idxs = [[None] * 200] * 200 + fdb_node_ranges = [[[IndexTree.root] * 200] * 200] * 200 lat_length = len(requests.children) for i in range(len(requests.children)): lat_child = requests.children[i] @@ -90,13 +102,13 @@ def handle_last_before_last_layer(self, requests, leaf_path={}): fdb_range_nodes = deepcopy(fdb_node_ranges[i]) key_value_path = {lat_child.axis.name: lat_child.value} ax = lat_child.axis - (key_value_path, leaf_path, self.unwanted_path) = ax.n_unmap_path_key(key_value_path, leaf_path, - self.unwanted_path) + (key_value_path, leaf_path, self.unwanted_path) = ax.n_unmap_path_key( + key_value_path, leaf_path, self.unwanted_path + ) leaf_path |= key_value_path - (range_lengths[i], - current_start_idxs[i], - fdb_node_ranges[i]) = self.get_last_layer_before_leaf(lat_child, leaf_path, range_length, - current_start_idx, fdb_range_nodes) + (range_lengths[i], current_start_idxs[i], fdb_node_ranges[i]) = self.get_last_layer_before_leaf( + lat_child, leaf_path, range_length, current_start_idx, fdb_range_nodes + ) self.give_fdb_val_to_node(leaf_path, range_lengths, current_start_idxs, fdb_node_ranges, lat_length) def get_last_layer_before_leaf(self, requests, leaf_path, range_l, current_idx, fdb_range_n): @@ -105,22 +117,24 @@ def get_last_layer_before_leaf(self, requests, leaf_path, range_l, current_idx, # now c are the leaves of the initial tree key_value_path = {c.axis.name: c.value} ax = c.axis - (key_value_path, leaf_path, self.unwanted_path) = ax.n_unmap_path_key(key_value_path, leaf_path, - self.unwanted_path) + (key_value_path, leaf_path, self.unwanted_path) = ax.n_unmap_path_key( + key_value_path, leaf_path, self.unwanted_path + ) leaf_path |= key_value_path last_idx = key_value_path["values"] if current_idx[i] is None: current_idx[i] = last_idx - fdb_range_n[i][range_l[i]-1] = c + fdb_range_n[i][range_l[i] - 1] = c else: if last_idx == current_idx[i] + range_l[i]: range_l[i] += 1 - fdb_range_n[i][range_l[i]-1] = c + fdb_range_n[i][range_l[i] - 1] = c else: key_value_path = {c.axis.name: c.value} ax = c.axis - (key_value_path, leaf_path, self.unwanted_path) = ax.n_unmap_path_key(key_value_path, leaf_path, - self.unwanted_path) + (key_value_path, leaf_path, self.unwanted_path) = ax.n_unmap_path_key( + key_value_path, leaf_path, self.unwanted_path + ) leaf_path |= key_value_path i += 1 current_start_idx = key_value_path["values"] @@ -128,8 +142,9 @@ def get_last_layer_before_leaf(self, requests, leaf_path, range_l, current_idx, return (range_l, current_idx, fdb_range_n) def give_fdb_val_to_node(self, leaf_path, range_lengths, current_start_idx, fdb_range_nodes, lat_length): - (output_values, original_indices) = self.find_fdb_values(leaf_path, range_lengths, current_start_idx, - lat_length) + (output_values, original_indices) = self.find_fdb_values( + leaf_path, range_lengths, current_start_idx, lat_length + ) new_fdb_range_nodes = [] new_range_lengths = [] for j in range(lat_length): diff --git a/polytope/datacube/datacube_axis.py b/polytope/datacube/datacube_axis.py index 57a971bcb..00102800d 100644 --- a/polytope/datacube/datacube_axis.py +++ b/polytope/datacube/datacube_axis.py @@ -322,7 +322,7 @@ def find_indices_between(index_ranges, low, up, datacube, method=None): if not axis_reversed: lower_idx = bisect.bisect_left(idxs, low) upper_idx = bisect.bisect_right(idxs, up) - indexes_between = idxs[lower_idx: upper_idx] + indexes_between = idxs[lower_idx:upper_idx] else: # TODO: do the custom bisect end_idx = bisect_left_cmp(idxs, low, cmp=lambda x, y: x > y) + 1 @@ -420,7 +420,7 @@ def find_indices_between(index_ranges, low, up, datacube, method=None): else: lower_idx = bisect.bisect_left(indexes, low) upper_idx = bisect.bisect_right(indexes, up) - indexes_between = indexes[lower_idx: upper_idx] + indexes_between = indexes[lower_idx:upper_idx] indexes_between_ranges.append(indexes_between) return indexes_between_ranges @@ -491,7 +491,7 @@ def find_indices_between(index_ranges, low, up, datacube, method=None): else: lower_idx = bisect.bisect_left(indexes, low) upper_idx = bisect.bisect_right(indexes, up) - indexes_between = indexes[lower_idx: upper_idx] + indexes_between = indexes[lower_idx:upper_idx] indexes_between_ranges.append(indexes_between) return indexes_between_ranges @@ -577,7 +577,7 @@ def find_indices_between(index_ranges, low, up, datacube, method=None): else: lower_idx = bisect.bisect_left(indexes, low) upper_idx = bisect.bisect_right(indexes, up) - indexes_between = indexes[lower_idx: upper_idx] + indexes_between = indexes[lower_idx:upper_idx] indexes_between_ranges.append(indexes_between) return indexes_between_ranges @@ -595,7 +595,6 @@ def remap(range): def null(cls): - if cls.type_change: old_find_indexes = cls.find_indexes diff --git a/polytope/datacube/transformations/datacube_mappers.py b/polytope/datacube/transformations/datacube_mappers.py index fa6f4fd8c..34af16bdc 100644 --- a/polytope/datacube/transformations/datacube_mappers.py +++ b/polytope/datacube/transformations/datacube_mappers.py @@ -2944,8 +2944,8 @@ def second_axis_spacing(self, first_val): def map_second_axis(self, first_val, lower, upper): second_axis_spacing, first_idx = self.second_axis_spacing(first_val) - start_idx = int(lower/second_axis_spacing) - end_idx = int(upper/second_axis_spacing) + 1 + start_idx = int(lower / second_axis_spacing) + end_idx = int(upper / second_axis_spacing) + 1 return_vals = [i * second_axis_spacing for i in range(start_idx, end_idx)] return return_vals @@ -2957,13 +2957,13 @@ def axes_idx_to_octahedral_idx(self, first_idx, second_idx): # NOTE: OR somehow cache this for a given first_idx and then only modify the axis idx for second_idx when the # first_idx changes - octa_idx = self._first_idx_map[first_idx-1] + second_idx + octa_idx = self._first_idx_map[first_idx - 1] + second_idx return octa_idx def create_first_idx_map(self): first_idx_list = {} idx = 0 - for i in range(2*self._resolution): + for i in range(2 * self._resolution): first_idx_list[i] = idx if i <= self._resolution - 1: idx += 20 + 4 * i @@ -2979,10 +2979,10 @@ def create_first_idx_map(self): def find_second_axis_idx(self, first_val, second_val): (second_axis_spacing, first_idx) = self.second_axis_spacing(first_val) tol = 1e-8 - if second_val/second_axis_spacing > int(second_val/second_axis_spacing) + 1 - tol: - second_idx = int(second_val/second_axis_spacing) + 1 + if second_val / second_axis_spacing > int(second_val / second_axis_spacing) + 1 - tol: + second_idx = int(second_val / second_axis_spacing) + 1 else: - second_idx = int(second_val/second_axis_spacing) + second_idx = int(second_val / second_axis_spacing) return (first_idx, second_idx) def unmap(self, first_val, second_val): diff --git a/polytope/engine/hullslicer.py b/polytope/engine/hullslicer.py index 10c3bd5f4..d361fb13c 100644 --- a/polytope/engine/hullslicer.py +++ b/polytope/engine/hullslicer.py @@ -129,7 +129,6 @@ def _reduce_dimension(intersects, slice_axis_idx): def slice(polytope: ConvexPolytope, axis, value, slice_axis_idx): - if len(polytope.points[0]) == 1: # Note that in this case, we do not need to do linear interpolation so we can save time if value in chain(*polytope.points): diff --git a/tests/test_regular_grid.py b/tests/test_regular_grid.py index 7247f73f6..c32a7760f 100644 --- a/tests/test_regular_grid.py +++ b/tests/test_regular_grid.py @@ -18,9 +18,7 @@ def setup_method(self, method): download_test_data(nexus_url, "era5-levels-members.grib") self.options = { "values": { - "transformation": { - "mapper": {"type": "regular", "resolution": 30, "axes": ["latitude", "longitude"]} - } + "transformation": {"mapper": {"type": "regular", "resolution": 30, "axes": ["latitude", "longitude"]}} }, "date": {"transformation": {"merge": {"with": "time", "linkers": [" ", "00"]}}}, "step": {"transformation": {"type_change": "int"}}, @@ -68,11 +66,11 @@ def test_regular_grid(self): Select("type", ["an"]), Disk(["latitude", "longitude"], [0, 0], [15, 15]), Select("levelist", ["500"]), - Select("number", ["0", "1"]) + Select("number", ["0", "1"]), ) result = self.API.retrieve(request) result.pprint() - assert len(result.leaves) == 46*2 + assert len(result.leaves) == 46 * 2 lats = [] lons = [] @@ -101,4 +99,4 @@ def test_regular_grid(self): # plt.colorbar(label="Temperature") # plt.show() - assert len(eccodes_lats) == 46*2 + assert len(eccodes_lats) == 46 * 2 From f8922df8c9fcc26645ddb9714bd45781b7d098b5 Mon Sep 17 00:00:00 2001 From: Mathilde Leuridan Date: Fri, 10 Nov 2023 14:58:50 +0000 Subject: [PATCH 27/37] remove data --- tests/data/era5-levels-members.grib | 3 --- tests/data/foo.grib | 3 --- tests/data/healpix.grib | 3 --- 3 files changed, 9 deletions(-) delete mode 100644 tests/data/era5-levels-members.grib delete mode 100644 tests/data/foo.grib delete mode 100644 tests/data/healpix.grib diff --git a/tests/data/era5-levels-members.grib b/tests/data/era5-levels-members.grib deleted file mode 100644 index 90d45deed..000000000 --- a/tests/data/era5-levels-members.grib +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c144fde61ca5d53702bf6f212775ef2cc783bdd66b6865160bf597c1b35ed898 -size 2361600 diff --git a/tests/data/foo.grib b/tests/data/foo.grib deleted file mode 100644 index 9c5efa68b..000000000 --- a/tests/data/foo.grib +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:12533bae9b3aa078a3298a82f289c7dbba6dbdb9a21e4e5e24e84b8695a75dee -size 26409360 diff --git a/tests/data/healpix.grib b/tests/data/healpix.grib deleted file mode 100644 index 693c98c12..000000000 --- a/tests/data/healpix.grib +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:df57790df280627b2883c01fa4b56986d9938ed69b7434fe09c4bede99d2895f -size 37030 From 5842a1be774bfcde98ce7faf71deecc07712dd33 Mon Sep 17 00:00:00 2001 From: Mathilde Leuridan Date: Fri, 10 Nov 2023 15:37:53 +0000 Subject: [PATCH 28/37] remove unnecessary code --- .gitignore | 6 +- polytope/datacube/backends/xarray.py | 5 +- polytope/datacube/datacube_axis.py | 101 --------------------------- 3 files changed, 6 insertions(+), 106 deletions(-) diff --git a/.gitignore b/.gitignore index 037872e66..525662725 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,8 @@ polytope.egg-info .pytest_cache *.prof -*.idx \ No newline at end of file +*.idx +*.grib +*.xml +site +.coverage \ No newline at end of file diff --git a/polytope/datacube/backends/xarray.py b/polytope/datacube/backends/xarray.py index 0d244764e..01d6a2915 100644 --- a/polytope/datacube/backends/xarray.py +++ b/polytope/datacube/backends/xarray.py @@ -49,14 +49,13 @@ def __init__(self, dataarray: xr.DataArray, axis_options={}): def get(self, requests: IndexTree): for r in requests.leaves: path = r.flatten() - # path = self.remap_path(path) if len(path.items()) == self.axis_counter: # first, find the grid mapper transform unmapped_path = {} path_copy = deepcopy(path) for key in path_copy: axis = self._axes[key] - (path, unmapped_path) = axis.unmap_total_path_to_datacube(path, unmapped_path) + (path, unmapped_path) = axis.unmap_to_datacube(path, unmapped_path) path = self.fit_path(path) subxarray = self.dataarray.sel(path, method="nearest") subxarray = subxarray.sel(unmapped_path) @@ -67,8 +66,6 @@ def get(self, requests: IndexTree): r.remove_branch() def datacube_natural_indexes(self, axis, subarray): - # if axis.name in self.fake_axes: - # indexes = subarray[axis.name].values if axis.name in self.complete_axes: indexes = next(iter(subarray.xindexes.values())).to_pandas_index() else: diff --git a/polytope/datacube/datacube_axis.py b/polytope/datacube/datacube_axis.py index 00102800d..2d3160354 100644 --- a/polytope/datacube/datacube_axis.py +++ b/polytope/datacube/datacube_axis.py @@ -118,20 +118,6 @@ def remap(range: List): def find_indexes(path, datacube): return old_find_indexes(path, datacube) - old_unmap_total_path_to_datacube = cls.unmap_total_path_to_datacube - - def unmap_total_path_to_datacube(path, unmapped_path): - for transform in cls.transformations: - if isinstance(transform, DatacubeAxisCyclic): - transformation = transform - if cls.name == transformation.name: - old_val = path.get(cls.name, None) - path.pop(cls.name, None) - new_val = _remap_val_to_axis_range(old_val) - path[cls.name] = new_val - (path, unmapped_path) = old_unmap_total_path_to_datacube(path, unmapped_path) - return (path, unmapped_path) - old_n_unmap_path_key = cls.n_unmap_path_key def n_unmap_path_key(key_value_path, leaf_path, unwanted_path): @@ -195,7 +181,6 @@ def offset(range): cls.offset = offset cls.find_indexes = find_indexes cls.unmap_to_datacube = unmap_to_datacube - cls.unmap_total_path_to_datacube = unmap_total_path_to_datacube cls.find_indices_between = find_indices_between cls.n_unmap_path_key = n_unmap_path_key @@ -247,43 +232,6 @@ def unmap_to_datacube(path, unmapped_path): unmapped_path[transform.old_axis] = unmapped_idx return (path, unmapped_path) - old_unmap_total_path_to_datacube = cls.unmap_total_path_to_datacube - - def unmap_total_path_to_datacube(path, unmapped_path): - # TODO: to be faster, could just compute the first lat unmapped idx, and do +1 for each subsequent lat idx? - (path, unmapped_path) = old_unmap_total_path_to_datacube(path, unmapped_path) - for transform in cls.transformations: - if isinstance(transform, DatacubeMapper): - if cls.name == transform._mapped_axes()[0]: - # if we are on the first axis, then need to add the first val to unmapped_path - first_val = path[cls.name] - del path[cls.name] - - if unmapped_path is None: - unmapped_path[cls.name] = first_val - elif cls.name not in unmapped_path: - # if for some reason, the unmapped_path already has the first axis val, then don't update - unmapped_path[cls.name] = first_val - if cls.name == transform._mapped_axes()[1]: - # if we are on the second axis, then the val of the first axis is stored - # inside unmapped_path so can get it from there - second_val = path[cls.name] - del path[cls.name] - first_val = unmapped_path.get(transform._mapped_axes()[0], None) - - unmapped_path.pop(transform._mapped_axes()[0], None) - # NOTE: here we first calculate the starting idx of the first_val grid line - # and then append the second_idx to get the final unmapped_idx - # To do this, also need to find second_idx from second_val... - - # if the first_val was not in the unmapped_path, then it's still in path - if first_val is None: - first_val = path.get(transform._mapped_axes()[0], None) - path.pop(transform._mapped_axes()[0], None) - unmapped_idx = transform.unmap(first_val, second_val) - unmapped_path[transform.old_axis] = unmapped_idx - return (path, unmapped_path) - old_n_unmap_path_key = cls.n_unmap_path_key def n_unmap_path_key(key_value_path, leaf_path, unwanted_path): @@ -340,7 +288,6 @@ def remap(range): cls.find_indexes = find_indexes cls.unmap_to_datacube = unmap_to_datacube cls.find_indices_between = find_indices_between - cls.unmap_total_path_to_datacube = unmap_total_path_to_datacube cls.n_unmap_path_key = n_unmap_path_key return cls @@ -359,20 +306,6 @@ def find_indexes(path, datacube): if cls.name == transformation._first_axis: return transformation.merged_values(datacube) - old_unmap_total_path_to_datacube = cls.unmap_total_path_to_datacube - - def unmap_total_path_to_datacube(path, unmapped_path): - (path, unmapped_path) = old_unmap_total_path_to_datacube(path, unmapped_path) - for transform in cls.transformations: - if isinstance(transform, DatacubeAxisMerger): - transformation = transform - if cls.name == transformation._first_axis: - old_val = path[cls.name] - (first_val, second_val) = transformation.unmerge(old_val) - path[transformation._first_axis] = first_val - path[transformation._second_axis] = second_val - return (path, unmapped_path) - old_n_unmap_path_key = cls.n_unmap_path_key def n_unmap_path_key(key_value_path, leaf_path, unwanted_path): @@ -431,7 +364,6 @@ def remap(range): cls.find_indexes = find_indexes cls.unmap_to_datacube = unmap_to_datacube cls.find_indices_between = find_indices_between - cls.unmap_total_path_to_datacube = unmap_total_path_to_datacube cls.n_unmap_path_key = n_unmap_path_key return cls @@ -452,9 +384,6 @@ def find_indexes(path, datacube): ordered_indices = unordered_indices return ordered_indices - def unmap_to_datacube(path, unmapped_path): - return (path, unmapped_path) - def find_indices_between(index_ranges, low, up, datacube, method=None): # TODO: add method for snappping indexes_between_ranges = [] @@ -500,7 +429,6 @@ def remap(range): cls.remap = remap cls.find_indexes = find_indexes - cls.unmap_to_datacube = unmap_to_datacube cls.find_indices_between = find_indices_between return cls @@ -520,21 +448,6 @@ def find_indexes(path, datacube): original_vals = old_find_indexes(path, datacube) return transformation.change_val_type(cls.name, original_vals) - old_unmap_total_path_to_datacube = cls.unmap_total_path_to_datacube - - def unmap_total_path_to_datacube(path, unmapped_path): - (path, unmapped_path) = old_unmap_total_path_to_datacube(path, unmapped_path) - for transform in cls.transformations: - if isinstance(transform, DatacubeAxisTypeChange): - transformation = transform - if cls.name == transformation.name: - changed_val = path.get(cls.name, None) - unchanged_val = transformation.make_str(changed_val) - if cls.name in path: - path.pop(cls.name, None) - unmapped_path[cls.name] = unchanged_val - return (path, unmapped_path) - old_n_unmap_path_key = cls.n_unmap_path_key def n_unmap_path_key(key_value_path, leaf_path, unwanted_path): @@ -588,7 +501,6 @@ def remap(range): cls.find_indexes = find_indexes cls.unmap_to_datacube = unmap_to_datacube cls.find_indices_between = find_indices_between - cls.unmap_total_path_to_datacube = unmap_total_path_to_datacube cls.n_unmap_path_key = n_unmap_path_key return cls @@ -601,14 +513,6 @@ def null(cls): def find_indexes(path, datacube): return old_find_indexes(path, datacube) - old_unmap_total_path_to_datacube = cls.unmap_total_path_to_datacube - - def unmap_total_path_to_datacube(path, unmapped_path): - return old_unmap_total_path_to_datacube(path, unmapped_path) - - def unmap_to_datacube(path, unmapped_path): - return (path, unmapped_path) - def find_indices_between(index_ranges, low, up, datacube, method=None): indexes_between_ranges = [] for indexes in index_ranges: @@ -621,9 +525,7 @@ def remap(range): cls.remap = remap cls.find_indexes = find_indexes - cls.unmap_to_datacube = unmap_to_datacube cls.find_indices_between = find_indices_between - cls.unmap_total_path_to_datacube = unmap_total_path_to_datacube return cls @@ -679,9 +581,6 @@ def find_indexes(self, path, datacube): def offset(self, value): return 0 - def unmap_total_path_to_datacube(self, path, unmapped_path): - return (path, unmapped_path) - def n_unmap_path_key(self, key_value_path, leaf_path, unwanted_path): return (key_value_path, leaf_path, unwanted_path) From 1065c722ee8756f83f1e447c543ce8e68e4b4747 Mon Sep 17 00:00:00 2001 From: Mathilde Leuridan Date: Tue, 14 Nov 2023 11:44:47 +0100 Subject: [PATCH 29/37] remove unnecessary code --- polytope/datacube/datacube_axis.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/polytope/datacube/datacube_axis.py b/polytope/datacube/datacube_axis.py index 2d3160354..77ad107e0 100644 --- a/polytope/datacube/datacube_axis.py +++ b/polytope/datacube/datacube_axis.py @@ -279,12 +279,6 @@ def find_indices_between(index_ranges, low, up, datacube, method=None): indexes_between_ranges.append(indexes_between) return indexes_between_ranges - old_remap = cls.remap - - def remap(range): - return old_remap(range) - - cls.remap = remap cls.find_indexes = find_indexes cls.unmap_to_datacube = unmap_to_datacube cls.find_indices_between = find_indices_between From 6fffbffd6b6e702c41566c08dc6c9ba5dc05929e Mon Sep 17 00:00:00 2001 From: Mathilde Leuridan Date: Wed, 15 Nov 2023 15:00:25 +0100 Subject: [PATCH 30/37] renaming and small fixes --- performance/fdb_performance.py | 2 +- performance/fdb_performance_3D.py | 2 +- .../backends/{FDB_datacube.py => fdb.py} | 51 +++++++------------ polytope/datacube/backends/xarray.py | 2 - polytope/datacube/datacube_axis.py | 34 ++++++------- tests/test_fdb_datacube.py | 2 +- tests/test_regular_grid.py | 2 +- 7 files changed, 38 insertions(+), 57 deletions(-) rename polytope/datacube/backends/{FDB_datacube.py => fdb.py} (87%) diff --git a/performance/fdb_performance.py b/performance/fdb_performance.py index 4ee8715be..78819d462 100644 --- a/performance/fdb_performance.py +++ b/performance/fdb_performance.py @@ -2,7 +2,7 @@ import pandas as pd -from polytope.datacube.backends.FDB_datacube import FDBDatacube +from polytope.datacube.backends.fdb import FDBDatacube from polytope.engine.hullslicer import HullSlicer from polytope.polytope import Polytope, Request from polytope.shapes import Box, Select diff --git a/performance/fdb_performance_3D.py b/performance/fdb_performance_3D.py index 2cfec94cf..547d865b0 100644 --- a/performance/fdb_performance_3D.py +++ b/performance/fdb_performance_3D.py @@ -2,7 +2,7 @@ import pandas as pd -from polytope.datacube.backends.FDB_datacube import FDBDatacube +from polytope.datacube.backends.fdb import FDBDatacube from polytope.engine.hullslicer import HullSlicer from polytope.polytope import Polytope, Request from polytope.shapes import Box, Select, Span diff --git a/polytope/datacube/backends/FDB_datacube.py b/polytope/datacube/backends/fdb.py similarity index 87% rename from polytope/datacube/backends/FDB_datacube.py rename to polytope/datacube/backends/fdb.py index 70a867cf0..34b455364 100644 --- a/polytope/datacube/backends/FDB_datacube.py +++ b/polytope/datacube/backends/fdb.py @@ -5,15 +5,9 @@ from .datacube import Datacube, IndexTree -def update_fdb_dataarray(fdb_dataarray): - fdb_dataarray["values"] = [] - return fdb_dataarray - - class FDBDatacube(Datacube): def __init__(self, config={}, axis_options={}): self.axis_options = axis_options - self.grid_mapper = None self.axis_counter = 0 self._axes = None treated_axes = [] @@ -21,31 +15,16 @@ def __init__(self, config={}, axis_options={}): self.complete_axes = [] self.blocked_axes = [] self.unwanted_axes = [] - self.transformation = None self.fake_axes = [] - self.final_path = { - "class": 0, - "date": 0, - "domain": 0, - "expver": 0, - "levtype": 0, - "param": 0, - "step": 0, - "stream": 0, - "time": 0, - "type": 0, - "values": 0, - } self.unwanted_path = {} partial_request = config # Find values in the level 3 FDB datacube # Will be in the form of a dictionary? {axis_name:values_available, ...} self.fdb = pyfdb.FDB() - fdb_dataarray = self.fdb.axes(partial_request).as_dict() - dataarray = update_fdb_dataarray(fdb_dataarray) - self.dataarray = dataarray - for name, values in dataarray.items(): + self.fdb_coordinates = self.fdb.axes(partial_request).as_dict() + self.fdb_coordinates["values"] = [] + for name, values in self.fdb_coordinates.items(): values.sort() options = axis_options.get(name, {}) self._check_and_add_axes(options, name, values) @@ -77,7 +56,7 @@ def get(self, requests: IndexTree, leaf_path={}): else: key_value_path = {requests.axis.name: requests.value} ax = requests.axis - (key_value_path, leaf_path, self.unwanted_path) = ax.n_unmap_path_key( + (key_value_path, leaf_path, self.unwanted_path) = ax.unmap_path_key( key_value_path, leaf_path, self.unwanted_path ) leaf_path |= key_value_path @@ -91,18 +70,22 @@ def get(self, requests: IndexTree, leaf_path={}): self.get(c, leaf_path) def handle_last_before_last_layer(self, requests, leaf_path={}): - range_lengths = [[1] * 200] * 200 - current_start_idxs = [[None] * 200] * 200 - fdb_node_ranges = [[[IndexTree.root] * 200] * 200] * 200 lat_length = len(requests.children) + range_lengths = [False] * lat_length + current_start_idxs = [False] * lat_length + fdb_node_ranges = [False] * lat_length for i in range(len(requests.children)): lat_child = requests.children[i] + lon_length = len(lat_child.children) + range_lengths[i] = [1] * lon_length + current_start_idxs[i] = [None] * lon_length + fdb_node_ranges[i] = [[IndexTree.root] * lon_length] * lon_length range_length = deepcopy(range_lengths[i]) current_start_idx = deepcopy(current_start_idxs[i]) fdb_range_nodes = deepcopy(fdb_node_ranges[i]) key_value_path = {lat_child.axis.name: lat_child.value} ax = lat_child.axis - (key_value_path, leaf_path, self.unwanted_path) = ax.n_unmap_path_key( + (key_value_path, leaf_path, self.unwanted_path) = ax.unmap_path_key( key_value_path, leaf_path, self.unwanted_path ) leaf_path |= key_value_path @@ -117,7 +100,7 @@ def get_last_layer_before_leaf(self, requests, leaf_path, range_l, current_idx, # now c are the leaves of the initial tree key_value_path = {c.axis.name: c.value} ax = c.axis - (key_value_path, leaf_path, self.unwanted_path) = ax.n_unmap_path_key( + (key_value_path, leaf_path, self.unwanted_path) = ax.unmap_path_key( key_value_path, leaf_path, self.unwanted_path ) leaf_path |= key_value_path @@ -132,7 +115,7 @@ def get_last_layer_before_leaf(self, requests, leaf_path, range_l, current_idx, else: key_value_path = {c.axis.name: c.value} ax = c.axis - (key_value_path, leaf_path, self.unwanted_path) = ax.n_unmap_path_key( + (key_value_path, leaf_path, self.unwanted_path) = ax.unmap_path_key( key_value_path, leaf_path, self.unwanted_path ) leaf_path |= key_value_path @@ -164,7 +147,7 @@ def find_fdb_values(self, path, range_lengths, current_start_idx, lat_length): fdb_requests = [] interm_request_ranges = [] for i in range(lat_length): - for j in range(200): + for j in range(len(range_lengths[i])): if current_start_idx[i][j] is not None: current_request_ranges = (current_start_idx[i][j], current_start_idx[i][j] + range_lengths[i][j]) interm_request_ranges.append(current_request_ranges) @@ -182,7 +165,7 @@ def datacube_natural_indexes(self, axis, subarray): return indexes def select(self, path, unmapped_path): - return self.dataarray + return self.fdb_coordinates def ax_vals(self, name): - return self.dataarray.get(name, None) + return self.fdb_coordinates.get(name, None) diff --git a/polytope/datacube/backends/xarray.py b/polytope/datacube/backends/xarray.py index 01d6a2915..650038e05 100644 --- a/polytope/datacube/backends/xarray.py +++ b/polytope/datacube/backends/xarray.py @@ -10,7 +10,6 @@ class XArrayDatacube(Datacube): def __init__(self, dataarray: xr.DataArray, axis_options={}): self.axis_options = axis_options - self.grid_mapper = None self.axis_counter = 0 self._axes = None self.dataarray = dataarray @@ -18,7 +17,6 @@ def __init__(self, dataarray: xr.DataArray, axis_options={}): self.non_complete_axes = [] self.complete_axes = [] self.blocked_axes = [] - self.transformation = None self.fake_axes = [] self.unwanted_axes = [] for name, values in dataarray.coords.variables.items(): diff --git a/polytope/datacube/datacube_axis.py b/polytope/datacube/datacube_axis.py index 77ad107e0..508caa849 100644 --- a/polytope/datacube/datacube_axis.py +++ b/polytope/datacube/datacube_axis.py @@ -118,16 +118,16 @@ def remap(range: List): def find_indexes(path, datacube): return old_find_indexes(path, datacube) - old_n_unmap_path_key = cls.n_unmap_path_key + old_unmap_path_key = cls.unmap_path_key - def n_unmap_path_key(key_value_path, leaf_path, unwanted_path): + def unmap_path_key(key_value_path, leaf_path, unwanted_path): value = key_value_path[cls.name] for transform in cls.transformations: if isinstance(transform, DatacubeAxisCyclic): if cls.name == transform.name: new_val = _remap_val_to_axis_range(value) key_value_path[cls.name] = new_val - key_value_path, leaf_path, unwanted_path = old_n_unmap_path_key(key_value_path, leaf_path, unwanted_path) + key_value_path, leaf_path, unwanted_path = old_unmap_path_key(key_value_path, leaf_path, unwanted_path) return (key_value_path, leaf_path, unwanted_path) old_unmap_to_datacube = cls.unmap_to_datacube @@ -182,7 +182,7 @@ def offset(range): cls.find_indexes = find_indexes cls.unmap_to_datacube = unmap_to_datacube cls.find_indices_between = find_indices_between - cls.n_unmap_path_key = n_unmap_path_key + cls.unmap_path_key = unmap_path_key return cls @@ -232,10 +232,10 @@ def unmap_to_datacube(path, unmapped_path): unmapped_path[transform.old_axis] = unmapped_idx return (path, unmapped_path) - old_n_unmap_path_key = cls.n_unmap_path_key + old_unmap_path_key = cls.unmap_path_key - def n_unmap_path_key(key_value_path, leaf_path, unwanted_path): - key_value_path, leaf_path, unwanted_path = old_n_unmap_path_key(key_value_path, leaf_path, unwanted_path) + def unmap_path_key(key_value_path, leaf_path, unwanted_path): + key_value_path, leaf_path, unwanted_path = old_unmap_path_key(key_value_path, leaf_path, unwanted_path) value = key_value_path[cls.name] for transform in cls.transformations: if isinstance(transform, DatacubeMapper): @@ -282,7 +282,7 @@ def find_indices_between(index_ranges, low, up, datacube, method=None): cls.find_indexes = find_indexes cls.unmap_to_datacube = unmap_to_datacube cls.find_indices_between = find_indices_between - cls.n_unmap_path_key = n_unmap_path_key + cls.unmap_path_key = unmap_path_key return cls @@ -300,10 +300,10 @@ def find_indexes(path, datacube): if cls.name == transformation._first_axis: return transformation.merged_values(datacube) - old_n_unmap_path_key = cls.n_unmap_path_key + old_unmap_path_key = cls.unmap_path_key - def n_unmap_path_key(key_value_path, leaf_path, unwanted_path): - key_value_path, leaf_path, unwanted_path = old_n_unmap_path_key(key_value_path, leaf_path, unwanted_path) + def unmap_path_key(key_value_path, leaf_path, unwanted_path): + key_value_path, leaf_path, unwanted_path = old_unmap_path_key(key_value_path, leaf_path, unwanted_path) new_key_value_path = {} value = key_value_path[cls.name] for transform in cls.transformations: @@ -358,7 +358,7 @@ def remap(range): cls.find_indexes = find_indexes cls.unmap_to_datacube = unmap_to_datacube cls.find_indices_between = find_indices_between - cls.n_unmap_path_key = n_unmap_path_key + cls.unmap_path_key = unmap_path_key return cls @@ -442,10 +442,10 @@ def find_indexes(path, datacube): original_vals = old_find_indexes(path, datacube) return transformation.change_val_type(cls.name, original_vals) - old_n_unmap_path_key = cls.n_unmap_path_key + old_unmap_path_key = cls.unmap_path_key - def n_unmap_path_key(key_value_path, leaf_path, unwanted_path): - key_value_path, leaf_path, unwanted_path = old_n_unmap_path_key(key_value_path, leaf_path, unwanted_path) + def unmap_path_key(key_value_path, leaf_path, unwanted_path): + key_value_path, leaf_path, unwanted_path = old_unmap_path_key(key_value_path, leaf_path, unwanted_path) value = key_value_path[cls.name] for transform in cls.transformations: if isinstance(transform, DatacubeAxisTypeChange): @@ -495,7 +495,7 @@ def remap(range): cls.find_indexes = find_indexes cls.unmap_to_datacube = unmap_to_datacube cls.find_indices_between = find_indices_between - cls.n_unmap_path_key = n_unmap_path_key + cls.unmap_path_key = unmap_path_key return cls @@ -575,7 +575,7 @@ def find_indexes(self, path, datacube): def offset(self, value): return 0 - def n_unmap_path_key(self, key_value_path, leaf_path, unwanted_path): + def unmap_path_key(self, key_value_path, leaf_path, unwanted_path): return (key_value_path, leaf_path, unwanted_path) def find_indices_between(self, index_ranges, low, up, datacube, method=None): diff --git a/tests/test_fdb_datacube.py b/tests/test_fdb_datacube.py index 952b0bb7b..84b3b2059 100644 --- a/tests/test_fdb_datacube.py +++ b/tests/test_fdb_datacube.py @@ -1,7 +1,7 @@ import pandas as pd import pytest -from polytope.datacube.backends.FDB_datacube import FDBDatacube +from polytope.datacube.backends.fdb import FDBDatacube from polytope.engine.hullslicer import HullSlicer from polytope.polytope import Polytope, Request from polytope.shapes import Box, Select diff --git a/tests/test_regular_grid.py b/tests/test_regular_grid.py index c32a7760f..c4d16baf7 100644 --- a/tests/test_regular_grid.py +++ b/tests/test_regular_grid.py @@ -3,7 +3,7 @@ from eccodes import codes_grib_find_nearest, codes_grib_new_from_file from helper_functions import download_test_data -from polytope.datacube.backends.FDB_datacube import FDBDatacube +from polytope.datacube.backends.fdb import FDBDatacube from polytope.engine.hullslicer import HullSlicer from polytope.polytope import Polytope, Request from polytope.shapes import Disk, Select From eef415dea5ca80e59730e7ba126514d55bb421c5 Mon Sep 17 00:00:00 2001 From: Mathilde Leuridan Date: Thu, 16 Nov 2023 10:37:36 +0100 Subject: [PATCH 31/37] renaming --- polytope/datacube/backends/fdb.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/polytope/datacube/backends/fdb.py b/polytope/datacube/backends/fdb.py index 34b455364..30f3d2a9c 100644 --- a/polytope/datacube/backends/fdb.py +++ b/polytope/datacube/backends/fdb.py @@ -51,8 +51,7 @@ def get(self, requests: IndexTree, leaf_path={}): else: for c in requests.children: self.get(c) - - # Second if request node has no children, we have a leaf so need to assign fdb values to it + # If request node has no children, we have a leaf so need to assign fdb values to it else: key_value_path = {requests.axis.name: requests.value} ax = requests.axis @@ -62,14 +61,16 @@ def get(self, requests: IndexTree, leaf_path={}): leaf_path |= key_value_path if len(requests.children[0].children[0].children) == 0: # remap this last key - self.handle_last_before_last_layer(requests, leaf_path) + self.get_2nd_last_values(requests, leaf_path) - # THIRD otherwise remap the path for this key and iterate again over children + # Otherwise remap the path for this key and iterate again over children else: for c in requests.children: self.get(c, leaf_path) - def handle_last_before_last_layer(self, requests, leaf_path={}): + def get_2nd_last_values(self, requests, leaf_path={}): + # In this function, we recursively loop over the last two layers of the tree and store the indices of the + # request ranges in those layers lat_length = len(requests.children) range_lengths = [False] * lat_length current_start_idxs = [False] * lat_length From 0dfabef4ec6847d3cf064f466c58f9b8ef0f6df3 Mon Sep 17 00:00:00 2001 From: Mathilde Leuridan Date: Mon, 20 Nov 2023 12:13:18 +0100 Subject: [PATCH 32/37] fix regular grid problem with too many points found --- .../transformations/datacube_mappers.py | 30 +++++++++++-------- polytope/shapes.py | 1 - tests/test_healpix_mapper.py | 6 ++-- tests/test_regular_grid.py | 8 +++-- 4 files changed, 26 insertions(+), 19 deletions(-) diff --git a/polytope/datacube/transformations/datacube_mappers.py b/polytope/datacube/transformations/datacube_mappers.py index 34af16bdc..22478f217 100644 --- a/polytope/datacube/transformations/datacube_mappers.py +++ b/polytope/datacube/transformations/datacube_mappers.py @@ -83,13 +83,14 @@ def __init__(self, base_axis, mapped_axes, resolution): self._resolution = resolution self.deg_increment = 90 / self._resolution self._axis_reversed = {mapped_axes[0]: True, mapped_axes[1]: False} + self._first_axis_vals = self.first_axis_vals() def first_axis_vals(self): - first_ax_vals = [-90 + i * self.deg_increment for i in range(2 * self._resolution)] + first_ax_vals = [90 - i * self.deg_increment for i in range(2 * self._resolution)] return first_ax_vals def map_first_axis(self, lower, upper): - axis_lines = self.first_axis_vals() + axis_lines = self._first_axis_vals return_vals = [val for val in axis_lines if lower <= val <= upper] return return_vals @@ -114,14 +115,14 @@ def find_second_idx(self, first_val, second_val): def unmap_first_val_to_start_line_idx(self, first_val): tol = 1e-8 - first_val = [i for i in self.first_axis_vals() if first_val - tol <= i <= first_val + tol][0] - first_idx = self.first_axis_vals().index(first_val) + first_val = [i for i in self._first_axis_vals if first_val - tol <= i <= first_val + tol][0] + first_idx = self._first_axis_vals.index(first_val) return first_idx * 4 * self._resolution def unmap(self, first_val, second_val): tol = 1e-8 - first_val = [i for i in self.first_axis_vals() if first_val - tol <= i <= first_val + tol][0] - first_idx = self.first_axis_vals().index(first_val) + first_val = [i for i in self._first_axis_vals if first_val - tol <= i <= first_val + tol][0] + first_idx = self._first_axis_vals.index(first_val) second_val = [i for i in self.second_axis_vals(first_val) if second_val - tol <= i <= second_val + tol][0] second_idx = self.second_axis_vals(first_val).index(second_val) final_index = self.axes_idx_to_regular_idx(first_idx, second_idx) @@ -134,6 +135,7 @@ def __init__(self, base_axis, mapped_axes, resolution): self._base_axis = base_axis self._resolution = resolution self._axis_reversed = {mapped_axes[0]: True, mapped_axes[1]: False} + self._first_axis_vals = self.first_axis_vals() def first_axis_vals(self): rad2deg = 180 / math.pi @@ -155,14 +157,14 @@ def first_axis_vals(self): return vals def map_first_axis(self, lower, upper): - axis_lines = self.first_axis_vals() + axis_lines = self._first_axis_vals return_vals = [val for val in axis_lines if lower <= val <= upper] return return_vals def second_axis_vals(self, first_val): tol = 1e-8 - first_val = [i for i in self.first_axis_vals() if first_val - tol <= i <= first_val + tol][0] - idx = self.first_axis_vals().index(first_val) + first_val = [i for i in self._first_axis_vals if first_val - tol <= i <= first_val + tol][0] + idx = self._first_axis_vals.index(first_val) # Polar caps if idx < self._resolution - 1 or 3 * self._resolution - 1 < idx <= 4 * self._resolution - 2: @@ -214,8 +216,8 @@ def find_second_idx(self, first_val, second_val): def unmap_first_val_to_start_line_idx(self, first_val): tol = 1e-8 - first_val = [i for i in self.first_axis_vals() if first_val - tol <= i <= first_val + tol][0] - first_idx = self.first_axis_vals().index(first_val) + first_val = [i for i in self._first_axis_vals if first_val - tol <= i <= first_val + tol][0] + first_idx = self._first_axis_vals.index(first_val) idx = 0 for i in range(self._resolution - 1): if i != first_idx: @@ -235,8 +237,10 @@ def unmap_first_val_to_start_line_idx(self, first_val): def unmap(self, first_val, second_val): tol = 1e-8 - first_val = [i for i in self.first_axis_vals() if first_val - tol <= i <= first_val + tol][0] - first_idx = self.first_axis_vals().index(first_val) + first_val = [i for i in self._first_axis_vals if first_val - tol <= i <= first_val + tol][0] + first_idx = self._first_axis_vals.index(first_val) + print(self.second_axis_vals(first_val)) + print(second_val) second_val = [i for i in self.second_axis_vals(first_val) if second_val - tol <= i <= second_val + tol][0] second_idx = self.second_axis_vals(first_val).index(second_val) healpix_index = self.axes_idx_to_healpix_idx(first_idx, second_idx) diff --git a/polytope/shapes.py b/polytope/shapes.py index 59ac39fd0..5ec6e10a0 100644 --- a/polytope/shapes.py +++ b/polytope/shapes.py @@ -110,7 +110,6 @@ def __init__(self, axes, lower_corner=None, upper_corner=None): if i >> d & 1: vertex[d] = upper_corner[d] self.vertices.append(vertex) - assert lower_corner in self.vertices assert upper_corner in self.vertices assert len(self.vertices) == 2**dimension diff --git a/tests/test_healpix_mapper.py b/tests/test_healpix_mapper.py index c80d51042..6487bd9ba 100644 --- a/tests/test_healpix_mapper.py +++ b/tests/test_healpix_mapper.py @@ -20,7 +20,8 @@ def setup_method(self, method): self.options = { "values": { "transformation": {"mapper": {"type": "healpix", "resolution": 32, "axes": ["latitude", "longitude"]}} - } + }, + "longitude": {"transformation": {"cyclic": [0, 360]}} } self.slicer = HullSlicer() self.API = Polytope(datacube=self.latlon_array, engine=self.slicer, axis_options=self.options) @@ -49,7 +50,7 @@ def find_nearest_latlon(self, grib_file, target_lat, target_lon): return nearest_points @pytest.mark.internet - def test_octahedral_grid(self): + def test_healpix_grid(self): request = Request( Box(["latitude", "longitude"], [-2, -2], [10, 10]), Select("time", ["2022-12-14T12:00:00"]), @@ -58,6 +59,7 @@ def test_octahedral_grid(self): Select("valid_time", ["2022-12-14T13:00:00"]), ) result = self.API.retrieve(request) + result.pprint() assert len(result.leaves) == 35 lats = [] diff --git a/tests/test_regular_grid.py b/tests/test_regular_grid.py index c4d16baf7..86337b6f0 100644 --- a/tests/test_regular_grid.py +++ b/tests/test_regular_grid.py @@ -22,6 +22,8 @@ def setup_method(self, method): }, "date": {"transformation": {"merge": {"with": "time", "linkers": [" ", "00"]}}}, "step": {"transformation": {"type_change": "int"}}, + "number": {"transformation": {"type_change": "int"}}, + "longitude": {"transformation": {"cyclic": [0, 360]}}, } self.config = {"class": "ea", "expver": "0001", "levtype": "pl", "step": 0} self.fdbdatacube = FDBDatacube(self.config, axis_options=self.options) @@ -64,13 +66,13 @@ def test_regular_grid(self): Select("class", ["ea"]), Select("stream", ["enda"]), Select("type", ["an"]), - Disk(["latitude", "longitude"], [0, 0], [15, 15]), + Disk(["latitude", "longitude"], [0, 0], [3, 3]), Select("levelist", ["500"]), Select("number", ["0", "1"]), ) result = self.API.retrieve(request) result.pprint() - assert len(result.leaves) == 46 * 2 + assert len(result.leaves) == 10 lats = [] lons = [] @@ -99,4 +101,4 @@ def test_regular_grid(self): # plt.colorbar(label="Temperature") # plt.show() - assert len(eccodes_lats) == 46 * 2 + assert len(eccodes_lats) == 10 From 458531d9749cf392c2c0d8d4eddb1169bdeda791 Mon Sep 17 00:00:00 2001 From: Mathilde Leuridan Date: Mon, 20 Nov 2023 15:49:20 +0100 Subject: [PATCH 33/37] make healpix grid work with cyclic axes --- polytope/datacube/transformations/datacube_mappers.py | 9 +++++---- tests/test_healpix_mapper.py | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/polytope/datacube/transformations/datacube_mappers.py b/polytope/datacube/transformations/datacube_mappers.py index 22478f217..f759a00bf 100644 --- a/polytope/datacube/transformations/datacube_mappers.py +++ b/polytope/datacube/transformations/datacube_mappers.py @@ -153,7 +153,6 @@ def first_axis_vals(self): vals[4 * self._resolution - 1 - i] = -val # Equator vals[2 * self._resolution - 1] = 0 - return vals def map_first_axis(self, lower, upper): @@ -176,6 +175,8 @@ def second_axis_vals(self, first_val): if self._resolution - 1 <= idx < 2 * self._resolution - 1 or 2 * self._resolution <= idx < 3 * self._resolution: r_start = start * (2 - (((idx + 1) - self._resolution + 1) % 2)) vals = [r_start + i * (360 / (4 * self._resolution)) for i in range(4 * self._resolution)] + if vals[-1] == 360: + vals[-1] = 0 return vals # Equator temp_val = 1 if self._resolution % 2 else 0 @@ -196,17 +197,19 @@ def axes_idx_to_healpix_idx(self, first_idx, second_idx): idx += 4 * (i + 1) else: idx += second_idx + return idx for i in range(self._resolution - 1, 3 * self._resolution): if i != first_idx: idx += 4 * self._resolution else: idx += second_idx + return idx for i in range(3 * self._resolution, 4 * self._resolution - 1): if i != first_idx: idx += 4 * (4 * self._resolution - 1 - i + 1) else: idx += second_idx - return idx + return idx def find_second_idx(self, first_val, second_val): tol = 1e-10 @@ -239,8 +242,6 @@ def unmap(self, first_val, second_val): tol = 1e-8 first_val = [i for i in self._first_axis_vals if first_val - tol <= i <= first_val + tol][0] first_idx = self._first_axis_vals.index(first_val) - print(self.second_axis_vals(first_val)) - print(second_val) second_val = [i for i in self.second_axis_vals(first_val) if second_val - tol <= i <= second_val + tol][0] second_idx = self.second_axis_vals(first_val).index(second_val) healpix_index = self.axes_idx_to_healpix_idx(first_idx, second_idx) diff --git a/tests/test_healpix_mapper.py b/tests/test_healpix_mapper.py index 6487bd9ba..bcdc7e3e5 100644 --- a/tests/test_healpix_mapper.py +++ b/tests/test_healpix_mapper.py @@ -60,7 +60,7 @@ def test_healpix_grid(self): ) result = self.API.retrieve(request) result.pprint() - assert len(result.leaves) == 35 + assert len(result.leaves) == 40 lats = [] lons = [] @@ -80,4 +80,4 @@ def test_healpix_grid(self): assert lat <= eccodes_lat + tol assert eccodes_lon - tol <= lon assert lon <= eccodes_lon + tol - assert len(eccodes_lats) == 35 + assert len(eccodes_lats) == 40 From ec07170deae56dfeb6323a6d16b05608904e42ce Mon Sep 17 00:00:00 2001 From: Mathilde Leuridan Date: Mon, 20 Nov 2023 15:52:15 +0100 Subject: [PATCH 34/37] black --- tests/test_healpix_mapper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_healpix_mapper.py b/tests/test_healpix_mapper.py index bcdc7e3e5..9014e5e3a 100644 --- a/tests/test_healpix_mapper.py +++ b/tests/test_healpix_mapper.py @@ -21,7 +21,7 @@ def setup_method(self, method): "values": { "transformation": {"mapper": {"type": "healpix", "resolution": 32, "axes": ["latitude", "longitude"]}} }, - "longitude": {"transformation": {"cyclic": [0, 360]}} + "longitude": {"transformation": {"cyclic": [0, 360]}}, } self.slicer = HullSlicer() self.API = Polytope(datacube=self.latlon_array, engine=self.slicer, axis_options=self.options) From d4697b85e1cb8e278018d0debe52861f3469838c Mon Sep 17 00:00:00 2001 From: Mathilde Leuridan Date: Tue, 21 Nov 2023 10:00:01 +0100 Subject: [PATCH 35/37] fdb axes indices are not always in sorted order --- polytope/datacube/transformations/datacube_type_change.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/polytope/datacube/transformations/datacube_type_change.py b/polytope/datacube/transformations/datacube_type_change.py index 8dee75341..cdc046b76 100644 --- a/polytope/datacube/transformations/datacube_type_change.py +++ b/polytope/datacube/transformations/datacube_type_change.py @@ -24,7 +24,9 @@ def transformation_axes_final(self): return [self._final_transformation.axis_name] def change_val_type(self, axis_name, values): - return [self._final_transformation.transform_type(val) for val in values] + return_idx = [self._final_transformation.transform_type(val) for val in values] + return_idx.sort() + return return_idx def make_str(self, value): return self._final_transformation.make_str(value) From 4f72f1fad5659e32ca15c282700e224458d7dcab Mon Sep 17 00:00:00 2001 From: Mathilde Leuridan Date: Wed, 22 Nov 2023 09:39:28 +0100 Subject: [PATCH 36/37] small fixes --- polytope/datacube/backends/fdb.py | 18 ++--- polytope/engine/hullslicer.py | 7 +- tests/test_datacube_axes_init.py | 1 - tests/test_fdb_datacube.py | 2 +- tests/test_incomplete_tree_fdb.py | 97 +++++++++++++++++++++++++++ tests/test_merge_cyclic_octahedral.py | 1 - tests/test_merge_transformation.py | 1 - tests/test_regular_grid.py | 2 +- 8 files changed, 114 insertions(+), 15 deletions(-) create mode 100644 tests/test_incomplete_tree_fdb.py diff --git a/polytope/datacube/backends/fdb.py b/polytope/datacube/backends/fdb.py index 30f3d2a9c..fd4bacfdf 100644 --- a/polytope/datacube/backends/fdb.py +++ b/polytope/datacube/backends/fdb.py @@ -4,6 +4,8 @@ from .datacube import Datacube, IndexTree +import time + class FDBDatacube(Datacube): def __init__(self, config={}, axis_options={}): @@ -44,13 +46,11 @@ def remove_unwanted_axes(self, leaf_path): return leaf_path def get(self, requests: IndexTree, leaf_path={}): + time1 = time.time() # First when request node is root, go to its children if requests.axis.name == "root": - if len(requests.children) == 0: - pass - else: - for c in requests.children: - self.get(c) + for c in requests.children: + self.get(c) # If request node has no children, we have a leaf so need to assign fdb values to it else: key_value_path = {requests.axis.name: requests.value} @@ -67,6 +67,8 @@ def get(self, requests: IndexTree, leaf_path={}): else: for c in requests.children: self.get(c, leaf_path) + print("TOTAL GET TIME") + print(time.time() - time1) def get_2nd_last_values(self, requests, leaf_path={}): # In this function, we recursively loop over the last two layers of the tree and store the indices of the @@ -154,11 +156,9 @@ def find_fdb_values(self, path, range_lengths, current_start_idx, lat_length): interm_request_ranges.append(current_request_ranges) request_ranges_with_idx = list(enumerate(interm_request_ranges)) sorted_list = sorted(request_ranges_with_idx, key=lambda x: x[1][0]) - sorted_request_ranges = [item[1] for item in sorted_list] - original_indices = [item[0] for item in sorted_list] + original_indices, sorted_request_ranges = zip(*sorted_list) fdb_requests.append(tuple((path, sorted_request_ranges))) - subxarray = self.fdb.extract(fdb_requests) - output_values = subxarray + output_values = self.fdb.extract(fdb_requests) return (output_values, original_indices) def datacube_natural_indexes(self, axis, subarray): diff --git a/polytope/engine/hullslicer.py b/polytope/engine/hullslicer.py index d361fb13c..6b0306ed2 100644 --- a/polytope/engine/hullslicer.py +++ b/polytope/engine/hullslicer.py @@ -48,7 +48,12 @@ def _build_sliceable_child(self, polytope, ax, node, datacube, lower, upper, nex upper = ax.from_float(upper + tol) flattened = node.flatten() method = polytope.method - for value in datacube.get_indices(flattened, ax, lower, upper, method): + values = datacube.get_indices(flattened, ax, lower, upper, method) + + if len(values) == 0: + node.remove_branch() + + for value in values: # convert to float for slicing fvalue = ax.to_float(value) new_polytope = slice(polytope, ax.name, fvalue, slice_axis_idx) diff --git a/tests/test_datacube_axes_init.py b/tests/test_datacube_axes_init.py index 248b59ff4..6f3d59bbf 100644 --- a/tests/test_datacube_axes_init.py +++ b/tests/test_datacube_axes_init.py @@ -36,7 +36,6 @@ def test_created_axes(self): assert self.datacube._axes["longitude"].has_mapper assert isinstance(self.datacube._axes["longitude"], FloatDatacubeAxis) assert not ("values" in self.datacube._axes.keys()) - print(list(self.datacube._axes["latitude"].find_indexes({}, self.datacube)[:5])) assert list(self.datacube._axes["latitude"].find_indexes({}, self.datacube)[:5]) == [ 89.94618771566562, 89.87647835333229, diff --git a/tests/test_fdb_datacube.py b/tests/test_fdb_datacube.py index 84b3b2059..9bbfa9bf1 100644 --- a/tests/test_fdb_datacube.py +++ b/tests/test_fdb_datacube.py @@ -28,7 +28,7 @@ def setup_method(self, method): self.API = Polytope(datacube=self.fdbdatacube, engine=self.slicer, axis_options=self.options) # Testing different shapes - @pytest.mark.skip(reason="can't install fdb branch on CI") + # @pytest.mark.skip(reason="can't install fdb branch on CI") def test_fdb_datacube(self): request = Request( Select("step", [0]), diff --git a/tests/test_incomplete_tree_fdb.py b/tests/test_incomplete_tree_fdb.py new file mode 100644 index 000000000..28c357465 --- /dev/null +++ b/tests/test_incomplete_tree_fdb.py @@ -0,0 +1,97 @@ +import pandas as pd +import pytest +from eccodes import codes_grib_find_nearest, codes_grib_new_from_file +from helper_functions import download_test_data + +from polytope.datacube.backends.fdb import FDBDatacube +from polytope.engine.hullslicer import HullSlicer +from polytope.polytope import Polytope, Request +from polytope.shapes import Select + + +class TestRegularGrid: + def setup_method(self, method): + nexus_url = "https://get.ecmwf.int/test-data/polytope/test-data/era5-levels-members.grib" + download_test_data(nexus_url, "era5-levels-members.grib") + self.options = { + "values": { + "transformation": {"mapper": {"type": "regular", "resolution": 30, "axes": ["latitude", "longitude"]}} + }, + "date": {"transformation": {"merge": {"with": "time", "linkers": [" ", "00"]}}}, + "step": {"transformation": {"type_change": "int"}}, + "number": {"transformation": {"type_change": "int"}}, + "longitude": {"transformation": {"cyclic": [0, 360]}}, + } + self.config = {"class": "ea", "expver": "0001", "levtype": "pl", "step": 0} + self.fdbdatacube = FDBDatacube(self.config, axis_options=self.options) + self.slicer = HullSlicer() + self.API = Polytope(datacube=self.fdbdatacube, engine=self.slicer, axis_options=self.options) + + def find_nearest_latlon(self, grib_file, target_lat, target_lon): + # Open the GRIB file + f = open(grib_file) + + # Load the GRIB messages from the file + messages = [] + while True: + message = codes_grib_new_from_file(f) + if message is None: + break + messages.append(message) + + # Find the nearest grid points + nearest_points = [] + for message in messages: + nearest_index = codes_grib_find_nearest(message, target_lat, target_lon) + nearest_points.append(nearest_index) + + # Close the GRIB file + f.close() + + return nearest_points + + @pytest.mark.internet + # @pytest.mark.skip(reason="can't install fdb branch on CI") + def test_incomplete_fdb_branch(self): + request = Request( + Select("step", [0]), + Select("levtype", ["pl"]), + Select("date", [pd.Timestamp("20170102T120000")]), + Select("domain", ["g"]), + Select("expver", ["0001"]), + Select("param", ["129"]), + Select("class", ["ea"]), + Select("stream", ["enda"]), + Select("type", ["an"]), + Select("latitude", [0]), + Select("longitude", [1]), + Select("levelist", ["500"]), + Select("number", ["0"]), + ) + result = self.API.retrieve(request) + result.pprint() + assert len(result.leaves) == 1 + assert result.is_root() + + @pytest.mark.internet + # @pytest.mark.skip(reason="can't install fdb branch on CI") + def test_incomplete_fdb_branch_2(self): + request = Request( + Select("step", [0]), + Select("levtype", ["pl"]), + Select("date", [pd.Timestamp("20170102T120000")]), + Select("domain", ["g"]), + Select("expver", ["0001"]), + Select("param", ["129"]), + Select("class", ["ea"]), + Select("stream", ["enda"]), + Select("type", ["an"]), + Select("latitude", [1]), + Select("longitude", [0]), + Select("levelist", ["500"]), + Select("number", ["0"]), + ) + result = self.API.retrieve(request) + result.pprint() + assert len(result.leaves) == 1 + assert result.is_root() diff --git a/tests/test_merge_cyclic_octahedral.py b/tests/test_merge_cyclic_octahedral.py index 7f633c0be..6fcf16323 100644 --- a/tests/test_merge_cyclic_octahedral.py +++ b/tests/test_merge_cyclic_octahedral.py @@ -34,7 +34,6 @@ def setup_method(self, method): self.slicer = HullSlicer() self.API = Polytope(datacube=self.array, engine=self.slicer, axis_options=self.options) - # @pytest.mark.skip(reason="Need date time to not be strings") def test_merge_axis(self): # NOTE: does not work because the date is a string in the merge option... date = np.datetime64("2000-01-01T06:00:00") diff --git a/tests/test_merge_transformation.py b/tests/test_merge_transformation.py index fe15cf987..63b7a39cd 100644 --- a/tests/test_merge_transformation.py +++ b/tests/test_merge_transformation.py @@ -27,5 +27,4 @@ def setup_method(self, method): def test_merge_axis(self): request = Request(Select("date", [pd.Timestamp("2000-01-01T06:00:00")])) result = self.API.retrieve(request) - # assert result.leaves[0].flatten()["date"] == np.datetime64("2000-01-01T06:00:00") assert result.leaves[0].flatten()["date"] == pd.Timestamp("2000-01-01T06:00:00") diff --git a/tests/test_regular_grid.py b/tests/test_regular_grid.py index 86337b6f0..e811a9c15 100644 --- a/tests/test_regular_grid.py +++ b/tests/test_regular_grid.py @@ -54,7 +54,7 @@ def find_nearest_latlon(self, grib_file, target_lat, target_lon): return nearest_points @pytest.mark.internet - @pytest.mark.skip(reason="can't install fdb branch on CI") + # @pytest.mark.skip(reason="can't install fdb branch on CI") def test_regular_grid(self): request = Request( Select("step", [0]), From 3312772dda1b2e4e1de1f53d5568d86c32a82a68 Mon Sep 17 00:00:00 2001 From: Mathilde Leuridan Date: Thu, 23 Nov 2023 09:43:18 +0100 Subject: [PATCH 37/37] clean up branch --- polytope/datacube/backends/fdb.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/polytope/datacube/backends/fdb.py b/polytope/datacube/backends/fdb.py index fd4bacfdf..0679dbdd0 100644 --- a/polytope/datacube/backends/fdb.py +++ b/polytope/datacube/backends/fdb.py @@ -4,8 +4,6 @@ from .datacube import Datacube, IndexTree -import time - class FDBDatacube(Datacube): def __init__(self, config={}, axis_options={}): @@ -46,7 +44,6 @@ def remove_unwanted_axes(self, leaf_path): return leaf_path def get(self, requests: IndexTree, leaf_path={}): - time1 = time.time() # First when request node is root, go to its children if requests.axis.name == "root": for c in requests.children: @@ -67,8 +64,6 @@ def get(self, requests: IndexTree, leaf_path={}): else: for c in requests.children: self.get(c, leaf_path) - print("TOTAL GET TIME") - print(time.time() - time1) def get_2nd_last_values(self, requests, leaf_path={}): # In this function, we recursively loop over the last two layers of the tree and store the indices of the