{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "tags": []
   },
   "source": [
    "# What's new in scippneutron\n",
    "\n",
    "This page highlights feature additions and discusses major changes from recent releases.\n",
    "For a full list of changes see the [Release Notes](https://scipp.github.io/scippneutron/about/release-notes.html)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import scipp as sc\n",
    "import scippneutron as scn"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "tags": []
   },
   "source": [
    "## File loading"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-info\">\n",
    "\n",
    "**New in 0.3**\n",
    "\n",
    "- `load_nexus` now loads the UB-matrix and orientation matrix if found in a Nexus file.\n",
    "- `load_nexus` now also loads pulse times for event data.\n",
    "\n",
    "</div>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Instrument View"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-info\">\n",
    "\n",
    "**New in 0.3**\n",
    "\n",
    "Additional components can be displayed using a range of shapes and related options to embellish the 3D instrument plot.\n",
    "\n",
    "</div>\n",
    "\n",
    "Full details are described in the [Instrument View](../user-guide/instrument-view.ipynb) documentation.\n",
    "Example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "da = scn.load(scn.data.get_path('PG3_4844_event.nxs'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sample_settings = {'center': da.meta['sample_position'], 'color': '#000000', 'wireframe': True,\n",
    "                   'size': sc.scalar(0.2, unit='m'), 'type': 'box'}\n",
    "source_settings = {'center': da.meta['source_position'], 'color': '#FFC133',\n",
    "                   'size': sc.vector(value=[1, 2, 1], unit='m'), 'type': 'cylinder'}\n",
    "scn.instrument_view(da, components={'sample': sample_settings, 'source': source_settings})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Coordinate Transformations\n",
    "(a.k.a 'Unit Conversions')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-info\">\n",
    "\n",
    "**New in 0.4**\n",
    "\n",
    "A new API based on [sc.transform_coords](https://scipp.github.io/generated/functions/scipp.transform_coords.html#scipp.transform_coords) that allows for more flexibility than [scn.convert](../generated/scippneutron.convert.rst#scippneutron.convert).\n",
    "\n",
    "</div>\n",
    "\n",
    "Full details are described in the [Coordinate Transformations](../user-guide/coordinate-transformations.ipynb) documentation.\n",
    "\n",
    "The new API uses graphs that describe how coordinates can be computed from each other.\n",
    "Scippneutron comes with a few predefined graphs for common use cases, see [scippneutron.conversion.graph](../generated/modules/scippneutron.conversion.graph.rst).\n",
    "Those graphs can be customized to, for example, account for gravity.\n",
    "This can be done by changing how $2\\theta$ is computed."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from scipp.constants import m_n, h\n",
    "\n",
    "\n",
    "def two_theta(gravity, wavelength, incident_beam, scattered_beam):\n",
    "    # Arbitrary internal convention: beam=z, gravity=y\n",
    "    g = sc.norm(gravity)\n",
    "    L2 = sc.norm(scattered_beam)\n",
    "    y = sc.dot(scattered_beam, gravity) / g\n",
    "    n = sc.cross(incident_beam, gravity)\n",
    "    n /= sc.norm(n)\n",
    "    x = sc.dot(scattered_beam, n)\n",
    "    wavelength = sc.to_unit(wavelength, \"m\", copy=False)\n",
    "    drop = g * m_n ** 2 / (2 * h ** 2) * wavelength ** 2 * L2 ** 2\n",
    "    return sc.asin(sc.sqrt(x ** 2 + (y + drop) ** 2) / L2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now construct a default graph for computing $Q$ and replace the implementation of `two_theta`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from scippneutron.conversion.graph.beamline import beamline\n",
    "from scippneutron.conversion.graph.tof import elastic_Q\n",
    "\n",
    "q_with_gravity = {**beamline(scatter=True), **elastic_Q(\"tof\")}\n",
    "q_with_gravity[\"two_theta\"] = two_theta"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Resulting in the following conversion graph."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sc.show_graph(q_with_gravity, simplified=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Which can be used with [sc.transform_coords](https://scipp.github.io/generated/functions/scipp.transform_coords.html#scipp.transform_coords) to convert from time-of-flight to $Q$:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from scipp.constants import g\n",
    "\n",
    "da = scn.data.tutorial_dense_data()\n",
    "da.coords[\"gravity\"] = sc.vector(value=[0, -1, 0]) * g\n",
    "da_gravity = da.transform_coords(\"Q\", graph=q_with_gravity)\n",
    "da_gravity"
   ]
  }
 ],
 "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": 4
}
