{ "cells": [ { "cell_type": "markdown", "id": "8bc9a443-dec8-44a4-bec7-4d3ebc2c9655", "metadata": {}, "source": [ "# Satellite data selection" ] }, { "cell_type": "code", "execution_count": null, "id": "0f6eec56-3613-431a-ad6d-f736329d078a", "metadata": {}, "outputs": [], "source": [ "import datetime as dt\n", "import numpy as np\n", "import xarray as xr\n", "import matplotlib as mpl\n", "import matplotlib.pyplot as plt\n", "from mpl_toolkits.axes_grid1.inset_locator import inset_axes\n", "import cartopy.crs as ccrs\n", "import cartopy.feature as cfeature\n", "\n", "from viresclient import SwarmRequest" ] }, { "cell_type": "markdown", "id": "1c4595be-0709-41c2-ac8c-3056fbf352e3", "metadata": {}, "source": [ "## Fetching Swarm data using VirES" ] }, { "cell_type": "markdown", "id": "15190996-9744-4ec1-a033-c909a14de83e", "metadata": {}, "source": [ "Magnetic field measurements from Swarm Alpha are available within the [SW_OPER_MAGA_LR_1B](https://swarmhandbook.earth.esa.int/catalogue/sw_magx_lr_1b) dataset. Here we use the [viresclient](https://viresclient.readthedocs.io/) Python package to fetch these measurements." ] }, { "cell_type": "code", "execution_count": null, "id": "8a9436ac-f4b0-4f1a-b271-77a5c9f15500", "metadata": {}, "outputs": [], "source": [ "def fetch_data():\n", " \"\"\"Fetch Swarm data using the VirES service\"\"\"\n", " \n", " request = SwarmRequest()\n", " # Specify dataset to use\n", " request.set_collection(\"SW_OPER_MAGA_LR_1B\")\n", " request.set_products(\n", " measurements=[\"B_NEC\"],\n", " sampling_step=\"PT1M\", # Sample at 1-minute resolution\n", " )\n", " # Fetch 1 month of data\n", " data = request.get_between(\n", " start_time=dt.datetime(2025,1,1),\n", " end_time=dt.datetime(2025,2,1)\n", " )\n", " # Load data using xarray\n", " ds = data.as_xarray()\n", " ds.attrs.pop(\"Sources\")\n", " return ds\n", "\n", "ds_1 = fetch_data()\n", "ds_1" ] }, { "cell_type": "markdown", "id": "b32e48b8-af96-4b04-b482-b07f3a8dd61e", "metadata": {}, "source": [ "## Inspecting data" ] }, { "cell_type": "code", "execution_count": null, "id": "d1524390-79f3-40a4-9160-ef9039105695", "metadata": {}, "outputs": [], "source": [ "def plot_data_preview(ds):\n", " \"\"\"Plot magnetic field vector against latitude and time\"\"\"\n", "\n", " # Configure figure layout\n", " fig = plt.figure(figsize=(20, 5))\n", " gs = fig.add_gridspec(3, 2)\n", " ax_L0 = fig.add_subplot(gs[:, 0])\n", " ax_R0 = fig.add_subplot(gs[0, 1])\n", " ax_R1 = fig.add_subplot(gs[1, 1])\n", " ax_R2 = fig.add_subplot(gs[2, 1])\n", " # Left: Plot B_NEC vector components against latitude, on one figure\n", " ax_L0.scatter(x=ds[\"Latitude\"], y=ds[\"B_NEC\"].sel(NEC=\"N\"), s=.1, label=\"$B_N$ (North)\")\n", " ax_L0.scatter(x=ds[\"Latitude\"], y=ds[\"B_NEC\"].sel(NEC=\"E\"), s=.1, label=\"$B_E$ (East)\")\n", " ax_L0.scatter(x=ds[\"Latitude\"], y=ds[\"B_NEC\"].sel(NEC=\"C\"), s=.1, label=\"$B_C$ (Centre)\")\n", " ax_L0.set_ylabel(\"$B_{NEC}$ [nT]\")\n", " ax_L0.set_xlabel(\"Latitude [deg]\")\n", " ax_L0.grid()\n", " ax_L0.legend(markerscale=10)\n", " # Right: Plot B_NEC against time, over three figures\n", " ax_R0.scatter(x=ds[\"Timestamp\"], y=ds[\"B_NEC\"].sel(NEC=\"N\"), s=.1, c=\"tab:blue\")\n", " ax_R1.scatter(x=ds[\"Timestamp\"], y=ds[\"B_NEC\"].sel(NEC=\"E\"), s=.1, c=\"tab:green\")\n", " ax_R2.scatter(x=ds[\"Timestamp\"], y=ds[\"B_NEC\"].sel(NEC=\"C\"), s=.1, c=\"tab:orange\")\n", " # Adjust axes etc\n", " fig.subplots_adjust(wspace=.1, hspace=0)\n", " ax_R0.set_xticklabels([])\n", " ax_R1.set_xticklabels([])\n", " plt.setp(ax_R2.get_xticklabels(), rotation=45, ha='right')\n", " N_samples = len(ds[\"B_NEC\"])\n", " fig.suptitle(f\"Exploratory plots of vector field components vs latitude and time\\nNumber of data = {N_samples}\");\n", "\n", " return fig\n", "\n", "fig_1 = plot_data_preview(ds_1)" ] }, { "cell_type": "markdown", "id": "ba276b8e-b19a-48b7-a648-eb17c78b4822", "metadata": {}, "source": [ "## Selecting data to use for modelling" ] }, { "cell_type": "markdown", "id": "44eaa9c6-99bf-4867-bd03-d354834f79a0", "metadata": {}, "source": [ "Here we apply three types of data selection:\n", "\n", "- Data quality: Instrumental problems can occur and should(!) be indicated by the quality flags (`Flags_B`, `Flags_F`, `Flags_q`)\n", "- Geomagnetic activity: Select quiet periods based on Kp and rate of change of Dst\n", "- Sunlight: The dayside ionosphere is more active so we choose to use only nightside data" ] }, { "cell_type": "code", "execution_count": null, "id": "c6789204-d38e-418d-9c8b-0d49875ecdf2", "metadata": {}, "outputs": [], "source": [ "def fetch_selected_data():\n", " \"\"\"Fetch Swarm data, using filters to select the \"clean\" measurements\"\"\"\n", " \n", " request = SwarmRequest()\n", " request.set_collection(\"SW_OPER_MAGA_LR_1B\")\n", " request.set_products(\n", " measurements=[\"B_NEC\"],\n", " sampling_step=\"PT1M\",\n", " # auxiliaries=[\"Kp\", \"dDst\", \"MLT\", \"SunZenithAngle\"],\n", " )\n", " # Reject bad data according to quality flags\n", " request.add_filter(\"Flags_B != 255\")\n", " request.add_filter(\"Flags_q != 255\")\n", " # Reject geomagnetically active times\n", " request.add_filter(\"Kp <= 3\")\n", " request.add_filter(\"dDst <= 3\")\n", " # Reject sunlit data (retain data where Sun is 10° below horizon)\n", " request.add_filter(\"SunZenithAngle >= 80\")\n", " data = request.get_between(\n", " start_time=dt.datetime(2025,1,1),\n", " end_time=dt.datetime(2025,2,1)\n", " # start_time=dt.datetime(2018, 9, 14),\n", " # end_time=dt.datetime(2018, 9, 28)\n", " )\n", " ds = data.as_xarray()\n", " ds.attrs.pop(\"Sources\")\n", " return ds\n", "\n", "ds_2 = fetch_selected_data()\n", "ds_2" ] }, { "cell_type": "code", "execution_count": null, "id": "0cbe2715-fd97-45c1-ba07-cf3628b98acd", "metadata": {}, "outputs": [], "source": [ "fig_2 = plot_data_preview(ds_2)" ] }, { "cell_type": "code", "execution_count": null, "id": "f184d3d7-cabd-4cf7-a73d-956652240a90", "metadata": {}, "outputs": [], "source": [ "def global_plot(ds):\n", " \"\"\"Plot intensity over the glob\"\"\"\n", " \n", " # Append intensity, F, to the dataset\n", " ds[\"F\"] = np.sqrt((ds[\"B_NEC\"]**2).sum(axis=1))\n", " \n", " fig = plt.figure(figsize=(10, 10))\n", " gs = fig.add_gridspec(2, 2)\n", " ax_N = fig.add_subplot(gs[1, 0], projection=ccrs.Orthographic(0,90))\n", " ax_S = fig.add_subplot(gs[1, 1], projection=ccrs.Orthographic(180,-90))\n", " ax_G = fig.add_subplot(gs[0, :], projection=ccrs.EqualEarth())\n", " \n", " for ax in (ax_N, ax_S, ax_G):\n", " pc = ax.scatter(\n", " ds[\"Longitude\"], y=ds[\"Latitude\"], c=ds[\"F\"],\n", " s=5, edgecolors=\"none\", cmap=\"inferno\", transform = ccrs.PlateCarree()\n", " )\n", " ax.coastlines(linewidth=1.1)\n", " # Add colorbar inset axes into global map and move upwards\n", " cax = inset_axes(ax_G, width=\"2%\", height=\"100%\", loc=\"right\", borderpad=-5)\n", " clb = plt.colorbar(pc, cax=cax)\n", " clb.set_label(\"Field intensity [nT]\", rotation=270, va=\"bottom\")\n", "\n", "fig_3 = global_plot(ds_2)" ] }, { "cell_type": "markdown", "id": "5189f2fe-7d8a-44a6-9a6c-a83f39e162eb", "metadata": {}, "source": [ "## Exercises\n", "\n", "1. Experiment with changing the selection criteria for Kp, dDst, solar zenith angle\n", " (hint: alter the line `request.add_filter(\"Kp <= 3\")`)\n", "1. Experiment using different months of data\n", "1. How might the selection criteria bias the measurements?\n", "1. Change the time period to:\n", " ```\n", " start_time=dt.datetime(2018, 9, 14),\n", " end_time=dt.datetime(2018, 9, 28)\n", " ```\n", " (which we will use in the following notebook)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "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.6" } }, "nbformat": 4, "nbformat_minor": 5 }