Skip to content

Commit

Permalink
Release 3.10.1, Merge pull request #518 from sentinel-hub/develop
Browse files Browse the repository at this point in the history
Release 3.10.1
  • Loading branch information
zigaLuksic authored Jan 10, 2024
2 parents 500cf5c + e4fb34f commit c7f5912
Show file tree
Hide file tree
Showing 21 changed files with 7,499 additions and 73 deletions.
6 changes: 3 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,18 @@ repos:
- id: debug-statements

- repo: https://github.com/psf/black
rev: 23.11.0
rev: 23.12.1
hooks:
- id: black
language_version: python3

- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: "v0.1.5"
rev: "v0.1.11"
hooks:
- id: ruff

- repo: https://github.com/nbQA-dev/nbQA
rev: 1.7.0
rev: 1.7.1
hooks:
- id: nbqa-black
- id: nbqa-ruff
11 changes: 10 additions & 1 deletion CHANGELOG.MD
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
## [Version 3.10.0] - 2023-12-07
## [Version 3.10.1] - 2024-01-10

- Improved documentation for Copernicus Data Space Ecosystem.
- Restrict numpy version to <2 in anticipation of numpy 2.0 release.


## [Version 3.10.0] - 2023-12-08

- Adjust session caching to mirror changes to the core services. Older version might no longer correctly cache sessions.
- Switch default auth endpoint to the new address.


## [Version 3.9.5] - 2023-12-07

Expand All @@ -12,6 +20,7 @@
- Fixed a problem with `dataclasses_json 0.6.2` that broke BYOC functionalities
- Removed AWS examples from the docs since the functionality is no longer maintained.


## [Version 3.9.3] - 2023-11-03

- `SHConfig` now correctly initializes a default profile in the file even if the first initialization call is done with a custom profile.
Expand Down
4 changes: 2 additions & 2 deletions docs/source/tutorials.rst → docs/source/advanced.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Advanced tutorials
==================
Sentinel Hub advanced tutorials
===============================

.. toctree::
:maxdepth: 4
Expand Down
12 changes: 12 additions & 0 deletions docs/source/cdse.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.. _cdse_tutorials:
Copernicus Data Space Ecosystem examples
========================================

.. toctree::
:maxdepth: 4

examples/process_request_cdse.ipynb
examples/data_search_cdse.ipynb
examples/ogc_request_cdse.ipynb
examples/large_area_utilities_cdse.ipynb
examples/statistical_request_cdse.ipynb
29 changes: 29 additions & 0 deletions docs/source/configure.rst
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,32 @@ Batch, BYOC, and other APIs). There is "OAuth clients" frame where we can create
For detailed instructions on how to obtain credentials, you can see the `Sentinel Hub webinar`_.


Copernicus Data Space Ecosystem Configuration
*********************************************


For Copernicus Data Space Ecosystem users, please follow the `Sentinel Hub Services Authentication instructions`_ to
register an OAuth client using the `Sentinel Hub Services Dashboard`_.

With the registered OAuth client, a valid Copernicus Data Space Ecosystem configuration should be configured as below:

.. code-block:: python
from sentinelhub import SHConfig
config = SHConfig()
config.sh_client_id = 'oauth-client-id'
config.sh_client_secret = 'oauth-client-secret'
config.sh_base_url = 'https://sh.dataspace.copernicus.eu'
config.sh_token_url = 'https://identity.dataspace.copernicus.eu/auth/realms/CDSE/protocol/openid-connect/token'
.. admonition:: Supported Data Collections

With the Copernicus Data Space Ecosystem Configuration, please find the available data collections on
`Copernicus Data Space Ecosystem indexed in Sentinel Hub`_. See the :ref:`cdse_tutorials` on how to configure them for direct use in `sentinelhub-py`.


Other configuration options
***************************

Expand All @@ -110,3 +136,6 @@ $ sentinelhub.config --help
.. _`Sentinel Hub services`: https://www.sentinel-hub.com/develop/documentation/api/ogc_api/
.. _`Sentinel Hub webinar`: https://www.youtube.com/watch?v=CBIlTOl2po4&t=1760s
.. _`Sentinel Hub public repository`: https://roda.sentinel-hub.com/sentinel-s2-l1c/
.. _`Sentinel Hub Services Authentication instructions`: https://documentation.dataspace.copernicus.eu/APIs/SentinelHub/Overview/Authentication.html
.. _`Sentinel Hub Services Dashboard`: https://shapps.dataspace.copernicus.eu/dashboard/#/
.. _`Copernicus Data Space Ecosystem indexed in Sentinel Hub`: https://documentation.dataspace.copernicus.eu/APIs/SentinelHub/Data.html
19 changes: 6 additions & 13 deletions docs/source/examples.rst
Original file line number Diff line number Diff line change
@@ -1,16 +1,9 @@
Basic examples
==============
Examples
========

