diff --git a/docs/examples/index.rst b/docs/examples/index.rst
index 65614ad8c..f9f5af4a9 100644
--- a/docs/examples/index.rst
+++ b/docs/examples/index.rst
@@ -133,6 +133,7 @@ Dictionary input
fields_from_dict_in_loop.ipynb
list_of_dicts_overview
list_of_dicts_geography
+ list_of_dicts_to_xarray
Other inputs
diff --git a/docs/examples/list_of_dicts_to_xarray.ipynb b/docs/examples/list_of_dicts_to_xarray.ipynb
new file mode 100644
index 000000000..955d60420
--- /dev/null
+++ b/docs/examples/list_of_dicts_to_xarray.ipynb
@@ -0,0 +1,968 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "ee0f0104-8077-45f1-9746-58f29b64db92",
+ "metadata": {
+ "editable": true,
+ "slideshow": {
+ "slide_type": ""
+ },
+ "tags": []
+ },
+ "source": [
+ "## list-of-dict: converting to Xarray"
+ ]
+ },
+ {
+ "cell_type": "raw",
+ "id": "6cadbfbf-c7af-4927-8927-c320d9160c4f",
+ "metadata": {
+ "editable": true,
+ "raw_mimetype": "text/x-rst",
+ "slideshow": {
+ "slide_type": ""
+ },
+ "tags": []
+ },
+ "source": [
+ "This example demonstrates how :ref:`data-sources-lod` fieldlists can be converted into Xarray."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2e087423-8c96-49b4-984c-f15472fa8381",
+ "metadata": {
+ "editable": true,
+ "slideshow": {
+ "slide_type": ""
+ },
+ "tags": []
+ },
+ "source": [
+ "#### Data containing geography"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "1e5ebf7a-2fc6-453a-9e14-6b04b5135810",
+ "metadata": {
+ "editable": true,
+ "slideshow": {
+ "slide_type": ""
+ },
+ "tags": []
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "
\n",
+ "
<xarray.Dataset> Size: 248B\n",
+ "Dimensions: (levelist: 2, latitude: 3, longitude: 2)\n",
+ "Coordinates:\n",
+ " * levelist (levelist) int64 16B 500 850\n",
+ " * latitude (latitude) float64 24B 10.0 0.0 -10.0\n",
+ " * longitude (longitude) float64 16B 20.0 40.0\n",
+ "Data variables:\n",
+ " t (levelist, latitude, longitude) float64 96B ...\n",
+ " u (levelist, latitude, longitude) float64 96B ...\n",
+ "Attributes:\n",
+ " Conventions: CF-1.8\n",
+ " institution: ECMWF
- levelist: 2
- latitude: 3
- longitude: 2
PandasIndex
PandasIndex(Index([500, 850], dtype='int64', name='levelist'))
PandasIndex
PandasIndex(Index([10.0, 0.0, -10.0], dtype='float64', name='latitude'))
PandasIndex
PandasIndex(Index([20.0, 40.0], dtype='float64', name='longitude'))
- Conventions :
- CF-1.8
- institution :
- ECMWF
"
+ ],
+ "text/plain": [
+ " Size: 248B\n",
+ "Dimensions: (levelist: 2, latitude: 3, longitude: 2)\n",
+ "Coordinates:\n",
+ " * levelist (levelist) int64 16B 500 850\n",
+ " * latitude (latitude) float64 24B 10.0 0.0 -10.0\n",
+ " * longitude (longitude) float64 16B 20.0 40.0\n",
+ "Data variables:\n",
+ " t (levelist, latitude, longitude) float64 96B ...\n",
+ " u (levelist, latitude, longitude) float64 96B ...\n",
+ "Attributes:\n",
+ " Conventions: CF-1.8\n",
+ " institution: ECMWF"
+ ]
+ },
+ "execution_count": 1,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "import earthkit.data as ekd\n",
+ "\n",
+ "prototype = {\n",
+ " \"latitudes\": [10.0, 0.0, -10.0],\n",
+ " \"longitudes\": [20, 40.0],\n",
+ " \"values\": [1, 2, 3, 4, 5, 6],\n",
+ " \"valid_datetime\": \"2018-08-01T09:00:00Z\",\n",
+ " }\n",
+ "\n",
+ "d = [\n",
+ " {\"param\": \"t\", \"level\": 500, **prototype},\n",
+ " {\"param\": \"t\", \"level\": 850, **prototype},\n",
+ " {\"param\": \"u\", \"level\": 500, **prototype},\n",
+ " {\"param\": \"u\", \"level\": 850, **prototype},\n",
+ " ]\n",
+ "\n",
+ "ds = ekd.from_source(\"list-of-dicts\", d)\n",
+ "ds.to_xarray()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "94b46ec8-614b-480a-8ffe-0b1dd4e344bb",
+ "metadata": {
+ "editable": true,
+ "slideshow": {
+ "slide_type": ""
+ },
+ "tags": []
+ },
+ "source": [
+ "#### Data without geography"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "7ea3d8bf-a432-4aef-94d9-5ac0c6b19503",
+ "metadata": {
+ "editable": true,
+ "slideshow": {
+ "slide_type": ""
+ },
+ "tags": []
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "
<xarray.Dataset> Size: 208B\n",
+ "Dimensions: (levelist: 2, values: 6)\n",
+ "Coordinates:\n",
+ " * levelist (levelist) int64 16B 500 850\n",
+ "Dimensions without coordinates: values\n",
+ "Data variables:\n",
+ " t (levelist, values) float64 96B ...\n",
+ " u (levelist, values) float64 96B ...\n",
+ "Attributes:\n",
+ " Conventions: CF-1.8\n",
+ " institution: ECMWF
"
+ ],
+ "text/plain": [
+ " Size: 208B\n",
+ "Dimensions: (levelist: 2, values: 6)\n",
+ "Coordinates:\n",
+ " * levelist (levelist) int64 16B 500 850\n",
+ "Dimensions without coordinates: values\n",
+ "Data variables:\n",
+ " t (levelist, values) float64 96B ...\n",
+ " u (levelist, values) float64 96B ...\n",
+ "Attributes:\n",
+ " Conventions: CF-1.8\n",
+ " institution: ECMWF"
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "prototype = {\n",
+ " \"values\": [1, 2, 3, 4, 5, 6],\n",
+ " \"valid_datetime\": \"2018-08-01T09:00:00Z\",\n",
+ " }\n",
+ "\n",
+ "d = [\n",
+ " {\"param\": \"t\", \"level\": 500, **prototype},\n",
+ " {\"param\": \"t\", \"level\": 850, **prototype},\n",
+ " {\"param\": \"u\", \"level\": 500, **prototype},\n",
+ " {\"param\": \"u\", \"level\": 850, **prototype},\n",
+ " ]\n",
+ "\n",
+ "ds = ekd.from_source(\"list-of-dicts\", d)\n",
+ "ds.to_xarray()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c6463409-7686-4d90-8cab-00a04b7119bb",
+ "metadata": {
+ "editable": true,
+ "slideshow": {
+ "slide_type": ""
+ },
+ "tags": []
+ },
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "dev",
+ "language": "python",
+ "name": "dev"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.12"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/docs/release_notes/index.rst b/docs/release_notes/index.rst
index 773423b42..f18ea27b4 100644
--- a/docs/release_notes/index.rst
+++ b/docs/release_notes/index.rst
@@ -15,6 +15,7 @@ Version updates
.. toctree::
:maxdepth: 1
+ version_0.15_updates
version_0.14_updates
version_0.13_updates
version_0.12_updates
diff --git a/docs/release_notes/version_0.15_updates.rst b/docs/release_notes/version_0.15_updates.rst
new file mode 100644
index 000000000..bc8a5d815
--- /dev/null
+++ b/docs/release_notes/version_0.15_updates.rst
@@ -0,0 +1,26 @@
+Version 0.15 Updates
+/////////////////////////
+
+
+Version 0.15.0
+===============
+
+Xarray engine
+++++++++++++++++++++++++++++++
+
+- Improved the serialisation of GRIB fieldlists to reduce memory usage when Xarray is generated with chunks (:pr:`700`). See the :ref:`/examples/xarray_engine_chunks.ipynb` notebook example.
+- TensorBackendArray, which implements the lazy loading of DataArrays in the Xarray engine, now uses a ``dask.utils.SerializableLock`` when accessing the data (:pr:`700`).
+- Enabled converting :ref:`data-sources-lod` fieldlists into Xarray (:pr:`701`). See the :ref:`/examples/list_of_dicts_to_xarray.ipynb` notebook example.
+
+
+New features
++++++++++++++++++
+
+- Added new config option ``grib-file-serialisation-policy`` to control how GRIB data on disk is pickled. The options are "path" and "memory". The default is "path". Previously, only "memory" was implemented (:pr:`700`).
+- Added serialisation to GRIB fields (both on disk and in-memory) (:pr:`700`)
+
+
+Fixes
++++++++++++++++++
+
+- Fixed issue when the :ref:`data-sources-forcings` source did not handle time-zone aware datetimes correctly (:pr:`693`).