{ "cells": [ { "cell_type": "markdown", "id": "6de7a703", "metadata": {}, "source": [ "# Use `E4CV`'s $Q$ calculation engine\n", "\n", "Many of the diffractometer geometries support different calculation *engines*. By\n", "default, *hklpy* provides `h`, `k`, & `l` pseudo positioners (the *hkl* engine)\n", "since this is the most common case. For example, the\n", "[E4CV](https://people.debian.org/~picca/hkl/hkl.html#org7ef08ba) geometry \n", "supports several calculation engines:\n", "\n", "engine | pseudo(s) | real(s)\n", ":--- | :--- | :---\n", "`hkl` | `h`, `k`, `l` | `omega`, `chi`, `phi`, `tth`\n", "`psi` | `psi` | `omega`, `chi`, `phi`, `tth`\n", "`q` | `q` | `tth`\n", "`incidence` | `incidence`, `azimuth` | `omega`, `chi`, `phi`\n", "`emergence` | `emergence`, `azimuth` | `omega`, `chi`, `phi`, `tth`\n", "\n", "NOTE: The choice of calculation engine is locked in the `hkl.diffract.Diffractometer()` class. Once the diffractometer object is created, the calculation engine cannot be changed.\n", "\n", "**Objective**\n", "\n", "Many of the examples in the *hklpy* repository use the *hkl* engine, it is the most common use case. Below, we'll demonstrate the `q` calculation engine of the `E4CV` (4-circle Eulerian in vertical scattering) geometry.\n", "\n", "## Standard Imports\n", "\n", "First, we start by importing the constant, `A_KEV` (product of Planck's constant and speed of light in a vacuum). The value of this constant is obtained from the [2019 NIST publication of 2018 CODATA Fundamental Physical Constants](https://www.nist.gov/programs-projects/codata-values-fundamental-physical-constants). (Keep in mind that `gi` is not the `Gtk` library, just the tools that enable other languages such as Python to use the libraries compiled with [Gnome's Glib Object: GObject](https://developer.gnome.org/gobject/stable/) framework.)" ] }, { "cell_type": "code", "execution_count": 1, "id": "600aeb41", "metadata": {}, "outputs": [], "source": [ "from hkl import A_KEV" ] }, { "cell_type": "markdown", "id": "98fb6c04", "metadata": {}, "source": [ "## `q` engine\n", "\n", "The [`q` engine](https://people.debian.org/~picca/hkl/hkl.html#org7ef08ba) is easy\n", "to demonstrate since it only involves the actions of the `tth` circle ($q=4\\pi\\sin(\\theta)/\\lambda$ where $\\theta$ is half of `tth`) **and** no crystal orientation reflections are necessary.\n", "\n", "**Still**, it is necessary to define *all* required real positioners of the geometry. The required positioners are listed as *Axes* directly under the section title in the *libhkl* documentation for each geometry. Also, specify them *in the order they appear in the documentation*. The *real* positioners stay the same for all engines of a diffractometer geometry. The *pseudo* positioners are defined by the calculation engine and may be different for each engine.\n", "\n", "TIP: If you do not define all the required *Axes* of the geometry, Python will likely terminate (and with no useful message, at that) when you first try to create the diffractometer object.\n", "\n", "\n", "term | value\n", ":--- | :---\n", "geometry | `E4CV`\n", "engine | `q`\n", "mode | *default*\n", "\n", "\n", "Create a custom class for the `E4CV` geometry with the `q` calculation engine. There is only one pseudo positioner, `q`, for the calculation engine and the four real positioners for the geometry. Since this demonstration uses `SoftPositioners`, we must provide an `init_pos` kwarg with the initial position for each real axis. There is no particular significance to the initial positions used in this example." ] }, { "cell_type": "code", "execution_count": 2, "id": "06bc260e", "metadata": {}, "outputs": [], "source": [ "from hkl import E4CV\n", "from ophyd import Component\n", "from ophyd import PseudoSingle\n", "from ophyd import SoftPositioner\n", "\n", "class FourcQ(E4CV):\n", " # one pseudo axis for the q calculation engine\n", " q = Component(PseudoSingle)\n", " \n", " # four real axes (MUST specify in canonical order)\n", " omega = Component(SoftPositioner, init_pos=20)\n", " chi = Component(SoftPositioner, init_pos=90)\n", " phi = Component(SoftPositioner, init_pos=0)\n", " tth = Component(SoftPositioner, init_pos=40) # \"q\" engine calls this \"tth\"" ] }, { "cell_type": "markdown", "id": "1f02b71b", "metadata": {}, "source": [ "## Create the diffractometer object.\n", "\n", "You specify the `q` calculation engine (`engine=\"q\"`) when you create the diffractometer object. Otherwise, the support will default to the `hkl` engine. Once the object is created, the calculation engine cannot be changed." ] }, { "cell_type": "code", "execution_count": 3, "id": "d17b3bfa", "metadata": {}, "outputs": [], "source": [ "fourcq = FourcQ(\"\", name=\"fourcq\", engine=\"q\")" ] }, { "cell_type": "markdown", "id": "a9037101", "metadata": {}, "source": [ "Test the `q` engine by calculating the angles associated with $Q=1.00$ 1/angstrom. There is only one pseudo positioner so only one value is provided to the `forward()` calculation. Notice that only the `tth` position is computed." ] }, { "cell_type": "code", "execution_count": 4, "id": "5ee944a4", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "q to angle: fourcq.forward(1) = PosCalcE4CV(omega=20.0, chi=90.0, phi=0.0, tth=14.0785064531777)\n" ] } ], "source": [ "print(f\"q to angle: {fourcq.forward(1) = }\")" ] }, { "cell_type": "markdown", "id": "91f450d9", "metadata": {}, "source": [ "Calculate the $q$ associated with `tth=1.0` degrees. While four real motors are defined, only `tth` is used for the calculation so only one value is provided to the `inverse()` calculation. " ] }, { "cell_type": "code", "execution_count": 5, "id": "cacda0c1", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "angle to q: fourcq.inverse(1) = FourcQPseudoPos(q=2.790877843251037)\n" ] } ], "source": [ "print(f\"angle to q: {fourcq.inverse(1) = }\")" ] }, { "cell_type": "markdown", "id": "c901a28b", "metadata": {}, "source": [ "Show the basic settings of the `fourcq` diffractometer." ] }, { "cell_type": "code", "execution_count": 6, "id": "5bc787d2", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "===================== ================= =========\n", "term value axis_type\n", "===================== ================= =========\n", "diffractometer fourcq \n", "sample name main \n", "energy (keV) 8.05092 \n", "wavelength (angstrom) 1.54000 \n", "calc engine q \n", "mode q \n", "q 2.790877843251037 pseudo \n", "omega 20 real \n", "chi 90 real \n", "phi 0 real \n", "tth 40 real \n", "===================== ================= =========\n", "\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fourcq.wh()" ] }, { "cell_type": "markdown", "id": "8270653e", "metadata": {}, "source": [ "Move `fourcq` to $Q=1.0$ 1/Angstrom and show the settings again." ] }, { "cell_type": "code", "execution_count": 7, "id": "a74459cb", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "===================== ================= =========\n", "term value axis_type\n", "===================== ================= =========\n", "diffractometer fourcq \n", "sample name main \n", "energy (keV) 8.05092 \n", "wavelength (angstrom) 1.54000 \n", "calc engine q \n", "mode q \n", "q 1.000000000000004 pseudo \n", "omega 20.0 real \n", "chi 90.0 real \n", "phi 0.0 real \n", "tth 14.0785064531777 real \n", "===================== ================= =========\n", "\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fourcq.move(1)\n", "fourcq.wh()" ] }, { "cell_type": "markdown", "id": "03a1f3e7", "metadata": {}, "source": [ "Show all the `fourcq` diffractometer settings." ] }, { "cell_type": "code", "execution_count": 8, "id": "d24c85d9", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "===================== ====================================================================\n", "term value \n", "===================== ====================================================================\n", "diffractometer fourcq \n", "geometry E4CV \n", "class FourcQ \n", "energy (keV) 8.05092 \n", "wavelength (angstrom) 1.54000 \n", "calc engine q \n", "mode q \n", "positions ===== ======== \n", " name value \n", " ===== ======== \n", " omega 20.00000 \n", " chi 90.00000 \n", " phi 0.00000 \n", " tth 14.07851 \n", " ===== ======== \n", "constraints ===== ========= ========== ================ ==== \n", " axis low_limit high_limit value fit \n", " ===== ========= ========== ================ ==== \n", " omega -180.0 180.0 20.0 True \n", " chi -180.0 180.0 90.0 True \n", " phi -180.0 180.0 0.0 True \n", " tth -180.0 180.0 14.0785064531777 True \n", " ===== ========= ========== ================ ==== \n", "sample: main ================ ===================================================\n", " term value \n", " ================ ===================================================\n", " unit cell edges a=1.54, b=1.54, c=1.54 \n", " unit cell angles alpha=90.0, beta=90.0, gamma=90.0 \n", " [U] [[1. 0. 0.] \n", " [0. 1. 0.] \n", " [0. 0. 1.]] \n", " [UB] [[ 4.07999046e+00 -2.49827363e-16 -2.49827363e-16] \n", " [ 0.00000000e+00 4.07999046e+00 -2.49827363e-16] \n", " [ 0.00000000e+00 0.00000000e+00 4.07999046e+00]]\n", " ================ ===================================================\n", "===================== ====================================================================\n", "\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fourcq.pa()" ] }, { "cell_type": "markdown", "id": "9bec27e7", "metadata": {}, "source": [ "Move to a different wavelength (1.00 Angstrom) and move back to the same $Q$ of 1.000 1/Angstrom." ] }, { "cell_type": "code", "execution_count": 9, "id": "63071b7a", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "===================== ================== =========\n", "term value axis_type\n", "===================== ================== =========\n", "diffractometer fourcq \n", "sample name main \n", "energy (keV) 12.39842 \n", "wavelength (angstrom) 1.00000 \n", "calc engine q \n", "mode q \n", "q 1.0000000000000022 pseudo \n", "omega 20.0 real \n", "chi 90.0 real \n", "phi 0.0 real \n", "tth 9.128558416134153 real \n", "===================== ================== =========\n", "\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fourcq.energy.set(A_KEV / 1.0)\n", "fourcq.move(1)\n", "fourcq.wh()" ] } ], "metadata": { "interpreter": { "hash": "cd09a60d4ca96784847e6d28c64916bc86a437fe6be574606d07ffca69ac8887" }, "kernelspec": { "display_name": "Python 3.9.12 ('training_2022')", "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.9.13" } }, "nbformat": 4, "nbformat_minor": 5 }