{ "cells": [ { "cell_type": "markdown", "id": "e9ebfe66-3d7d-44b2-b1cf-0d1bf47393de", "metadata": {}, "source": [ "\n", "**Audience**: Advanced beginner / intermediate (*requires basic knowledge of* `scipp.DataArray`)\n", "\n", "**Objectives**: Constructing binned data from an event list, modifying binning in order to extract different quantities, and basic masking and filtering of event and binned data." ] }, { "cell_type": "markdown", "id": "ae0c6664-2a07-47e7-a411-f45773fd6eeb", "metadata": { "tags": [] }, "source": [ "# RHESSI Solar Flares" ] }, { "cell_type": "markdown", "id": "b467cb78-845d-4d0f-a31b-f8df93419de5", "metadata": { "tags": [] }, "source": [ "This tutorial covers the basics of binned data in Scipp by analyzing the list of solar flares recorded by NASA's RHESSI small explorer [[Lin *et al*](#lin2002)].\n", "\n", "The input data has been constructed from the official [flare list](https://hesperia.gsfc.nasa.gov/rhessi3/data-access/rhessi-data/flare-list/index.html).\n", "It is available as a HDF5 file in Scipp's own format and can be downloaded and accessed directly via `scipp.data` as shown below.\n", "\n", "
\n", "\n", "**Attention**\n", "\n", "The tutorial data has been filtered and modified.\n", "It should not be used for any actual scientific analyses!\n", "\n", "See `docs/tutorials/prepare_data_rhessi.py` in the [scipp source](https://github.com/scipp/scipp) for details.\n", "
" ] }, { "cell_type": "markdown", "id": "d1c256c4-f55c-49e0-bff0-99da53c4f47a", "metadata": {}, "source": [ "## 1 Loading and preprocessing data" ] }, { "cell_type": "code", "execution_count": null, "id": "31ded75c-b917-4db4-9117-e5546b2dd9bb", "metadata": { "tags": [] }, "outputs": [], "source": [ "import scipp as sc" ] }, { "cell_type": "markdown", "id": "3cdb853b-8382-4b37-bcbb-dd75857e7d1e", "metadata": {}, "source": [ "### 1.1 Load Flare List" ] }, { "cell_type": "markdown", "id": "dbb321a3-0993-44cd-bb8a-1802cc9ed71d", "metadata": {}, "source": [ "The data (`flares.data`) contains a weight for each flare.\n", "Initially, all weights are 1.\n", "\n", "The most important metadata items are:\n", "\n", "- `start_time`, `end_time`: Time interval of flare.\n", "- `peak_time`: Date and time of the highest x-ray flux.\n", "- `x`, `y`: Position in the image seen by RHESSI.\n", "- `min_energy`, `max_energy`: Energy band that a flare was observed in. Bands do not overlap.\n", "- `non_solar`: The event was flagged as not coming from the Sun." ] }, { "cell_type": "code", "execution_count": null, "id": "86c3f363-21d8-47f5-9ec7-992544e6fdf6", "metadata": { "tags": [] }, "outputs": [], "source": [ "filename = sc.data.rhessi_flares()\n", "flares = sc.io.open_hdf5(filename)\n", "flares" ] }, { "cell_type": "markdown", "id": "3aa11b4b-c769-4a7d-a114-cc496be4ed93", "metadata": { "tags": [] }, "source": [ "### 1.2 Inspect the Loaded Data" ] }, { "cell_type": "markdown", "id": "28450a77-9148-491f-983b-bd120a9ea3d5", "metadata": { "tags": [] }, "source": [ "Begin by inspecting the data array to gain a basic understanding of the data.\n", "This task is open-ended, and you can continue when you feel confident that you know what `flares` contains.\n", "\n", "Possible actions:\n", "\n", "- Use [scipp.show](https://scipp.github.io/generated/functions/scipp.show.html) and [scipp.table](https://scipp.github.io/generated/functions/scipp.table.html) in addition to the HTML output of the cell above.\n", "- Extract individual coordinates and attributes using `flares.coords['']` and `flares.attrs['']`.\n", "\n", "For guidance, you can answer the following questions. Or find your own.\n", "\n", "- How many flares are there in the dataset?\n", "- How many flares are flagged as 'non_solar'?\n", "- What is the time range of the data?\n", "\n", "**Tip**: Use [scipp.sum](https://scipp.github.io/generated/functions/scipp.sum.html), [scipp.max](https://scipp.github.io/generated/functions/scipp.max.html), and [scipp.min](https://scipp.github.io/generated/functions/scipp.min.html) with the coordinates and attributes of `flares`." ] }, { "cell_type": "code", "execution_count": null, "id": "dab75b95-8b00-41e0-a3b6-50a1b0d71321", "metadata": {}, "outputs": [], "source": [ "# YOUR CODE" ] }, { "cell_type": "markdown", "id": "1f0281e1-dc40-4f06-a772-eaa455c67bb0", "metadata": {}, "source": [ "---\n", "
\n", "\n", " Solution\n", "\n", "\n", "
\n", "Number of flares:\n", "\n", "```python\n", "flares.sizes['flare']\n", "```\n", "\n", "
\n", "Number flagged as non-solar:\n", "\n", "```python\n", "flares.attrs['non_solar'].sum()\n", "```\n", "\n", "
\n", "Time range:\n", "\n", "```python\n", "flares.coords['start_time'].min(), flares.coords['end_time'].max()\n", "```\n", "
" ] }, { "cell_type": "markdown", "id": "043d7773-c568-4ac0-9fbc-5e51f6b66d82", "metadata": {}, "source": [ "---" ] }, { "cell_type": "markdown", "id": "e93c038d-564f-4a73-8f8a-190a42e18aaa", "metadata": {}, "source": [ "### 1.3 Compute Duration" ] }, { "cell_type": "markdown", "id": "e42adacc-4a6f-431b-af35-0b1e4dd2b2ed", "metadata": {}, "source": [ "Calculate the duration of flares as `end_time - start_time` and store the result as a new coordinate in `flares`.\n", "Remember that `flares.coords` functions like a Python `dict`." ] }, { "cell_type": "code", "execution_count": null, "id": "923be2ea-e1bf-47bf-9f3f-46d2556512cf", "metadata": {}, "outputs": [], "source": [ "# YOUR CODE" ] }, { "cell_type": "markdown", "id": "9cb29a55-0956-45a2-bc3d-a6e727dfc581", "metadata": { "tags": [] }, "source": [ "---\n", "
\n", "\n", " Solution\n", "\n", "\n", "
\n", "Simple:\n", "\n", "```python\n", "duration = flares.coords['end_time'] - flares.coords['start_time']\n", "flares.coords['duration'] = duration\n", "```\n", "\n", "
\n", "Advanced, using a [coordinate transformation](https://scipp.github.io/user-guide/coordinate-transformations.html):\n", " \n", "```python\n", "def compute_duration(start_time, end_time):\n", " return end_time - start_time\n", "\n", "\n", "flares = flares.transform_coords('duration', {'duration': compute_duration})\n", "```\n", "
" ] }, { "cell_type": "markdown", "id": "6457ac49-10b6-4027-b146-d5f06ca43628", "metadata": {}, "source": [ "---" ] }, { "cell_type": "markdown", "id": "2bccb9a9-e1e3-40ba-a6a8-ccb87dcc7ec8", "metadata": {}, "source": [ "What is the combined duration of flares?\n", "(Find an appropriate function in https://scipp.github.io/reference/free-functions.html#reduction)" ] }, { "cell_type": "code", "execution_count": null, "id": "8346ed0f-a8f1-4b76-a739-a45dcbcb1e32", "metadata": { "tags": [] }, "outputs": [], "source": [ "# YOUR CODE" ] }, { "cell_type": "markdown", "id": "e20382fc-b277-4a16-acf7-207dd1536442", "metadata": {}, "source": [ "---\n", "
\n", "\n", " Solution\n", "\n", "\n", "
\n", "\n", "```python\n", "sc.sum(duration).to(unit='D', dtype='float64')\n", "```\n", "
" ] }, { "cell_type": "markdown", "id": "e6961c33-f7e6-4a90-aea5-02b6bef44006", "metadata": {}, "source": [ "---" ] }, { "cell_type": "markdown", "id": "b5097a65-69cb-4869-a59f-3659ec507f9f", "metadata": {}, "source": [ "### 1.4 Create Masks" ] }, { "cell_type": "markdown", "id": "dc6d5a37-f492-4500-b083-51139611b4c5", "metadata": {}, "source": [ "Some events in the input data did not originate from the Sun.\n", "\n", "There are two options for handling those events, removing them or masking them.\n", "You can choose a solution, but the descriptions guide you through masking, which is a method for removing events non-destructively.\n", "That is, the masks can be removed later to get the full event list back in order to determine the impact of the masks.\n", "\n", "First, store `'non_solar'` as a mask and remove it from the attributes.\n", "Use `flares.attrs` and `flares.masks` which are `dict`-like objects (similar to `flares.coords`)." ] }, { "cell_type": "code", "execution_count": null, "id": "32eea6cf-382d-4599-a9a9-0598e00065bf", "metadata": { "tags": [] }, "outputs": [], "source": [ "# YOUR CODE" ] }, { "cell_type": "markdown", "id": "dd4296be-c17f-4b2a-9604-b192dcf0afa2", "metadata": {}, "source": [ "---\n", "
\n", "\n", " Solution\n", "\n", "\n", "
\n", "\n", "```python\n", "flares.masks['non_solar'] = flares.attrs.pop('non_solar')\n", "```\n", "
" ] }, { "cell_type": "markdown", "id": "fe86e758-5dda-4725-a737-0bcfe19894d6", "metadata": {}, "source": [ "---" ] }, { "cell_type": "markdown", "id": "baf4b39e-1349-4ffd-bd3f-820e0a318202", "metadata": {}, "source": [ "Second, there are some flares whose positions could not be determined.\n", "Those are stored with `x == y == 0` and need to be removed, as well.\n", "\n", "Construct a boolean variable by comparing `flares.coords['']` to 0.\n", "Note that `x` and `y` have unit 'asec'.\n", "This means that you have to construct a '0' with the same unit which can be done using `0 * sc.Unit('asec')`.\n", "\n", "Finally, combine the variables for `x` and `y` using `mask_x & mask_y` and store the result as a new mask in `flares`." ] }, { "cell_type": "code", "execution_count": null, "id": "2d6da120-aa3a-4122-8403-da3fb274927a", "metadata": {}, "outputs": [], "source": [ "# YOUR CODE" ] }, { "cell_type": "markdown", "id": "379dac75-6b1d-4b46-8eed-2bf31a8fec4f", "metadata": { "tags": [] }, "source": [ "---\n", "
\n", "\n", " Solution\n", "\n", "\n", "
\n", "\n", "```python\n", "flares.masks['unknown_position'] = (\n", " (flares.coords['x'] == 0 * sc.Unit('asec')) &\n", " (flares.coords['y'] == 0 * sc.Unit('asec')))\n", "```\n", "
" ] }, { "cell_type": "markdown", "id": "b24196a9-76ba-4a03-90ca-4d1e9192c99b", "metadata": {}, "source": [ "---\n", "\n", "How many flares are now masked? (By each mask individually and by the combination.)\n", "\n", "**Tip**: You can `sum` booleans." ] }, { "cell_type": "code", "execution_count": null, "id": "37ece29c-a823-4a77-9a17-8e1e33345b06", "metadata": {}, "outputs": [], "source": [ "# YOUR CODE" ] }, { "cell_type": "markdown", "id": "5cdece34-32b5-4df4-8386-21762b22e8fc", "metadata": { "tags": [] }, "source": [ "---\n", "
\n", "\n", " Solution\n", "\n", "\n", "
\n", "\n", "```python\n", "ns_mask = flares.masks['non_solar']\n", "pos_mask = flares.masks['unknown_position']\n", "{\n", " 'non_solar': ns_mask.sum().value,\n", " 'unknown_position': pos_mask.sum().value,\n", " 'combined': sc.sum(ns_mask | pos_mask).value,\n", "}\n", "```\n", "
" ] }, { "cell_type": "markdown", "id": "79424a2e-1ccb-4536-9d51-06ff572a02db", "metadata": {}, "source": [ "---" ] }, { "cell_type": "markdown", "id": "13b063d3-a932-41c9-a63c-1a9566e9417e", "metadata": {}, "source": [ "## 2 Spatial Distribution" ] }, { "cell_type": "markdown", "id": "eac62e2d-c2cf-4749-b211-df7d561ea6fc", "metadata": {}, "source": [ "### 2.1 Bin by x and y" ] }, { "cell_type": "markdown", "id": "f34e4191-aaf5-4d3b-b3ba-375f745f8ba9", "metadata": {}, "source": [ "Plot the spatial distribution of flares.\n", "\n", "Plotting the event list `flares` would yield a scatter plot which is not particularly useful.\n", "A better approach is computing and plotting the density as a function of `x` and `y`.\n", "This is commonly done by histogramming the events.\n", "But Scipp offers an alternative: binning.\n", "\n", "Scipp's 'binned data' is similar to a histogram, except that the individual events are preserved.\n", "They are simply collected into bins as defined by bin-edge coordinates.\n", "\n", "Define bin-edges for `x` and `y`, use [scipp.bin](https://scipp.github.io/generated/functions/scipp.bin.html) to create binned data from `flares`, and plot the result.\n", "\n", "**Tip**:\n", "\n", "- Use [scipp.arange](https://scipp.github.io/generated/functions/scipp.arange.html) or [scipp.linspace](https://scipp.github.io/generated/functions/scipp.linspace.html) to construct the edges. Make sure to use the correct unit!\n", "- Use `sc.bin(flares, edges=[, ])`.\n", "- Turn your binned data into a histogram before plotting using `.bins.sum()`.\n", "- See [Plotting 2D data](https://scipp.github.io/visualization/plotting/plotting-2d-data.html) for the relevant parts of the plotting API." ] }, { "cell_type": "code", "execution_count": null, "id": "9cd94184-605e-4942-9a37-66ef1bfe9836", "metadata": {}, "outputs": [], "source": [ "# YOUR CODE" ] }, { "cell_type": "markdown", "id": "c6a3a7d7-06ab-484b-896a-d4a0848e08a1", "metadata": { "tags": [] }, "source": [ "---\n", "
\n", "\n", " Solution\n", "\n", "\n", "
\n", "Bin spatially.\n", "\n", "```python\n", "spatial = flares.bin(y=sc.linspace('y', -1200, 1200, 100, unit='asec'),\n", " x=sc.linspace('x', -1200, 1200, 100, unit='asec'))\n", "```\n", "\n", "
\n", "Histogram and plot.\n", "The arguments to `plot` are optional but improve the result here.\n", "\n", "```python\n", "spatial.hist().plot(aspect='equal',\n", " norm='log',\n", " labels={\n", " 'x': 'x [asec]',\n", " 'y': 'y [asec]'\n", " },\n", " cmap='inferno')\n", "```\n", "
" ] }, { "cell_type": "markdown", "id": "90be7375-28fa-44eb-8d90-5168cecb5172", "metadata": {}, "source": [ "---" ] }, { "cell_type": "markdown", "id": "51110da7-380d-4148-b6ca-aa2d0b7d0e9c", "metadata": {}, "source": [ "### 2.2 Remove Outliers" ] }, { "cell_type": "markdown", "id": "ec304dcf-0026-4abb-a758-eca093219b5a", "metadata": {}, "source": [ "The plot shows a lot of outliers.\n", "They are not the non-solar events from before because those are not visible in the plot as they were masked out.\n", "Instead, the outliers are caused by RHESSI's electronics or analysis software glitching out and assigning bad positions to the flares.\n", "This includes the circular shape even though it looks deceptively Sun-like.\n", "\n", "The flare list does not include enough information to exclude all such bad positions.\n", "But the instrument can only detect x-rays for $x \\in [-1000~\\text{asec}, 1000~\\text{asec}]$ and $y \\in [-600~\\text{asec}, 600~\\text{asec}]$.\n", "So to first order, all events outside that range should be removed.\n", "\n", "Instead of using a mask as before, use binning this time.\n", "Create new bin-edges for `x` and `y` with the proper limits and bin the data with them, this will remove all events outside the valid range.\n", "Plot the result.\n", "(You can either bin the original `flares` data array or apply new bins to the previously binned array; both via [scipp.bin](https://scipp.github.io/generated/functions/scipp.bin.html))." ] }, { "cell_type": "code", "execution_count": null, "id": "3aca7442-6d7f-484f-9250-e4aa4a76ad56", "metadata": {}, "outputs": [], "source": [ "# YOUR CODE" ] }, { "cell_type": "markdown", "id": "9113724b-e546-4698-bae9-c9c397a23b58", "metadata": { "tags": [] }, "source": [ "---\n", "
\n", "\n", " Solution\n", "\n", "\n", "
\n", "Bin into a more narrow range.\n", "Bin sizes are chosen such that bins are square.\n", "\n", "```python\n", "spatial = flares.bin(y=sc.linspace('y', -600, 600, 90, unit='asec'),\n", " x=sc.linspace('x', -1000, 1000, 150, unit='asec'))\n", "```\n", " \n", "
\n", "And plot like before.\n", "\n", "```python\n", "spatial.hist().plot(aspect='equal',\n", " norm='log',\n", " labels={\n", " 'x': 'x [asec]',\n", " 'y': 'y [asec]'\n", " },\n", " cmap='inferno')\n", "```\n", "
" ] }, { "cell_type": "markdown", "id": "6e50f022-daef-4b2d-bb3c-85e3a0382bed", "metadata": { "tags": [] }, "source": [ "---" ] }, { "cell_type": "markdown", "id": "ef565c40-3bd4-46a8-8b2d-bef301518705", "metadata": {}, "source": [ "### 2.3 Correct for Detector Efficiency" ] }, { "cell_type": "markdown", "id": "1bf0f6ea-e3a6-41db-8b18-7239b34071e0", "metadata": {}, "source": [ "In this tutorial, we assume that the instrument consists of a 3x3 grid of detectors which each record x-rays from distinct directions.\n", "(The reality is more complicated, of course. See the [wiki](https://sprg.ssl.berkeley.edu/~tohban/wiki/index.php/Category:RHESSI) for more information.)\n", "Furthermore, the tutorial data has been manipulated to simulate different efficiencies of the individual detectors.\n", "\n", "The efficiency is available as an attribute:" ] }, { "cell_type": "code", "execution_count": null, "id": "6064650d-13cf-4321-a26d-8c95a6cc2d87", "metadata": { "tags": [] }, "outputs": [], "source": [ "efficiency = flares.attrs['detector_efficiency'].value\n", "efficiency" ] }, { "cell_type": "markdown", "id": "09e44b83-25dd-45fe-b9e1-57d5b1bd3467", "metadata": {}, "source": [ "Normalize the data by dividing by `efficiency`.\n", "You first need to bin into the correct bins as defined by the coordinates of `efficiency`." ] }, { "cell_type": "code", "execution_count": null, "id": "a1a31620-f3a1-4e4d-9727-1a751006447c", "metadata": {}, "outputs": [], "source": [ "# YOUR CODE" ] }, { "cell_type": "markdown", "id": "c1fcefac-1d52-479b-beaa-129f0ca3065a", "metadata": { "tags": [] }, "source": [ "---\n", "
\n", "\n", " Solution\n", "\n", "\n", "
\n", "\n", "```python\n", "coarse_spatial = spatial.bin(x=efficiency.coords['x'],\n", " y=efficiency.coords['y'])\n", "corrected = coarse_spatial / efficiency\n", "```\n", "
" ] }, { "cell_type": "markdown", "id": "b8b78bf0-362b-4e17-903e-37261f08a2b9", "metadata": {}, "source": [ "---\n", "\n", "You can plot the corrected data as before.\n", "But it makes sense to return to smaller bins in order to resolve the distribution properly.\n", "This can be done using [scipp.bin](https://scipp.github.io/generated/functions/scipp.bin.html) with finer edges because the data was only binned and not histogrammed." ] }, { "cell_type": "code", "execution_count": null, "id": "33135bc5-794a-4d6b-8a76-21466b69e4f0", "metadata": {}, "outputs": [], "source": [ "# YOUR CODE" ] }, { "cell_type": "markdown", "id": "1c95f462-89c8-4d3f-85b6-97b8bff9c083", "metadata": { "tags": [] }, "source": [ "---\n", "
\n", "\n", " Solution\n", "\n", "\n", "
\n", "Bin in the same way as before but using `corrected` as input\n", "\n", "```python\n", "spatial = corrected.bin(y=sc.linspace('y', -600, 600, 90, unit='asec'),\n", " x=sc.linspace('x', -1000, 1000, 150, unit='asec'))\n", "```\n", " \n", "
\n", "And plot like before.\n", "\n", "```python\n", "spatial.hist().plot(aspect='equal',\n", " norm='log',\n", " labels={\n", " 'x': 'x [asec]',\n", " 'y': 'y [asec]'\n", " },\n", " cmap='inferno')\n", "```\n", "
" ] }, { "cell_type": "markdown", "id": "3765d625-cbc6-4b61-a58d-dda741b836a3", "metadata": {}, "source": [ "---" ] }, { "cell_type": "markdown", "id": "aa228f77-04fb-49ca-afea-d2644fc4ce21", "metadata": {}, "source": [ "## 3 Time Series" ] }, { "cell_type": "markdown", "id": "957d42ca-84a1-43ac-9e30-c2d91d9e3452", "metadata": {}, "source": [ "Now, we want to look at the distribution of flares over time.\n", "The temporal distribution can be obtained like the spatial one using binning.\n", "\n", "Select one of the time coordinates (e.g. 'peak_time') and bin with an appropriate bin size.\n", "Plot the result.\n", "\n", "**Important**: Use the pre-binned data from the previous task in order to include the detector normalization.\n", "\n", "**Tip**:\n", "\n", "- The time coordinates are event-coordinates, that is, they are not defined at the top level of the binned data (i.e. per bin) but inside of the bins (i.e. per event). You can access them using `.bins.coords['peak_time']`.\n", "- You can add binning by time using `.bin(peak_time=)` and produce a three-dimensional array.\n", " But here, we are more interested in a one-dimensional distribution.\n", " So we need to erase the binning in `x` and `y` which can be achieved, e.g., using `.bins.concat('x')`.\n", " \n", " Alternatively, the lower level function [scipp.binning.make_binned](https://scipp.github.io/generated/modules/scipp.binning.make_binned.html) can be used to bin in time and erase spatial binning at the same time." ] }, { "cell_type": "code", "execution_count": null, "id": "dcacee40-c14b-4650-85dd-d43f9db00f51", "metadata": {}, "outputs": [], "source": [ "# YOUR CODE" ] }, { "cell_type": "markdown", "id": "61d012c3-76f6-41e8-9294-686bad746738", "metadata": { "tags": [] }, "source": [ "---\n", "
\n", "\n", " Solution\n", "\n", "\n", "
\n", "Bin in time and keep the existing spatial binning.\n", "`transpose` is used to put the time dimension on the slider in the plot.\n", "\n", "```python\n", "temporal_and_spatial = spatial.bin(peak_time=200)\n", "to_plot = temporal_and_spatial.hist()\n", "to_plot.transpose(['peak_time', 'y', 'x']).plot(vmin=0.0 * sc.units.one,\n", " vmax=0.66 * sc.units.one,\n", " labels={\n", " 'x': 'x [asec]',\n", " 'y': 'y [asec]'\n", " },\n", " cmap='inferno')\n", "```\n", "\n", "
\n", "Or remove the existing binning, yielding a 1D-variable.\n", "\n", "```python\n", "temporal = spatial.bins.concat('x').bins.concat('y').bin(peak_time=200)\n", "temporal.hist().plot(ylabel='number of flares')\n", "```\n", "\n", "
\n", "Note that it is important to first remove the binning in x and y by using `concat`.\n", "Binning in time first and then removing other binning would use too much memory.\n", "It is possible to do everything in one step using a lower-level API:\n", "\n", "```python\n", "from scipp.binning import make_binned\n", "\n", "time = spatial.bins.coords['peak_time']\n", "min_time = time.min().value\n", "max_time = time.max().value\n", "step = (max_time - min_time) / 200\n", "time_edges = sc.arange('peak_time',\n", " min_time,\n", " max_time,\n", " step,\n", " unit=time.bins.unit)\n", "temporal = make_binned(spatial, edges=[time_edges], erase=('x', 'y'))\n", "temporal.hist().plot(ylabel='number of flares')\n", "```\n", "
\n" ] }, { "cell_type": "markdown", "id": "8b1ec693-d842-4cd0-9789-5d7ef985b4ea", "metadata": {}, "source": [ "---" ] }, { "cell_type": "markdown", "id": "4eac1ac7-aba8-4a78-a72c-9cdedbb82308", "metadata": {}, "source": [ "### 3.1 Flare Durations" ] }, { "cell_type": "markdown", "id": "b0e83bdb-2a7e-4dc3-ae81-1596ad7eb533", "metadata": {}, "source": [ "Another interesting quantity to look at is the duration of flares.\n", "The duration was computed earlier and should already be stored as an event coordinate.\n", "\n", "Plot the duration as a function of time.\n", "\n", "**Tip**:\n", "\n", "- Construct a new data array from the previous result: `duration = .copy()`.\n", " And assign new data using `duration.bins.data = `.\n", "- Previously, we used `.hist()` (which is an alias for `.bins.sum()`) to make histograms because the data was given as counts.\n", " Now the data is seconds which should be averaged instead of summed.\n", " So use `.bins.mean()` instead." ] }, { "cell_type": "code", "execution_count": null, "id": "ce5e6a81-3bfd-4cf3-91e4-cef76626af8f", "metadata": {}, "outputs": [], "source": [ "# YOUR CODE" ] }, { "cell_type": "markdown", "id": "aa907e4b-524c-4ef2-8cf4-38d68b3c7b61", "metadata": {}, "source": [ "---\n", "
\n", "\n", " Solution\n", "\n", "\n", "
\n", "Create a new data array containing the duration as its `data`.\n", "\n", "```python\n", "duration = temporal.copy()\n", "duration.name = 'duration'\n", "duration.bins.data = duration.bins.coords.pop('duration')\n", "```\n", "\n", "
\n", "Plot duration vs time.\n", "\n", "```python\n", "duration.bins.mean().plot()\n", "```\n", "
" ] }, { "cell_type": "markdown", "id": "2d7984a8-ec75-4501-a1a3-cf587830b17c", "metadata": {}, "source": [ "---" ] }, { "cell_type": "markdown", "id": "b43eb0ed-7147-4078-83f7-d16a78e1472e", "metadata": { "tags": [] }, "source": [ "## 4 Energy Bands" ] }, { "cell_type": "markdown", "id": "f04eee29-e902-4ac9-bbe2-9e9af10c6269", "metadata": {}, "source": [ "The flares were recorded in several non-overlapping energy bands.\n", "Those are identified by the 'min_energy' and 'max_energy' attributes in `flares`.\n", "Since the bands do not overlap, it is sufficient to label them with 'min_energy' for simplicity.\n", "\n", "In this section, we want to split the temporal distribution from above into the different energy bands.\n", "Group the temporal distribution by 'min_energy' to obtain two-dimensional data.\n", "Use [scipp.group](https://scipp.github.io/generated/functions/scipp.group.html) instead of `scipp.bin` this time because every event has exactly one of a set of possible energies instead of a value in a range." ] }, { "cell_type": "code", "execution_count": null, "id": "3d0568f0-fbb8-43f6-9b69-2148d2567e13", "metadata": {}, "outputs": [], "source": [ "# YOUR CODE" ] }, { "cell_type": "markdown", "id": "e6548d37-73bd-4270-b814-d17b94b4176d", "metadata": { "tags": [] }, "source": [ "---\n", "
\n", "\n", " Solution\n", "\n", "\n", "
\n", "Skipping the lowest energy band here because those events are not confirmed to be solar flares.\n", "This is optional.\n", "\n", "```python\n", "grouped_by_energy = temporal.group('min_energy')['min_energy', 1:]\n", "```\n", "
" ] }, { "cell_type": "markdown", "id": "5e30c365-a6b0-4bcf-9453-eb0b714828a7", "metadata": {}, "source": [ "---\n", "\n", "Plot the result.\n", "A 2D plot is not very useful here, so split the data by 'min_energy' and either plot each energy in a separate plot or combine them into a dictionary and plot that:\n", "```python\n", "lines = {'': }\n", "sc.plot(lines)\n", "```" ] }, { "cell_type": "code", "execution_count": null, "id": "636e5f80-e2bb-4717-9a2a-2aa426232187", "metadata": {}, "outputs": [], "source": [ "# YOUR CODE" ] }, { "cell_type": "markdown", "id": "f8c62519-5e18-44c2-9fa2-f8abc43e2b15", "metadata": { "tags": [] }, "source": [ "---\n", "
\n", "\n", " Solution\n", "\n", "\n", "
\n", "\n", "```python\n", "lines = {\n", " f\"min_energy={grouped_by_energy['min_energy', i].attrs['min_energy'].value}\":\n", " grouped_by_energy['min_energy', i].bins.sum()\n", " for i in range(grouped_by_energy.sizes['min_energy'])\n", "}\n", "sc.plot(lines, ylabel='number of flares')\n", "```\n", "
" ] }, { "cell_type": "markdown", "id": "b0072401-b6df-459f-894d-a15d235be2c6", "metadata": {}, "source": [ "---" ] }, { "cell_type": "markdown", "id": "583e4f9b-0329-4ccc-87fc-69c2d855e29e", "metadata": {}, "source": [ "## References" ] }, { "cell_type": "markdown", "id": "e4aded2c-d89e-4d4e-9ce1-f19074b7edcd", "metadata": {}, "source": [ "
\n", "\n", "Lin, R., Dennis, B., Hurford, G. et al. *The Reuven Ramaty High-Energy Solar Spectroscopic Imager (RHESSI)*. Sol Phys 210, 3–32 (**2002**). [doi:10.1023/A:1022428818870](https://doi.org/10.1023/A:1022428818870)" ] } ], "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" } }, "nbformat": 4, "nbformat_minor": 5 }