{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Set and compute $\\psi$ (psi)\n", "\n", "Show how to set and compute $\\psi$ with the E6C diffractometer geometry.\n", "\n", "The angle $\\psi$ is a rotation around some _virtual_ azimuthal axis as the\n", "diffractometer is oriented for a different axis.\n", "\n", "This operation is a bit complicated. It requires two instances of the E6C\n", "diffractometer geometry, each with a different calculation engine. The `\"hkl\"`\n", "engine is used to work in reciprocal-space coordinates $h, k, l$. The `\"psi\"`\n", "engine is used to work with the $\\psi$ rotation.\n", "\n", "First, we'll orient a crystalline sample with the `\"hkl\"` engine. Then, we'll\n", "define the azimuthal reflection $h_2, k_2, l_2$ and a $\\psi$ rotation around\n", "that azimuthal reflection. Next, we'll position the diffractometer for the $h,\n", "k, l$ reflection.\n", "\n", "Then we copy sample, orientation, and position information from the `\"hkl\"`\n", "instance to the `\"psi\"` instance. After these steps, we can compare the\n", "computed `psi` value with the value we set previously." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# SimulatedE6C" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import hkl\n", "e6c_hkl = hkl.SimulatedE6C(\"\", name=\"e6c_hkl\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Show the different calculation engines available for the E6C geometry." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'hkl': Engine(parameters=[], pseudo_axes=OrderedDict([('h', 0.0), ('k', 0.0), ('l', 0.0)]), mode='bissector_vertical', modes=['bissector_vertical', 'constant_omega_vertical', 'constant_chi_vertical', 'constant_phi_vertical', 'lifting_detector_phi', 'lifting_detector_omega', 'lifting_detector_mu', 'double_diffraction_vertical', 'bissector_horizontal', 'double_diffraction_horizontal', 'psi_constant_vertical', 'psi_constant_horizontal', 'constant_mu_horizontal'], units='user'),\n", " 'psi': Engine(parameters=['h2', 'k2', 'l2'], pseudo_axes=OrderedDict([('psi', 0.0)]), mode='psi_vertical', modes=['psi_vertical'], units='user'),\n", " 'q2': Engine(parameters=[], pseudo_axes=OrderedDict([('q', 0.0), ('alpha', 0.0)]), mode='q2', modes=['q2'], units='user'),\n", " 'qper_qpar': Engine(parameters=['x', 'y', 'z'], pseudo_axes=OrderedDict([('qper', 0.0), ('qpar', 0.0)]), mode='qper_qpar', modes=['qper_qpar'], units='user'),\n", " 'tth2': Engine(parameters=[], pseudo_axes=OrderedDict([('tth', 0.0), ('alpha', 0.0)]), mode='tth2', modes=['tth2'], units='user'),\n", " 'incidence': Engine(parameters=['x', 'y', 'z'], pseudo_axes=OrderedDict([('incidence', 0.0), ('azimuth', 0.0)]), mode='incidence', modes=['incidence'], units='user'),\n", " 'emergence': Engine(parameters=['x', 'y', 'z'], pseudo_axes=OrderedDict([('emergence', 0.0), ('azimuth', 0.0)]), mode='emergence', modes=['emergence'], units='user')}" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "e6c_hkl.calc.engines" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- The `hkl` engine has a `\"psi_constant_vertical\"` mode that can be used to calculate reals given some fixed parameters (UB, wavelength, $(hkl)$, $(hkl)_2$, $\\psi$)\n", "- The `psi` engine has a pseudo axis `\"psi\"` that can be used to calculate $\\psi$ given some fixed parameters (reals, UB, wavelength, $(hkl)$, $(hkl)_2$)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Define and orient a sample" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The sample for this notebook is crystalline vibranium, with a cubic lattice of exactly $2\\pi$. With it mounted on oru diffractometer, we have identified two reflections which define its orientation." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[ 7.65988346e-01, -6.42854457e-01, -7.53977616e-18],\n", " [ 0.00000000e+00, 0.00000000e+00, -1.00000000e+00],\n", " [ 6.42854457e-01, 7.65988346e-01, -8.62667415e-17]])" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a0 = 2 * 3.141592653589793\n", "vibranium_lattice = hkl.Lattice(a=a0, b=a0, c=a0, alpha=90, beta=90, gamma=90)\n", "sample = e6c_hkl.calc.new_sample(\"vibranium\", lattice=vibranium_lattice)\n", "sample.compute_UB(\n", " sample.add_reflection(4, 0, 0, [0, 29.35, 0, 50, 0, 58.71]),\n", " sample.add_reflection(0, 4, 0, [0, 29.35, 0, -40, 0, 58.71]),\n", ")\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Move to the $(111)$ orientation" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "e6c_hkl.engine.parameters=['h2', 'k2', 'l2', 'psi']\n" ] } ], "source": [ "e6c_hkl.move(1, 1, 1)\n", "e6c_hkl.engine.mode = \"psi_constant_vertical\"\n", "print(f\"{e6c_hkl.engine.parameters=}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Set azimuthal reflection $(110)$ and $\\psi=12$." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "e6c_hkl.engine._engine.parameters_values_get(1)=[1.0, 1.0, 0.0, 12.0]\n" ] } ], "source": [ "e6c_hkl.engine._engine.parameters_values_set([1, 1, 0, 12], 1)\n", "print(f\"{e6c_hkl.engine._engine.parameters_values_get(1)=}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Compute the real-axis motor values with the $(111)$ reflection oriented and $\\psi$ rotation around the azimuthal reflection." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "p_111=PosCalcE6C(mu=0.0, omega=66.39160677520167, chi=-80.22618091661815, phi=-78.00866699932374, gamma=0.0, delta=24.50984451740515)\n" ] } ], "source": [ "p_111 = e6c_hkl.forward(1, 1, 1)\n", "print(f\"{p_111=}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Move all reals to the $(111)$ reflection." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "e6c_hkl.position=SimulatedE6CPseudoPos(h=0.9999999973844704, k=1.0000000120446895, l=0.9999999932554844)\n", "e6c_hkl.real_position=SimulatedE6CRealPos(mu=0.0, omega=66.39160677520167, chi=-80.22618091661815, phi=-78.00866699932374, gamma=0.0, delta=24.50984451740515)\n", "e6c_hkl.engine._engine.parameters_values_get(1)=[1.0, 1.0, 0.0, 12.0]\n" ] } ], "source": [ "for axis in p_111._fields:\n", " getattr(e6c_hkl, axis).move(getattr(p_111, axis))\n", "print(f\"{e6c_hkl.position=}\")\n", "print(f\"{e6c_hkl.real_position=}\")\n", "print(f\"{e6c_hkl.engine._engine.parameters_values_get(1)=}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Calculate $\\psi$" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "import hkl.diffract\n", "from ophyd import Component as Cpt\n", "from ophyd import PseudoSingle\n", "from ophyd import SoftPositioner\n", "\n", "class SimulatedPsiE6C(hkl.E6C):\n", " \"\"\"SimulatedE6C: Eulerian 6-circle diffractometer, psi engine\"\"\"\n", "\n", " calc_class = hkl.calc.CalcE6C\n", "\n", " psi = Cpt(PseudoSingle, \"\", kind=\"hinted\")\n", "\n", " mu = Cpt(SoftPositioner, limits=(-180, 180), init_pos=0, kind=\"normal\")\n", " omega = Cpt(SoftPositioner, limits=(-180, 180), init_pos=0, kind=\"normal\")\n", " chi = Cpt(SoftPositioner, limits=(-180, 180), init_pos=0, kind=\"normal\")\n", " phi = Cpt(SoftPositioner, limits=(-180, 180), init_pos=0, kind=\"normal\")\n", " gamma = Cpt(SoftPositioner, limits=(-180, 180), init_pos=0, kind=\"normal\")\n", " delta = Cpt(SoftPositioner, limits=(-180, 180), init_pos=0, kind=\"normal\")\n", "\n", " def __init__(self, prefix, **kwargs):\n", " super().__init__(prefix, engine=\"psi\", **kwargs)\n" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "e6c_psi.engine.mode='psi_vertical'\n", "e6c_psi.engine.parameters=['h2', 'k2', 'l2']\n" ] } ], "source": [ "e6c_psi = SimulatedPsiE6C(\"\", name=\"e6c_psi\")\n", "print(f\"{e6c_psi.engine.mode=}\")\n", "print(f\"{e6c_psi.engine.parameters=}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Same sample, lattice, and orientation. Same real-axis position." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "e6c_psi.position=SimulatedPsiE6CPseudoPos(psi=12.000007801823596)\n", "e6c_psi.real_position=SimulatedPsiE6CRealPos(mu=0.0, omega=66.39160677520167, chi=-80.22618091661815, phi=-78.00866699932374, gamma=0.0, delta=24.50984451740515)\n", "===================== ================== =========\n", "term value axis_type\n", "===================== ================== =========\n", "diffractometer e6c_psi \n", "sample name vibranium \n", "energy (keV) 8.05092 \n", "wavelength (angstrom) 1.54000 \n", "calc engine psi \n", "mode psi_vertical \n", "psi 12.000007801823596 pseudo \n", "mu 0.0 real \n", "omega 66.39160677520167 real \n", "chi -80.22618091661815 real \n", "phi -78.00866699932374 real \n", "gamma 0.0 real \n", "delta 24.50984451740515 real \n", "===================== ================== =========\n", "\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "e6c_psi.calc.new_sample(e6c_hkl.calc.sample.name, lattice=e6c_hkl.calc.sample.lattice)\n", "e6c_psi.calc.sample.UB = e6c_hkl.UB.get()\n", "e6c_psi.engine._engine.parameters_values_set([1, 1, 0], 1)\n", "for axis in p_111._fields: # move all reals to the (111) reflection\n", " getattr(e6c_psi, axis).move(getattr(p_111, axis))\n", "print(f\"{e6c_psi.position=}\")\n", "print(f\"{e6c_psi.real_position=}\")\n", "e6c_psi.wh()" ] } ], "metadata": { "kernelspec": { "display_name": "bluesky_2024_2", "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.11.0" } }, "nbformat": 4, "nbformat_minor": 2 }