From 5de3c9d970e6343422b164c70d7f32f9f8d52da6 Mon Sep 17 00:00:00 2001 From: AmberMulder <46423091+AmberMulder@users.noreply.github.com> Date: Mon, 28 Oct 2024 11:45:38 +0100 Subject: [PATCH] Add swc backward average script (#331) * Add initial setup SWC backward average * Add SWC Backward Average to index page * Remove abundant ; * Ensure average is also returned when there is no data for the last day * Ensure average is also returned when there is no data for the last day and created opacity mask from calculated average pixels * Make constants out of returned mean swc values * Add documentation on SWC backward average * Add SWC docs link and update examples of short-term fluctuations * Return one NaN when no data Co-authored-by: Jonas <53001455+jonasViehweger@users.noreply.github.com> * Avoid the use of mapping * Auto-formatting, added back FLOAT32 output --------- Co-authored-by: Amber Mulder Co-authored-by: Jonas <53001455+jonasViehweger@users.noreply.github.com> Co-authored-by: Jonas Viehweger --- .../soil-water-content/index.md | 1 + .../index.md | 34 +++++++ .../raw.js | 56 +++++++++++ .../script.js | 94 +++++++++++++++++++ 4 files changed, 185 insertions(+) create mode 100644 planetary-variables/soil-water-content/soil-water-content-backward-average/index.md create mode 100644 planetary-variables/soil-water-content/soil-water-content-backward-average/raw.js create mode 100644 planetary-variables/soil-water-content/soil-water-content-backward-average/script.js diff --git a/planetary-variables/soil-water-content/index.md b/planetary-variables/soil-water-content/index.md index 0992ca32..cd33272a 100644 --- a/planetary-variables/soil-water-content/index.md +++ b/planetary-variables/soil-water-content/index.md @@ -14,3 +14,4 @@ Planet's SWC product provides near-daily measurements at spatial resolutions of - [Soil Water Content Visualization]({% link planetary-variables/soil-water-content/soil-water-content-visualization/index.md %}) - [Soil Water Content Anomaly]({% link planetary-variables/soil-water-content/soil-water-content-anomaly/index.md %}) - [Derived Root-Zone Soil Water Content]({% link planetary-variables/soil-water-content/derived-root-zone-soil-water-content/index.md %}) +- [Soil Water Content Backward Average]({% link planetary-variables/soil-water-content/soil-water-content-backward-average/index.md %}) \ No newline at end of file diff --git a/planetary-variables/soil-water-content/soil-water-content-backward-average/index.md b/planetary-variables/soil-water-content/soil-water-content-backward-average/index.md new file mode 100644 index 00000000..d75886a5 --- /dev/null +++ b/planetary-variables/soil-water-content/soil-water-content-backward-average/index.md @@ -0,0 +1,34 @@ +--- +title: Soil Water Content Backward Average +grand_parent: Planetary Variables +parent: Soil Water Content +layout: script +nav_exclude: false +scripts: + - [Visualization, script.js] + - [Raw Values, raw.js] +examples: +- zoom: '11' + lat: '41.1921' + lng: '-93.845' + datasetId: '65f7e4fb-a27a-4fae-8d79-06a59d7e6ede' + fromTime: '2022-05-01T00:00:00.000Z' + toTime: '2022-05-26T23:59:59.999Z' + platform: + - EOB + evalscripturl: https://custom-scripts.sentinel-hub.com/custom-scripts/planetary-variables/soil-water-content/soil-water-content-backward-average/script.js + additionalQueryParams: + - - themeId + - PLANET_SANDBOX +--- +## General description +The Soil Water Content Backward Average is a method to reduce data gaps and measurement noise in the Soil Water Content (SWC) data. Depending on the requirements, we can choose a lookback period, for example 20 days. The 20-day backward average of SWC for day n is the average of SWC 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 +Our [Soil Water Content](https://custom-scripts.sentinel-hub.com/planetary-variables/soil-water-content/soil-water-content-visualization/) provides a great reflection of the immediate soil conditions. However, daily measurements often exhibit short-term fluctuations due to for example rainfall events and evaporation. The Soil Water Content Backward Average is suitable for applications where long-term soil moisture conditions 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 +- [SWC Technical specifications](https://developers.planet.com/docs/planetary-variables/soil-water-content-technical-specification/) +- [SWC Data sheet](https://planet.widen.net/s/cv7bfjhhd5) +- [Sentinel Hub documentation about Soil Water Content](https://docs.sentinel-hub.com/api/latest/data/planetary-variables/soil-water-content/) \ No newline at end of file diff --git a/planetary-variables/soil-water-content/soil-water-content-backward-average/raw.js b/planetary-variables/soil-water-content/soil-water-content-backward-average/raw.js new file mode 100644 index 00000000..8c5fba73 --- /dev/null +++ b/planetary-variables/soil-water-content/soil-water-content-backward-average/raw.js @@ -0,0 +1,56 @@ +//VERSION=3 + +const nDays = 20; // The number of days to load data for +const scaleFactor = 1000; // The scale factor for the SWC values + +function setup() { + return { + input: ["SWC", "dataMask"], + output: { bands: 1, sampleType: "FLOAT32" }, + mosaicking: "ORBIT", + }; +} + +function preProcessScenes(collections) { + collections.scenes.orbits = collections.scenes.orbits.filter(function ( + orbit + ) { + var orbitDateFrom = new Date(orbit.dateFrom); + // Select all images within the last nDays + return ( + orbitDateFrom.getTime() >= + collections.to.getTime() - nDays * 24 * 3600 * 1000 + ); + }); + return collections; +} + +function get_mean_swc_value(samples) { + // Get the sum of all SWC values + let n_valid_dates = 0; + let sum = 0; + for (let i = 0; i < samples.length; i++) { + if (samples[i].dataMask) { + sum += samples[i].SWC / scaleFactor; + n_valid_dates += 1; + } + } + + // Calculate the mean SWC value + let mean_swc_value = NaN; + if (n_valid_dates > 0) { + mean_swc_value = sum / n_valid_dates; + } + + return mean_swc_value; +} + +function evaluatePixel(samples) { + // When there are no dates, return no data + if (samples.length == 0) return [NaN]; + + // Calculate mean SWC value + const mean_swc_val = get_mean_swc_value(samples); + + return [mean_swc_val]; +} diff --git a/planetary-variables/soil-water-content/soil-water-content-backward-average/script.js b/planetary-variables/soil-water-content/soil-water-content-backward-average/script.js new file mode 100644 index 00000000..72d19a65 --- /dev/null +++ b/planetary-variables/soil-water-content/soil-water-content-backward-average/script.js @@ -0,0 +1,94 @@ +//VERSION=3 + +const nDays = 20; // The number of days to load data for +const scaleFactor = 1000; // The scale factor for the SWC values +const vmin = 0.0; // The minimum value of the colormap +const vmax = 0.4; // The maximum value of the colormap + +function setup() { + return { + input: ["SWC", "dataMask"], + output: { id: "default", bands: 4 }, + mosaicking: "ORBIT", + }; +} + +function preProcessScenes(collections) { + collections.scenes.orbits = collections.scenes.orbits.filter(function ( + orbit + ) { + var orbitDateFrom = new Date(orbit.dateFrom); + // Select all images within the last nDays + return ( + orbitDateFrom.getTime() >= + collections.to.getTime() - nDays * 24 * 3600 * 1000 + ); + }); + return collections; +} + +function get_mean_swc_value(samples) { + // Get the sum of all SWC values + let n_valid_dates = 0; + let sum = 0; + for (let i = 0; i < samples.length; i++) { + if (samples[i].dataMask) { + sum += samples[i].SWC / scaleFactor; + n_valid_dates += 1; + } + } + + // Calculate the mean SWC value + let mean_swc_value = NaN; + if (n_valid_dates > 0) { + mean_swc_value = sum / n_valid_dates; + } + + return mean_swc_value; +} + +const cmap = [ + [0.0, 0xfff7ea], + [0.05, 0xfaedda], + [0.1, 0xede4cb], + [0.15, 0xdedcbd], + [0.2, 0xced3af], + [0.25, 0xbdcba3], + [0.3, 0xaac398], + [0.35, 0x96bc90], + [0.4, 0x80b48a], + [0.45, 0x68ac86], + [0.5, 0x4da484], + [0.55, 0x269c83], + [0.6, 0x009383], + [0.65, 0x008a85], + [0.7, 0x008186], + [0.75, 0x007788], + [0.8, 0x006d8a], + [0.85, 0x00618c], + [0.9, 0x00558d], + [0.95, 0x00478f], + [1.0, 0x003492], +]; + +// Prepare colormap based on provided min and max values +const visualizer = new ColorRampVisualizer(cmap, vmin, vmax); + +function evaluatePixel(samples) { + // When there are no dates, return no data + if (samples.length == 0) return [NaN, NaN, NaN, 0]; + + // Calculate mean SWC value + const mean_swc_val = get_mean_swc_value(samples); + + // Set opacity to 0 if there is no valid data + let opacity = 1; + if (isNaN(mean_swc_val)) { + opacity = 0; + } + + // Apply colormap + imgVals = visualizer.process(mean_swc_val); + + return [...imgVals, opacity]; +}