Skip to content

Commit 5f05c28

Browse files
charliemoriartyanne
and
anne
authored
Add flash drought example for Soil Water Content (#334)
* Add initial flash drought script * Add raw file * add flash drought * add flash drought * right links on index page * Add superscript to SWC units * Add improved formatting, align whitespace * Refactor to remove map --------- Co-authored-by: anne <[email protected]>
1 parent 65721e0 commit 5f05c28

File tree

5 files changed

+181
-1
lines changed

5 files changed

+181
-1
lines changed

planetary-variables/soil-water-content/index.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,5 @@ Planet's SWC product provides near-daily measurements at spatial resolutions of
1515
- [Soil Water Content Anomaly]({% link planetary-variables/soil-water-content/soil-water-content-anomaly/index.md %})
1616
- [Derived Root-Zone Soil Water Content]({% link planetary-variables/soil-water-content/derived-root-zone-soil-water-content/index.md %})
1717
- [Soil Water Content Backward Average]({% link planetary-variables/soil-water-content/soil-water-content-backward-average/index.md %})
18-
- [Soil Water Content Quality Flags]({% link planetary-variables/soil-water-content/soil-water-content-quality-flags/index.md %})
18+
- [Soil Water Content Quality Flags]({% link planetary-variables/soil-water-content/soil-water-content-quality-flags/index.md %})
19+
- [Flash Drought]({% link planetary-variables/soil-water-content/soil-water-content-flash-drought/index.md %})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
---
2+
title: Flash Drought
3+
grand_parent: Planetary Variables
4+
parent: Soil Water Content
5+
layout: script
6+
nav_exclude: false
7+
scripts:
8+
- [Visualization, script.js]
9+
- [Raw Values, raw.js]
10+
---
11+
## General description
12+
Droughts that are formed in just a few weeks are called flash droughts. We have published a [series of blog posts](https://www.planet.com/pulse/drying-up-in-a-flash-what-satellite-data-can-tell-us-about-flash-drought-risks-and-the-regions-we-should-be-watching/) about this fast-emerging and increasingly impactful climate phenomenon. This custom script uses the same principles as described in the blogs and can be used to highlight areas with potential flash droughts.
13+
14+
## Method
15+
Based on the work of Eswar et al. (2018), we developed a methodology that highlights areas that reach a certain threshold for dryness and changes in SWC over a 28-day period. Specific thresholds for dryness and changes in SWC are set; by default, areas are highlighted where the 14-days backward average SWC was under 0.15 m<sup>3</sup>/m<sup>3</sup> and the average decrease in the 14-days backward average SWC was above 0.12 m<sup>3</sup>/m<sup>3</sup> compared to 28 days ago. Visualizing the areas that meet those criteria over time show these rapidly drying regions in red, and as conditions continue to change, they fade away.
16+
17+
## Description of representative images
18+
[One of the blog posts](https://www.planet.com/pulse/flash-drought-hotspots-southwestern-united-states/) describes the flash drought in Southwestern United States in 2023. The example below shows the flash drought in a part of the Southwest on 22 April 2023.
19+
![Flash Drought Southwestern U.S.A. 22 April 2023](fig/flash_drought.png)
20+
21+
## Usage of the script
22+
The amount of days to calculate the backward average is 14, but can be changed by setting *nDaysBackwardAverage*. By default, the backward average SWC value is compared to the backward average SWC value of 28 days ago, which can be changed by setting *nDaysPrevious*. If you have a collection with SWC data, the first day on which this flash drought script can be applied is day 42 (*nDaysBackwardAverage + nDaysPrevious*). Be also aware that you set the timespan correctly in the EO Browser or Requests Builder (the difference between the start and end date must be at least *nDaysBackwardAverage + nDaysPrevious*), otherwise *no data* will be returned.
23+
24+
## Useful links
25+
- [Drying Up in a Flash: What Satellite Data Can Tell Us About Flash Drought Risks and the Regions We Should Be Watching](https://www.planet.com/pulse/drying-up-in-a-flash-what-satellite-data-can-tell-us-about-flash-drought-risks-and-the-regions-we-should-be-watching/)
26+
- [Flash Drought Hotspots: Southwestern United States](https://www.planet.com/pulse/flash-drought-hotspots-southwestern-united-states/)
27+
- [Flash Drought Hotspots: Iberian Peninsula](https://www.planet.com/pulse/flash-drought-hotspots-iberian-peninsula/)
28+
29+
## References
30+
Eswar R., Das N.N., Poulsen C., Behrangi A., Swigart J., Svoboda M., Entekhabi D., Yueh S., Doorn B., Entin J. (2018). SMAP Soil Moisture Change as an Indicator of Drought Conditions. Remote Sensing, 10(5), 788. [https://doi.org/10.3390/rs10050788](https://doi.org/10.3390/rs10050788)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
//VERSION=3
2+
3+
const nDaysBackwardAverage = 14; // The number of days that is used to calculate the swc backward average
4+
const nDaysPrevious = 28; // The number of days to look back to compare the current value with the previous value
5+
const scaleFactor = 1000; // The scale factor for the SWC values
6+
const droughtThreshold = 0.15; // The SWC value under which conditions are considered drought-like
7+
const differenceThreshold = -0.12; // Threshold signifying a rapid drop in SWC from the previous average value
8+
9+
function setup() {
10+
return {
11+
input: ["SWC", "dataMask"],
12+
output: { bands: 1 },
13+
mosaicking: "ORBIT",
14+
};
15+
}
16+
17+
const daysToLoad = nDaysBackwardAverage + nDaysPrevious; // The number of days looking back to load data for
18+
19+
function preProcessScenes(collections) {
20+
const millisecondsBack = daysToLoad * 24 * 3600 * 1000;
21+
22+
collections.scenes.orbits = collections.scenes.orbits.filter(function (
23+
orbit
24+
) {
25+
const orbitDateFrom = new Date(orbit.dateFrom);
26+
return (
27+
orbitDateFrom.getTime() >= collections.to.getTime() - millisecondsBack
28+
);
29+
});
30+
return collections;
31+
}
32+
33+
function getMeanSWCValue(samples) {
34+
// Get the sum of all SWC values
35+
let validDateCount = 0;
36+
let sum = 0;
37+
for (let i = 0; i < samples.length; i++) {
38+
if (samples[i].dataMask) {
39+
sum += samples[i].swc;
40+
validDateCount += 1;
41+
}
42+
}
43+
44+
// Calculate the mean SWC value
45+
let meanSWCValue = NaN;
46+
if (validDateCount > 0) {
47+
meanSWCValue = sum / validDateCount;
48+
}
49+
50+
return meanSWCValue;
51+
}
52+
53+
function evaluatePixel(samples) {
54+
// When there are no dates, return no data
55+
if (samples.length == 0) return [NaN];
56+
// When the search interval of the request body is too short to perform the calculation, return no data
57+
if (samples.length < daysToLoad) return [NaN];
58+
59+
// Extract samples for the two time periods
60+
const initialSamples = samples.slice(0, nDaysBackwardAverage)
61+
const previousSamples = samples.slice(nDaysPrevious, nDaysBackwardAverage + nDaysPrevious)
62+
63+
// Calculate mean SWC value
64+
const meanSWC = getMeanSWCValue(initialSamples);
65+
const meanSWCPrevious = getMeanSWCValue(previousSamples);
66+
67+
const swcDifference = meanSWC - meanSWCPrevious;
68+
const isFlashDrought =
69+
meanSWC < droughtThreshold && swcDifference < differenceThreshold ? 1 : 0;
70+
71+
return [isFlashDrought];
72+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
//VERSION=3
2+
3+
const nDaysBackwardAverage = 14; // The number of days that is used to calculate the swc backward average
4+
const nDaysPrevious = 28; // The number of days to look back to compare the current value with the previous value
5+
const scaleFactor = 1000; // The scale factor for the SWC values
6+
const droughtThreshold = 0.15; // The SWC value under which conditions are considered drought-like
7+
const differenceThreshold = -0.12; // Threshold signifying a rapid drop in SWC from the previous average value
8+
9+
function setup() {
10+
return {
11+
input: ["SWC", "dataMask"],
12+
output: { bands: 4 },
13+
mosaicking: "ORBIT",
14+
};
15+
}
16+
17+
const daysToLoad = nDaysBackwardAverage + nDaysPrevious; // The number of days looking back to load data for
18+
19+
function preProcessScenes(collections) {
20+
const millisecondsBack = daysToLoad * 24 * 3600 * 1000;
21+
22+
collections.scenes.orbits = collections.scenes.orbits.filter(function (
23+
orbit
24+
) {
25+
const orbitDateFrom = new Date(orbit.dateFrom);
26+
return (
27+
orbitDateFrom.getTime() >= collections.to.getTime() - millisecondsBack
28+
);
29+
});
30+
return collections;
31+
}
32+
33+
function getMeanSWCValue(samples) {
34+
// Get the sum of all SWC values
35+
let validDateCount = 0;
36+
let sum = 0;
37+
for (let i = 0; i < samples.length; i++) {
38+
if (samples[i].dataMask) {
39+
sum += samples[i].swc;
40+
validDateCount += 1;
41+
}
42+
}
43+
44+
// Calculate the mean SWC value
45+
let meanSWCValue = NaN;
46+
if (validDateCount > 0) {
47+
meanSWCValue = sum / validDateCount;
48+
}
49+
50+
return meanSWCValue;
51+
}
52+
53+
function evaluatePixel(samples) {
54+
// When there are no dates, return no data
55+
if (samples.length == 0) return [NaN, NaN, NaN, 0];
56+
// When the search interval of the request body is too short to perform the calculation, return no data
57+
if (samples.length < daysToLoad) return [NaN, NaN, NaN, 0];
58+
59+
// Extract samples for the two time periods
60+
const initialSamples = samples.slice(0, nDaysBackwardAverage)
61+
const previousSamples = samples.slice(nDaysPrevious, nDaysBackwardAverage + nDaysPrevious)
62+
63+
// Calculate mean SWC value
64+
const meanSWC = getMeanSWCValue(initialSamples);
65+
const meanSWCPrevious = getMeanSWCValue(previousSamples);
66+
67+
const swcDifference = meanSWC - meanSWCPrevious;
68+
const isFlashDrought =
69+
meanSWC < droughtThreshold && swcDifference < differenceThreshold ? 1 : 0;
70+
71+
let opacity = 0;
72+
if (isFlashDrought) {
73+
opacity = 1;
74+
}
75+
76+
return [isFlashDrought, 0, 0, opacity];
77+
}

0 commit comments

Comments
 (0)