.. toctree::
:maxdepth: 4
:maxdepth: 1

examples/process_request.ipynb
examples/data_collections.ipynb
examples/data_search.ipynb
examples/ogc_request.ipynb
examples/large_area_utilities.ipynb
examples/batch_processing.ipynb
examples/batch_statistical.ipynb
examples/byoc_request.ipynb
examples/statistical_request.ipynb
examples/fis_request.ipynb
sh
cdse
advanced
1 change: 0 additions & 1 deletion docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,4 @@ Documentation of `sentinelhub` Python package
configure
logging
examples
tutorials
reference/sentinelhub
16 changes: 16 additions & 0 deletions docs/source/sh.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
Sentinel Hub examples
=====================

.. toctree::
:maxdepth: 4

examples/process_request.ipynb
examples/data_collections.ipynb
examples/data_search.ipynb
examples/ogc_request.ipynb
examples/large_area_utilities.ipynb
examples/batch_processing.ipynb
examples/batch_statistical.ipynb
examples/byoc_request.ipynb
examples/statistical_request.ipynb
examples/fis_request.ipynb
177 changes: 177 additions & 0 deletions examples/data/interpolation_evalscript_cdse.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
//VERSION=3

// Calculate number of bands needed for all intervals
// Initialize dates and interval
// Beware: in JS months are 0 indexed
var start_date = new Date(2020, 6, 1, 0, 0, 0);
var end_date = new Date(2020, 6, 30, 0, 0, 0);
var sampled_dates = sample_timestamps(start_date, end_date, 7, 'day').map(d => withoutTime(d));
var nb_bands = sampled_dates.length;
var n_valid = 0;
var n_all = 0;

function interval_search(x, arr) {
let start_idx = 0, end_idx = arr.length - 2;

// Iterate while start not meets end
while (start_idx <= end_idx) {
// Find the mid index
let mid_idx = (start_idx + end_idx) >> 1;

// If element is present at mid, return True
if (arr[mid_idx] <= x && x < arr[mid_idx + 1]) {
return mid_idx;
}
// Else look in left or right half accordingly
else if (arr[mid_idx + 1] <= x) start_idx = mid_idx + 1;
else end_idx = mid_idx - 1;
}
if (x == arr[arr.length-1]){
return arr.length-2;
}
return undefined;
}

function linearInterpolation(x, x0, y0, x1, y1, no_data_value=NaN) {
if (x < x0 || x > x1) {
return no_data_value;
}
var a = (y1 - y0) / (x1 - x0);
var b = -a * x0 + y0;
return a * x + b;
}

function lininterp(x_arr, xp_arr, fp_arr, no_data_value=NaN) {
results = [];
data_mask = [];
xp_arr_idx = 0;
for (var i=0; i<x_arr.length; i++) {
var x = x_arr[i];
n_all+=1;
interval = interval_search(x, xp_arr);
if (interval === undefined) {
data_mask.push(0);
results.push(no_data_value);
continue;
}
data_mask.push(1);
n_valid+=1;
results.push(
linearInterpolation(
x,
xp_arr[interval],
fp_arr[interval],
xp_arr[interval+1],
fp_arr[interval+1],
no_data_value
)
);
}
return [results, data_mask];
}

function interpolated_index(index_a, index_b) {
// Calculates the index for all bands in array
var index_data = [];
for (var i = 0; i < index_a.length; i++){
// UINT index returned
let ind = (index_a[i] - index_b[i]) / (index_a[i] + index_b[i]);
index_data.push(ind * 10000 + 10000);
}
return index_data
}

