diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..e0ea542 --- /dev/null +++ b/.flake8 @@ -0,0 +1,3 @@ +[flake8] +max-line-length = 88 +extend-ignore = E203 \ No newline at end of file diff --git a/ee_lst/aster_bare_emiss.py b/ee_lst/aster_bare_emiss.py index 9e9aa68..ed6c0a6 100644 --- a/ee_lst/aster_bare_emiss.py +++ b/ee_lst/aster_bare_emiss.py @@ -4,10 +4,10 @@ aster = ee.Image("NASA/ASTER_GED/AG100_003") # Calculate ASTER FVC from NDVI -aster_ndvi = aster.select('ndvi').multiply(0.01) +aster_ndvi = aster.select("ndvi").multiply(0.01) aster_fvc = aster_ndvi.expression( - '((ndvi - ndvi_bg) / (ndvi_vg - ndvi_bg)) ** 2', - {'ndvi': aster_ndvi, 'ndvi_bg': 0.2, 'ndvi_vg': 0.86} + "((ndvi - ndvi_bg) / (ndvi_vg - ndvi_bg)) ** 2", + {"ndvi": aster_ndvi, "ndvi_bg": 0.2, "ndvi_vg": 0.86}, ) aster_fvc = aster_fvc.where(aster_fvc.lt(0.0), 0.0) aster_fvc = aster_fvc.where(aster_fvc.gt(1.0), 1.0) @@ -25,30 +25,27 @@ def emiss_bare_band(band, image): - ee.Image: Bare ground emissivity of the specified band """ return image.expression( - '(EM - 0.99 * fvc) / (1.0 - fvc)', - { - 'EM': aster.select(band).multiply(0.001), - 'fvc': aster_fvc - } + "(EM - 0.99 * fvc) / (1.0 - fvc)", + {"EM": aster.select(band).multiply(0.001), "fvc": aster_fvc}, ).clip(image.geometry()) # Define functions for each band def emiss_bare_band10(image): - return emiss_bare_band('emissivity_band10', image) + return emiss_bare_band("emissivity_band10", image) def emiss_bare_band11(image): - return emiss_bare_band('emissivity_band11', image) + return emiss_bare_band("emissivity_band11", image) def emiss_bare_band12(image): - return emiss_bare_band('emissivity_band12', image) + return emiss_bare_band("emissivity_band12", image) def emiss_bare_band13(image): - return emiss_bare_band('emissivity_band13', image) + return emiss_bare_band("emissivity_band13", image) def emiss_bare_band14(image): - return emiss_bare_band('emissivity_band14', image) + return emiss_bare_band("emissivity_band14", image) diff --git a/ee_lst/broadband_emiss.py b/ee_lst/broadband_emiss.py index 35baa8c..9fb0425 100644 --- a/ee_lst/broadband_emiss.py +++ b/ee_lst/broadband_emiss.py @@ -4,7 +4,7 @@ emiss_bare_band11, emiss_bare_band12, emiss_bare_band13, - emiss_bare_band14 + emiss_bare_band14, ) @@ -28,24 +28,21 @@ def add_band(dynamic, image): def compute_emissivity(orig_band, emiss_bare_func): orig = aster.select(orig_band).multiply(0.001) dynam = image.expression( - 'fvc * 0.99 + (1 - fvc) * em_bare', - { - 'fvc': image.select('FVC'), - 'em_bare': emiss_bare_func(image) - } + "fvc * 0.99 + (1 - fvc) * em_bare", + {"fvc": image.select("FVC"), "em_bare": emiss_bare_func(image)}, ) return ee.Image(ee.Algorithms.If(dynamic, dynam, orig)) - em10 = compute_emissivity('emissivity_band10', emiss_bare_band10) - em11 = compute_emissivity('emissivity_band11', emiss_bare_band11) - em12 = compute_emissivity('emissivity_band12', emiss_bare_band12) - em13 = compute_emissivity('emissivity_band13', emiss_bare_band13) - em14 = compute_emissivity('emissivity_band14', emiss_bare_band14) + em10 = compute_emissivity("emissivity_band10", emiss_bare_band10) + em11 = compute_emissivity("emissivity_band11", emiss_bare_band11) + em12 = compute_emissivity("emissivity_band12", emiss_bare_band12) + em13 = compute_emissivity("emissivity_band13", emiss_bare_band13) + em14 = compute_emissivity("emissivity_band14", emiss_bare_band14) bbe = image.expression( - '0.128 + 0.014 * em10 + 0.145 * em11 + 0.241 * em12 + \ - 0.467 * em13 + 0.004 * em14', - {'em10': em10, 'em11': em11, 'em12': em12, 'em13': em13, 'em14': em14} + "0.128 + 0.014 * em10 + 0.145 * em11 + 0.241 * em12 + \ + 0.467 * em13 + 0.004 * em14", + {"em10": em10, "em11": em11, "em12": em12, "em13": em13, "em14": em14}, ) - return image.addBands(bbe.rename('BBE')) + return image.addBands(bbe.rename("BBE")) diff --git a/ee_lst/cloudmask.py b/ee_lst/cloudmask.py index 18056cd..81de50d 100644 --- a/ee_lst/cloudmask.py +++ b/ee_lst/cloudmask.py @@ -1,5 +1,6 @@ # import ee + def mask_sr(image): """ Apply cloud mask to surface reflectance Landsat image. @@ -11,8 +12,12 @@ def mask_sr(image): - ee.Image: Cloud-masked Landsat image. """ - cloud_mask = image.select('QA_PIXEL').bitwiseAnd(1 << 3) \ - .Or(image.select('QA_PIXEL').bitwiseAnd(1 << 4)).eq(0) + cloud_mask = ( + image.select("QA_PIXEL") + .bitwiseAnd(1 << 3) + .Or(image.select("QA_PIXEL").bitwiseAnd(1 << 4)) + .eq(0) + ) return image.updateMask(cloud_mask) @@ -27,5 +32,5 @@ def mask_toa(image): - ee.Image: Cloud-masked Landsat image. """ - cloud_mask = image.select('QA_PIXEL').bitwiseAnd(1 << 3).eq(0) + cloud_mask = image.select("QA_PIXEL").bitwiseAnd(1 << 3).eq(0) return image.updateMask(cloud_mask) diff --git a/ee_lst/compute_emissivity.py b/ee_lst/compute_emissivity.py index 5369fd8..9b0a5c6 100644 --- a/ee_lst/compute_emissivity.py +++ b/ee_lst/compute_emissivity.py @@ -17,67 +17,55 @@ def add_emissivity_band(landsat, use_ndvi, image): - ee.Image: Image with added EM band """ - c13 = { - 'L4': 0.3222, - 'L5': -0.0723, - 'L7': 0.2147, - 'L8': 0.6820 - }.get(landsat, 0.6820) # Default to L8 if not found + c13 = {"L4": 0.3222, "L5": -0.0723, "L7": 0.2147, "L8": 0.6820}.get( + landsat, 0.6820 + ) # Default to L8 if not found - c14 = { - 'L4': 0.6498, - 'L5': 1.0521, - 'L7': 0.7789, - 'L8': 0.2578 - }.get(landsat, 0.2578) # Default to L8 if not found + c14 = {"L4": 0.6498, "L5": 1.0521, "L7": 0.7789, "L8": 0.2578}.get( + landsat, 0.2578 + ) # Default to L8 if not found - c = { - 'L4': 0.0272, - 'L5': 0.0195, - 'L7': 0.0059, - 'L8': 0.0584 - }.get(landsat, 0.0584) # Default to L8 if not found + c = {"L4": 0.0272, "L5": 0.0195, "L7": 0.0059, "L8": 0.0584}.get( + landsat, 0.0584 + ) # Default to L8 if not found # Get ASTER emissivity and convolve to Landsat band emiss_bare = image.expression( - 'c13 * EM13 + c14 * EM14 + c', + "c13 * EM13 + c14 * EM14 + c", { - 'EM13': emiss_bare_band13(image), - 'EM14': emiss_bare_band14(image), - 'c13': ee.Image(c13), - 'c14': ee.Image(c14), - 'c': ee.Image(c) - } + "EM13": emiss_bare_band13(image), + "EM14": emiss_bare_band14(image), + "c13": ee.Image(c13), + "c14": ee.Image(c14), + "c": ee.Image(c), + }, ) # Compute the dynamic emissivity for Landsat EMd = image.expression( - 'fvc * 0.99 + (1 - fvc) * em_bare', - { - 'fvc': image.select('FVC'), - 'em_bare': emiss_bare - } + "fvc * 0.99 + (1 - fvc) * em_bare", + {"fvc": image.select("FVC"), "em_bare": emiss_bare}, ) # Compute emissivity directly from ASTER without vegetation correction aster = ee.Image("NASA/ASTER_GED/AG100_003").clip(image.geometry()) EM0 = image.expression( - 'c13 * EM13 + c14 * EM14 + c', + "c13 * EM13 + c14 * EM14 + c", { - 'EM13': aster.select('emissivity_band13').multiply(0.001), - 'EM14': aster.select('emissivity_band14').multiply(0.001), - 'c13': ee.Image(c13), - 'c14': ee.Image(c14), - 'c': ee.Image(c) - } + "EM13": aster.select("emissivity_band13").multiply(0.001), + "EM14": aster.select("emissivity_band14").multiply(0.001), + "c13": ee.Image(c13), + "c14": ee.Image(c14), + "c": ee.Image(c), + }, ) # Select which emissivity to output based on user selection EM = EMd if use_ndvi else EM0 # Prescribe emissivity of water and snow/ice bodies - qa = image.select('QA_PIXEL') + qa = image.select("QA_PIXEL") EM = EM.where(qa.bitwiseAnd(1 << 7), 0.99) EM = EM.where(qa.bitwiseAnd(1 << 5), 0.989) - return image.addBands(EM.rename('EM')) + return image.addBands(EM.rename("EM")) diff --git a/ee_lst/compute_fvc.py b/ee_lst/compute_fvc.py index 9e1c810..906c093 100644 --- a/ee_lst/compute_fvc.py +++ b/ee_lst/compute_fvc.py @@ -15,20 +15,16 @@ def add_fvc_band(landsat, image): - ee.Image: Image with added FVC band """ - ndvi = image.select('NDVI') + ndvi = image.select("NDVI") # Compute FVC fvc = image.expression( - '((ndvi - ndvi_bg) / (ndvi_vg - ndvi_bg)) ** 2', - { - 'ndvi': ndvi, - 'ndvi_bg': 0.2, - 'ndvi_vg': 0.86 - } + "((ndvi - ndvi_bg) / (ndvi_vg - ndvi_bg)) ** 2", + {"ndvi": ndvi, "ndvi_bg": 0.2, "ndvi_vg": 0.86}, ) # Apply constraints to FVC values fvc = fvc.where(fvc.lt(0.0), 0.0) fvc = fvc.where(fvc.gt(1.0), 1.0) - return image.addBands(fvc.rename('FVC')) + return image.addBands(fvc.rename("FVC")) diff --git a/ee_lst/compute_ndvi.py b/ee_lst/compute_ndvi.py index edd6dff..698439d 100644 --- a/ee_lst/compute_ndvi.py +++ b/ee_lst/compute_ndvi.py @@ -14,20 +14,20 @@ def add_ndvi_band(landsat, image): """ # Choose bands based on the Landsat satellite ID - if landsat in ['L8', 'L9']: - nir = 'SR_B5' - red = 'SR_B4' + if landsat in ["L8", "L9"]: + nir = "SR_B5" + red = "SR_B4" else: - nir = 'SR_B4' - red = 'SR_B3' + nir = "SR_B4" + red = "SR_B3" # Compute NDVI ndvi = image.expression( - '(nir - red) / (nir + red)', + "(nir - red) / (nir + red)", { - 'nir': image.select(nir).multiply(0.0000275).add(-0.2), - 'red': image.select(red).multiply(0.0000275).add(-0.2) - } - ).rename('NDVI') + "nir": image.select(nir).multiply(0.0000275).add(-0.2), + "red": image.select(red).multiply(0.0000275).add(-0.2), + }, + ).rename("NDVI") return image.addBands(ndvi) diff --git a/ee_lst/constants.py b/ee_lst/constants.py index 403ca6c..b5149be 100644 --- a/ee_lst/constants.py +++ b/ee_lst/constants.py @@ -1,102 +1,115 @@ # Landsat satellites TOA, SR, TIR and VISW bands LANDSAT_BANDS = { - 'L4': { - 'TOA': 'LANDSAT/LT04/C02/T1_TOA', - 'SR': 'LANDSAT/LT04/C02/T1_L2', - 'TIR': ['B6'], - 'VISW': ['SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B7', - 'QA_PIXEL'] + "L4": { + "TOA": "LANDSAT/LT04/C02/T1_TOA", + "SR": "LANDSAT/LT04/C02/T1_L2", + "TIR": ["B6"], + "VISW": ["SR_B1", "SR_B2", "SR_B3", "SR_B4", "SR_B5", "SR_B7", "QA_PIXEL"], }, - 'L5': { - 'TOA': 'LANDSAT/LT05/C02/T1_TOA', - 'SR': 'LANDSAT/LT05/C02/T1_L2', - 'TIR': ['B6'], - 'VISW': ['SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B7', - 'QA_PIXEL'] + "L5": { + "TOA": "LANDSAT/LT05/C02/T1_TOA", + "SR": "LANDSAT/LT05/C02/T1_L2", + "TIR": ["B6"], + "VISW": ["SR_B1", "SR_B2", "SR_B3", "SR_B4", "SR_B5", "SR_B7", "QA_PIXEL"], }, - 'L7': { - 'TOA': 'LANDSAT/LE07/C02/T1_TOA', - 'SR': 'LANDSAT/LE07/C02/T1_L2', - 'TIR': ['B6_VCID_1', 'B6_VCID_2'], - 'VISW': ['SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B7', - 'QA_PIXEL'] + "L7": { + "TOA": "LANDSAT/LE07/C02/T1_TOA", + "SR": "LANDSAT/LE07/C02/T1_L2", + "TIR": ["B6_VCID_1", "B6_VCID_2"], + "VISW": ["SR_B1", "SR_B2", "SR_B3", "SR_B4", "SR_B5", "SR_B7", "QA_PIXEL"], }, - 'L8': { - 'TOA': 'LANDSAT/LC08/C02/T1_TOA', - 'SR': 'LANDSAT/LC08/C02/T1_L2', - 'TIR': ['B10', 'B11'], - 'VISW': ['SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', - 'SR_B7', 'QA_PIXEL'] + "L8": { + "TOA": "LANDSAT/LC08/C02/T1_TOA", + "SR": "LANDSAT/LC08/C02/T1_L2", + "TIR": ["B10", "B11"], + "VISW": [ + "SR_B1", + "SR_B2", + "SR_B3", + "SR_B4", + "SR_B5", + "SR_B6", + "SR_B7", + "QA_PIXEL", + ], + }, + "L9": { + "TOA": "LANDSAT/LC09/C02/T1_TOA", + "SR": "LANDSAT/LC09/C02/T1_L2", + "TIR": ["B10", "B11"], + "VISW": [ + "SR_B1", + "SR_B2", + "SR_B3", + "SR_B4", + "SR_B5", + "SR_B6", + "SR_B7", + "QA_PIXEL", + ], }, - 'L9': { - 'TOA': 'LANDSAT/LC09/C02/T1_TOA', - 'SR': 'LANDSAT/LC09/C02/T1_L2', - 'TIR': ['B10', 'B11'], - 'VISW': ['SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7', - 'QA_PIXEL'] - } } # Coefficients for the Statistical Mono-Window Algorithm SMW_COEFFICIENTS = { "L4": [ - {'TPWpos': 0, 'A': 0.9755, 'B': -205.2767, 'C': 212.0051}, - {'TPWpos': 1, 'A': 1.0155, 'B': -233.8902, 'C': 230.4049}, - {'TPWpos': 2, 'A': 1.0672, 'B': -257.1884, 'C': 239.3072}, - {'TPWpos': 3, 'A': 1.1499, 'B': -286.2166, 'C': 244.8497}, - {'TPWpos': 4, 'A': 1.2277, 'B': -316.7643, 'C': 253.0033}, - {'TPWpos': 5, 'A': 1.3649, 'B': -361.8276, 'C': 258.5471}, - {'TPWpos': 6, 'A': 1.5085, 'B': -410.1157, 'C': 265.1131}, - {'TPWpos': 7, 'A': 1.7045, 'B': -472.4909, 'C': 270.7000}, - {'TPWpos': 8, 'A': 1.5886, 'B': -442.9489, 'C': 277.1511}, - {'TPWpos': 9, 'A': 2.0215, 'B': -571.8563, 'C': 279.9854} + {"TPWpos": 0, "A": 0.9755, "B": -205.2767, "C": 212.0051}, + {"TPWpos": 1, "A": 1.0155, "B": -233.8902, "C": 230.4049}, + {"TPWpos": 2, "A": 1.0672, "B": -257.1884, "C": 239.3072}, + {"TPWpos": 3, "A": 1.1499, "B": -286.2166, "C": 244.8497}, + {"TPWpos": 4, "A": 1.2277, "B": -316.7643, "C": 253.0033}, + {"TPWpos": 5, "A": 1.3649, "B": -361.8276, "C": 258.5471}, + {"TPWpos": 6, "A": 1.5085, "B": -410.1157, "C": 265.1131}, + {"TPWpos": 7, "A": 1.7045, "B": -472.4909, "C": 270.7000}, + {"TPWpos": 8, "A": 1.5886, "B": -442.9489, "C": 277.1511}, + {"TPWpos": 9, "A": 2.0215, "B": -571.8563, "C": 279.9854}, ], "L5": [ - {'TPWpos': 0, 'A': 0.9765, 'B': -204.6584, 'C': 211.1321}, - {'TPWpos': 1, 'A': 1.0229, 'B': -235.5384, 'C': 230.0619}, - {'TPWpos': 2, 'A': 1.0817, 'B': -261.3886, 'C': 239.5256}, - {'TPWpos': 3, 'A': 1.1738, 'B': -293.6128, 'C': 245.6042}, - {'TPWpos': 4, 'A': 1.2605, 'B': -327.1417, 'C': 254.2301}, - {'TPWpos': 5, 'A': 1.4166, 'B': -377.7741, 'C': 259.9711}, - {'TPWpos': 6, 'A': 1.5727, 'B': -430.0388, 'C': 266.9520}, - {'TPWpos': 7, 'A': 1.7879, 'B': -498.1947, 'C': 272.8413}, - {'TPWpos': 8, 'A': 1.6347, 'B': -457.8183, 'C': 279.6160}, - {'TPWpos': 9, 'A': 2.1168, 'B': -600.7079, 'C': 282.4583} + {"TPWpos": 0, "A": 0.9765, "B": -204.6584, "C": 211.1321}, + {"TPWpos": 1, "A": 1.0229, "B": -235.5384, "C": 230.0619}, + {"TPWpos": 2, "A": 1.0817, "B": -261.3886, "C": 239.5256}, + {"TPWpos": 3, "A": 1.1738, "B": -293.6128, "C": 245.6042}, + {"TPWpos": 4, "A": 1.2605, "B": -327.1417, "C": 254.2301}, + {"TPWpos": 5, "A": 1.4166, "B": -377.7741, "C": 259.9711}, + {"TPWpos": 6, "A": 1.5727, "B": -430.0388, "C": 266.9520}, + {"TPWpos": 7, "A": 1.7879, "B": -498.1947, "C": 272.8413}, + {"TPWpos": 8, "A": 1.6347, "B": -457.8183, "C": 279.6160}, + {"TPWpos": 9, "A": 2.1168, "B": -600.7079, "C": 282.4583}, ], "L7": [ - {'TPWpos': 0, 'A': 0.9764, 'B': -205.3511, 'C': 211.8507}, - {'TPWpos': 1, 'A': 1.0201, 'B': -235.2416, 'C': 230.5468}, - {'TPWpos': 2, 'A': 1.0750, 'B': -259.6560, 'C': 239.6619}, - {'TPWpos': 3, 'A': 1.1612, 'B': -289.8190, 'C': 245.3286}, - {'TPWpos': 4, 'A': 1.2425, 'B': -321.4658, 'C': 253.6144}, - {'TPWpos': 5, 'A': 1.3864, 'B': -368.4078, 'C': 259.1390}, - {'TPWpos': 6, 'A': 1.5336, 'B': -417.7796, 'C': 265.7486}, - {'TPWpos': 7, 'A': 1.7345, 'B': -481.5714, 'C': 271.3659}, - {'TPWpos': 8, 'A': 1.6066, 'B': -448.5071, 'C': 277.9058}, - {'TPWpos': 9, 'A': 2.0533, 'B': -581.2619, 'C': 280.6800} + {"TPWpos": 0, "A": 0.9764, "B": -205.3511, "C": 211.8507}, + {"TPWpos": 1, "A": 1.0201, "B": -235.2416, "C": 230.5468}, + {"TPWpos": 2, "A": 1.0750, "B": -259.6560, "C": 239.6619}, + {"TPWpos": 3, "A": 1.1612, "B": -289.8190, "C": 245.3286}, + {"TPWpos": 4, "A": 1.2425, "B": -321.4658, "C": 253.6144}, + {"TPWpos": 5, "A": 1.3864, "B": -368.4078, "C": 259.1390}, + {"TPWpos": 6, "A": 1.5336, "B": -417.7796, "C": 265.7486}, + {"TPWpos": 7, "A": 1.7345, "B": -481.5714, "C": 271.3659}, + {"TPWpos": 8, "A": 1.6066, "B": -448.5071, "C": 277.9058}, + {"TPWpos": 9, "A": 2.0533, "B": -581.2619, "C": 280.6800}, ], "L8": [ - {'TPWpos': 0, 'A': 0.9751, 'B': -205.8929, 'C': 212.7173}, - {'TPWpos': 1, 'A': 1.0090, 'B': -232.2750, 'C': 230.5698}, - {'TPWpos': 2, 'A': 1.0541, 'B': -253.1943, 'C': 238.9548}, - {'TPWpos': 3, 'A': 1.1282, 'B': -279.4212, 'C': 244.0772}, - {'TPWpos': 4, 'A': 1.1987, 'B': -307.4497, 'C': 251.8341}, - {'TPWpos': 5, 'A': 1.3205, 'B': -348.0228, 'C': 257.2740}, - {'TPWpos': 6, 'A': 1.4540, 'B': -393.1718, 'C': 263.5599}, - {'TPWpos': 7, 'A': 1.6350, 'B': -451.0790, 'C': 268.9405}, - {'TPWpos': 8, 'A': 1.5468, 'B': -429.5095, 'C': 275.0895}, - {'TPWpos': 9, 'A': 1.9403, 'B': -547.2681, 'C': 277.9953} + {"TPWpos": 0, "A": 0.9751, "B": -205.8929, "C": 212.7173}, + {"TPWpos": 1, "A": 1.0090, "B": -232.2750, "C": 230.5698}, + {"TPWpos": 2, "A": 1.0541, "B": -253.1943, "C": 238.9548}, + {"TPWpos": 3, "A": 1.1282, "B": -279.4212, "C": 244.0772}, + {"TPWpos": 4, "A": 1.1987, "B": -307.4497, "C": 251.8341}, + {"TPWpos": 5, "A": 1.3205, "B": -348.0228, "C": 257.2740}, + {"TPWpos": 6, "A": 1.4540, "B": -393.1718, "C": 263.5599}, + {"TPWpos": 7, "A": 1.6350, "B": -451.0790, "C": 268.9405}, + {"TPWpos": 8, "A": 1.5468, "B": -429.5095, "C": 275.0895}, + {"TPWpos": 9, "A": 1.9403, "B": -547.2681, "C": 277.9953}, ], "L9": [ - {'TPWpos': 0, 'A': 0.9751, 'B': -206.2187, 'C': 213.0526}, - {'TPWpos': 1, 'A': 1.0093, 'B': -232.7408, 'C': 230.9401}, - {'TPWpos': 2, 'A': 1.0539, 'B': -253.4430, 'C': 239.2572}, - {'TPWpos': 3, 'A': 1.1267, 'B': -279.1685, 'C': 244.2379}, - {'TPWpos': 4, 'A': 1.1961, 'B': -306.7961, 'C': 251.8873}, - {'TPWpos': 5, 'A': 1.3155, 'B': -346.5312, 'C': 257.2174}, - {'TPWpos': 6, 'A': 1.4463, 'B': -390.7794, 'C': 263.3479}, - {'TPWpos': 7, 'A': 1.6229, 'B': -447.2745, 'C': 268.5970}, - {'TPWpos': 8, 'A': 1.5396, 'B': -427.0904, 'C': 274.6380}, - {'TPWpos': 9, 'A': 1.9223, 'B': -541.7084, 'C': 277.4964} - ] + {"TPWpos": 0, "A": 0.9751, "B": -206.2187, "C": 213.0526}, + {"TPWpos": 1, "A": 1.0093, "B": -232.7408, "C": 230.9401}, + {"TPWpos": 2, "A": 1.0539, "B": -253.4430, "C": 239.2572}, + {"TPWpos": 3, "A": 1.1267, "B": -279.1685, "C": 244.2379}, + {"TPWpos": 4, "A": 1.1961, "B": -306.7961, "C": 251.8873}, + {"TPWpos": 5, "A": 1.3155, "B": -346.5312, "C": 257.2174}, + {"TPWpos": 6, "A": 1.4463, "B": -390.7794, "C": 263.3479}, + {"TPWpos": 7, "A": 1.6229, "B": -447.2745, "C": 268.5970}, + {"TPWpos": 8, "A": 1.5396, "B": -427.0904, "C": 274.6380}, + {"TPWpos": 9, "A": 1.9223, "B": -541.7084, "C": 277.4964}, + ], } diff --git a/ee_lst/landsat_lst.py b/ee_lst/landsat_lst.py index 97511f7..4cbb10f 100644 --- a/ee_lst/landsat_lst.py +++ b/ee_lst/landsat_lst.py @@ -18,8 +18,7 @@ def initialize_ee(): ee.Initialize() -def fetch_landsat_collection(landsat, date_start, date_end, - geometry, use_ndvi): +def fetch_landsat_collection(landsat, date_start, date_end, geometry, use_ndvi): """ Fetches a Landsat collection based on the provided parameters and applies several transformations. @@ -39,32 +38,36 @@ def fetch_landsat_collection(landsat, date_start, date_end, # Check if the provided Landsat collection is valid if landsat not in LANDSAT_BANDS.keys(): - raise ValueError(f"Invalid Landsat constellation: {landsat}. \ - Valid options are: {list(LANDSAT_BANDS.keys())}") + raise ValueError( + f"Invalid Landsat constellation: {landsat}. \ + Valid options are: {list(LANDSAT_BANDS.keys())}" + ) collection_dict = LANDSAT_BANDS[landsat] # Load TOA Radiance/Reflectance - landsat_toa = (ee.ImageCollection(collection_dict['TOA']) - .filterDate(date_start, date_end) - .filterBounds(geometry)) + landsat_toa = ( + ee.ImageCollection(collection_dict["TOA"]) + .filterDate(date_start, date_end) + .filterBounds(geometry) + ) # Load Surface Reflectance collection for NDVI and apply transformations - landsat_sr = (ee.ImageCollection(collection_dict['SR']) - .filterDate(date_start, date_end) - .filterBounds(geometry) - .map(mask_sr) - .map(lambda image: add_ndvi_band(landsat, image)) - .map(lambda image: add_fvc_band(landsat, image)) - .map(add_tpw_band) - .map(lambda image: add_emissivity_band(landsat, - use_ndvi, image))) + landsat_sr = ( + ee.ImageCollection(collection_dict["SR"]) + .filterDate(date_start, date_end) + .filterBounds(geometry) + .map(mask_sr) + .map(lambda image: add_ndvi_band(landsat, image)) + .map(lambda image: add_fvc_band(landsat, image)) + .map(add_tpw_band) + .map(lambda image: add_emissivity_band(landsat, use_ndvi, image)) + ) # Combine collections - tir = collection_dict['TIR'] - visw = collection_dict['VISW'] + ['NDVI', 'FVC', 'TPW', 'TPWpos', 'EM'] - landsat_all = landsat_sr.select(visw).combine(landsat_toa.select(tir), - True) + tir = collection_dict["TIR"] + visw = collection_dict["VISW"] + ["NDVI", "FVC", "TPW", "TPWpos", "EM"] + landsat_all = landsat_sr.select(visw).combine(landsat_toa.select(tir), True) # Compute the LST landsat_lst = landsat_all.map(lambda image: add_lst_band(landsat, image)) diff --git a/ee_lst/ncep_tpw.py b/ee_lst/ncep_tpw.py index a8981bb..3eab5c2 100644 --- a/ee_lst/ncep_tpw.py +++ b/ee_lst/ncep_tpw.py @@ -14,57 +14,70 @@ def add_tpw_band(image): - ee.Image: Image with added 'TPW' and 'TPWpos' bands. """ - date = ee.Date(image.get('system:time_start')) - year = date.get('year') - month = date.get('month') - day = date.get('day') - dateString = year.format() \ - .cat('-').cat(month.format()) \ - .cat('-').cat(day.format()) + date = ee.Date(image.get("system:time_start")) + year = date.get("year") + month = date.get("month") + day = date.get("day") + dateString = year.format().cat("-").cat(month.format()).cat("-").cat(day.format()) date1 = ee.Date(dateString) - date2 = date1.advance(1, 'days') + date2 = date1.advance(1, "days") def datedist(img): - return img.set('DateDist', ee.Number(img.get('system:time_start')) - .subtract(date.millis()).abs()) + return img.set( + "DateDist", + ee.Number(img.get("system:time_start")).subtract(date.millis()).abs(), + ) - tpw_collection = (ee.ImageCollection('NCEP_RE/surface_wv') - .filterDate(date1.format('yyyy-MM-dd'), - date2.format('yyyy-MM-dd')) - .map(datedist)) + tpw_collection = ( + ee.ImageCollection("NCEP_RE/surface_wv") + .filterDate(date1.format("yyyy-MM-dd"), date2.format("yyyy-MM-dd")) + .map(datedist) + ) - closest = tpw_collection.sort('DateDist').toList(2) + closest = tpw_collection.sort("DateDist").toList(2) - tpw1 = ee.Image(closest.get(0)).select('pr_wtr') \ - if closest.size() else ee.Image.constant(-999.0) - tpw2 = ee.Image(closest.get(1)).select('pr_wtr') \ - if ee.Number(closest.size()).gt(1) else tpw1 + tpw1 = ( + ee.Image(closest.get(0)).select("pr_wtr") + if closest.size() + else ee.Image.constant(-999.0) + ) + tpw2 = ( + ee.Image(closest.get(1)).select("pr_wtr") + if ee.Number(closest.size()).gt(1) + else tpw1 + ) - time1 = ee.Number(tpw1.get('DateDist')).divide(21600000) \ - if ee.Number(closest.size()).gt(0) else ee.Number(1.0) - time2 = ee.Number(tpw2.get('DateDist')).divide(21600000) \ - if ee.Number(closest.size()).gt(1) else ee.Number(0.0) + time1 = ( + ee.Number(tpw1.get("DateDist")).divide(21600000) + if ee.Number(closest.size()).gt(0) + else ee.Number(1.0) + ) + time2 = ( + ee.Number(tpw2.get("DateDist")).divide(21600000) + if ee.Number(closest.size()).gt(1) + else ee.Number(0.0) + ) - tpw = tpw1.expression('tpw1*time2+tpw2*time1', { - 'tpw1': tpw1, - 'time1': time1, - 'tpw2': tpw2, - 'time2': time2 - }).clip(image.geometry()) + tpw = tpw1.expression( + "tpw1*time2+tpw2*time1", + {"tpw1": tpw1, "time1": time1, "tpw2": tpw2, "time2": time2}, + ).clip(image.geometry()) pos = tpw.expression( - "value = (TPW>0 && TPW<=6) ? 0" + - ": (TPW>6 && TPW<=12) ? 1" + - ": (TPW>12 && TPW<=18) ? 2" + - ": (TPW>18 && TPW<=24) ? 3" + - ": (TPW>24 && TPW<=30) ? 4" + - ": (TPW>30 && TPW<=36) ? 5" + - ": (TPW>36 && TPW<=42) ? 6" + - ": (TPW>42 && TPW<=48) ? 7" + - ": (TPW>48 && TPW<=54) ? 8" + - ": (TPW>54) ? 9" + - ": 0", {'TPW': tpw}).clip(image.geometry()) + "value = (TPW>0 && TPW<=6) ? 0" + + ": (TPW>6 && TPW<=12) ? 1" + + ": (TPW>12 && TPW<=18) ? 2" + + ": (TPW>18 && TPW<=24) ? 3" + + ": (TPW>24 && TPW<=30) ? 4" + + ": (TPW>30 && TPW<=36) ? 5" + + ": (TPW>36 && TPW<=42) ? 6" + + ": (TPW>42 && TPW<=48) ? 7" + + ": (TPW>48 && TPW<=54) ? 8" + + ": (TPW>54) ? 9" + + ": 0", + {"TPW": tpw}, + ).clip(image.geometry()) - withTPW = image.addBands(tpw.rename('TPW')).addBands(pos.rename('TPWpos')) + withTPW = image.addBands(tpw.rename("TPW")).addBands(pos.rename("TPWpos")) return withTPW diff --git a/ee_lst/smw_algorithm.py b/ee_lst/smw_algorithm.py index 48e307f..0b46008 100644 --- a/ee_lst/smw_algorithm.py +++ b/ee_lst/smw_algorithm.py @@ -25,35 +25,31 @@ def add_lst_band(landsat, image): # Select algorithm coefficients # Default to L9 if not found - coeff_SMW = SMW_COEFFICIENTS.get(landsat, - SMW_COEFFICIENTS['L9']) + coeff_SMW = SMW_COEFFICIENTS.get(landsat, SMW_COEFFICIENTS["L9"]) # Create lookups for the algorithm coefficients - A_lookup = get_lookup_table(coeff_SMW, 'TPWpos', 'A') - B_lookup = get_lookup_table(coeff_SMW, 'TPWpos', 'B') - C_lookup = get_lookup_table(coeff_SMW, 'TPWpos', 'C') + A_lookup = get_lookup_table(coeff_SMW, "TPWpos", "A") + B_lookup = get_lookup_table(coeff_SMW, "TPWpos", "B") + C_lookup = get_lookup_table(coeff_SMW, "TPWpos", "C") # Map coefficients to the image using the TPW bin position - A_img = image.remap(A_lookup[0], A_lookup[1], 0.0, 'TPWpos') \ - .resample('bilinear') - B_img = image.remap(B_lookup[0], B_lookup[1], 0.0, 'TPWpos') \ - .resample('bilinear') - C_img = image.remap(C_lookup[0], C_lookup[1], 0.0, 'TPWpos') \ - .resample('bilinear') + A_img = image.remap(A_lookup[0], A_lookup[1], 0.0, "TPWpos").resample("bilinear") + B_img = image.remap(B_lookup[0], B_lookup[1], 0.0, "TPWpos").resample("bilinear") + C_img = image.remap(C_lookup[0], C_lookup[1], 0.0, "TPWpos").resample("bilinear") # Select TIR band - tir = LANDSAT_BANDS[landsat]['TIR'][0] + tir = LANDSAT_BANDS[landsat]["TIR"][0] # Compute the LST lst = image.expression( - 'A * Tb1 / em1 + B / em1 + C', + "A * Tb1 / em1 + B / em1 + C", { - 'A': A_img, - 'B': B_img, - 'C': C_img, - 'em1': image.select('EM'), - 'Tb1': image.select(tir) - } - ).updateMask(image.select('TPW').lt(0).Not()) - - return image.addBands(lst.rename('LST')) + "A": A_img, + "B": B_img, + "C": C_img, + "em1": image.select("EM"), + "Tb1": image.select(tir), + }, + ).updateMask(image.select("TPW").lt(0).Not()) + + return image.addBands(lst.rename("LST")) diff --git a/examples/example_1.py b/examples/example_1.py index c091d9f..139d0f0 100644 --- a/examples/example_1.py +++ b/examples/example_1.py @@ -15,26 +15,23 @@ # Define parameters geometry = ee.Geometry.Rectangle([-8.91, 40.0, -8.3, 40.4]) -satellite = 'L8' -date_start = '2022-05-15' -date_end = '2022-05-31' +satellite = "L8" +date_start = "2022-05-15" +date_end = "2022-05-31" use_ndvi = True # Get Landsat collection with added variables: NDVI, FVC, TPW, EM, LST landsat_coll = fetch_landsat_collection( - satellite, - date_start, - date_end, - geometry, - use_ndvi) + satellite, date_start, date_end, geometry, use_ndvi +) print(landsat_coll.getInfo()) # Select the first feature ex_image = landsat_coll.first() # Visualization parameters -cmap1 = ['blue', 'cyan', 'green', 'yellow', 'red'] -cmap2 = ['F2F2F2', 'EFC2B3', 'ECB176', 'E9BD3A', 'E6E600', '63C600', '00A600'] +cmap1 = ["blue", "cyan", "green", "yellow", "red"] +cmap2 = ["F2F2F2", "EFC2B3", "ECB176", "E9BD3A", "E6E600", "63C600", "00A600"] # To visualize the result on a map, you'd typically use a library # like folium or ipyleaflet @@ -45,11 +42,11 @@ def add_ee_layer(self, ee_image_object, vis_params, name): map_id_dict = ee.Image(ee_image_object).getMapId(vis_params) folium.raster_layers.TileLayer( - tiles=map_id_dict['tile_fetcher'].url_format, - attr='Map Data © Google Earth Engine', + tiles=map_id_dict["tile_fetcher"].url_format, + attr="Map Data © Google Earth Engine", name=name, overlay=True, - control=True + control=True, ).add_to(self) @@ -60,28 +57,29 @@ def add_ee_layer(self, ee_image_object, vis_params, name): my_map = folium.Map(location=[40.2, -8.6], zoom_start=10, height=500) # Add the Earth Engine layers to the folium map -my_map.add_ee_layer(ex_image.select('TPW'), - {'min': 0, 'max': 60, 'palette': cmap1}, - 'TCWV') -my_map.add_ee_layer(ex_image.select('TPWpos'), - {'min': 0, 'max': 9, 'palette': cmap1}, - 'TCWVpos') -my_map.add_ee_layer(ex_image.select('FVC'), - {'min': 0, 'max': 1, 'palette': cmap2}, - 'FVC') -my_map.add_ee_layer(ex_image.select('EM'), - {'min': 0.9, 'max': 1.0, 'palette': cmap1}, - 'Emissivity') -my_map.add_ee_layer(ex_image.select('B10'), - {'min': 290, 'max': 320, 'palette': cmap1}, - 'TIR BT') -my_map.add_ee_layer(ex_image.select('LST'), - {'min': 290, 'max': 320, 'palette': cmap1}, - 'LST') -my_map.add_ee_layer(ex_image.multiply(0.0000275).add(-0.2), - {'bands': ['SR_B4', 'SR_B3', 'SR_B2'], - 'min': 0, 'max': 0.3}, - 'RGB') +my_map.add_ee_layer( + ex_image.select("TPW"), {"min": 0, "max": 60, "palette": cmap1}, "TCWV" +) +my_map.add_ee_layer( + ex_image.select("TPWpos"), {"min": 0, "max": 9, "palette": cmap1}, "TCWVpos" +) +my_map.add_ee_layer( + ex_image.select("FVC"), {"min": 0, "max": 1, "palette": cmap2}, "FVC" +) +my_map.add_ee_layer( + ex_image.select("EM"), {"min": 0.9, "max": 1.0, "palette": cmap1}, "Emissivity" +) +my_map.add_ee_layer( + ex_image.select("B10"), {"min": 290, "max": 320, "palette": cmap1}, "TIR BT" +) +my_map.add_ee_layer( + ex_image.select("LST"), {"min": 290, "max": 320, "palette": cmap1}, "LST" +) +my_map.add_ee_layer( + ex_image.multiply(0.0000275).add(-0.2), + {"bands": ["SR_B4", "SR_B3", "SR_B2"], "min": 0, "max": 0.3}, + "RGB", +) # Display the map # my_map.save('map.html') diff --git a/examples/example_gee_book.py b/examples/example_gee_book.py index b04c3dc..ff2b305 100644 --- a/examples/example_gee_book.py +++ b/examples/example_gee_book.py @@ -1,5 +1,6 @@ import ee import geopandas as gpd + # Define the Landsat LST module (assuming you've refactored it to Python) from ee_lst.landsat_lst import collection as landsat_collection import folium @@ -8,31 +9,31 @@ ee.Initialize() # Load the KML file using geopandas -gdf = gpd.read_file('path_to_your_kml_file.kml') +gdf = gpd.read_file("path_to_your_kml_file.kml") geometry = ee.Geometry.Polygon(gdf.geometry[0].exterior.coords[:]) # Define parameters -satellite = 'L8' -date_start = '2014-01-01' -date_end = '2019-01-01' +satellite = "L8" +date_start = "2014-01-01" +date_end = "2019-01-01" use_ndvi = True # Define the summer filter sum_filter = ee.Filter.dayOfYear(152, 243) # Get Landsat collection with additional necessary variables -landsat_coll = landsat_collection(satellite, date_start, date_end, - geometry, use_ndvi) +landsat_coll = landsat_collection(satellite, date_start, date_end, geometry, use_ndvi) # Create composite, clip, filter to summer, mask, and convert to degree Celsius not_water = True -landsat_comp = (landsat_coll - .select('LST') - .filter(sum_filter) - .median() - .clip(geometry) - .updateMask(not_water) # Define the not_water mask - .subtract(273.15)) +landsat_comp = ( + landsat_coll.select("LST") + .filter(sum_filter) + .median() + .clip(geometry) + .updateMask(not_water) # Define the not_water mask + .subtract(273.15) +) # To visualize the result on a map, you'd typically # use a library like folium or ipyleaflet @@ -43,11 +44,11 @@ def add_ee_layer(self, ee_image_object, vis_params, name): map_id_dict = ee.Image(ee_image_object).getMapId(vis_params) folium.raster_layers.TileLayer( - tiles=map_id_dict['tile_fetcher'].url_format, - attr='Map Data © Google Earth Engine', + tiles=map_id_dict["tile_fetcher"].url_format, + attr="Map Data © Google Earth Engine", name=name, overlay=True, - control=True + control=True, ).add_to(self) @@ -58,12 +59,8 @@ def add_ee_layer(self, ee_image_object, vis_params, name): my_map = folium.Map(location=[20, 0], zoom_start=3, height=500) # Add the Earth Engine layer to the folium map -vis_params = { - 'min': 25, - 'max': 38, - 'palette': ['blue', 'white', 'red'] -} -my_map.add_ee_layer(landsat_comp, vis_params, 'LST_SMW') +vis_params = {"min": 25, "max": 38, "palette": ["blue", "white", "red"]} +my_map.add_ee_layer(landsat_comp, vis_params, "LST_SMW") # Display the map -my_map.save('map.html') +my_map.save("map.html") diff --git a/tests/test_aster_bare_emiss.py b/tests/test_aster_bare_emiss.py index 3d282fb..90de770 100644 --- a/tests/test_aster_bare_emiss.py +++ b/tests/test_aster_bare_emiss.py @@ -36,5 +36,7 @@ def test_emiss_bare_band10(): # Assert that the result matches the expected output # (this is a placeholder, adjust as needed) - assert result == expected_output, f"Expected {expected_output}, \ + assert ( + result == expected_output + ), f"Expected {expected_output}, \ but got {result}" diff --git a/tests/test_broadband_emiss.py b/tests/test_broadband_emiss.py index 75afbfb..a4f7380 100644 --- a/tests/test_broadband_emiss.py +++ b/tests/test_broadband_emiss.py @@ -37,5 +37,7 @@ def test_add_band(): # Assert that the result matches the expected output # (this is a placeholder, adjust as needed) - assert result == expected_output, f"Expected {expected_output}, \ + assert ( + result == expected_output + ), f"Expected {expected_output}, \ but got {result}" diff --git a/tests/test_cloudmask.py b/tests/test_cloudmask.py index f6d0f4f..c8c01f8 100644 --- a/tests/test_cloudmask.py +++ b/tests/test_cloudmask.py @@ -55,7 +55,9 @@ def test_sr(): # Assert that the result matches the expected output # (this is a placeholder, adjust as needed) - assert result == expected_output, f"Expected {expected_output}, \ + assert ( + result == expected_output + ), f"Expected {expected_output}, \ but got {result}" @@ -74,7 +76,10 @@ def test_toa(): # Assert that the result matches the expected output # (this is a placeholder, adjust as needed) - assert result == expected_output, f"Expected {expected_output}, \ + assert ( + result == expected_output + ), f"Expected {expected_output}, \ but got {result}" + # Add more tests as needed for other functionalities in the cloudmask module. diff --git a/tests/test_compute_emissivity.py b/tests/test_compute_emissivity.py index 576dc6e..cd213a8 100644 --- a/tests/test_compute_emissivity.py +++ b/tests/test_compute_emissivity.py @@ -31,12 +31,14 @@ def test_add_band(): # Compute emissivity using the refactored function # Example for Landsat 8 with use_ndvi=True - result = compute_emissivity.add_band('L8', True, test_image) + result = compute_emissivity.add_band("L8", True, test_image) # Compare the result with the expected output expected_output = expected_output_em() # Assert that the result matches the expected output # (this is a placeholder, adjust as needed) - assert result == expected_output, f"Expected {expected_output}, \ + assert ( + result == expected_output + ), f"Expected {expected_output}, \ but got {result}" diff --git a/tests/test_compute_fvc.py b/tests/test_compute_fvc.py index 201acfc..3d02a0e 100644 --- a/tests/test_compute_fvc.py +++ b/tests/test_compute_fvc.py @@ -29,14 +29,17 @@ def test_add_band(): test_image = load_test_image() # Compute FVC using the refactored function - result = compute_FVC.add_band('L8', test_image) # Example for Landsat 8 + result = compute_FVC.add_band("L8", test_image) # Example for Landsat 8 # Compare the result with the expected output expected_output = expected_output_fvc() # Assert that the result matches the expected output # (this is a placeholder, adjust as needed) - assert result == expected_output, f"Expected {expected_output}, \ + assert ( + result == expected_output + ), f"Expected {expected_output}, \ but got {result}" + # Add more tests as needed for other functionalities in the compute_FVC module. diff --git a/tests/test_compute_ndvi.py b/tests/test_compute_ndvi.py index aa0173b..47973f5 100644 --- a/tests/test_compute_ndvi.py +++ b/tests/test_compute_ndvi.py @@ -29,12 +29,14 @@ def test_add_band(): test_image = load_test_image() # Compute NDVI using the refactored function - result = compute_NDVI.add_band('L8', test_image) # Example for Landsat 8 + result = compute_NDVI.add_band("L8", test_image) # Example for Landsat 8 # Compare the result with the expected output expected_output = expected_output_ndvi() # Assert that the result matches the expected output # (this is a placeholder, adjust as needed) - assert result == expected_output, f"Expected {expected_output}, \ + assert ( + result == expected_output + ), f"Expected {expected_output}, \ but got {result}" diff --git a/tests/test_landsat_lst.py b/tests/test_landsat_lst.py index 27adfca..f29ac49 100644 --- a/tests/test_landsat_lst.py +++ b/tests/test_landsat_lst.py @@ -36,5 +36,7 @@ def test_compute_LST(): # Assert that the result matches the expected output # (this is a placeholder, adjust as needed) - assert result == expected_output, f"Expected {expected_output}, \ + assert ( + result == expected_output + ), f"Expected {expected_output}, \ but got {result}" diff --git a/tests/test_ncep_tpw.py b/tests/test_ncep_tpw.py index a5b31cb..900d2d5 100644 --- a/tests/test_ncep_tpw.py +++ b/tests/test_ncep_tpw.py @@ -36,5 +36,7 @@ def test_add_band(): # Assert that the result matches the expected output # (this is a placeholder, adjust as needed) - assert result == expected_output, f"Expected {expected_output}, \ + assert ( + result == expected_output + ), f"Expected {expected_output}, \ but got {result}" diff --git a/tests/test_smw_algorithm.py b/tests/test_smw_algorithm.py index 1c28d2c..30092b1 100644 --- a/tests/test_smw_algorithm.py +++ b/tests/test_smw_algorithm.py @@ -29,12 +29,14 @@ def test_add_band(): test_image = load_test_image() # Compute LST using the refactored function - result = smw_algorithm.add_band('L8', test_image) # Example for Landsat 8 + result = smw_algorithm.add_band("L8", test_image) # Example for Landsat 8 # Compare the result with the expected output expected_output = expected_output_lst() # Assert that the result matches the expected output # (this is a placeholder, adjust as needed) - assert result == expected_output, f"Expected {expected_output}, \ + assert ( + result == expected_output + ), f"Expected {expected_output}, \ but got {result}"