-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathgenerate_requests.py
More file actions
215 lines (185 loc) · 7.87 KB
/
Copy pathgenerate_requests.py
File metadata and controls
215 lines (185 loc) · 7.87 KB
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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
"""A module to generate specific request strings."""
from collections import namedtuple
from urllib.parse import quote
def generate_mmm_wcs_getcov_str(x, y, cov_id, model, scenario, encoding="json"):
"""Generate a WCS GetCoverage request for fetching a
subset of a coverage over X and Y axes.
Args:
x (float or str): x-coordinate for point query (float), or string
composed as "x1,x2" for bbox query, where x1 and x2 are
lower and upper bounds of bbox
y (float or str): y-coordinate for point query (float), or string
composed as "y1,y2" for bbox query, where y1 and y2 are
lower and upper bounds of bbox
cov_id (str): Rasdaman coverage ID
model (int): Model number defined in Rasdaman coverage
- 0: CRU-TS 4.0
- 2: GFDL-CM3
- 3: GISS-E2-R
- 4: IPSL-CM5A-LR
- 5: MRI-CGCM3
- 6: NCAR-CCSM4
scenario (int): Scenario number defined in Rasdaman coverage
- 0: historical
- 1: RCP 4.5
- 2: RCP 6.0
- 3: RCP 8.5
Returns:
wcs_getcov_str (str): WCS GetCoverage Request to append to a query URL
"""
var_subset_str = f"&SUBSET=model({model})&SUBSET=scenario({scenario})"
wcs_getcov_str = (
f"GetCoverage&COVERAGEID={cov_id}"
f"&SUBSET=X({x})&SUBSET=Y({y}){var_subset_str}"
f"&FORMAT=application/{encoding}"
)
return wcs_getcov_str
def generate_wcs_getcov_str(
x,
y,
cov_id,
var_coord=None,
time_slice=None,
encoding="json",
projection="EPSG:3338",
):
"""Generate a WCS GetCoverage request for fetching a
subset of a coverage over X and Y axes.
Args:
x (float or str): x-coordinate for point query (float), or string
composed as "x1,x2" for bbox query, where x1 and x2 are
lower and upper bounds of bbox
y (float or str): y-coordinate for point query (float), or string
composed as "y1,y2" for bbox query, where y1 and y2 are
lower and upper bounds of bbox
cov_id (str): Rasdaman coverage ID
var_coord (int): coordinate value corresponding to variable name to query, default=None will include all variables
time_slice (tuple): two-tuple of the time axis name (e.g., `year`) and the ISO time-string used to slice the data
encoding (str): currently supports either "json" or "netcdf"
for point or bbox queries, respectively
Returns:
wcs_getcov_str (str): WCS GetCoverage Request to append to a query URL
"""
# if var_coord is specified, subsetting using the specific variable
if var_coord is not None:
var_subset_str = f"&SUBSET=varname({var_coord})"
else:
var_subset_str = ""
if time_slice is not None:
time_axis, slice_string = time_slice
time_slice_str = f"&SUBSET={time_axis}({slice_string})"
else:
time_slice_str = ""
if projection == "EPSG:4326":
wcs_getcov_str = (
f"GetCoverage&COVERAGEID={cov_id}"
f"&SUBSET=lon({x})&SUBSET=lat({y}){var_subset_str}{time_slice_str}"
f"&FORMAT=application/{encoding}"
)
else:
wcs_getcov_str = (
f"GetCoverage&COVERAGEID={cov_id}"
f"&SUBSET=X({x})&SUBSET=Y({y}){var_subset_str}{time_slice_str}"
f"&FORMAT=application/{encoding}"
)
return wcs_getcov_str
def generate_netcdf_wcs_getcov_str(bbox_bounds, cov_id, var_coord=None):
"""Generate a WCS GetCoverage request for netCDF data over an area.
Args:
bbox_bounds (tuple): 4-tuple of bounding polygon extent (xmin, ymin, xmax, ymax)
cov_id (str): Rasdaman coverage ID
var_coord (int): coordinate value corresponding to variable name to query,
default=None will include all variables
Returns:
netcdf_wcs_getcov_str (str): WCS GetCoverage Request to append to a query URL
"""
x1, y1, x2, y2 = bbox_bounds
x = f"{x1},{x2}"
y = f"{y1},{y2}"
netcdf_wcs_getcov_str = generate_wcs_getcov_str(
x, y, cov_id, var_coord, encoding="netcdf"
)
return netcdf_wcs_getcov_str
def generate_average_wcps_str(
x, y, cov_id, axis_name, axis_coords, slice_di=None, encoding="json"
):
"""Generates a WCPS request string for computing
the average over specified axes.
Args:
x (float or str): x-coordinate for point query, or string
composed as "x1:x2" for bbox query, where x1 and x2 are
lower and upper bounds of bbox
y (float or str): y-coordinate for point query, or string
composed as "y1:y2" for bbox query, where y1 and y2 are
lower and upper bounds of bbox
cov_id (str): Rasdaman coverage ID
axis_name (str): name of the axis to take average over
axis_coords (tuple): 2-tuple of coordinates to average over
of the form (start, stop)
slice_di (dict): dict with axis names for keys and
coordinates for the values to be used in further
subsetting in WCPS query. E.g., {"varname": 0}
encoding (str): currently supports either "json" or "netcdf"
for point or bbox queries, respectively
Returns:
WCPS query to be included in generate_wcs_url()
"""
if slice_di is not None:
subset_str = "".join([f",{k}({v})" for k, v in slice_di.items()])
else:
subset_str = ""
c1, c2 = axis_coords
summary_str = f"{axis_name}({c1}:{c2})"
n = len(range(c1, c2 + 1))
wcps_request_str = quote(
(
f"ProcessCoverages&query=for $c in ({cov_id}) "
f"let $a := (condense + over $t {summary_str} "
f"using $c[{axis_name}($t),X({x}),Y({y}){subset_str}] ) / {n} "
f'return encode( $a , "application/{encoding}")'
)
)
return wcps_request_str
def generate_netcdf_average_wcps_str(bbox_bounds, generate_average_wcps_str_kwargs):
"""Generate a WCPS GetCoverage request for netCDF data over an area.
Args:
bbox_bounds (tuple): 4-tuple of bounding polygon extent (xmin, ymin, xmax, ymax)
generate_average_wcps_str_kwargs (dict): Args to pass on to generate_average_wcps_str_kwargs
Returns:
netcdf_avg_wcps_str (str): WCPS GetCoverage Request to append to a query URL
"""
x1, y1, x2, y2 = bbox_bounds
x = f"{x1}:{x2}"
y = f"{y1}:{y2}"
netcdf_avg_wcps_str = generate_average_wcps_str(
x,
y,
**generate_average_wcps_str_kwargs,
)
return netcdf_avg_wcps_str
def generate_wcps_describe_coverage_str(cov_id):
"""Generate a WCPS DescribeCoverage request for a given coverage.
The describe() operation returns a description of the coverage equivalent to a WCS DescribeCoverage request, and the output adheres to the same WCS schema, but we're able to get it in JSON format instead of only XML, GML, or string.
Args:
cov_id (str): rasdaman coverage ID
Returns:
describe_coverage_str (str): encoded WCPS string fragment to append to a query URL
"""
query_str = f'for $c in ({cov_id}) return describe($c, "application/json", "outputType=GeneralGridCoverage")'
return quote(query_str)
def generate_conus_hydrology_wcs_str(cov_id, stream_id, source=None):
"""Generate a WCS GetCoverage request for fetching CONUS hydrology data as netCDF.
Args:
cov_id (str): Coverage ID
stream_id (str): Stream ID
source (str, optional): Source ID (for stats coverage only)
Returns:
request_string (str): WCS GetCoverage Request to append to a query URL
"""
request_string = f"ows?&SERVICE=WCS&VERSION=2.0.1&REQUEST=GetCoverage&"
request_string += f"COVERAGEID={cov_id}&"
request_string += f"SUBSET=stream_id({stream_id})&"
if source is not None:
request_string += f"SUBSET=source({source})&"
request_string += f"FORMAT=application/netcdf"
return request_string