From 59d4b9d7e6e25f794cc6c01bed3a831d8e7d4456 Mon Sep 17 00:00:00 2001 From: AmberMulder <46423091+AmberMulder@users.noreply.github.com> Date: Tue, 5 Nov 2024 08:43:28 +0100 Subject: [PATCH] Add LST Backward Average script (#333) * Initial setup LST Backwar Average scripts and docs * Create and update color ramp in one command --------- Co-authored-by: Amber Mulder --- .../land-surface-temperature/index.md | 1 + .../index.md | 33 +++++++ .../raw.js | 60 +++++++++++ .../script.js | 99 +++++++++++++++++++ 4 files changed, 193 insertions(+) create mode 100644 planetary-variables/land-surface-temperature/land-surface-temperature-backward-average/index.md create mode 100644 planetary-variables/land-surface-temperature/land-surface-temperature-backward-average/raw.js create mode 100644 planetary-variables/land-surface-temperature/land-surface-temperature-backward-average/script.js diff --git a/planetary-variables/land-surface-temperature/index.md b/planetary-variables/land-surface-temperature/index.md index 0d2943ce..2257a703 100644 --- a/planetary-variables/land-surface-temperature/index.md +++ b/planetary-variables/land-surface-temperature/index.md @@ -13,4 +13,5 @@ Planet's LST product provides near real-time measurements twice a day at 1:30 an - [Land Surface Temperature Visualization]({% link planetary-variables/land-surface-temperature/land-surface-temperature-visualization/index.md %}) - [Land Surface Temperature Anomaly]({% link planetary-variables/land-surface-temperature/land-surface-temperature-anomaly/index.md %}) +- [Land Surface Temperature Backward Average]({% link planetary-variables/land-surface-temperature/land-surface-temperature-backward-average/index.md %}) - [Land Surface Temperature Quality Flags]({% link planetary-variables/land-surface-temperature/land-surface-temperature-quality-flags/index.md %}) \ No newline at end of file diff --git a/planetary-variables/land-surface-temperature/land-surface-temperature-backward-average/index.md b/planetary-variables/land-surface-temperature/land-surface-temperature-backward-average/index.md new file mode 100644 index 00000000..4bd2e453 --- /dev/null +++ b/planetary-variables/land-surface-temperature/land-surface-temperature-backward-average/index.md @@ -0,0 +1,33 @@ +--- +title: Land Surface Temperature Backward Average +grand_parent: Planetary Variables +parent: Land Surface Temperature +layout: script +nav_exclude: false +scripts: + - [Visualization, script.js] + - [Raw Values, raw.js] +examples: +- zoom: '11' + lat: '44.8398' + lng: '-0.5294' + datasetId: '8d977093-cf9e-4351-8159-90f2522c29c1' + fromTime: '2022-12-01T00:00:00.000Z' + toTime: '2022-12-30T23:59:59.999Z' + platform: + - EOB + evalscripturl: https://custom-scripts.sentinel-hub.com/custom-scripts/planetary-variables/land-surface-temperature/land-surface-temperature-backward-average/script.js + additionalQueryParams: + - - themeId + - PLANET_SANDBOX +--- +## General description +The Land Surface Temperature Backward Average is a method to reduce data gaps and measurement noise in the Land Surface Temperature (LST) data. Depending on the requirements, we can choose a lookback period, for example 20 days. The 20-day backward average of LST for day n is the average of LST over the 20 days preceding day n. We compute the backward average using all available measurements within this 20-day period, and therefore, we do have a valid value for every day, except in case of prolonged data unavailability, such as during long frost and snow periods. + +## Why it is useful +The Land Surface Temperature Backward Average is suitable for applications where long-term temperatures are more relevant than daily fluctuations. The moving average operation reduces day-to-day variations and in the resulting time series, seasonal and longer-term changes can be easily detected. It can be used for monitoring drought risk, yield forecasting and analysis of climate change. + +## Useful links +- [Product specifications](https://planet.widen.net/s/tltwk6hnps) +- [Data sheet](https://planet.widen.net/s/ttvp2rvwzd) +- [Sentinel Hub documentation about Land Surface Temperature](https://docs.sentinel-hub.com/api/latest/data/planetary-variables/land-surface-temp/) diff --git a/planetary-variables/land-surface-temperature/land-surface-temperature-backward-average/raw.js b/planetary-variables/land-surface-temperature/land-surface-temperature-backward-average/raw.js new file mode 100644 index 00000000..126f7483 --- /dev/null +++ b/planetary-variables/land-surface-temperature/land-surface-temperature-backward-average/raw.js @@ -0,0 +1,60 @@ +//VERSION=3 + +// LST has two observations per day: 1h30 and 13h30 solar local time + +const date = "2022-12-31"; // The date for which the backward average is calculated +const nDays = 20; // The number of days to load data for +const scaleFactor = 100; // The scale factor for the SWC values +const sensing_time = "0130"; // Observation time: "0130" or "1330" or "" +const variable = "LST"; // Variable of interest: "LST" or "LST_MaskedPixels" + +function setup() { + return { + input: [variable, "dataMask"], + output: { bands: 1, sampleType: "FLOAT32" }, + mosaicking: "TILE", + }; +} + +// Select files based on sensing time (0130 or 1330) and within the last nDays +function preProcessScenes(collections) { + var calculationDate = new Date(date); + collections.scenes.tiles = collections.scenes.tiles.filter(function (tile) { + var tileDate = new Date(tile.date); + return ( + tile.dataPath.includes("T" + sensing_time) && + tileDate.getTime() >= calculationDate.getTime() - nDays * 24 * 3600 * 1000 + ); + }); + return collections; +} + +function get_mean_lst_value(samples) { + // Get the sum of all LST values + let n_valid_dates = 0; + let sum = 0; + for (let i = 0; i < samples.length; i++) { + if (samples[i].dataMask) { + sum += samples[i].LST / scaleFactor; + n_valid_dates += 1; + } + } + + // Calculate the mean LST value + let mean_lst_value = NaN; + if (n_valid_dates > 0) { + mean_lst_value = sum / n_valid_dates; + } + + return mean_lst_value; +} + +function evaluatePixel(samples) { + // When there are no dates, return no data + if (samples.length == 0) return [NaN]; + + // Calculate mean LST value + const mean_lst_val = get_mean_lst_value(samples); + + return [mean_lst_val]; +} diff --git a/planetary-variables/land-surface-temperature/land-surface-temperature-backward-average/script.js b/planetary-variables/land-surface-temperature/land-surface-temperature-backward-average/script.js new file mode 100644 index 00000000..e2efd6d5 --- /dev/null +++ b/planetary-variables/land-surface-temperature/land-surface-temperature-backward-average/script.js @@ -0,0 +1,99 @@ +//VERSION=3 + +// Set defaultVis to false to scale and set color_min and color_max values. +// LST has two observations per day: 1h30 and 13h30 solar local time + +const date = "2022-12-31"; // The date for which the backward average is calculated +const nDays = 20; // The number of days to load data for +const scaleFactor = 100; // The scale factor for the SWC values +const color_min = 260; // The minimum value of the colormap. +const color_max = 280; // The maximum value of the colormap. +const sensing_time = "0130"; // Observation time: "0130" or "1330" or "" +const variable = "LST"; // Variable of interest: "LST" or "LST_MaskedPixels" + +function setup() { + return { + input: [variable, "dataMask"], + output: { id: "default", bands: 4 }, + mosaicking: "TILE", + }; +} + +// Select files based on sensing time (0130 or 1330) and within the last nDays +function preProcessScenes(collections) { + var calculationDate = new Date(date); + collections.scenes.tiles = collections.scenes.tiles.filter(function (tile) { + var tileDate = new Date(tile.date); + return ( + tile.dataPath.includes("T" + sensing_time) && + tileDate.getTime() >= calculationDate.getTime() - nDays * 24 * 3600 * 1000 + ); + }); + return collections; +} + +function get_mean_lst_value(samples) { + // Get the sum of all LST values + let n_valid_dates = 0; + let sum = 0; + for (let i = 0; i < samples.length; i++) { + if (samples[i].dataMask) { + sum += samples[i].LST / scaleFactor; + n_valid_dates += 1; + } + } + + // Calculate the mean LST value + let mean_lst_value = NaN; + if (n_valid_dates > 0) { + mean_lst_value = sum / n_valid_dates; + } + + return mean_lst_value; +} + +// Create color ramp 250 - 340 (full range) +const cmap = [ + [263, 0x000004], + [266, 0x06051a], + [270, 0x140e36], + [274, 0x251255], + [278, 0x3b0f70], + [282, 0x51127c], + [286, 0x641a80], + [289, 0x782281], + [293, 0x8c2981], + [297, 0xa1307e], + [301, 0xb73779], + [305, 0xca3e72], + [309, 0xde4968], + [313, 0xed5a5f], + [316, 0xf7705c], + [320, 0xfc8961], + [324, 0xfe9f6d], + [328, 0xfeb77e], + [332, 0xfecf92], + [336, 0xfde7a9], + [340, 0xfcfdbf], +]; + +// Initialize the ColorRamp +const visualizer = new ColorRampVisualizer(cmap, color_min, color_max); + +function evaluatePixel(samples) { + // When there are no dates, return no data + if (samples.length == 0) return [NaN, NaN, NaN, 0]; + + // Calculate mean LST value + const mean_lst_val = get_mean_lst_value(samples); + + // Set opacity to 0 if there is no valid data + let opacity = 1; + if (isNaN(mean_lst_val)) { + opacity = 0; + } + + // Apply colormap + imgVals = visualizer.process(mean_lst_val); + return [...imgVals, opacity]; +}