ECOv003-L2T-STARS 1.0.0__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.
Files changed (75) hide show
  1. ECOv003_L2T_STARS/BRDF/BRDF.py +57 -0
  2. ECOv003_L2T_STARS/BRDF/SZA.py +65 -0
  3. ECOv003_L2T_STARS/BRDF/__init__.py +1 -0
  4. ECOv003_L2T_STARS/BRDF/statistical_radiative_transport.txt +90 -0
  5. ECOv003_L2T_STARS/BRDF/version.txt +1 -0
  6. ECOv003_L2T_STARS/ECOv003_DL.py +527 -0
  7. ECOv003_L2T_STARS/ECOv003_DL.xml +47 -0
  8. ECOv003_L2T_STARS/ECOv003_L2T_STARS.py +162 -0
  9. ECOv003_L2T_STARS/ECOv003_L2T_STARS.xml +47 -0
  10. ECOv003_L2T_STARS/L2TSTARSConfig.py +188 -0
  11. ECOv003_L2T_STARS/L2T_STARS.py +489 -0
  12. ECOv003_L2T_STARS/LPDAAC/LPDAACDataPool.py +444 -0
  13. ECOv003_L2T_STARS/LPDAAC/__init__.py +9 -0
  14. ECOv003_L2T_STARS/LPDAAC/version.txt +1 -0
  15. ECOv003_L2T_STARS/Manifest.toml +2332 -0
  16. ECOv003_L2T_STARS/Project.toml +14 -0
  17. ECOv003_L2T_STARS/VIIRS/VIIRSDataPool.py +294 -0
  18. ECOv003_L2T_STARS/VIIRS/VIIRSDownloader.py +26 -0
  19. ECOv003_L2T_STARS/VIIRS/VIIRS_CMR_LOGIN.py +36 -0
  20. ECOv003_L2T_STARS/VIIRS/VNP09GA.py +1277 -0
  21. ECOv003_L2T_STARS/VIIRS/VNP43IA4.py +288 -0
  22. ECOv003_L2T_STARS/VIIRS/VNP43MA3.py +323 -0
  23. ECOv003_L2T_STARS/VIIRS/__init__.py +9 -0
  24. ECOv003_L2T_STARS/VIIRS/version.txt +1 -0
  25. ECOv003_L2T_STARS/VNP43NRT/VNP43NRT.py +863 -0
  26. ECOv003_L2T_STARS/VNP43NRT/__init__.py +1 -0
  27. ECOv003_L2T_STARS/VNP43NRT/process_VNP43NRT.jl +169 -0
  28. ECOv003_L2T_STARS/VNP43NRT/version.txt +1 -0
  29. ECOv003_L2T_STARS/VNP43NRT_jl/Manifest.toml +995 -0
  30. ECOv003_L2T_STARS/VNP43NRT_jl/Project.toml +15 -0
  31. ECOv003_L2T_STARS/VNP43NRT_jl/__init__.py +0 -0
  32. ECOv003_L2T_STARS/VNP43NRT_jl/instantiate.jl +25 -0
  33. ECOv003_L2T_STARS/VNP43NRT_jl/instantiate.py +13 -0
  34. ECOv003_L2T_STARS/VNP43NRT_jl/src/VNP43NRT.jl +411 -0
  35. ECOv003_L2T_STARS/VNP43NRT_jl/src/__init__.py +0 -0
  36. ECOv003_L2T_STARS/__init__.py +3 -0
  37. ECOv003_L2T_STARS/calibrate_fine_to_coarse.py +60 -0
  38. ECOv003_L2T_STARS/constants.py +38 -0
  39. ECOv003_L2T_STARS/daterange/__init__.py +1 -0
  40. ECOv003_L2T_STARS/daterange/daterange.py +35 -0
  41. ECOv003_L2T_STARS/generate_L2T_STARS_runconfig.py +249 -0
  42. ECOv003_L2T_STARS/generate_NDVI_coarse_directory.py +21 -0
  43. ECOv003_L2T_STARS/generate_NDVI_coarse_image.py +30 -0
  44. ECOv003_L2T_STARS/generate_NDVI_fine_directory.py +14 -0
  45. ECOv003_L2T_STARS/generate_NDVI_fine_image.py +28 -0
  46. ECOv003_L2T_STARS/generate_STARS_inputs.py +231 -0
  47. ECOv003_L2T_STARS/generate_albedo_coarse_directory.py +18 -0
  48. ECOv003_L2T_STARS/generate_albedo_coarse_image.py +30 -0
  49. ECOv003_L2T_STARS/generate_albedo_fine_directory.py +17 -0
  50. ECOv003_L2T_STARS/generate_albedo_fine_image.py +30 -0
  51. ECOv003_L2T_STARS/generate_filename.py +37 -0
  52. ECOv003_L2T_STARS/generate_input_staging_directory.py +23 -0
  53. ECOv003_L2T_STARS/generate_model_state_tile_date_directory.py +28 -0
  54. ECOv003_L2T_STARS/generate_output_directory.py +28 -0
  55. ECOv003_L2T_STARS/install_STARS_jl.py +43 -0
  56. ECOv003_L2T_STARS/instantiate_STARS_jl.py +38 -0
  57. ECOv003_L2T_STARS/load_prior.py +248 -0
  58. ECOv003_L2T_STARS/prior.py +56 -0
  59. ECOv003_L2T_STARS/process_ECOSTRESS_data_fusion_distributed_bias.jl +420 -0
  60. ECOv003_L2T_STARS/process_STARS_product.py +507 -0
  61. ECOv003_L2T_STARS/process_julia_data_fusion.py +110 -0
  62. ECOv003_L2T_STARS/retrieve_STARS_sources.py +101 -0
  63. ECOv003_L2T_STARS/runconfig.py +70 -0
  64. ECOv003_L2T_STARS/timer/__init__.py +1 -0
  65. ECOv003_L2T_STARS/timer/timer.py +77 -0
  66. ECOv003_L2T_STARS/version.py +8 -0
  67. ECOv003_L2T_STARS/version.txt +1 -0
  68. {ECOv003_L2T_STARS-1.0.0.dist-info → ecov003_l2t_stars-1.1.0.dist-info}/METADATA +30 -23
  69. ecov003_l2t_stars-1.1.0.dist-info/RECORD +73 -0
  70. {ECOv003_L2T_STARS-1.0.0.dist-info → ecov003_l2t_stars-1.1.0.dist-info}/WHEEL +1 -1
  71. ecov003_l2t_stars-1.1.0.dist-info/entry_points.txt +3 -0
  72. ecov003_l2t_stars-1.1.0.dist-info/top_level.txt +1 -0
  73. ECOv003_L2T_STARS-1.0.0.dist-info/RECORD +0 -5
  74. ECOv003_L2T_STARS-1.0.0.dist-info/top_level.txt +0 -1
  75. {ECOv003_L2T_STARS-1.0.0.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