{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "source": [
    "# Creation of hydrocerussite calibrant\n",
    "\n",
    "In this tutorial we will see how to create a new calibrant. For this example we will use one of the componant of mostpaintings: hydrocerussite.\n",
    "\n",
    "The cell parameter are definied in this document:\n",
    "http://rruff.geo.arizona.edu/AMS/AMC_text_files/11987_amc.txt\n",
    "\n",
    "The first step is to record the cell parameters and provide them to pyFAI to define the cell."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "pyFAI version 2025.11.0-dev0\n"
     ]
    }
   ],
   "source": [
    "import pyFAI\n",
    "print(\"pyFAI version\",pyFAI.version)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "from pyFAI.calibrant import Cell\n",
    "hydroc_hex = Cell.hexagonal(5.24656, 23.7023)\n",
    "\n",
    "#This is an alternative representation, where extinction rules are already definied ... but that's cheating\n",
    "hydroc_rho = Cell.hexagonal(5.24656, 23.7023, lattice_type=\"R\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Chromium oxide has a crystal structure de Corrundom which is R-3m (space group 166). \n",
    "The selection rules are rather complicated and are available in:\n",
    "![Space-group 166](http://img.chem.ucl.ac.uk/sgp/large/166bz2.gif \"Space-group 166\")\n",
    "\n",
    "\n",
    "We will setup a function corresponding to the selection rules. It returns True if the reflection is active and False  otherwise.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "    @staticmethod\n",
      "    def group166_R3bar_m(h: int, k: int, l: int) -> bool:  # noqa: E741\n",
      "        \"\"\"\n",
      "        Space group 166: R3̅m. Trigonal (hexagonal axes), rhombohedral lattice.\n",
      "        Valid reflections must satisfy:\n",
      "        - hkil:                          -h + k + l = 3n\n",
      "        - hki0 (l = 0):                  -h + k = 3n\n",
      "        - hh(-2h)l:                      l = 3n\n",
      "        - h(-h)0l (i = 0, k = -h):       h + l = 3n\n",
      "        - 000l (h = k = 0):              l = 3n\n",
      "        - h(-h)00 (l = 0, k = -h):       h = 3n\n",
      "\n",
      "        Source:\n",
      "            Reflection conditions from ITC (in hkil), adapted to (h, k, l)\n",
      "            using the relation i = -(h + k).\n",
      "            JKC: http://img.chem.ucl.ac.uk/sgp/large/166bz2.htm\n",
      "        validated\n",
      "        \"\"\"\n",
      "        if (-h + k + l) % 3 != 0:\n",
      "            return False  # hkil\n",
      "        if l == 0:\n",
      "            return (-h + k) % 3 == 0  # hki0\n",
      "        if h == k:\n",
      "            return l % 3 == 0  # hh(-2h)l\n",
      "        if k == -h:\n",
      "            return (h + l) % 3 == 0  # h(-h)0l (i = 0)\n",
      "        if h == 0 and k == 0:\n",
      "            return l % 3 == 0  # 000l\n",
      "        if k == -h and l == 0:\n",
      "            return h % 3 == 0  # h(-h)00\n",
      "        return True\n",
      "\n"
     ]
    }
   ],
   "source": [
    "from pyFAI.crystallography.space_groups import ReflectionCondition\n",
    "#from http://img.chem.ucl.ac.uk/sgp/large/166bz2.htm\n",
    "reflection_condition_166 = ReflectionCondition.group166_R3bar_m\n",
    "import inspect\n",
    "print(inspect.getsource(reflection_condition_166))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Use the actual selection rule, not the short version:\n",
    "#cro.selection_rules.append(lambda h, k, l: ((-h + k + l) % 3 == 0))\n",
    "hydroc_hex.selection_rules.append(reflection_condition_166)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "+---------+------------------------------------------------------------+\n",
      "|d-spacing|Miller indices                                              |\n",
      "+---------+------------------------------------------------------------+\n",
      "| 7.900767|(0 0 -3) (0 0 3)                                            |\n",
      "| 4.462403|(1 -1 -1) (-1 0 -1) (0 1 -1) (0 -1 1) (1 0 1) (-1 1 1)      |\n",
      "| 4.242534|(0 -1 -2) (1 0 -2) (-1 1 -2) (1 -1 2) (-1 0 2) (0 1 2)      |\n",
      "| 3.950383|(0 0 -6) (0 0 6)                                            |\n",
      "| 3.605663|(1 -1 -4) (-1 0 -4) (0 1 -4) (0 -1 4) (1 0 4) (-1 1 4)      |\n",
      "| 3.280218|(0 -1 -5) (1 0 -5) (-1 1 -5) (1 -1 5) (-1 0 5) (0 1 5)      |\n",
      "| 2.715045|(1 -1 -7) (-1 0 -7) (0 1 -7) (0 -1 7) (1 0 7) (-1 1 7)      |\n",
      "| 2.633589|(0 0 -9) (0 0 9)                                            |\n",
      "| 2.623280|(1 -2 0) (-1 -1 0) (2 -1 0) (-2 1 0) (1 1 0) (-1 2 0)       |\n",
      "| 2.489635|(1 -2 -3) (-1 -1 -3) (2 -1 -3) (-2 1 -3) (1 1 -3) (-1 2 -3) |\n",
      "| 2.481778|(0 -1 -8) (1 0 -8) (-1 1 -8) (1 -1 8) (-1 0 8) (0 1 8)      |\n",
      "| 2.261463|(0 -2 -1) (2 0 -1) (-2 2 -1) (2 -2 1) (-2 0 1) (0 2 1)      |\n",
      "| 2.231201|(2 -2 -2) (-2 0 -2) (0 2 -2) (0 -2 2) (2 0 2) (-2 2 2)      |\n",
      "| 2.185329|(1 -2 -6) (-1 -1 -6) (2 -1 -6) (-2 1 -6) (1 1 -6) (-1 2 -6) |\n",
      "| 2.121267|(0 -2 -4) (2 0 -4) (-2 2 -4) (2 -2 4) (-2 0 4) (0 2 4)      |\n",
      "| 2.101481|(1 -1 -10) (-1 0 -10) (0 1 -10) (0 -1 10) (1 0 10) (-1 1 10)|\n",
      "| 2.048710|(2 -2 -5) (-2 0 -5) (0 2 -5) (0 -2 5) (2 0 5) (-2 2 5)      |\n",
      "| 1.975192|(0 0 -12) (0 0 12)                                          |\n",
      "| 1.946919|(0 -1 -11) (1 0 -11) (-1 1 -11) (1 -1 11) (-1 0 11) (0 1 11)|\n",
      "| 1.886546|(0 -2 -7) (2 0 -7) (-2 2 -7) (2 -2 7) (-2 0 7) (0 2 7)      |\n",
      "| 1.858573|(1 -2 -9) (-1 -1 -9) (2 -1 -9) (-2 1 -9) (1 1 -9) (-1 2 -9) |\n",
      "| 1.802832|(2 -2 -8) (-2 0 -8) (0 2 -8) (0 -2 8) (2 0 8) (-2 2 8)      |\n",
      "| 1.712850|(2 -3 -1) (3 -2 -1) (-2 -1 -1) (-3 1 -1) (1 2 -1) (-1 3 -1) |\n",
      "| 1.699588|(1 -3 -2) (-1 -2 -2) (3 -1 -2) (2 1 -2) (-3 2 -2) (-2 3 -2) |\n",
      "| 1.692104|(1 -1 -13) (-1 0 -13) (0 1 -13) (0 -1 13) (1 0 13) (-1 1 13)|\n",
      "| 1.649463|(2 -3 -4) (3 -2 -4) (-2 -1 -4) (-3 1 -4) (1 2 -4) (-1 3 -4) |\n",
      "| 1.640109|(0 -2 -10) (2 0 -10) (-2 2 -10) (2 -2 10) (-2 0 10) (0 2 10)|\n",
      "| 1.614651|(1 -3 -5) (-1 -2 -5) (3 -1 -5) (2 1 -5) (-3 2 -5) (-2 3 -5) |\n",
      "| 1.586467|(0 -1 -14) (1 0 -14) (-1 1 -14) (1 -1 14) (-1 0 14) (0 1 14)|\n",
      "| 1.580153|(0 0 -15) (0 0 15)                                          |\n",
      "| 1.577918|(1 -2 -12) (-1 -1 -12) (2 -1 -12) (-2 1 -12) (1 1 -12) (-1 2|\n",
      "| 1.563392|(2 -2 -11) (-2 0 -11) (0 2 -11) (0 -2 11) (2 0 11) (-2 2 11)|\n",
      "| 1.531610|(2 -3 -7) (3 -2 -7) (-2 -1 -7) (-3 1 -7) (1 2 -7) (-1 3 -7) |\n",
      "| 1.514551|(0 -3 0) (3 -3 0) (-3 0 0) (3 0 0) (-3 3 0) (0 3 0)         |\n",
      "| 1.487468|(0 -3 -3) (3 -3 -3) (-3 0 -3) (3 0 -3) (-3 3 -3) (0 3 -3) (0|\n",
      "| 1.485787|(1 -3 -8) (-1 -2 -8) (3 -1 -8) (2 1 -8) (-3 2 -8) (-2 3 -8) |\n",
      "| 1.421952|(0 -2 -13) (2 0 -13) (-2 2 -13) (2 -2 13) (-2 0 13) (0 2 13)|\n",
      "| 1.414178|(0 -3 -6) (3 -3 -6) (-3 0 -6) (3 0 -6) (-3 3 -6) (0 3 -6) (0|\n",
      "| 1.408427|(1 -1 -16) (-1 0 -16) (0 1 -16) (0 -1 16) (1 0 16) (-1 1 16)|\n",
      "| 1.390676|(2 -3 -10) (3 -2 -10) (-2 -1 -10) (-3 1 -10) (1 2 -10) (-1 3|\n",
      "| 1.357522|(2 -2 -14) (-2 0 -14) (0 2 -14) (0 -2 14) (2 0 14) (-2 2 14)|\n",
      "| 1.353560|(1 -2 -15) (-1 -1 -15) (2 -1 -15) (-2 1 -15) (1 1 -15) (-1 2|\n",
      "| 1.342980|(1 -3 -11) (-1 -2 -11) (3 -1 -11) (2 1 -11) (-3 2 -11) (-2 3|\n",
      "| 1.332910|(0 -1 -17) (1 0 -17) (-1 1 -17) (1 -1 17) (-1 0 17) (0 1 17)|\n",
      "| 1.316794|(0 0 -18) (0 0 18)                                          |\n",
      "| 1.312923|(0 -3 -9) (3 -3 -9) (-3 0 -9) (3 0 -9) (-3 3 -9) (0 3 -9) (0|\n",
      "| 1.311640|(2 -4 0) (-2 -2 0) (4 -2 0) (-4 2 0) (2 2 0) (-2 4 0)       |\n",
      "| 1.293930|(2 -4 -3) (-2 -2 -3) (4 -2 -3) (-4 2 -3) (2 2 -3) (-2 4 -3) |\n",
      "| 1.258406|(1 -4 -1) (-1 -3 -1) (4 -1 -1) (3 1 -1) (-4 3 -1) (-3 4 -1) |\n",
      "| 1.253118|(3 -4 -2) (4 -3 -2) (-3 -1 -2) (-4 1 -2) (1 3 -2) (-1 4 -2) |\n",
      "| 1.250110|(2 -3 -13) (3 -2 -13) (-2 -1 -13) (-3 1 -13) (1 2 -13) (-1 3|\n",
      "| 1.244817|(2 -4 -6) (-2 -2 -6) (4 -2 -6) (-4 2 -6) (2 2 -6) (-2 4 -6) |\n",
      "| 1.240889|(0 -2 -16) (2 0 -16) (-2 2 -16) (2 -2 16) (-2 0 16) (0 2 16)|\n",
      "| 1.232617|(1 -4 -4) (-1 -3 -4) (4 -1 -4) (3 1 -4) (-4 3 -4) (-3 4 -4) |\n",
      "| 1.217884|(3 -4 -5) (4 -3 -5) (-3 -1 -5) (-4 1 -5) (1 3 -5) (-1 4 -5) |\n",
      "| 1.205653|(1 -3 -14) (-1 -2 -14) (3 -1 -14) (2 1 -14) (-3 2 -14) (-2 3|\n",
      "| 1.202972|(1 -1 -19) (-1 0 -19) (0 1 -19) (0 -1 19) (1 0 19) (-1 1 19)|\n",
      "| 1.201888|(0 -3 -12) (3 -3 -12) (-3 0 -12) (3 0 -12) (-3 3 -12) (0 3 -|\n",
      "| 1.188312|(2 -2 -17) (-2 0 -17) (0 2 -17) (0 -2 17) (2 0 17) (-2 2 17)|\n",
      "| 1.181041|(1 -4 -7) (-1 -3 -7) (4 -1 -7) (3 1 -7) (-4 3 -7) (-3 4 -7) |\n",
      "| 1.176850|(1 -2 -18) (-1 -1 -18) (2 -1 -18) (-2 1 -18) (1 1 -18) (-1 2|\n",
      "| 1.174084|(2 -4 -9) (-2 -2 -9) (4 -2 -9) (-4 2 -9) (2 2 -9) (-2 4 -9) |\n",
      "| 1.159645|(3 -4 -8) (4 -3 -8) (-3 -1 -8) (-4 1 -8) (1 3 -8) (-1 4 -8) |\n",
      "| 1.146749|(0 -1 -20) (1 0 -20) (-1 1 -20) (1 -1 20) (-1 0 20) (0 1 20)|\n",
      "| 1.134611|(4 -4 -1) (-4 0 -1) (0 4 -1) (0 -4 1) (4 0 1) (-4 4 1)      |\n",
      "| 1.130731|(0 -4 -2) (4 0 -2) (-4 4 -2) (4 -4 2) (-4 0 2) (0 4 2)      |\n",
      "| 1.128681|(0 0 -21) (0 0 21)                                          |\n",
      "| 1.121722|(2 -3 -16) (3 -2 -16) (-2 -1 -16) (-3 1 -16) (1 2 -16) (-1 3|\n",
      "| 1.115601|(4 -4 -4) (-4 0 -4) (0 4 -4) (0 -4 4) (4 0 4) (-4 4 4)      |\n",
      "| 1.112693|(1 -4 -10) (-1 -3 -10) (4 -1 -10) (3 1 -10) (-4 3 -10) (-3 4|\n",
      "| 1.104643|(0 -4 -5) (4 0 -5) (-4 4 -5) (4 -4 5) (-4 0 5) (0 4 5)      |\n",
      "| 1.093479|(0 -2 -19) (2 0 -19) (-2 2 -19) (2 -2 19) (-2 0 19) (0 2 19)|\n",
      "| 1.093406|(0 -3 -15) (3 -3 -15) (-3 0 -15) (3 0 -15) (-3 3 -15) (0 3 -|\n",
      "| 1.092665|(2 -4 -12) (-2 -2 -12) (4 -2 -12) (-4 2 -12) (2 2 -12) (-2 4|\n",
      "| 1.087806|(3 -4 -11) (4 -3 -11) (-3 -1 -11) (-4 1 -11) (1 3 -11) (-1 4|\n",
      "| 1.082434|(1 -3 -17) (-1 -2 -17) (3 -1 -17) (2 1 -17) (-3 2 -17) (-2 3|\n",
      "| 1.076930|(4 -4 -7) (-4 0 -7) (0 4 -7) (0 -4 7) (4 0 7) (-4 4 7)      |\n",
      "| 1.060634|(0 -4 -8) (4 0 -8) (-4 4 -8) (4 -4 8) (-4 0 8) (0 4 8)      |\n",
      "| 1.050740|(2 -2 -20) (-2 0 -20) (0 2 -20) (0 -2 20) (2 0 20) (-2 2 20)|\n",
      "| 1.048310|(1 -1 -22) (-1 0 -22) (0 1 -22) (0 -1 22) (1 0 22) (-1 1 22)|\n",
      "| 1.041379|(3 -5 -1) (5 -3 -1) (-3 -2 -1) (-5 2 -1) (2 3 -1) (-2 5 -1) |\n",
      "| 1.038377|(2 -5 -2) (-2 -3 -2) (5 -2 -2) (3 2 -2) (-5 3 -2) (-3 5 -2) |\n",
      "| 1.036788|(1 -2 -21) (-1 -1 -21) (2 -1 -21) (-2 1 -21) (1 1 -21) (-1 2|\n",
      "| 1.036663|(1 -4 -13) (-1 -3 -13) (4 -1 -13) (3 1 -13) (-4 3 -13) (-3 4|\n",
      "| 1.026622|(3 -5 -4) (5 -3 -4) (-3 -2 -4) (-5 2 -4) (2 3 -4) (-2 5 -4) |\n",
      "| 1.024355|(4 -4 -10) (-4 0 -10) (0 4 -10) (0 -4 10) (4 0 10) (-4 4 10)|\n",
      "| 1.018064|(2 -5 -5) (-2 -3 -5) (5 -2 -5) (3 2 -5) (-5 3 -5) (-3 5 -5) |\n",
      "| 1.010886|(3 -4 -14) (4 -3 -14) (-3 -1 -14) (-4 1 -14) (1 3 -14) (-1 4|\n",
      "| 1.009305|(2 -3 -19) (3 -2 -19) (-2 -1 -19) (-3 1 -19) (1 2 -19) (-1 3|\n",
      "| 1.009247|(2 -4 -15) (-2 -2 -15) (4 -2 -15) (-4 2 -15) (2 2 -15) (-2 4|\n",
      "| 1.005009|(0 -1 -23) (1 0 -23) (-1 1 -23) (1 -1 23) (-1 0 23) (0 1 23)|\n",
      "| 1.004838|(0 -4 -11) (4 0 -11) (-4 4 -11) (4 -4 11) (-4 0 11) (0 4 11)|\n",
      "+---------+------------------------------------------------------------+\n"
     ]
    }
   ],
   "source": [
    "reflections = hydroc_hex.calculate_dspacing(1)\n",
    "d_spacing = list(reflections.keys())\n",
    "d_spacing.sort(reverse=True)\n",
    "\n",
    "print(\"+\" + \"-\"*9 + \"+\" + \"-\"*60 + \"+\")\n",
    "print(\"|\" + \"d-spacing\" + \"|\" + \"Miller indices\"+ \" \"*46 + \"|\")\n",
    "print(\"+\" + \"-\"*9 + \"+\" + \"-\"*60 + \"+\")\n",
    "for d in d_spacing:\n",
    "    print(f\"|{d:9f}|{' '.join([str(i) for i in reflections[d]])[:60]:60s}|\")\n",
    "print(\"+\" + \"-\"*9 + \"+\" + \"-\"*60 + \"+\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hexagonal vs Rhombohedral:\n",
      "length is the same:  True\n",
      "Content is the same: True\n"
     ]
    }
   ],
   "source": [
    "print(\"Hexagonal vs Rhombohedral:\")\n",
    "print(\"length is the same: \", len(hydroc_hex.calculate_dspacing(1)) == len(hydroc_rho.calculate_dspacing(1)))\n",
    "ds_hex=list(hydroc_hex.calculate_dspacing(1).keys())\n",
    "ds_hex.sort()\n",
    "ds_rho=list(hydroc_rho.calculate_dspacing(1).keys())\n",
    "ds_rho.sort()\n",
    "print(\"Content is the same:\", ds_hex == ds_rho)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "hydroc_rho.save(\"hydrocerussite\", \"basic lead carbonate (R-3m)\", dmin=1, doi=\"https://doi.org/10.1107/S0108270102006844\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Conclusion\n",
    "This is an advanced tutorial, most user won't have to define their own calibrant. You can also contact the developers to get your own calibrant integrated into pyFAI which makes things easier for you and other users."
   ]
  }
 ],
 "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.13.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
