geos5fp 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- geos5fp/__init__.py +8 -0
- geos5fp/downscaling/__init__.py +1 -0
- geos5fp/downscaling/downscaling.py +271 -0
- geos5fp/geos5fp.py +1774 -0
- geos5fp/timer/__init__.py +1 -0
- geos5fp/timer/timer.py +75 -0
- geos5fp/version.txt +1 -0
- geos5fp-1.0.0.dist-info/LICENSE +201 -0
- geos5fp-1.0.0.dist-info/METADATA +34 -0
- geos5fp-1.0.0.dist-info/RECORD +12 -0
- geos5fp-1.0.0.dist-info/WHEEL +5 -0
- geos5fp-1.0.0.dist-info/top_level.txt +1 -0
geos5fp/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .downscaling import *
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from dateutil import parser
|
|
3
|
+
import numpy as np
|
|
4
|
+
from rasters import Raster, RasterGeometry, RasterGrid
|
|
5
|
+
import rasters as rt
|
|
6
|
+
|
|
7
|
+
DEFAULT_UPSAMPLING = "average"
|
|
8
|
+
DEFAULT_DOWNSAMPLING = "linear"
|
|
9
|
+
|
|
10
|
+
def bias_correct(
|
|
11
|
+
coarse_image: Raster,
|
|
12
|
+
fine_image: Raster,
|
|
13
|
+
upsampling: str = "average",
|
|
14
|
+
downsampling: str = "linear",
|
|
15
|
+
return_bias: bool = False):
|
|
16
|
+
fine_geometry = fine_image.geometry
|
|
17
|
+
coarse_geometry = coarse_image.geometry
|
|
18
|
+
upsampled = fine_image.to_geometry(coarse_geometry, resampling=upsampling)
|
|
19
|
+
bias_coarse = upsampled - coarse_image
|
|
20
|
+
bias_fine = bias_coarse.to_geometry(fine_geometry, resampling=downsampling)
|
|
21
|
+
bias_corrected_fine = fine_image - bias_fine
|
|
22
|
+
|
|
23
|
+
if return_bias:
|
|
24
|
+
return bias_corrected_fine, bias_fine
|
|
25
|
+
else:
|
|
26
|
+
return bias_corrected_fine
|
|
27
|
+
|
|
28
|
+
def linear_downscale(
|
|
29
|
+
coarse_image: Raster,
|
|
30
|
+
fine_image: Raster,
|
|
31
|
+
upsampling: str = "average",
|
|
32
|
+
downsampling: str = "linear",
|
|
33
|
+
use_gap_filling: bool = False,
|
|
34
|
+
apply_scale: bool = True,
|
|
35
|
+
apply_bias: bool = True,
|
|
36
|
+
return_scale_and_bias: bool = False) -> Raster:
|
|
37
|
+
if upsampling is None:
|
|
38
|
+
upsampling = DEFAULT_UPSAMPLING
|
|
39
|
+
|
|
40
|
+
if downsampling is None:
|
|
41
|
+
downsampling = DEFAULT_DOWNSAMPLING
|
|
42
|
+
|
|
43
|
+
coarse_geometry = coarse_image.geometry
|
|
44
|
+
fine_geometry = fine_image.geometry
|
|
45
|
+
upsampled = fine_image.to_geometry(coarse_geometry, resampling=upsampling)
|
|
46
|
+
|
|
47
|
+
if apply_scale:
|
|
48
|
+
scale_coarse = coarse_image / upsampled
|
|
49
|
+
scale_coarse = rt.where(coarse_image == 0, 0, scale_coarse)
|
|
50
|
+
scale_coarse = rt.where(upsampled == 0, 0, scale_coarse)
|
|
51
|
+
scale_fine = scale_coarse.to_geometry(fine_geometry, resampling=downsampling)
|
|
52
|
+
scale_corrected_fine = fine_image * scale_fine
|
|
53
|
+
fine_image = scale_corrected_fine
|
|
54
|
+
else:
|
|
55
|
+
scale_fine = fine_image * 0 + 1
|
|
56
|
+
|
|
57
|
+
if apply_bias:
|
|
58
|
+
upsampled = fine_image.to_geometry(coarse_geometry, resampling=upsampling)
|
|
59
|
+
bias_coarse = upsampled - coarse_image
|
|
60
|
+
bias_fine = bias_coarse.to_geometry(fine_geometry, resampling=downsampling)
|
|
61
|
+
bias_corrected_fine = fine_image - bias_fine
|
|
62
|
+
fine_image = bias_corrected_fine
|
|
63
|
+
else:
|
|
64
|
+
bias_fine = fine_image * 0
|
|
65
|
+
|
|
66
|
+
if use_gap_filling:
|
|
67
|
+
gap_fill = coarse_image.to_geometry(fine_geometry, resampling=downsampling)
|
|
68
|
+
fine_image = fine_image.fill(gap_fill)
|
|
69
|
+
|
|
70
|
+
if return_scale_and_bias:
|
|
71
|
+
fine_image["scale"] = scale_fine
|
|
72
|
+
fine_image["bias"] = bias_fine
|
|
73
|
+
|
|
74
|
+
return fine_image
|
|
75
|
+
|
|
76
|
+
def NDVI_to_FVC(NDVI: Raster) -> Raster:
|
|
77
|
+
NDVIv = 0.52 # +- 0.03
|
|
78
|
+
NDVIs = 0.04 # +- 0.03
|
|
79
|
+
FVC = rt.clip((NDVI - NDVIs) / (NDVIv - NDVIs), 0, 1)
|
|
80
|
+
|
|
81
|
+
return FVC
|
|
82
|
+
|
|
83
|
+
def downscale_air_temperature(
|
|
84
|
+
time_UTC: datetime,
|
|
85
|
+
Ta_K_coarse: Raster,
|
|
86
|
+
ST_K: Raster,
|
|
87
|
+
water: Raster = None,
|
|
88
|
+
fine_geometry: RasterGeometry = None,
|
|
89
|
+
coarse_geometry: RasterGeometry = None,
|
|
90
|
+
resampling: str = None,
|
|
91
|
+
upsampling: str = None,
|
|
92
|
+
downsampling: str = None,
|
|
93
|
+
apply_scale: bool = True,
|
|
94
|
+
apply_bias: bool = True,
|
|
95
|
+
return_scale_and_bias: bool = False) -> Raster:
|
|
96
|
+
"""
|
|
97
|
+
near-surface air temperature (Ta) in Kelvin
|
|
98
|
+
:param time_UTC: date/time in UTC
|
|
99
|
+
:param geometry: optional target geometry
|
|
100
|
+
:param resampling: optional sampling method for resampling to target geometry
|
|
101
|
+
:return: raster of Ta
|
|
102
|
+
"""
|
|
103
|
+
|
|
104
|
+
if isinstance(time_UTC, str):
|
|
105
|
+
time_UTC = parser.parse(time_UTC)
|
|
106
|
+
|
|
107
|
+
if fine_geometry is None:
|
|
108
|
+
fine_geometry = ST_K.geometry
|
|
109
|
+
|
|
110
|
+
if coarse_geometry is None:
|
|
111
|
+
coarse_geometry = Ta_K_coarse.geometry
|
|
112
|
+
|
|
113
|
+
ST_K_water = None
|
|
114
|
+
|
|
115
|
+
if water is not None:
|
|
116
|
+
ST_K_water = rt.where(water, ST_K, np.nan)
|
|
117
|
+
ST_K = rt.where(water, np.nan, ST_K)
|
|
118
|
+
|
|
119
|
+
scale = None
|
|
120
|
+
bias = None
|
|
121
|
+
|
|
122
|
+
Ta_K = linear_downscale(
|
|
123
|
+
coarse_image=Ta_K_coarse,
|
|
124
|
+
fine_image=ST_K,
|
|
125
|
+
upsampling=upsampling,
|
|
126
|
+
downsampling=downsampling,
|
|
127
|
+
apply_scale=apply_scale,
|
|
128
|
+
apply_bias=apply_bias,
|
|
129
|
+
return_scale_and_bias=return_scale_and_bias
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
if water is not None:
|
|
133
|
+
Ta_K_water = linear_downscale(
|
|
134
|
+
coarse_image=Ta_K_coarse,
|
|
135
|
+
fine_image=ST_K_water,
|
|
136
|
+
upsampling=upsampling,
|
|
137
|
+
downsampling=downsampling,
|
|
138
|
+
apply_scale=apply_scale,
|
|
139
|
+
apply_bias=apply_bias,
|
|
140
|
+
return_scale_and_bias=False
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
Ta_K = rt.where(water, Ta_K_water, Ta_K)
|
|
144
|
+
|
|
145
|
+
Ta_K.filenames = Ta_K_coarse.filenames
|
|
146
|
+
|
|
147
|
+
return Ta_K
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def downscale_soil_moisture(
|
|
151
|
+
time_UTC: datetime,
|
|
152
|
+
fine_geometry: RasterGrid,
|
|
153
|
+
coarse_geometry: RasterGrid,
|
|
154
|
+
SM_coarse: Raster,
|
|
155
|
+
SM_resampled: Raster,
|
|
156
|
+
ST_fine: Raster,
|
|
157
|
+
NDVI_fine: Raster,
|
|
158
|
+
water: Raster,
|
|
159
|
+
fvlim=0.5,
|
|
160
|
+
a=0.5,
|
|
161
|
+
smoothing="linear") -> Raster:
|
|
162
|
+
fine = fine_geometry
|
|
163
|
+
ST_fine = ST_fine.mask(~water)
|
|
164
|
+
NDVI_fine = NDVI_fine.mask(~water)
|
|
165
|
+
FVC_fine = NDVI_to_FVC(NDVI_fine)
|
|
166
|
+
soil_fine = FVC_fine < fvlim
|
|
167
|
+
Tmin_coarse = ST_fine.to_geometry(coarse_geometry, resampling="min")
|
|
168
|
+
Tmax_coarse = ST_fine.to_geometry(coarse_geometry, resampling="max")
|
|
169
|
+
Ts_fine = ST_fine.mask(soil_fine)
|
|
170
|
+
Tsmin_coarse = Ts_fine.to_geometry(coarse_geometry, resampling="min").fill(Tmin_coarse)
|
|
171
|
+
Tsmax_coarse = Ts_fine.to_geometry(coarse_geometry, resampling="max").fill(Tmax_coarse)
|
|
172
|
+
ST_coarse = ST_fine.to_geometry(coarse_geometry, resampling="average")
|
|
173
|
+
SEE_coarse = (Tsmax_coarse - ST_coarse) / rt.clip(Tsmax_coarse - Tsmin_coarse, 1, None)
|
|
174
|
+
SM_SEE_proportion = (SM_coarse / SEE_coarse).to_geometry(fine, resampling=smoothing)
|
|
175
|
+
Tsmax_fine = Tsmax_coarse.to_geometry(fine_geometry, resampling=smoothing)
|
|
176
|
+
Tsrange_fine = (Tsmax_coarse - Tsmin_coarse).to_geometry(fine, resampling=smoothing)
|
|
177
|
+
SEE_fine = (Tsmax_fine - ST_fine) / rt.clip(Tsrange_fine, 1, None)
|
|
178
|
+
|
|
179
|
+
SEE_mean = SEE_coarse.to_geometry(fine, resampling=smoothing)
|
|
180
|
+
SM_fine = rt.clip(SM_resampled + a * SM_SEE_proportion * (SEE_fine - SEE_mean), 0, 1)
|
|
181
|
+
SM_fine = SM_fine.mask(~water)
|
|
182
|
+
|
|
183
|
+
return SM_fine
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def downscale_vapor_pressure_deficit(
|
|
187
|
+
time_UTC: datetime,
|
|
188
|
+
VPD_Pa_coarse: Raster,
|
|
189
|
+
ST_K: Raster,
|
|
190
|
+
fine_geometry: RasterGeometry = None,
|
|
191
|
+
coarse_geometry: RasterGeometry = None,
|
|
192
|
+
resampling: str = None,
|
|
193
|
+
upsampling: str = None,
|
|
194
|
+
downsampling: str = None,
|
|
195
|
+
return_scale_and_bias: bool = False) -> Raster:
|
|
196
|
+
if upsampling is None:
|
|
197
|
+
upsampling = "average"
|
|
198
|
+
|
|
199
|
+
if downsampling is None:
|
|
200
|
+
downsampling = "linear"
|
|
201
|
+
|
|
202
|
+
if fine_geometry is None:
|
|
203
|
+
fine_geometry = ST_K.geometry
|
|
204
|
+
|
|
205
|
+
if coarse_geometry is None:
|
|
206
|
+
coarse_geometry = VPD_Pa_coarse.geometry
|
|
207
|
+
|
|
208
|
+
return linear_downscale(
|
|
209
|
+
coarse_image=VPD_Pa_coarse,
|
|
210
|
+
fine_image=ST_K,
|
|
211
|
+
upsampling=upsampling,
|
|
212
|
+
downsampling=downsampling,
|
|
213
|
+
return_scale_and_bias=return_scale_and_bias
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def downscale_relative_humidity(
|
|
218
|
+
time_UTC: datetime,
|
|
219
|
+
RH_coarse: Raster,
|
|
220
|
+
SM,
|
|
221
|
+
ST_K,
|
|
222
|
+
VPD_kPa,
|
|
223
|
+
water: Raster = None,
|
|
224
|
+
fine_geometry: RasterGeometry = None,
|
|
225
|
+
coarse_geometry: RasterGeometry = None,
|
|
226
|
+
resampling: str = None,
|
|
227
|
+
upsampling: str = None,
|
|
228
|
+
downsampling: str = None) -> Raster:
|
|
229
|
+
if upsampling is None:
|
|
230
|
+
upsampling = "average"
|
|
231
|
+
|
|
232
|
+
if downsampling is None:
|
|
233
|
+
downsampling = "linear"
|
|
234
|
+
|
|
235
|
+
if fine_geometry is None:
|
|
236
|
+
fine_geometry = SM.geometry
|
|
237
|
+
|
|
238
|
+
if coarse_geometry is None:
|
|
239
|
+
coarse_geometry = RH_coarse.geometry
|
|
240
|
+
|
|
241
|
+
bias_fine = None
|
|
242
|
+
|
|
243
|
+
RH_estimate_fine = SM ** (1 / VPD_kPa)
|
|
244
|
+
|
|
245
|
+
RH = bias_correct(
|
|
246
|
+
coarse_image=RH_coarse,
|
|
247
|
+
fine_image=RH_estimate_fine,
|
|
248
|
+
upsampling=upsampling,
|
|
249
|
+
downsampling=downsampling,
|
|
250
|
+
return_bias=False
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
if water is not None:
|
|
254
|
+
ST_K_water = rt.where(water, ST_K, np.nan)
|
|
255
|
+
RH_coarse_complement = 1 - RH_coarse
|
|
256
|
+
RH_complement_water = linear_downscale(
|
|
257
|
+
coarse_image=RH_coarse_complement,
|
|
258
|
+
fine_image=ST_K_water,
|
|
259
|
+
upsampling=upsampling,
|
|
260
|
+
downsampling=downsampling,
|
|
261
|
+
apply_bias=True,
|
|
262
|
+
return_scale_and_bias=False
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
RH_water = 1 - RH_complement_water
|
|
266
|
+
RH = rt.where(water, RH_water, RH)
|
|
267
|
+
|
|
268
|
+
RH = rt.clip(RH, 0, 1)
|
|
269
|
+
|
|
270
|
+
return RH
|
|
271
|
+
|