<?xml version="1.0" encoding="UTF-8"?>
<rss  xmlns:atom="http://www.w3.org/2005/Atom" 
      xmlns:media="http://search.yahoo.com/mrss/" 
      xmlns:content="http://purl.org/rss/1.0/modules/content/" 
      xmlns:dc="http://purl.org/dc/elements/1.1/" 
      version="2.0">
<channel>
<title>Jonas Viehweger</title>
<link>https://jonasviehweger.github.io/blog/</link>
<atom:link href="https://jonasviehweger.github.io/blog/index.xml" rel="self" type="application/rss+xml"/>
<description>Remote Sensing Specialist — satellite imagery, machine learning, geospatial analysis.</description>
<generator>quarto-1.9.38</generator>
<lastBuildDate>Fri, 26 Jun 2026 00:00:00 GMT</lastBuildDate>
<item>
  <title>Accessing Satellite Time-series on CDSE</title>
  <link>https://jonasviehweger.github.io/blog/posts/s2-time-series-access/</link>
  <description><![CDATA[ 





<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://jonasviehweger.github.io/blog/posts/s2-time-series-access/assets/beta.png" class="img-fluid figure-img"></p>
<figcaption>RGB visualization of the first three components for a second order harmonic regression model</figcaption>
</figure>
</div>
<p>I recently have a use-case which requires long satellite time-series for somewhat small AOIs.</p>
<p>With all the recent advances in cloud optimized formats and the standardization of data catalogs with STAC, I thought this should be really easy.</p>
<p>And indeed; There’s tons of options, maybe even a bit too many to keep track of. We’ll go through them in a structured way, providing usage examples/benchmarks for all of them.</p>
<section id="example-use-case" class="level2">
<h2 class="anchored" data-anchor-id="example-use-case">Example Use Case</h2>
<p>For this example use case we are going to try and query 1 year of Sentinel 2 data over an AOI with 10x10km.</p>
<p>Let’s do some napkin math to figure out how much data that will be. To ground it in reality let’s actually query the CDSE STAC catalog.</p>
<div id="e2ceb399" class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> datetime</span>
<span id="cb1-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> pickle</span>
<span id="cb1-3"></span>
<span id="cb1-4"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> pystac_client</span>
<span id="cb1-5"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> shapely</span>
<span id="cb1-6"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> shapely.ops <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> transform</span>
<span id="cb1-7"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> pyproj <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> Transformer</span></code></pre></div></div>
</div>
<div id="99e50959" class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1">point <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> shapely.geometry.Point(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">14.39903</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">47.03920</span>)</span>
<span id="cb2-2">event <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> datetime.date(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2022</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb2-3">start <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> datetime.date(event.year <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, event.month, event.day)</span></code></pre></div></div>
</div>
<div id="dfefa2ce" class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1">crs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:3035"</span></span>
<span id="cb3-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># WGS84 -&gt; LAEA Europe (EPSG:3035)</span></span>
<span id="cb3-3">transformer <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Transformer.from_crs(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:4326"</span>, crs, always_xy<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb3-4">point_3035 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> transform(transformer.transform, point)</span>
<span id="cb3-5"></span>
<span id="cb3-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># 5 km square buffer -&gt; 10x10 km box centered on the point</span></span>
<span id="cb3-7">box_10km <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> point_3035.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">buffer</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5000</span>, cap_style<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"square"</span>)</span>
<span id="cb3-8">bounds <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> box_10km.bounds</span>
<span id="cb3-9"></span>
<span id="cb3-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># for search:</span></span>
<span id="cb3-11">back <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Transformer.from_crs(crs, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:4326"</span>, always_xy<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb3-12">box_4326 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> transform(back.transform, box_10km)</span>
<span id="cb3-13"></span>
<span id="cb3-14"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># We'll also pickle those file for later use</span></span>
<span id="cb3-15"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># write out the geoms so they can be used by other notebooks</span></span>
<span id="cb3-16"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">with</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">open</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"params.pkl"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"wb"</span>) <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> fp:</span>
<span id="cb3-17">    pickle.dump(</span>
<span id="cb3-18">        {</span>
<span id="cb3-19">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"start"</span>: start,</span>
<span id="cb3-20">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"end"</span>: event,</span>
<span id="cb3-21">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"point"</span>: point,</span>
<span id="cb3-22">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"point_3035"</span>: point_3035,</span>
<span id="cb3-23">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"box_3035"</span>: box_10km,</span>
<span id="cb3-24">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"box_4326"</span>: box_4326,</span>
<span id="cb3-25">        },</span>
<span id="cb3-26">        fp,</span>
<span id="cb3-27">    )</span></code></pre></div></div>
</div>
<div id="54930ffa" class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1">URL <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"https://stac.dataspace.copernicus.eu/v1"</span></span>
<span id="cb4-2">cat <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pystac_client.Client.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">open</span>(URL)</span>
<span id="cb4-3">cat.add_conforms_to(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ITEM_SEARCH"</span>)</span></code></pre></div></div>
</div>
<div id="d1886dec" class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb5-1">params <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb5-2">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"limit"</span>: <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>,</span>
<span id="cb5-3">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"collections"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sentinel-2-l2a"</span>,</span>
<span id="cb5-4">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"datetime"</span>: <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>start<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>strftime(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'%Y-%m-</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%d</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">/</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>event<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>strftime(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'%Y-%m-</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%d</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>,</span>
<span id="cb5-5">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"bbox"</span>: box_4326.bounds,</span>
<span id="cb5-6">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"query"</span>: {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"eo:cloud_cover"</span>: {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lte"</span>: <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">80</span>}},</span>
<span id="cb5-7">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sortby"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"properties.eo:cloud_cover"</span>,</span>
<span id="cb5-8">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"fields"</span>: {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"exclude"</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"geometry"</span>]},</span>
<span id="cb5-9">}</span></code></pre></div></div>
</div>
<div id="4fb6bd4d" class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb6-1">items <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">list</span>(cat.search(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span>params).items_as_dicts())</span>
<span id="cb6-2"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(items)</span></code></pre></div></div>
<div class="cell-output cell-output-display" data-execution_count="6">
<pre><code>89</code></pre>
</div>
</div>
<p>It’s 89 acquisitions in total for 1 year with a cloud cover of less than or equal 80%.</p>
<p>For this example we’ll just pretend to want to use NDMI and would like to get 3 bands: B08, B11 and SCL.</p>
<p>B08 is at 10m resolution, B11 and SCL at 20m resolution. For a 10x10km AOI this works out to around 276MB of uncompressed data.</p>
<details>
<summary>
Calculation details
</summary>
<p>So if we could only get exactly the data amount we need directly from the server we would need to transfer:</p>
<section id="at-10m-resolution-b08" class="level4">
<h4 class="anchored" data-anchor-id="at-10m-resolution-b08">At 10m resolution (B08):</h4>
<p><img src="https://latex.codecogs.com/png.latex?1000px%20*%201000px%20*%2092time%20*%2016%20bit%20=%20184%20MB"></p>
</section>
<section id="at-20m-resolution-b11-scl" class="level4">
<h4 class="anchored" data-anchor-id="at-20m-resolution-b11-scl">At 20m resolution (B11, SCL):</h4>
<p><img src="https://latex.codecogs.com/png.latex?500px%20*%20500px%20*%2092time%20*%2016%20bit%20=%2046%20MB"></p>
<p><img src="https://latex.codecogs.com/png.latex?2%20*%2046%20+%20184%20=%20276MB"></p>
</section></details>
<p>At the maximum 20MB/s download speed that Creodias S3 provides, this should only take a few seconds. Let’s see how long it actually takes.</p>
</section>

<section id="results" class="level2">
<h2 class="anchored" data-anchor-id="results">Results</h2>
<table class="table">
<thead>
<tr>
<th>
Type
</th>
<th>
Library
</th>
<th>
Approach
</th>
<th>
Time
</th>
<th>
Catalog Query / Lazy cube init
</th>
</tr>
</thead>
<tbody>
<tr>
<td rowspan="4">
Hosted
</td>
<td rowspan="2">
<a href="../../../blog/posts/s2-time-series-access/sh-nb/index.html">Sentinel Hub</a>
</td>
<td>
Download Client
</td>
<td>
00m 28s
</td>
<td>
2s
</td>
</tr>
<tr>
<td>
Zarr Wrapper
</td>
<td>
00m 23s
</td>
<td>
-
</td>
</tr>
<tr>
<td rowspan="2">
<a href="../../../blog/posts/s2-time-series-access/openeo-nb/index.html">OpenEO</a>
</td>
<td>
Synchronous
</td>
<td>
08m 58s
</td>
<td>
-
</td>
</tr>
<tr>
<td>
Batch Job
</td>
<td>
13m 53s
</td>
<td>
-
</td>
</tr>
<tr>
<td rowspan="6">
Local
</td>
<td rowspan="2">
<a href="../../../blog/posts/s2-time-series-access/odc-stac-nb/index.html">odc-stac</a>
</td>
<td>
Single thread
</td>
<td>
19m 16s
</td>
<td>
2s
</td>
</tr>
<tr>
<td>
Multi-threaded
</td>
<td>
08m 03s
</td>
<td>
2s
</td>
</tr>
<tr>
<td rowspan="3">
<a href="../../../blog/posts/s2-time-series-access/xcube-nb/index.html">xcube</a>
</td>
<td>
Multi-threaded
</td>
<td>
25m 01s
</td>
<td>
3m 8s
</td>
</tr>
<tr>
<td>
Multi-core
</td>
<td>
08m 47s
</td>
<td>
3m 8s
</td>
</tr>
<tr>
<td>
Native UTM, Threaded
</td>
<td>
17m 50s¹
</td>
<td>
25s
</td>
</tr>
<tr>
<td>
<a href="../../../blog/posts/s2-time-series-access/tlm-kerchunk-nb/index.html">JP2 TLM Virtualizarr</a>
</td>
<td>
Multithreaded
</td>
<td>
01m 30s
</td>
<td>
8s²
</td>
</tr>
</tbody>
</table>
<p>¹ only queried 48 acquisitions for some reason<br>
² not including pre-computing/downloading TLM headers</p>
<p>From these results we can see that Sentinel Hub is by far the fastest option to get the full data cube. The fastest local option is the JP2 TLM Virtualizarr, this however is not an operational option (see details below).</p>
<p>The biggest disappointment is xcube: It takes very long to intitialize even the lazy cube, and does not seem to be set up for dask multi-threading, taking as long as the odc single threaded approach.</p>
<p>But why is everything else so slow?</p>
</section>
<section id="the-devil-details" class="level2">
<h2 class="anchored" data-anchor-id="the-devil-details">The devil (details)</h2>
<p>There’s a few complications we are glossing over which can add a lot of overhead. To understand them we first need to understand how Sentinel-2 data is provided by CDSE. We’ll be talking about tiles, blocks and what we need to do to get those blocks. First a high level visual overview. We’ll go into detail for each level below.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://jonasviehweger.github.io/blog/posts/s2-time-series-access/assets/s2_data_structure.svg" class="img-fluid figure-img"></p>
<figcaption>Image of the different levels of Sentinel-2 tiling</figcaption>
</figure>
</div>
<p>The largest level of tiling which Sentinel-2 provides is the MGRS tiles. These are 110x110km in size, with around 10km of overlap between tiles (this can be more or less depending on latitude and longitude). This leads us to:</p>
<section id="complication-1-multiple-tiles" class="level3">
<h3 class="anchored" data-anchor-id="complication-1-multiple-tiles">Complication 1: Multiple tiles</h3>
<p>If the <em>WGS84 bounding box</em> of your AOI is less than around 10x10km it most often fits within a single tile. If it is larger, it can happen that multiple tiles need to be queried, mosaiced and possibly also reprojected if your AOI crosses UTM Zones.</p>
<p>For these MGRS tiles Sentinel 2 data on CDSE is saved in a .SAFE format. The .SAFE format provides metadata of the acquisition and each spectral band as it’s own JP2 file. A JP2 file is short for JPEG2000 and is a file type which in theory supports chunked random reads similar to a Cloud Optimized GeoTIFF (COG). In case of Sentinel-2 the bands with 10m resolution have a blocksize of 1024x1024 pixels. This means that you can get subsets of data from the full S2 tile in pre-defined 1024x1024 chunks. This is a great advantage. You don’t need to get the entire tile, but only smaller subsets. However it also brings us to our next complication:</p>
</section>
<section id="complication-2-multiple-blocks" class="level3">
<h3 class="anchored" data-anchor-id="complication-2-multiple-blocks">Complication 2: Multiple Blocks</h3>
<p>We have a AOI with 1000x1000 pixels, just slightly below the block size. This means that unless we got extremely lucky and our AOI perfectly lands within a single block, we actually have to get 2 or most likely 4 blocks at 10m resolution to get all the data for our full AOI. So the calculated 184 MB of data quickly becomes 4*184 MB = 763 MB. Almost a full Gigabyte. And this is for each 10m band we need to get.</p>
</section>
<section id="complication-3-number-of-requests" class="level3">
<h3 class="anchored" data-anchor-id="complication-3-number-of-requests">Complication 3: Number of requests</h3>
<p>Sentinel-2 Files are separate per band. This means we need to send at least one request per band. In reality we need to send a request for the header of the file to first learn where each block begins in the file, and can then issue separate range requests to get the data subsets. In even more reality most of the Sentinel-2 archive does not provide the necessary headers for the data (see <a href="https://github.com/Kayrros/sentinel-2-jp2-tlm">here</a> for some analysis) meaning that we need a lot more requests to first learn about the structure of the data before we can actually get to querying.</p>
<p>This whole process is heavily IO bound. You are always waiting for a request to complete or for data to be transmitted. Smart multi-threading can speed this up a lot, since data from multiple bands and acquisitions can be requested and transmitted in parallel while waiting for responses or data from already sent requests.</p>
<p>However the CDSE S3 service has a limit of <a href="https://documentation.dataspace.copernicus.eu/Quotas.html">2000 requests/minute</a>. In our case since we need to learn the structure of each file first due to the missing headers, around 100 range requests have to be sent <strong>per file</strong>. With a limit of 2000 requests per minute this means that local options can not query data any faster than the ~8 minutes which odc-stac achieve.</p>
<p>This is the great advantage that the JP2-TLM solution has. It uses pre-computed headers and thus does not send as many requests, does not get rate limited and completes a lot faster. This is however very experimental and not at all production ready. However it would be by far the best option to query streamlined Sentinel-2 data directly from S3.</p>
</section>
</section>
<section id="direct-access-vs-hosted-services" class="level2">
<h2 class="anchored" data-anchor-id="direct-access-vs-hosted-services">Direct Access vs Hosted Services</h2>
<p>All of this is most relevant when collecting your datacube directly from the data on a remote S3 bucket. Libraries which do it in this way are:</p>
<ul>
<li>odc-stac</li>
<li>stackstac</li>
<li>xcube-stac</li>
</ul>
<p>All of these options only rely on a STAC catalog and a file server.</p>
<p>There is another option. CDSE also provides hosted services. These are services running on computing infrastructure in the same datacenter as where the Sentinel data is hosted. These services have the big advantage that they are a lot closer to the data than we are. Requests for data are handled entirely within the datacenter. This means that more bandwidth is available and requests complete faster.</p>
<p>The two hosted services available are:</p>
<ul>
<li>SentinelHub</li>
<li>openEO</li>
</ul>
<p>These services can assemble the finished datacube entirely within the datacenter, carrying out reprojection and mosaicing for you. Data from extra blocks which aren’t needed can be already discarded on the server and only the finished datacube can be sent to you. If the hosted service is efficient in doing this, it should be faster than compiling the data cube through direct access.</p>
<p>The disadvantage is that this pre-processing on the server has a cost. Because of this cost resources are limited per month. SentinelHub offers 20.000 Processing Units per month and 10.000 Credits for openEO for free users. How far this gets you depends on the amount of requested data.</p>
<p>For these hosted services the absolute best way to use them is to implement your entire workflow to run on the cloud. However for fast prototyping, having the data local is often much quicker.</p>


</section>

 ]]></description>
  <category>Python</category>
  <category>CDSE</category>
  <category>Sentinel-2</category>
  <category>Time-series</category>
  <category>odc-stac</category>
  <category>Sentinel Hub</category>
  <category>OpenEO</category>
  <category>xcube</category>
  <category>virtualizarr</category>
  <guid>https://jonasviehweger.github.io/blog/posts/s2-time-series-access/</guid>
  <pubDate>Fri, 26 Jun 2026 00:00:00 GMT</pubDate>
  <media:content url="https://jonasviehweger.github.io/blog/posts/s2-time-series-access/assets/beta.png" medium="image" type="image/png" height="85" width="144"/>
</item>
<item>
  <title>Does large-scale Irrigation impact Precipitation?</title>
  <link>https://jonasviehweger.github.io/blog/posts/irrigation/</link>
  <description><![CDATA[ 





<p><strong>Using Google Earth Engine and 20 years of MODIS and GPM (Global Precipitation Monitoring) data, we were able to show that large-scale irrigation increases the precipitation frequency in close proximity to the irrigated areas.</strong></p>
<p><em>More details below.</em></p>
<p><img src="https://jonasviehweger.github.io/blog/posts/irrigation/Al-Jouf_animated.gif" class="img-fluid"></p>
<p><em>This is a quick and very reduced summary of the work done for this analysis.</em></p>
<p>With irrigation, most arid landscapes are very suitable for year-round agriculture. Over the last decades Saudi Arabia has used groundwater stored in aquifers to increase its agricultural output. One of the regions which benefited from the development of wells the most was Al-Jawf, where an area of 10,000 km² is irrigated almost year round using groundwater.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://jonasviehweger.github.io/blog/posts/irrigation/irrigated-area.png" class="img-fluid figure-img"></p>
<figcaption>Change in irrigated area in Al-Jawf, Saudi Arabia (2000–2019).</figcaption>
</figure>
</div>
<p>We analysed if this large-scale irrigation impacts local precipitation patterns through increased evapotranspiration.</p>
<p>Using MODIS data from 2000–2019 to classify irrigated areas and Global Precipitation Measurement (GPM) data to analyse local precipitation patterns, correlations between the irrigated area and precipitation frequency and amount could be identified.</p>
<p>The analysis was carried out using Google Earth Engine and showed an increased precipitation frequency to the north of the irrigated area, while the sum of precipitation decreased south of the irrigated area.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://jonasviehweger.github.io/blog/posts/irrigation/Trend.png" class="img-fluid figure-img"></p>
<figcaption>Precipitation trend relative to the irrigated area.</figcaption>
</figure>
</div>



 ]]></description>
  <category>Remote Sensing</category>
  <category>Google Earth Engine</category>
  <category>MODIS</category>
  <guid>https://jonasviehweger.github.io/blog/posts/irrigation/</guid>
  <pubDate>Wed, 23 Feb 2022 00:00:00 GMT</pubDate>
  <media:content url="https://jonasviehweger.github.io/blog/posts/irrigation/Trend.png" medium="image" type="image/png" height="92" width="144"/>
</item>
</channel>
</rss>
