ECOv003-L2T-STARS 1.0.1__py3-none-any.whl → 1.1.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.
- ECOv003_L2T_STARS/BRDF/BRDF.py +57 -0
- ECOv003_L2T_STARS/BRDF/SZA.py +65 -0
- ECOv003_L2T_STARS/BRDF/__init__.py +1 -0
- ECOv003_L2T_STARS/BRDF/statistical_radiative_transport.txt +90 -0
- ECOv003_L2T_STARS/BRDF/version.txt +1 -0
- ECOv003_L2T_STARS/ECOv003_DL.py +527 -0
- ECOv003_L2T_STARS/ECOv003_DL.xml +47 -0
- ECOv003_L2T_STARS/ECOv003_L2T_STARS.py +162 -0
- ECOv003_L2T_STARS/ECOv003_L2T_STARS.xml +47 -0
- ECOv003_L2T_STARS/L2TSTARSConfig.py +188 -0
- ECOv003_L2T_STARS/L2T_STARS.py +489 -0
- ECOv003_L2T_STARS/LPDAAC/LPDAACDataPool.py +444 -0
- ECOv003_L2T_STARS/LPDAAC/__init__.py +9 -0
- ECOv003_L2T_STARS/LPDAAC/version.txt +1 -0
- ECOv003_L2T_STARS/Manifest.toml +2332 -0
- ECOv003_L2T_STARS/Project.toml +14 -0
- ECOv003_L2T_STARS/VIIRS/VIIRSDataPool.py +294 -0
- ECOv003_L2T_STARS/VIIRS/VIIRSDownloader.py +26 -0
- ECOv003_L2T_STARS/VIIRS/VIIRS_CMR_LOGIN.py +36 -0
- ECOv003_L2T_STARS/VIIRS/VNP09GA.py +1277 -0
- ECOv003_L2T_STARS/VIIRS/VNP43IA4.py +288 -0
- ECOv003_L2T_STARS/VIIRS/VNP43MA3.py +323 -0
- ECOv003_L2T_STARS/VIIRS/__init__.py +9 -0
- ECOv003_L2T_STARS/VIIRS/version.txt +1 -0
- ECOv003_L2T_STARS/VNP43NRT/VNP43NRT.py +863 -0
- ECOv003_L2T_STARS/VNP43NRT/__init__.py +1 -0
- ECOv003_L2T_STARS/VNP43NRT/process_VNP43NRT.jl +169 -0
- ECOv003_L2T_STARS/VNP43NRT/version.txt +1 -0
- ECOv003_L2T_STARS/VNP43NRT_jl/Manifest.toml +995 -0
- ECOv003_L2T_STARS/VNP43NRT_jl/Project.toml +15 -0
- ECOv003_L2T_STARS/VNP43NRT_jl/__init__.py +0 -0
- ECOv003_L2T_STARS/VNP43NRT_jl/instantiate.jl +25 -0
- ECOv003_L2T_STARS/VNP43NRT_jl/instantiate.py +13 -0
- ECOv003_L2T_STARS/VNP43NRT_jl/src/VNP43NRT.jl +411 -0
- ECOv003_L2T_STARS/VNP43NRT_jl/src/__init__.py +0 -0
- ECOv003_L2T_STARS/__init__.py +3 -0
- ECOv003_L2T_STARS/calibrate_fine_to_coarse.py +60 -0
- ECOv003_L2T_STARS/constants.py +38 -0
- ECOv003_L2T_STARS/daterange/__init__.py +1 -0
- ECOv003_L2T_STARS/daterange/daterange.py +35 -0
- ECOv003_L2T_STARS/generate_L2T_STARS_runconfig.py +249 -0
- ECOv003_L2T_STARS/generate_NDVI_coarse_directory.py +21 -0
- ECOv003_L2T_STARS/generate_NDVI_coarse_image.py +30 -0
- ECOv003_L2T_STARS/generate_NDVI_fine_directory.py +14 -0
- ECOv003_L2T_STARS/generate_NDVI_fine_image.py +28 -0
- ECOv003_L2T_STARS/generate_STARS_inputs.py +231 -0
- ECOv003_L2T_STARS/generate_albedo_coarse_directory.py +18 -0
- ECOv003_L2T_STARS/generate_albedo_coarse_image.py +30 -0
- ECOv003_L2T_STARS/generate_albedo_fine_directory.py +17 -0
- ECOv003_L2T_STARS/generate_albedo_fine_image.py +30 -0
- ECOv003_L2T_STARS/generate_filename.py +37 -0
- ECOv003_L2T_STARS/generate_input_staging_directory.py +23 -0
- ECOv003_L2T_STARS/generate_model_state_tile_date_directory.py +28 -0
- ECOv003_L2T_STARS/generate_output_directory.py +28 -0
- ECOv003_L2T_STARS/install_STARS_jl.py +43 -0
- ECOv003_L2T_STARS/instantiate_STARS_jl.py +38 -0
- ECOv003_L2T_STARS/load_prior.py +248 -0
- ECOv003_L2T_STARS/prior.py +56 -0
- ECOv003_L2T_STARS/process_ECOSTRESS_data_fusion_distributed_bias.jl +420 -0
- ECOv003_L2T_STARS/process_STARS_product.py +507 -0
- ECOv003_L2T_STARS/process_julia_data_fusion.py +110 -0
- ECOv003_L2T_STARS/retrieve_STARS_sources.py +101 -0
- ECOv003_L2T_STARS/runconfig.py +70 -0
- ECOv003_L2T_STARS/timer/__init__.py +1 -0
- ECOv003_L2T_STARS/timer/timer.py +77 -0
- ECOv003_L2T_STARS/version.py +8 -0
- ECOv003_L2T_STARS/version.txt +1 -0
- {ECOv003_L2T_STARS-1.0.1.dist-info → ecov003_l2t_stars-1.1.0.dist-info}/METADATA +30 -23
- ecov003_l2t_stars-1.1.0.dist-info/RECORD +73 -0
- {ECOv003_L2T_STARS-1.0.1.dist-info → ecov003_l2t_stars-1.1.0.dist-info}/WHEEL +1 -1
- ecov003_l2t_stars-1.1.0.dist-info/entry_points.txt +3 -0
- ecov003_l2t_stars-1.1.0.dist-info/top_level.txt +1 -0
- ECOv003_L2T_STARS-1.0.1.dist-info/RECORD +0 -5
- ECOv003_L2T_STARS-1.0.1.dist-info/top_level.txt +0 -1
- {ECOv003_L2T_STARS-1.0.1.dist-info → ecov003_l2t_stars-1.1.0.dist-info/licenses}/LICENSE +0 -0
@@ -0,0 +1,288 @@
|
|
1
|
+
import logging
|
2
|
+
from datetime import datetime, date
|
3
|
+
from os.path import exists, join
|
4
|
+
from typing import List, Union
|
5
|
+
from dateutil import parser
|
6
|
+
import h5py
|
7
|
+
import numpy as np
|
8
|
+
import pandas as pd
|
9
|
+
from modland import find_modland_tiles
|
10
|
+
from shapely.geometry import Point, Polygon
|
11
|
+
|
12
|
+
import colored_logging as cl
|
13
|
+
import rasters as rt
|
14
|
+
from modland import generate_modland_grid
|
15
|
+
from rasters import Raster, RasterGrid, RasterGeometry
|
16
|
+
|
17
|
+
from .VIIRSDownloader import VIIRSDownloaderNDVI
|
18
|
+
from .VIIRSDataPool import VIIRSDataPool, VIIRSGranule
|
19
|
+
|
20
|
+
NDVI_COLORMAP = "jet_r"
|
21
|
+
ALBEDO_COLORMAP = "gray"
|
22
|
+
|
23
|
+
logger = logging.getLogger(__name__)
|
24
|
+
|
25
|
+
|
26
|
+
class VIIRSUnavailableError(Exception):
|
27
|
+
pass
|
28
|
+
|
29
|
+
|
30
|
+
class VNP43IA4Granule(VIIRSGranule):
|
31
|
+
def reflectance(
|
32
|
+
self,
|
33
|
+
band: int,
|
34
|
+
geometry: RasterGeometry = None,
|
35
|
+
save_data: bool = False,
|
36
|
+
include_preview: bool = True,
|
37
|
+
apply_QA: bool = True,
|
38
|
+
product_filename: str = None) -> Raster:
|
39
|
+
if product_filename is None:
|
40
|
+
product_filename = self.product_filename(f"I{band}")
|
41
|
+
|
42
|
+
if product_filename is not None and exists(product_filename):
|
43
|
+
logger.info(f"loading VNP43IA4 NBAR I{band}: {cl.file(product_filename)}")
|
44
|
+
image = Raster.open(product_filename)
|
45
|
+
else:
|
46
|
+
image = self.dataset(
|
47
|
+
filename=self.filename,
|
48
|
+
dataset_name=f"HDFEOS/GRIDS/VIIRS_Grid_BRDF/Data Fields/Nadir_Reflectance_I{int(band)}",
|
49
|
+
fill_value=32767,
|
50
|
+
scale_factor=0.0001
|
51
|
+
)
|
52
|
+
|
53
|
+
if apply_QA:
|
54
|
+
QA = self.QA(
|
55
|
+
band=band,
|
56
|
+
geometry=geometry,
|
57
|
+
save_data=save_data,
|
58
|
+
include_preview=include_preview
|
59
|
+
)
|
60
|
+
|
61
|
+
image = rt.where(QA == 0, image, np.nan)
|
62
|
+
|
63
|
+
if save_data and not exists(product_filename):
|
64
|
+
logger.info(f"writing VNP43IA4 NBAR I{band}: {cl.file(product_filename)}")
|
65
|
+
image.to_geotiff(product_filename, include_preview=include_preview)
|
66
|
+
|
67
|
+
if geometry is not None:
|
68
|
+
image = image.to_geometry(geometry)
|
69
|
+
|
70
|
+
return image
|
71
|
+
|
72
|
+
def QA(
|
73
|
+
self,
|
74
|
+
band: int,
|
75
|
+
geometry: RasterGeometry = None,
|
76
|
+
save_data: bool = True,
|
77
|
+
include_preview: bool = True,
|
78
|
+
product_filename: str = None) -> Raster:
|
79
|
+
if product_filename is None:
|
80
|
+
product_filename = self.product_filename(f"VNP43IA4_QA_I{band}")
|
81
|
+
|
82
|
+
if product_filename is not None and exists(product_filename):
|
83
|
+
logger.info(f"loading VNP43IA4 QA I{band}: {cl.file(product_filename)}")
|
84
|
+
image = Raster.open(product_filename)
|
85
|
+
else:
|
86
|
+
dataset_name = f"HDFEOS/GRIDS/VIIRS_Grid_BRDF/Data Fields/BRDF_Albedo_Band_Mandatory_Quality_I{int(band)}"
|
87
|
+
|
88
|
+
with h5py.File(self.filename, "r") as f:
|
89
|
+
image = np.array(f[dataset_name])
|
90
|
+
h, v = self.hv
|
91
|
+
grid = generate_modland_grid(h, v, image.shape[0])
|
92
|
+
logger.info(f"opening file: {cl.file(self.filename)}")
|
93
|
+
logger.info(f"loading {cl.val(dataset_name)} at {cl.val(f'{grid.cell_size:0.2f} m')} resolution")
|
94
|
+
image = Raster(image, geometry=grid)
|
95
|
+
|
96
|
+
if save_data and not exists(product_filename):
|
97
|
+
logger.info(f"writing VNP43IA4 QA I{band}: {cl.file(product_filename)}")
|
98
|
+
image.to_geotiff(product_filename, include_preview=include_preview)
|
99
|
+
|
100
|
+
if geometry is not None:
|
101
|
+
image = image.to_geometry(geometry)
|
102
|
+
|
103
|
+
return image
|
104
|
+
|
105
|
+
@property
|
106
|
+
def red(self) -> Raster:
|
107
|
+
return self.reflectance(1)
|
108
|
+
|
109
|
+
@property
|
110
|
+
def NIR(self) -> Raster:
|
111
|
+
return self.reflectance(2)
|
112
|
+
|
113
|
+
@property
|
114
|
+
def NDVI(self) -> Raster:
|
115
|
+
NDVI = (self.NIR - self.red) / (self.NIR + self.red)
|
116
|
+
NDVI = rt.clip(NDVI, -1, 1)
|
117
|
+
|
118
|
+
return NDVI
|
119
|
+
|
120
|
+
@property
|
121
|
+
def SWIR1(self) -> Raster:
|
122
|
+
return self.reflectance(3)
|
123
|
+
|
124
|
+
def product(self, product: str) -> Raster:
|
125
|
+
if product == "red":
|
126
|
+
return self.red
|
127
|
+
elif product == "NIR":
|
128
|
+
return self.NIR
|
129
|
+
elif product == "NDVI":
|
130
|
+
return self.NDVI
|
131
|
+
elif product == "SWIR1":
|
132
|
+
return self.SWIR1
|
133
|
+
else:
|
134
|
+
raise ValueError(f"unrecognized product: {product}")
|
135
|
+
|
136
|
+
|
137
|
+
class VNP43IA4(VIIRSDataPool, VIIRSDownloaderNDVI):
|
138
|
+
DEFAULT_DOWNLOAD_DIRECTORY = "VNP43IA4_download"
|
139
|
+
DEFAULT_PRODUCTS_DIRECTORY = "VNP43IA4_products"
|
140
|
+
DEFAULT_MOSAIC_DIRECTORY = "VNP43IA4_mosaics"
|
141
|
+
|
142
|
+
def __init__(
|
143
|
+
self,
|
144
|
+
username: str = None,
|
145
|
+
password: str = None,
|
146
|
+
remote: str = None,
|
147
|
+
working_directory: str = None,
|
148
|
+
download_directory: str = None,
|
149
|
+
products_directory: str = None,
|
150
|
+
mosaic_directory: str = None,
|
151
|
+
*args,
|
152
|
+
**kwargs):
|
153
|
+
super(VNP43IA4, self).__init__(
|
154
|
+
username=username,
|
155
|
+
password=password,
|
156
|
+
remote=remote,
|
157
|
+
working_directory=working_directory,
|
158
|
+
download_directory=download_directory,
|
159
|
+
products_directory=products_directory,
|
160
|
+
mosaic_directory=mosaic_directory,
|
161
|
+
*args,
|
162
|
+
**kwargs
|
163
|
+
)
|
164
|
+
|
165
|
+
logger.info(f"VNP43IA4 LP-DAAC URL: {cl.URL(self.remote)}")
|
166
|
+
logger.info(f"VNP43IA4 working directory: {cl.dir(self.working_directory)}")
|
167
|
+
logger.info(f"VNP43IA4 download directory: {cl.dir(self.download_directory)}")
|
168
|
+
logger.info(f"VNP43IA4 products directory: {cl.dir(self.products_directory)}")
|
169
|
+
|
170
|
+
def search(
|
171
|
+
self,
|
172
|
+
start_date: date or datetime or str,
|
173
|
+
end_date: date or datetime or str = None,
|
174
|
+
build: str = None,
|
175
|
+
tiles: List[str] or str = None,
|
176
|
+
target_geometry: Point or Polygon or RasterGrid = None,
|
177
|
+
*args,
|
178
|
+
**kwargs) -> pd.DataFrame:
|
179
|
+
return super(VNP43IA4, self).search(
|
180
|
+
product="VNP43IA4",
|
181
|
+
start_date=start_date,
|
182
|
+
end_date=end_date,
|
183
|
+
build=build,
|
184
|
+
tiles=tiles,
|
185
|
+
target_geometry=target_geometry,
|
186
|
+
*args,
|
187
|
+
**kwargs
|
188
|
+
)
|
189
|
+
|
190
|
+
def granule(
|
191
|
+
self,
|
192
|
+
date_UTC: Union[date, str],
|
193
|
+
tile: str,
|
194
|
+
download_location: str = None,
|
195
|
+
build: str = None) -> VNP43IA4Granule:
|
196
|
+
listing = self.search(
|
197
|
+
start_date=date_UTC,
|
198
|
+
end_date=date_UTC,
|
199
|
+
build=build,
|
200
|
+
tiles=[tile]
|
201
|
+
)
|
202
|
+
|
203
|
+
if len(listing) > 0:
|
204
|
+
URL = listing.iloc[0].URL
|
205
|
+
|
206
|
+
filename = super(VNP43IA4, self).download_URL(
|
207
|
+
URL=URL,
|
208
|
+
download_location=download_location
|
209
|
+
)
|
210
|
+
|
211
|
+
granule = VNP43IA4Granule(
|
212
|
+
filename=filename,
|
213
|
+
products_directory=self.products_directory
|
214
|
+
)
|
215
|
+
|
216
|
+
return granule
|
217
|
+
|
218
|
+
def product_filename(self, target: str, date_UTC: Union[date, str], product: str, resolution: int) -> str:
|
219
|
+
if not isinstance(date_UTC, date):
|
220
|
+
date_UTC = parser.parse(str(date_UTC)).date()
|
221
|
+
|
222
|
+
timestamp = date_UTC.strftime("%Y.%m.%d")
|
223
|
+
product_directory = join(self.products_directory, product, timestamp)
|
224
|
+
product_filename_base = f"VNP43IA4_{target}_{timestamp}_{product}_{resolution}m.tif"
|
225
|
+
product_filename = join(product_directory, product_filename_base)
|
226
|
+
|
227
|
+
return product_filename
|
228
|
+
|
229
|
+
def product(
|
230
|
+
self,
|
231
|
+
product: str,
|
232
|
+
date_UTC: Union[date, str],
|
233
|
+
geometry: RasterGeometry,
|
234
|
+
target: str = None,
|
235
|
+
filename: str = None,
|
236
|
+
save_data: bool = True,
|
237
|
+
resampling: str = None) -> Raster:
|
238
|
+
if isinstance(date_UTC, str):
|
239
|
+
date_UTC = parser.parse(date_UTC).date()
|
240
|
+
|
241
|
+
if filename is None and target is not None:
|
242
|
+
filename = self.product_filename(
|
243
|
+
target=target,
|
244
|
+
date_UTC=date_UTC,
|
245
|
+
product=product,
|
246
|
+
resolution=int(geometry.cell_size_meters)
|
247
|
+
)
|
248
|
+
|
249
|
+
if filename is not None and exists(filename):
|
250
|
+
return Raster.open(filename)
|
251
|
+
|
252
|
+
tiles = sorted(find_modland_tiles(geometry.boundary_latlon.geometry))
|
253
|
+
|
254
|
+
if len(tiles) == 0:
|
255
|
+
raise ValueError("no VIIRS tiles found covering target geometry")
|
256
|
+
|
257
|
+
composite = None
|
258
|
+
|
259
|
+
for tile in tiles:
|
260
|
+
granule = self.granule(date_UTC=date_UTC, tile=tile)
|
261
|
+
granule_image = granule.product(product=product)
|
262
|
+
producted_image = granule_image.to_geometry(geometry, resampling=resampling)
|
263
|
+
|
264
|
+
if composite is None:
|
265
|
+
composite = producted_image
|
266
|
+
else:
|
267
|
+
composite = rt.where(np.isnan(composite), producted_image, composite)
|
268
|
+
|
269
|
+
if composite is None:
|
270
|
+
raise ValueError("VIIRS composite did not generate")
|
271
|
+
|
272
|
+
if save_data and filename is not None:
|
273
|
+
logger.info(f"writing composite: {cl.file(filename)}")
|
274
|
+
composite.to_geotiff(filename)
|
275
|
+
|
276
|
+
return composite
|
277
|
+
|
278
|
+
def red(self, date_UTC: Union[date, str], geometry: RasterGeometry) -> Raster:
|
279
|
+
return self.product(product="red", date_UTC=date_UTC, geometry=geometry)
|
280
|
+
|
281
|
+
def NIR(self, date_UTC: Union[date, str], geometry: RasterGeometry) -> Raster:
|
282
|
+
return self.product(product="NIR", date_UTC=date_UTC, geometry=geometry)
|
283
|
+
|
284
|
+
def NDVI(self, date_UTC: Union[date, str], geometry: RasterGeometry) -> Raster:
|
285
|
+
return self.product(product="NDVI", date_UTC=date_UTC, geometry=geometry)
|
286
|
+
|
287
|
+
def SWIR1(self, date_UTC: Union[date, str], geometry: RasterGeometry) -> Raster:
|
288
|
+
return self.product(product="SWIR1", date_UTC=date_UTC, geometry=geometry)
|
@@ -0,0 +1,323 @@
|
|
1
|
+
import logging
|
2
|
+
from datetime import datetime, date
|
3
|
+
from os.path import exists
|
4
|
+
from typing import List
|
5
|
+
import h5py
|
6
|
+
import numpy as np
|
7
|
+
import pandas as pd
|
8
|
+
from shapely.geometry import Point, Polygon
|
9
|
+
from dateutil import parser
|
10
|
+
import colored_logging as cl
|
11
|
+
import rasters as rt
|
12
|
+
from rasters import Raster, RasterGrid, RasterGeometry
|
13
|
+
from GEOS5FP import GEOS5FP
|
14
|
+
from modland import find_modland_tiles, generate_modland_grid, parsehv
|
15
|
+
|
16
|
+
from ..BRDF import bidirectional_reflectance
|
17
|
+
from ..BRDF.SZA import calculate_SZA
|
18
|
+
from .VIIRSDownloader import VIIRSDownloaderAlbedo
|
19
|
+
from .VIIRSDataPool import VIIRSDataPool, VIIRSGranule
|
20
|
+
|
21
|
+
NDVI_COLORMAP = "jet_r"
|
22
|
+
ALBEDO_COLORMAP = "gray"
|
23
|
+
|
24
|
+
logger = logging.getLogger(__name__)
|
25
|
+
|
26
|
+
|
27
|
+
class VIIRSUnavailableError(Exception):
|
28
|
+
pass
|
29
|
+
|
30
|
+
|
31
|
+
class VNP43MA3Granule(VIIRSGranule):
|
32
|
+
def __init__(
|
33
|
+
self,
|
34
|
+
filename: str,
|
35
|
+
working_directory: str = None,
|
36
|
+
products_directory: str = None,
|
37
|
+
GEOS5FP_connection: GEOS5FP = None,
|
38
|
+
GEOS5FP_download: str = None,
|
39
|
+
GEOS5FP_products: str = None):
|
40
|
+
super(VNP43MA3Granule, self).__init__(
|
41
|
+
filename=filename,
|
42
|
+
working_directory=working_directory,
|
43
|
+
products_directory=products_directory
|
44
|
+
)
|
45
|
+
|
46
|
+
if GEOS5FP_connection is None:
|
47
|
+
GEOS5FP_connection = GEOS5FP(
|
48
|
+
working_directory=working_directory,
|
49
|
+
download_directory=GEOS5FP_download,
|
50
|
+
products_directory=GEOS5FP_products
|
51
|
+
)
|
52
|
+
|
53
|
+
self.GEOS5FP = GEOS5FP_connection
|
54
|
+
|
55
|
+
def BSA(
|
56
|
+
self,
|
57
|
+
band: int,
|
58
|
+
geometry: RasterGeometry = None,
|
59
|
+
save_data: bool = True,
|
60
|
+
include_preview: bool = True,
|
61
|
+
apply_QA: bool = True,
|
62
|
+
product_filename: str = None) -> Raster:
|
63
|
+
if product_filename is None:
|
64
|
+
product_filename = self.product_filename(f"BSA_M{band}")
|
65
|
+
|
66
|
+
if product_filename is not None and exists(product_filename):
|
67
|
+
logger.info(f"loading VNP43MA3 BSA M{band}: {cl.file(product_filename)}")
|
68
|
+
image = Raster.open(product_filename)
|
69
|
+
else:
|
70
|
+
image = self.dataset(
|
71
|
+
filename=self.filename,
|
72
|
+
dataset_name=f"HDFEOS/GRIDS/VIIRS_Grid_BRDF/Data Fields/Albedo_BSA_M{int(band)}",
|
73
|
+
fill_value=32767,
|
74
|
+
scale_factor=0.001
|
75
|
+
)
|
76
|
+
|
77
|
+
if apply_QA:
|
78
|
+
QA = self.QA(
|
79
|
+
band=band,
|
80
|
+
geometry=geometry,
|
81
|
+
save_data=save_data,
|
82
|
+
include_preview=include_preview
|
83
|
+
)
|
84
|
+
|
85
|
+
image = rt.where(QA == 0, image, np.nan)
|
86
|
+
|
87
|
+
if save_data and not exists(product_filename):
|
88
|
+
logger.info(f"writing VNP43MA3 BSA M{band}: {cl.file(product_filename)}")
|
89
|
+
image.to_geotiff(product_filename, include_preview=include_preview)
|
90
|
+
|
91
|
+
if geometry is not None:
|
92
|
+
image = image.to_geometry(geometry)
|
93
|
+
|
94
|
+
return image
|
95
|
+
|
96
|
+
def WSA(
|
97
|
+
self,
|
98
|
+
band: int,
|
99
|
+
geometry: RasterGeometry = None,
|
100
|
+
save_data: bool = True,
|
101
|
+
include_preview: bool = True,
|
102
|
+
apply_QA: bool = True,
|
103
|
+
product_filename: str = None) -> Raster:
|
104
|
+
if product_filename is None:
|
105
|
+
product_filename = self.product_filename(f"WSA_M{band}")
|
106
|
+
|
107
|
+
if product_filename is not None and exists(product_filename):
|
108
|
+
logger.info(f"loading VNP43MA3 WSA M{band}: {cl.file(product_filename)}")
|
109
|
+
image = Raster.open(product_filename)
|
110
|
+
else:
|
111
|
+
image = self.dataset(
|
112
|
+
filename=self.filename,
|
113
|
+
dataset_name=f"HDFEOS/GRIDS/VIIRS_Grid_BRDF/Data Fields/Albedo_WSA_M{int(band)}",
|
114
|
+
fill_value=32767,
|
115
|
+
scale_factor=0.001
|
116
|
+
)
|
117
|
+
|
118
|
+
if apply_QA:
|
119
|
+
QA = self.QA(
|
120
|
+
band=band,
|
121
|
+
geometry=geometry,
|
122
|
+
save_data=save_data,
|
123
|
+
include_preview=include_preview
|
124
|
+
)
|
125
|
+
|
126
|
+
image = rt.where(QA == 0, image, np.nan)
|
127
|
+
|
128
|
+
if save_data and not exists(product_filename):
|
129
|
+
logger.info(f"writing VNP43MA3 WSA M{band}: {cl.file(product_filename)}")
|
130
|
+
image.to_geotiff(product_filename, include_preview=include_preview)
|
131
|
+
|
132
|
+
if geometry is not None:
|
133
|
+
image = image.to_geometry(geometry)
|
134
|
+
|
135
|
+
return image
|
136
|
+
|
137
|
+
def QA(
|
138
|
+
self,
|
139
|
+
band: int,
|
140
|
+
geometry: RasterGeometry = None,
|
141
|
+
save_data: bool = True,
|
142
|
+
include_preview: bool = True,
|
143
|
+
product_filename: str = None) -> Raster:
|
144
|
+
if product_filename is None:
|
145
|
+
product_filename = self.product_filename(f"VNP43MA3_QA_M{band}")
|
146
|
+
|
147
|
+
if product_filename is not None and exists(product_filename):
|
148
|
+
logger.info(f"loading VNP43MA3 QA M{band}: {cl.file(product_filename)}")
|
149
|
+
image = Raster.open(product_filename)
|
150
|
+
else:
|
151
|
+
dataset_name = f"HDFEOS/GRIDS/VIIRS_Grid_BRDF/Data Fields/BRDF_Albedo_Band_Mandatory_Quality_M{int(band)}"
|
152
|
+
|
153
|
+
with h5py.File(self.filename, "r") as f:
|
154
|
+
image = np.array(f[dataset_name])
|
155
|
+
h, v = self.hv
|
156
|
+
grid = generate_modland_grid(h, v, image.shape[0])
|
157
|
+
logger.info(f"opening file: {cl.file(self.filename)}")
|
158
|
+
logger.info(f"loading {cl.val(dataset_name)} at {cl.val(f'{grid.cell_size:0.2f} m')} resolution")
|
159
|
+
image = Raster(image, geometry=grid)
|
160
|
+
|
161
|
+
if save_data and not exists(product_filename):
|
162
|
+
logger.info(f"writing VNP43MA3 QA M{band}: {cl.file(product_filename)}")
|
163
|
+
image.to_geotiff(product_filename, include_preview=include_preview)
|
164
|
+
|
165
|
+
if geometry is not None:
|
166
|
+
image = image.to_geometry(geometry)
|
167
|
+
|
168
|
+
return image
|
169
|
+
|
170
|
+
@property
|
171
|
+
def geometry(self) -> RasterGrid:
|
172
|
+
return generate_modland_grid(*parsehv(self.tile), 1200)
|
173
|
+
|
174
|
+
def get_albedo(
|
175
|
+
self,
|
176
|
+
geometry: RasterGeometry = None,
|
177
|
+
save_data: bool = True,
|
178
|
+
include_preview: bool = True,
|
179
|
+
product_filename: str = None) -> Raster:
|
180
|
+
if product_filename is None:
|
181
|
+
product_filename = self.product_filename("albedo")
|
182
|
+
|
183
|
+
if product_filename is not None and exists(product_filename):
|
184
|
+
logger.info(f"loading VNP43MA3 albedo: {cl.file(product_filename)}")
|
185
|
+
image = Raster.open(product_filename)
|
186
|
+
else:
|
187
|
+
date_UTC = self.date_UTC
|
188
|
+
doy = date_UTC.timetuple().tm_yday
|
189
|
+
SZA = calculate_SZA(doy, 10.5, self.geometry)
|
190
|
+
time_UTC = datetime(date_UTC.year, date_UTC.month, date_UTC.day, 10, 30)
|
191
|
+
AOT = self.GEOS5FP.AOT(time_UTC=time_UTC, geometry=self.geometry, resampling="cubic")
|
192
|
+
|
193
|
+
b = {}
|
194
|
+
|
195
|
+
for m in (1, 2, 3, 4, 5, 7, 8, 10, 11):
|
196
|
+
WSA = self.WSA(m)
|
197
|
+
BSA = self.BSA(m)
|
198
|
+
|
199
|
+
band_albedo = bidirectional_reflectance(
|
200
|
+
white_sky_albedo=WSA,
|
201
|
+
black_sky_albedo=BSA,
|
202
|
+
SZA=SZA,
|
203
|
+
AOT=AOT
|
204
|
+
)
|
205
|
+
|
206
|
+
b[m] = band_albedo
|
207
|
+
|
208
|
+
image = 0.2418 * b[1] \
|
209
|
+
- 0.201 * b[2] \
|
210
|
+
+ 0.2093 * b[3] \
|
211
|
+
+ 0.1146 * b[4] \
|
212
|
+
+ 0.1348 * b[5] \
|
213
|
+
+ 0.2251 * b[7] \
|
214
|
+
+ 0.1123 * b[8] \
|
215
|
+
+ 0.0860 * b[10] \
|
216
|
+
+ 0.0803 * b[11] \
|
217
|
+
- 0.0131
|
218
|
+
|
219
|
+
if save_data and not exists(product_filename):
|
220
|
+
logger.info(f"writing VNP43MA3 albedo: {cl.file(product_filename)}")
|
221
|
+
image.to_geotiff(product_filename, include_preview=include_preview)
|
222
|
+
|
223
|
+
if geometry is not None:
|
224
|
+
image = image.to_geometry(geometry)
|
225
|
+
|
226
|
+
image.cmap = ALBEDO_COLORMAP
|
227
|
+
|
228
|
+
return image
|
229
|
+
|
230
|
+
albedo = property(get_albedo)
|
231
|
+
|
232
|
+
|
233
|
+
class VNP43MA3(VIIRSDataPool, VIIRSDownloaderAlbedo):
|
234
|
+
DEFAULT_DOWNLOAD_DIRECTORY = "VNP43MA3_download"
|
235
|
+
DEFAULT_PRODUCTS_DIRECTORY = "VNP43MA3_products"
|
236
|
+
DEFAULT_MOSAIC_DIRECTORY = "VNP43MA3_mosaics"
|
237
|
+
|
238
|
+
def search(
|
239
|
+
self,
|
240
|
+
start_date: date or datetime or str,
|
241
|
+
end_date: date or datetime or str = None,
|
242
|
+
build: str = None,
|
243
|
+
tiles: List[str] or str = None,
|
244
|
+
target_geometry: Point or Polygon or RasterGrid = None,
|
245
|
+
*args,
|
246
|
+
**kwargs) -> pd.DataFrame:
|
247
|
+
return super(VNP43MA3, self).search(
|
248
|
+
product="VNP43MA3",
|
249
|
+
start_date=start_date,
|
250
|
+
end_date=end_date,
|
251
|
+
build=build,
|
252
|
+
tiles=tiles,
|
253
|
+
target_geometry=target_geometry,
|
254
|
+
*args,
|
255
|
+
**kwargs
|
256
|
+
)
|
257
|
+
|
258
|
+
def granule(
|
259
|
+
self,
|
260
|
+
date_UTC: date or str,
|
261
|
+
tile: str,
|
262
|
+
download_location: str = None,
|
263
|
+
build: str = None) -> VNP43MA3Granule:
|
264
|
+
listing = self.search(
|
265
|
+
start_date=date_UTC,
|
266
|
+
end_date=date_UTC,
|
267
|
+
build=build,
|
268
|
+
tiles=[tile]
|
269
|
+
)
|
270
|
+
|
271
|
+
if len(listing) > 0:
|
272
|
+
URL = listing.iloc[0].URL
|
273
|
+
|
274
|
+
filename = super(VNP43MA3, self).download_URL(
|
275
|
+
URL=URL,
|
276
|
+
download_location=download_location
|
277
|
+
)
|
278
|
+
|
279
|
+
granule = VNP43MA3Granule(
|
280
|
+
filename=filename,
|
281
|
+
products_directory=self.products_directory
|
282
|
+
)
|
283
|
+
|
284
|
+
return granule
|
285
|
+
|
286
|
+
def albedo(
|
287
|
+
self,
|
288
|
+
date_UTC: date or str,
|
289
|
+
geometry: RasterGeometry,
|
290
|
+
filename: str = None,
|
291
|
+
resampling: str = None) -> Raster:
|
292
|
+
if isinstance(date_UTC, str):
|
293
|
+
date_UTC = parser.parse(date_UTC).date()
|
294
|
+
|
295
|
+
if filename is not None and exists(filename):
|
296
|
+
return Raster.open(filename, cmap=ALBEDO_COLORMAP)
|
297
|
+
|
298
|
+
# if resampling is None:
|
299
|
+
# resampling = self.resampling
|
300
|
+
|
301
|
+
tiles = sorted(find_modland_tiles(geometry.boundary_latlon.geometry))
|
302
|
+
albedo = None
|
303
|
+
|
304
|
+
for tile in tiles:
|
305
|
+
granule = self.granule(date_UTC=date_UTC, tile=tile)
|
306
|
+
granule_albedo = granule.albedo
|
307
|
+
source_cell_size = granule_albedo.geometry.cell_size
|
308
|
+
dest_cell_size = geometry.cell_size
|
309
|
+
logger.info(f"projecting VIIRS albedo from {cl.val(f'{source_cell_size} m')} to {cl.val(f'{dest_cell_size} m')}")
|
310
|
+
projected_albedo = granule_albedo.to_geometry(geometry, resampling=resampling)
|
311
|
+
|
312
|
+
if albedo is None:
|
313
|
+
albedo = projected_albedo
|
314
|
+
else:
|
315
|
+
albedo = rt.where(np.isnan(albedo), projected_albedo, albedo)
|
316
|
+
|
317
|
+
albedo.cmap = ALBEDO_COLORMAP
|
318
|
+
|
319
|
+
if filename is not None:
|
320
|
+
logger.info(f"writing albedo mosaic: {cl.file(filename)}")
|
321
|
+
albedo.to_geotiff(filename)
|
322
|
+
|
323
|
+
return albedo
|
@@ -0,0 +1,9 @@
|
|
1
|
+
from os.path import join, abspath, dirname
|
2
|
+
|
3
|
+
from .VIIRSDownloader import VIIRSDownloaderAlbedo, VIIRSDownloaderNDVI
|
4
|
+
|
5
|
+
with open(join(abspath(dirname(__file__)), "version.txt")) as f:
|
6
|
+
version = f.read()
|
7
|
+
|
8
|
+
__version__ = version
|
9
|
+
__author__ = "Gregory H. Halverson"
|
@@ -0,0 +1 @@
|
|
1
|
+
0.6.0
|