function increase(original_date, period, period_unit) {
date = new Date(original_date)
switch (period_unit) {
case 'millisecond':
return new Date(date.setMilliseconds(date.getMilliseconds()+period));
case 'second':
return new Date(date.setSeconds(date.getSeconds()+period));
case 'minute':
return new Date(date.setMinutes(date.getMinutes()+period));
case 'hour':
return new Date(date.setHours(date.getHours()+period));
case 'day':
return new Date(date.setDate(date.getDate()+period));
case 'month':
return new Date(date.setMonth(date.getMonth()+period));
default:
return undefined
}
}

function sample_timestamps(start, end, period, period_unit) {
var cDate = new Date(start);
var sampled_dates = []
while (cDate < end) {
sampled_dates.push(cDate);
cDate = increase(cDate, period, period_unit);
}
return sampled_dates;
}

function is_valid(smp) {
// Check if the sample is valid (i.e. contains no clouds or snow)
let scl = smp.SCL;
let dm = smp.dataMask;
const clouds = [0, 3, 7, 8, 9, 10];

if (clouds.includes(scl)) {
return false;
}
if (dm !=1 ) {
return false;
}
return true;
}

function withoutTime(intime) {
// Return date without time
intime.setHours(0, 0, 0, 0);
return intime;
}

// Sentinel Hub functions
function setup() {
// Setup input/output parameters
return {
input: [{
bands: ["B04", "B08", "SCL", "dataMask"],
units: "DN"
}],
output: [
{id: "NDVI", bands: nb_bands, sampleType: SampleType.UINT16},
{id: "data_mask", bands: nb_bands, sampleType: SampleType.UINT8}
],
mosaicking: "ORBIT"
}
}

// Evaluate pixels in the bands
function evaluatePixel(samples, scenes) {

// Initialise arrays
var valid_samples = {'B04':[], 'B08':[]};

var valid_dates = []
// Loop over samples.
for (var i = samples.length-1; i >= 0; i--){
if (is_valid(samples[i])) {
valid_dates.push(withoutTime(new Date(scenes[i].date)));
valid_samples['B04'].push(samples[i].B04);
valid_samples['B08'].push(samples[i].B08);
}
}

// Calculate indices and return optimised for UINT16 format (will need unpacking)
var ndvi = interpolated_index(valid_samples['B08'], valid_samples['B04'])

var [ndvi_interpolated, dm] = lininterp(sampled_dates, valid_dates, ndvi, 0);

// Return all arrays
return {
NDVI: ndvi,
data_mask: dm
}
}
66 changes: 66 additions & 0 deletions examples/data/statapi_evalscript_cdse.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//VERSION=3

function setup() {
return {
input: [{
bands: ["B01", "B02", "B03", "B04", "B05", "B06", "B07", "B08", "B8A", "B09", "B11", "B12", "SCL", "dataMask"],
units: "DN"
}],
output: [
{
id: "bands",
bands: ["B01", "B02", "B03", "B04", "B05", "B06", "B07", "B08", "B8A", "B09", "B11", "B12"],
sampleType: "UINT16"
},
{
id: "masks",
bands: ["SCL"],
sampleType: "UINT16"
},
{
id: "indices",
bands: ["NDVI", "NDVI_RE1", "NBSI"],
sampleType: "UINT16"
},
{
id: "dataMask",
bands: 1
}]
}
}

function evaluatePixel(samples) {
// Normalised Difference Vegetation Index and variation
let NDVI = index(samples.B08, samples.B04);
let NDVI_RE1 = index(samples.B08, samples.B05);

// Bare Soil Index
let NBSI = index((samples.B11 + samples.B04), (samples.B08 + samples.B02));

// masking cloudy pixels
const clouds = [0, 3, 7, 8, 9, 10];
let combinedMask = samples.dataMask
if (clouds.includes(samples.SCL)) {
combinedMask = 0;
}

const f = 5000;
return {
bands: [samples.B01, samples.B02, samples.B03, samples.B04, samples.B05, samples.B06,
samples.B07, samples.B08, samples.B8A, samples.B09, samples.B11, samples.B12],
masks: [samples.CLM],
indices: [toUINT(NDVI, f), toUINT(NDVI_RE1, f), toUINT(NBSI, f)],
dataMask: [combinedMask]
};
}

function toUINT(product, constant){
// Clamp the output to [-1, 10] and convert it to a UNIT16
// value that can be converted back to float later.
if (product < -1) {
product = -1;
} else if (product > 10) {
product = 10;
}
return Math.round(product * constant) + constant;
}
Loading

0 comments on commit c7f5912

Please sign in to comment.