-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathpresent_day_rasters.py
166 lines (143 loc) · 5.75 KB
/
present_day_rasters.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
import glob
import json
import logging
import os
from hashlib import sha256
from typing import List, Union, Dict
import requests
from .network_requests import fetch_file
from .utils import download, misc
DEFAULT_PRESENT_DAY_RASTERS_MANIFEST = (
"https://repo.gplates.org/webdav/pmm/present_day_rasters.json"
)
logger = logging.getLogger("pmm")
class RasterNameNotFound(Exception):
pass
class PresentDayRasterManager:
"""manage present-day rasters"""
def __init__(self, raster_manifest=None):
"""constructor
:param raster_manifest: the path to a present_day_rasters.json file
"""
if not raster_manifest:
self.raster_manifest = DEFAULT_PRESENT_DAY_RASTERS_MANIFEST
else:
self.raster_manifest = raster_manifest
self._rasters = None
self.data_dir = "present-day-rasters"
# check if the model manifest file is a local file
if os.path.isfile(self.raster_manifest):
with open(self.raster_manifest) as f:
self._rasters = json.load(f)
elif self.raster_manifest.startswith(
"http://"
) or self.raster_manifest.startswith("https://"):
# try the http(s) url
try:
r = requests.get(self.raster_manifest)
self._rasters = r.json()
except requests.exceptions.ConnectionError:
raise Exception(
f"Unable to fetch {self.raster_manifest}. "
+ "No network connection or invalid URL!"
)
else:
raise Exception(
f"The model_manifest '{self.raster_manifest}' should be either a local file path or a http(s) URL."
)
@property
def rasters(self) -> Dict:
if self._rasters is not None:
return self._rasters
else:
raise Exception(
"The self._rasters is None. This should not happen. Something Extraordinary must have happened."
)
@rasters.setter
def rasters(self, var) -> None:
self._rasters = var
def set_data_dir(self, folder):
self.data_dir = folder
def list_present_day_rasters(self):
return [name for name in self.rasters]
def _check_raster_avail(self, _name: str):
"""check if the raster name is in raster configuration"""
name = _name.lower()
if not name in self.rasters:
raise RasterNameNotFound(f"Raster {name} is not found in {self.rasters}.")
return name
def is_wms(self, _name: str, check_raster_avail_flag=True):
"""return True if the raster is served by Web Map Service, otherwise False"""
if check_raster_avail_flag:
name = self._check_raster_avail(_name)
else:
name = _name.lower()
if (
isinstance(self.rasters[name], dict)
and "service" in self.rasters[name]
and self.rasters[name]["service"] == "WMS"
):
return True
else:
return False
def get_raster(
self,
_name: str,
width=1800,
height=800,
bbox=[-180, -80, 180, 80],
large_file_hint=True,
):
"""download the raster by name. Save the raster in self.data_dir"""
name = self._check_raster_avail(_name)
is_wms_flag = self.is_wms(name, check_raster_avail_flag=False)
if not is_wms_flag:
downloader = download.FileDownloader(
self.rasters[name],
f"{self.data_dir}/{name}/.metadata.json",
f"{self.data_dir}/{name}/",
large_file_hint=large_file_hint,
)
# only re-download when necessary
if downloader.check_if_file_need_update():
downloader.download_file_and_update_metadata()
else:
if downloader.check_if_expire_date_need_update():
# update the expiry date
downloader.update_metadata()
logger.debug(
f"The local raster file {self.data_dir}/{name} is still good. Will not download again at this moment."
)
files = glob.glob(f"{self.data_dir}/{name}/*")
if len(files) == 0:
raise Exception(f"Failed to get raster {name}")
if len(files) > 1:
misc.print_warning(
f"Multiple raster files have been detected.{files}. Return the first one found {files[0]}."
)
return files[0]
else:
server_url = self.rasters[name]["server_url"]
version = self.rasters[name]["version"]
layers = self.rasters[name]["layers"]
if self.rasters[name]["hillshade_layer"]:
layers.append(self.rasters[name]["hillshade_layer"])
styles = self.rasters[name]["styles"]
if self.rasters[name]["hillshade_style"]:
styles.append(self.rasters[name]["hillshade_style"])
format = "image/geotiff"
url = (
f"{server_url}/wms?service=WMS&version={version}&request=GetMap&layers={','.join(layers)}"
+ f"&bbox={bbox[0]},{bbox[1]},{bbox[2]},{bbox[3]}&width={width}&height={height}&srs=EPSG:4326"
+ f"&styles={','.join(styles)}&format={format}"
)
filepath = (
f"{self.data_dir}/{name}/{sha256(url.encode('utf-8')).hexdigest()}"
)
if not os.path.isfile(f"{filepath}/{name}.tiff"):
fetch_file(
url,
f"{self.data_dir}/{name}/{sha256(url.encode('utf-8')).hexdigest()}",
filename=f"{name}.tiff",
)
return f"{filepath}/{name}.tiff"