{
 "cells": [
  {
   "cell_type": "raw",
   "metadata": {
    "raw_mimetype": "text/restructuredtext"
   },
   "source": [
    "Download this notebook :download:`here <particles.ipynb>`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Particle database"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {
    "raw_mimetype": "text/restructuredtext"
   },
   "source": [
    ".. note::\n",
    "    This functionality will be deprecated once `issue 40 <https://github.com/ComPWA/expertsystem/issues/40>`_ has been addressed."
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {
    "raw_mimetype": "text/restructuredtext"
   },
   "source": [
    "In PWA, you usually want to search for special resonances, possibly even some not listed in the PDG. The particle database that the `expertsystem` loads by default is therefore often not sufficient for your analysis. In this notebook, we go through a few ways to add or overwrite the database with your own particle definitions."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Loading the default database"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {
    "raw_mimetype": "text/restructuredtext"
   },
   "source": [
    "In the usual :doc:`workflow </usage/quickstart>`, you start by calling the `.StateTransitionManager`. Upon construction, the function `.load_default_particle_list` is called, which fills the :code:`expertsystem.state.particle.DATABASE` instance with particle definitions as defined in `particle_list.xml <https://github.com/ComPWA/expertsystem/blob/master/expertsystem/particle_list.xml>`_. Here, we call this method directly to illustrate what happens:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from expertsystem.state import particle\n",
    "from expertsystem.ui import load_default_particle_list\n",
    "\n",
    "print(\"Before loading:\", len(particle.DATABASE))\n",
    "load_default_particle_list()\n",
    "print(\"After loading:\", len(particle.DATABASE))"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {
    "raw_mimetype": "text/restructuredtext"
   },
   "source": [
    "The functions in the :mod:`.particle` module can be used to add or modify particle definitions in the particle database. There are a few ways to add or overwrite particle definitions."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Adding custom particle definitions through Python"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {
    "raw_mimetype": "text/restructuredtext"
   },
   "source": [
    "A quick way to modify or overwrite particles, is through your Python script of notebook. It's quite easy to modify one particle from the particle database, as it's simply a `dict`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "omega = particle.DATABASE[\"omega(782)\"]\n",
    "omega"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {
    "raw_mimetype": "text/restructuredtext"
   },
   "source": [
    "A useful (even if rather hackable) modification is for instance the width. In the `expertsystem`, the width is used for the mass conservation check, while in `tensorwaves`, the width is important when generating a toy MC sample (see :ref:`tensorwaves:usage/2_generate_data:2.3 Generate intensity-based sample`):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "omega[\"DecayInfo\"][\"Parameter\"][0][\"Value\"] = 0.001"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {
    "raw_mimetype": "text/restructuredtext"
   },
   "source": [
    "More relevant for your research is adding particles. Here it is useful to work with an existing particle as template. Let's say we want to study :math:`e^+e^-` collisions of several energies:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "energies_mev = [4180, 4220, 4420, 4600]\n",
    "for counter, energy_mev in enumerate(energies_mev, 1):\n",
    "    energy_gev = energy_mev / 1e3\n",
    "    new_particle = particle.get_particle_copy(\"EpEm (4230 MeV)\")\n",
    "    new_particle[\"Name\"] = f\"EpEm ({energy_mev} MeV)\"\n",
    "    new_particle[\"Parameter\"][\"Value\"] = energy_gev  # set the mass\n",
    "    new_particle[\"Pid\"] = int(new_particle[\"Pid\"]) + counter\n",
    "    particle.add_to_particle_database(new_particle)\n",
    "len(particle.DATABASE)"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {
    "raw_mimetype": "text/restructuredtext"
   },
   "source": [
    "Note that there are also functions to search for particles, either by name or PID (see `.find_particle`):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "search_results = particle.find_particle(\"f0\")\n",
    "search_results.keys()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "particle.find_particle(22)"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {
    "raw_mimetype": "text/restructuredtext"
   },
   "source": [
    "Note that `.get_particle_copy` works in the same way as `.find_particle`, the only difference being that it returns a `~copy.deepcopy`, so that you can modify the search results."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Loading custom definitions from a YAML file"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {
    "raw_mimetype": "text/restructuredtext"
   },
   "source": [
    "It's also possible to add particles from a config file, with `.load_particles`. It's easiest to work with YAML. Here, we use the provided :download:`additional_particles.yml` example file:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "particle.load_particles(\"additional_particles.yml\")\n",
    "len(particle.DATABASE)"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {
    "raw_mimetype": "text/restructuredtext"
   },
   "source": [
    "Notice how the `dict` structure of the newly added entries is similar to what we saw before:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "particle.DATABASE[\"Sigma(1385)+\"]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Writing to XML or YAML"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {
    "raw_mimetype": "text/restructuredtext"
   },
   "source": [
    "You can also dump the existing particle lists to either YAML or XML."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "particle.write_particle_database(\"dumped_particle_list.xml\")\n",
    "particle.write_particle_database(\"dumped_particle_list.yaml\")"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {
    "raw_mimetype": "text/restructuredtext"
   },
   "source": [
    "This is useful if you want to check the expected syntax. In fact, the `expertsystem` provides `JSON schemas <https://json-schema.org/>`_ (e.g. :download:`yaml/particle-list.json <../../expertsystem/schemas/yaml/particle-list.json>`) to validate your particle list files (see also `jsonschema.validate`):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import yaml\n",
    "from expertsystem import io\n",
    "\n",
    "with open(\"dumped_particle_list.yaml\") as stream:\n",
    "    definition = yaml.load(stream, Loader=yaml.SafeLoader)\n",
    "io.yaml.validation.particle_list(definition)"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {
    "raw_mimetype": "text/restructuredtext"
   },
   "source": [
    "In addition, if you have installed the `expertsystem` in :ref:`install:Development mode` and :ref:`use VSCode <contribute:Visual Studio code>`, your YAML particle list are checked automatically in the GUI."
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Raw Cell Format",
  "kernelspec": {
   "display_name": "Python 3",
   "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.8.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
