{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Particle database"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    ":::{warning}\n",
    "\n",
    "The {doc}`pycompwa </index>` is no longer maintained. Use the [ComPWA](https://compwa-org.rtfd.io) packages [QRules](https://qrules.rtfd.io), [AmpForm](https://ampform.rtfd.io), and [TensorWaves](https://tensorwaves.rtfd.io) instead!\n",
    "\n",
    ":::"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This notebook explains the difference between the particle list in {mod}`pycompwa` and the list used in the ComPWA C++ back-end. The two are only related the way they import and export XML files."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## pycompwa particle list"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The {mod}`.particle` module is required for the expert system (see {doc}`/usage/workflow/step1`): when you create an instance of the {class}`.StateTransitionManager`, it loads the [default list of particles that is shipped with ComPWA](https://github.com/ComPWA/ComPWA/blob/master/Physics/particle_list.xml). This default list is loaded into a {class}`dict` called `particle_list` and is **used internally by the expert system**."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from pycompwa.expertsystem.state.particle import particle_list\n",
    "from pycompwa.expertsystem.ui.system_control import StateTransitionManager\n",
    "\n",
    "initial_state = [(\"J/psi\", [-1, 1])]\n",
    "final_state = [(\"gamma\"), (\"pi0\"), (\"pi0\")]\n",
    "tbd_manager = StateTransitionManager(\n",
    "    initial_state,\n",
    "    final_state,\n",
    "    formalism_type=\"helicity\",\n",
    "    topology_building=\"isobar\",\n",
    ")\n",
    "original_number_of_entries = len(particle_list)\n",
    "print(\"loaded\", original_number_of_entries, \"particles\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In PWA research, it is quite likely that this particle list is incomplete, particularly if you search for rare resonances or if you analyze a $e^+e^-$ collision of a particular energy as the initial state. You may therefore want to manipulate this particle list before you do call {meth}`.StateTransitionManager.find_solutions`. There are two ways to do this: (1) through Python or (2) by modifying a copy of the default XML file."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### (1) through Python"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The particle list instance is a tree of {class}`~collections.OrderedDict` and {class}`dict` instances that represent the structure of the XML file."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "particle_list[\"D*(2010)+\"]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Although this is a bit arduous to work with, it is possible to directly manipulate the entries in there through Python. Whatever modifications to the `particle_list` instance are later on also used in the expert system. In this case, for instance, we can set a wider width for the $D^*$:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "particle_list[\"D*(2010)+\"][\"DecayInfo\"][\"Parameter\"][0][\"Value\"] = 0.01"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "It can also happen that you want to add new particles. Because of the hierarchical structure of entries in the `particle_list`, it is best to work with a {func}`~copy.deepcopy` of a similar particle that is already in that list. You can get such a copy with {func}`.get_particle_copy_by_name` and add it back with {func}`.add_to_particle_list`. This can for instance come in handy if you want to work with several $e^+e^-$ collision energies:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from pycompwa.expertsystem.state import particle"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "energies = [4180, 4220, 4420, 4600]  # MeV\n",
    "\n",
    "for counter, energy in enumerate(energies, 1):\n",
    "    new_particle = particle.get_particle_copy_by_name(\"EpEm\")\n",
    "    new_particle[\"Parameter\"][\"Value\"] = energy / 1e3  # GeV\n",
    "    pid = int(new_particle[\"Pid\"]) + counter\n",
    "    new_particle[\"@Name\"] += str(energy)  # new name to not overwrite the old\n",
    "    new_particle[\"Pid\"] = str(pid)  # set unique PID\n",
    "    particle.add_to_particle_list(new_particle)\n",
    "\n",
    "assert original_number_of_entries + len(energies) == len(particle_list)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from IPython.display import display\n",
    "\n",
    "display(particle.particle_list[\"EpEm\"][\"Parameter\"])\n",
    "display(particle.particle_list[\"EpEm4180\"][\"Parameter\"])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "particle.particle_list[\"D*(2010)+\"][\"DecayInfo\"][\"Parameter\"][0][\n",
    "    \"Value\"\n",
    "] = 0.01"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally, you can write particle to another XML file, so that you can have this particle list manipulation in a separate Python script:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "particle.write_particle_list_to_xml(\"new_particle_list.xml\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### (2) through XML"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Alternatively, you can copy the default XML file and manipulate it by hand (copy a section, tweak some names, change some parameters) and load it as follows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "particle.load_particle_list_from_xml(\"../particle_list.xml\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that duplicate values in the particle list are overwritten, but that old values are kept:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(\"Number of entries in particle_list\")\n",
    "print(\"  old:\", original_number_of_entries)\n",
    "print(\"  new:\", len(particle.particle_list))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "particle_list[\"D*(2010)+\"][\"DecayInfo\"][\"Parameter\"][0][\"Value\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "particle_list[\"EpEm4420\"][\"Parameter\"]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## ComPWA particle list"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "ComPWA, which we manage through the {mod}`pycompwa.ui` module, works with a different particle list than the one discussed in the {ref}`previous section <usage/tools/particles:pycompwa particle list>`, because ComPWA's objects 'live' in the C++ backend. We saw this {class}`.ParticleList` class before, for instance when, {doc}`generating data </usage/workflow/step2>`. A {class}`pycompwa.ui.ParticleList` can be created from an XML file as follows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pycompwa.ui\n",
    "\n",
    "particles = pycompwa.ui.read_particles(\"../particle_list.xml\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can append particles to this instance from another list with"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pycompwa.ui.Logging(\"error\")  # switch off overwrite warnings\n",
    "pycompwa.ui.insert_particles(particles, \"../particle_list.xml\")"
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Raw Cell Format",
  "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.7.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
