{ "cells": [ { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "# Lesson 7: 4-circle diffractometer\n", "\n", "Operate a four-circle diffractometer using the *hkl* package.\n", "The lesson will first show how to setup the diffractometer and \n", "demonstrate the basic features of the software. Then, the lesson\n", "will setup a diffractometer with a single crystal sample, orient\n", "it, and scan along one axis of reciprocal space. Examples are then\n", "provided for several different crystals.\n", "\n", "The [*hkl*](https://github.com/bluesky/hklpy) package is a python\n", "interface to the C++ [*hkl*](https://repo.or.cz/hkl.git) library, \n", "written by Frederic Picca.\n", "\n", "Documentation for the C++ library is here: \n", "https://people.debian.org/~picca/hkl/hkl.html" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Setup\n", "\n", "Setup involves starting the bluesky session, importing various support packages, and defining any custom classes or functions as needed." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Preparation\n", "\n", "Import the instrument package as our routine initialization." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "tags": [] }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "I Wed-17:24:44 - ############################################################ startup\n", "I Wed-17:24:44 - logging started\n", "I Wed-17:24:44 - logging level = 10\n", "I Wed-17:24:44 - /home/prjemian/Documents/projects/BCDA-APS/bluesky_training/lessons/instrument/collection.py\n", "I Wed-17:24:44 - /home/prjemian/Documents/projects/BCDA-APS/bluesky_training/lessons/instrument/mpl/notebook.py\n", "Activating auto-logging. Current session state plus future input saved.\n", "Filename : /home/prjemian/Documents/projects/BCDA-APS/bluesky_training/lessons/.logs/ipython_console.log\n", "Mode : rotate\n", "Output logging : True\n", "Raw input log : False\n", "Timestamping : True\n", "State : active\n", "I Wed-17:24:45 - bluesky framework\n", "I Wed-17:24:45 - /home/prjemian/Documents/projects/BCDA-APS/bluesky_training/lessons/instrument/framework/check_python.py\n", "I Wed-17:24:45 - /home/prjemian/Documents/projects/BCDA-APS/bluesky_training/lessons/instrument/framework/check_bluesky.py\n", "I Wed-17:24:46 - /home/prjemian/Documents/projects/BCDA-APS/bluesky_training/lessons/instrument/framework/initialize.py\n", "I Wed-17:24:47 - /home/prjemian/Documents/projects/BCDA-APS/bluesky_training/lessons/instrument/framework/metadata.py\n", "I Wed-17:24:47 - /home/prjemian/Documents/projects/BCDA-APS/bluesky_training/lessons/instrument/framework/callbacks.py\n", "I Wed-17:24:47 - writing to SPEC file: /home/prjemian/Documents/projects/BCDA-APS/bluesky_training/lessons/20201216-172447.dat\n", "I Wed-17:24:47 - >>>> Using default SPEC file name <<<<\n", "I Wed-17:24:47 - file will be created when bluesky ends its next scan\n", "I Wed-17:24:47 - to change SPEC file, use command: newSpecFile('title')\n" ] } ], "source": [ "from instrument.collection import *" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "After starting a bluesky console or notebook session\n", "and after importing the instrument package,\n", "import the python [gobject-introspection](https://pygobject.readthedocs.io) package that\n", "is **required** to load the *hkl* support library.\n", "This step *must* happen before the *hkl* package is first imported." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "import gi\n", "gi.require_version('Hkl', '5.0')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next, import the desired diffractometer geometry from the\n", "[*hklpy*](https://github.com/bluesky/hklpy) package. We pick\n", "[E4CV](https://people.debian.org/~picca/hkl/hkl.html#orge78e5c4)\n", "(Eulerian 4-Circle with Vertical scattering geometry)\n", "as is typical at synchrotron beamlines." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "from hkl.diffract import E4CV\n", "from hkl.util import Lattice" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next, we get additional packages that we may use." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "from apstools.diffractometer import Constraint\n", "from apstools.diffractometer import DiffractometerMixin\n", "\n", "from bluesky import plans as bp\n", "from bluesky import plan_stubs as bps\n", "\n", "from ophyd import Component\n", "from ophyd import PseudoSingle\n", "from ophyd import SoftPositioner" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### The diffractometer object\n", "\n", "Define a 4-circle class for our example with simulated motors.\n", "There are attributes for the reciprocal space axes `h`, `k`, & `l`\n", "and for the real space axes: `phi`, `omega`, `chi`, & `tth`." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "class FourCircleDiffractometer(DiffractometerMixin, E4CV):\n", " h = Component(PseudoSingle, '',\n", " labels=(\"hkl\", \"fourc\"), kind=\"hinted\")\n", " k = Component(PseudoSingle, '',\n", " labels=(\"hkl\", \"fourc\"), kind=\"hinted\")\n", " l = Component(PseudoSingle, '',\n", " labels=(\"hkl\", \"fourc\"), kind=\"hinted\")\n", "\n", " omega = Component(SoftPositioner,\n", " labels=(\"motor\", \"fourc\"), kind=\"hinted\")\n", " chi = Component(SoftPositioner,\n", " labels=(\"motor\", \"fourc\"), kind=\"hinted\")\n", " phi = Component(SoftPositioner,\n", " labels=(\"motor\", \"fourc\"), kind=\"hinted\")\n", " tth = Component(SoftPositioner,\n", " labels=(\"motor\", \"fourc\"), kind=\"hinted\")\n", "\n", " def __init__(self, *args, **kwargs):\n", " \"\"\"\n", " start the SoftPositioner objects with initial values\n", "\n", " Since this diffractometer uses simulated motors,\n", " prime the SoftPositioners (motors) with initial values.\n", " Otherwise, with position == None, then describe(), and \n", " other functions get borked.\n", " \"\"\"\n", " super().__init__(*args, **kwargs)\n", "\n", " for axis in self.real_positioners:\n", " axis.move(0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "use EPICS motors instead of simulators\n", "\n", "To use EPICS motors (`ophyd.EpicsMotor`) instead\n", "of the `ophyd.SoftPositioner` simulators, redefine the\n", "`FourCircleDiffractometer` class (or define a new\n", "class) as follows, substituting with the proper motor PVs.\n", "\n", "**NOTE**: \n", " Unlike the example above with `SoftPositioner` objects \n", " as motors, do not need to initialize the motor positions \n", " in here since EPICS has already initialized each of the motors.\n", "\n", "```python\n", "class FourCircleDiffractometer(DiffractometerMixin, E4CV):\n", " h = Component(PseudoSingle, '',\n", " labels=(\"hkl\", \"fourc\"), kind=\"hinted\")\n", " k = Component(PseudoSingle, '',\n", " labels=(\"hkl\", \"fourc\"), kind=\"hinted\")\n", " l = Component(PseudoSingle, '',\n", " labels=(\"hkl\", \"fourc\"), kind=\"hinted\")\n", "\n", " omega = Component(EpicsMotor, \"ioc:m1\",\n", " labels=(\"motor\", \"fourc\"), kind=\"hinted\")\n", " chi = Component(EpicsMotor, \"ioc:m2\",\n", " labels=(\"motor\", \"fourc\"), kind=\"hinted\")\n", " phi = Component(EpicsMotor, \"ioc:m3\",\n", " labels=(\"motor\", \"fourc\"), kind=\"hinted\")\n", " tth = Component(EpicsMotor, \"ioc:m4\",\n", " labels=(\"motor\", \"fourc\"), kind=\"hinted\")\n", "```\n", "\n", "
\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Create the diffractometer object:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "fourc = FourCircleDiffractometer('', name='fourc')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `fourc.wh()` method provides a quick summary of\n", "the diffractometer:\n" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "===================== ========= =========\n", "term value axis_type\n", "===================== ========= =========\n", "diffractometer fourc \n", "sample name main \n", "energy (keV) 8.05092 \n", "wavelength (angstrom) 1.54000 \n", "calc engine hkl \n", "mode bissector \n", "h 0.0 pseudo \n", "k 0.0 pseudo \n", "l 0.0 pseudo \n", "omega 0 real \n", "chi 0 real \n", "phi 0 real \n", "tth 0 real \n", "===================== ========= =========\n", "\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fourc.wh()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Print the value of the `omega` axis:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "SoftPositioner(name='fourc_omega', parent='fourc', settle_time=0.0, timeout=None, egu='', limits=(0, 0), source='computed')\n" ] } ], "source": [ "print(fourc.omega)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "That's the object. It's `.position` property shows the position." ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0\n" ] } ], "source": [ "print(fourc.omega.position)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Use the `%mov` magic command to move a motor:" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1\n", "0\n" ] } ], "source": [ "%mov fourc.omega 1\n", "print(fourc.omega.position)\n", "%mov fourc.omega 0\n", "print(fourc.omega.position)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The diffractometer reciprocal-space coordinates are available:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "FourCircleDiffractometerPseudoPos(h=0.0, k=0.0, l=0.0)\n" ] } ], "source": [ "print(fourc.position)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When a diffractometer object is first created, it comes pre-defined\n", "with certain defaults:\n", "\n", "* operating mode\n", "* wavelength\n", "* sample\n", "* orientation matrix\n", "* axis constraints\n", "\n", "The sections below will cover each of these." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Operating mode\n", "\n", "The default operating mode is `bissector`. This mode\n", "constrains `tth` to equal `2*omega`." ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'bissector'" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fourc.calc.engine.mode" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Print the list of available operating modes:" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['bissector', 'constant_omega', 'constant_chi', 'constant_phi', 'double_diffraction', 'psi_constant']\n" ] } ], "source": [ "print(fourc.engine.modes)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Change to `constant_phi` mode:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "constant_phi\n" ] } ], "source": [ "fourc.calc.engine.mode = \"constant_phi\"\n", "print(fourc.calc.engine.mode)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Change it back:" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "bissector\n" ] } ], "source": [ "fourc.calc.engine.mode = \"bissector\"\n", "print(fourc.calc.engine.mode)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Wavelength\n", "\n", "The default wavelength is `1.54` angstroms. The units must match the units of the unit cell." ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1.54" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fourc.calc.wavelength" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Change the wavelength (use angstrom):" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": [ "fourc.calc.wavelength = 1.62751693358" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**NOTE**:\n", "Stick to wavelength, at least for now.\n", "Do not specify X-ray photon energy.\n", "For the *hkl* code, specify wavelength in angstrom. While the\n", "documentation may state wavelength in `nm`, use `angstrom` since\n", "these units *must* match the units used for the lattice parameters.\n", "Also, note that the (internal) calculation of X-ray energy assumes\n", "the units were `nm` so its conversion between energy and wavelength\n", "is off by a factor of 10." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Sample\n", "\n", "The default sample is named `main` and is a hypothetical cubic\n", "lattice with 1.54 angstrom edges." ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "HklSample(name='main', lattice=LatticeTuple(a=1.54, b=1.54, c=1.54, alpha=90.0, beta=90.0, gamma=90.0), ux=Parameter(name='None (internally: ux)', limits=(min=-180.0, max=180.0), value=0.0, fit=True, inverted=False, units='Degree'), uy=Parameter(name='None (internally: uy)', limits=(min=-180.0, max=180.0), value=0.0, fit=True, inverted=False, units='Degree'), uz=Parameter(name='None (internally: uz)', limits=(min=-180.0, max=180.0), value=0.0, fit=True, inverted=False, units='Degree'), U=array([[1., 0., 0.],\n", " [0., 1., 0.],\n", " [0., 0., 1.]]), UB=array([[ 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]]), reflections=[])" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fourc.calc.sample" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The diffractometer support maintains a dictionary of all defined samples\n", "(`fourc.calc._samples`). The `fourc.calc.sample` symbol points\n", "to one of these. Let's illustrate by creating a new\n", "sample named `orthorhombic`:" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "HklSample(name='orthorhombic', lattice=LatticeTuple(a=1.0, b=2.0, c=3.0, alpha=90.0, beta=90.0, gamma=90.0), ux=Parameter(name='None (internally: ux)', limits=(min=-180.0, max=180.0), value=0.0, fit=True, inverted=False, units='Degree'), uy=Parameter(name='None (internally: uy)', limits=(min=-180.0, max=180.0), value=0.0, fit=True, inverted=False, units='Degree'), uz=Parameter(name='None (internally: uz)', limits=(min=-180.0, max=180.0), value=0.0, fit=True, inverted=False, units='Degree'), U=array([[1., 0., 0.],\n", " [0., 1., 0.],\n", " [0., 0., 1.]]), UB=array([[ 6.28318531e+00, -1.92367069e-16, -1.28244713e-16],\n", " [ 0.00000000e+00, 3.14159265e+00, -1.28244713e-16],\n", " [ 0.00000000e+00, 0.00000000e+00, 2.09439510e+00]]), reflections=[])" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fourc.calc.new_sample('orthorhombic',\n", " lattice=Lattice(\n", " a=1, b=2, c=3,\n", " alpha=90.0, beta=90.0, gamma=90.0))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, there are two samples defined. The `fourc.calc.sample` symbol\n", "points to the new one:" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "len(fourc.calc._samples)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Show the name of the current sample:" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "orthorhombic\n" ] } ], "source": [ "print(fourc.calc.sample.name)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Switch back to the `main` sample:" ] }, { "cell_type": "code", "execution_count": 22, "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "main\n" ] } ], "source": [ "fourc.calc.sample = \"main\"\n", "print(fourc.calc.sample.name)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's create another sample and define an orientation:" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "HklSample(name='EuPtIn4_eh1_ver', lattice=LatticeTuple(a=4.542, b=16.955, c=7.389, alpha=90.0, beta=90.0, gamma=90.0), ux=Parameter(name='None (internally: ux)', limits=(min=-180.0, max=180.0), value=0.0, fit=True, inverted=False, units='Degree'), uy=Parameter(name='None (internally: uy)', limits=(min=-180.0, max=180.0), value=0.0, fit=True, inverted=False, units='Degree'), uz=Parameter(name='None (internally: uz)', limits=(min=-180.0, max=180.0), value=0.0, fit=True, inverted=False, units='Degree'), U=array([[1., 0., 0.],\n", " [0., 1., 0.],\n", " [0., 0., 1.]]), UB=array([[ 1.38335212e+00, -2.26914856e-17, -5.20684990e-17],\n", " [ 0.00000000e+00, 3.70580083e-01, -5.20684990e-17],\n", " [ 0.00000000e+00, 0.00000000e+00, 8.50343119e-01]]), reflections=[])" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fourc.calc.new_sample('EuPtIn4_eh1_ver',\n", " lattice=Lattice(\n", " a=4.542, b=16.955, c=7.389,\n", " alpha=90.0, beta=90.0, gamma=90.0))\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This is the orientation matrix defined by default:" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[1., 0., 0.],\n", " [0., 1., 0.],\n", " [0., 0., 1.]])" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fourc.calc.sample.U" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[ 1.38335212e+00, -2.26914856e-17, -5.20684990e-17],\n", " [ 0.00000000e+00, 3.70580083e-01, -5.20684990e-17],\n", " [ 0.00000000e+00, 0.00000000e+00, 8.50343119e-01]])" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fourc.calc.sample.UB" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Change it by providing a new 3x3 array:" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[0., 1., 0.],\n", " [0., 0., 1.],\n", " [1., 0., 0.]])" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fourc.calc.sample.U = [[0, 1, 0], [0,0,1], [1,0,0]]\n", "fourc.calc.sample.U" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[ 0.00000000e+00, 3.70580083e-01, -5.20684990e-17],\n", " [ 0.00000000e+00, 0.00000000e+00, 8.50343119e-01],\n", " [ 1.38335212e+00, -2.26914856e-17, -5.20684990e-17]])" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fourc.calc.sample.UB" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Set it back:" ] }, { "cell_type": "code", "execution_count": 28, "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[U]:\n", " [[1. 0. 0.]\n", " [0. 1. 0.]\n", " [0. 0. 1.]]\n", "[UB]:\n", " [[ 1.38335212e+00 -2.26914856e-17 -5.20684990e-17]\n", " [ 0.00000000e+00 3.70580083e-01 -5.20684990e-17]\n", " [ 0.00000000e+00 0.00000000e+00 8.50343119e-01]]\n" ] } ], "source": [ "fourc.calc.sample.U = [[1,0,0], [0, 1, 0], [0,0,1]]\n", "print(\"[U]:\\n\", fourc.calc.sample.U)\n", "print(\"[UB]:\\n\", fourc.calc.sample.UB)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The *UB* matrix (`fourc.calc.sample.UB`) can be changed in similar fashion." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The diffractometer reciprocal-space coordinates are available:" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "FourCircleDiffractometerPseudoPos(h=0.0, k=0.0, l=0.0)" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fourc.position" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Move the diffractometer to the (*020*) reflection:" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "FourCircleDiffractometerPseudoPos(h=1.5121846940302517e-16, k=1.9999999974773768, l=4.6102208393375324e-10)" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fourc.move(0, 2, 0)\n", "fourc.position" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Reflections\n", "\n", "A reflection associates a set of reciprocal-space axes (*hkl*) with\n", "a set of real-space motor positions. Following the method of Busing & Levy\n", "([Acta Cryst (1967) 22, pp 457-464](https://www.psi.ch/sites/default/files/import/sinq/zebra/PracticalsEN/1967-Busing-Levy-3-4-circle-Acta22.pdf)),\n", "two reflections are used to calculate an orientation matix (*UB* matrix) which is used to\n", "convert between motor positions and *hkl* values.\n", "\n", "There are no reflections defined by default.\n", "\n", "Define a reflection by associating a known *hkl* reflection\n", "with a set of motor positions." ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [], "source": [ "rp1 = fourc.calc.Position(omega=22.31594, chi=89.1377, phi=0, tth=45.15857)\n", "r1 = fourc.calc.sample.add_reflection(0, 8, 0, position=rp1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Define a second reflection (that is not a multiple\n", "of the first reflection):" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [], "source": [ "rp2 = fourc.calc.Position(omega=34.96232, chi=78.3139, phi=0, tth=71.8007)\n", "r2 = fourc.calc.sample.add_reflection(0, 12, 1, position=rp2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Calculate the *UB* matrix from these two reflections." ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[ 1.38058756 -0.00170327 -0.05359029]\n", " [ 0.00503279 0.3705342 -0.01301801]\n", " [ 0.08726811 0.00557695 0.8485529 ]]\n" ] } ], "source": [ "fourc.calc.sample.compute_UB(r1, r2)\n", "print(fourc.calc.sample.UB)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "### Forward Solutions\n", "\n", "Forward solutions are the calculated combinations of real-space motor\n", "positions given the sample oreitnation matrix,\n", "reciprocal-space axes, operating mode,\n", "wavelength, and applied constraints. These combinations\n", "are presented as a python list which may be empty if there are\n", "no solutions.\n", "\n", "Show default solution for a few reflections (*100*), (*010*) and (*001*):" ] }, { "cell_type": "code", "execution_count": 34, "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "========= ======== ========= ========== ========= =========\n", "(hkl) solution omega chi phi tth \n", "========= ======== ========= ========== ========= =========\n", "(1, 0, 0) 0 -10.32101 -179.79155 86.38310 -20.64202\n", "(0, 1, 0) 0 -2.75098 -90.90161 -16.98318 -5.50196 \n", "(0, 0, 1) 0 6.32287 -0.87718 -3.61371 12.64574 \n", "========= ======== ========= ========== ========= =========\n", "\n" ] } ], "source": [ "r = [] # list of reflections - (hkl) tuples\n", "r.append((1,0,0))\n", "r.append((0,1,0))\n", "r.append((0,0,1))\n", "print(fourc.forwardSolutionsTable(r))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**NOTE**: \n", " The method to select the default solution can be changed.\n", " See `decision_fcn` in https://blueskyproject.io/hklpy/master/calc.html#hkl.calc.CalcRecip.forward_iter." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Show *all* the possible solutions by adding the `full=True` keyword:" ] }, { "cell_type": "code", "execution_count": 35, "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "========= ======== ========== ========== ========= =========\n", "(hkl) solution omega chi phi tth \n", "========= ======== ========== ========== ========= =========\n", "(1, 0, 0) 0 -10.32101 -179.79155 86.38310 -20.64202\n", "(1, 0, 0) 1 -10.32101 -0.20845 -93.61690 -20.64202\n", "(1, 0, 0) 2 10.32101 0.20845 86.38310 20.64202 \n", "(1, 0, 0) 3 -169.67899 -179.79155 86.38310 20.64202 \n", "(1, 0, 0) 4 -169.67899 -0.20845 -93.61690 20.64202 \n", "(1, 0, 0) 5 10.32101 179.79155 -93.61690 20.64202 \n", "(0, 1, 0) 0 -2.75098 -90.90161 -16.98318 -5.50196 \n", "(0, 1, 0) 1 -2.75098 -89.09839 163.01682 -5.50196 \n", "(0, 1, 0) 2 -177.24902 -90.90161 -16.98318 5.50196 \n", "(0, 1, 0) 3 2.75098 89.09839 -16.98318 5.50196 \n", "(0, 1, 0) 4 -177.24902 -89.09839 163.01682 5.50196 \n", "(0, 1, 0) 5 2.75098 90.90161 163.01682 5.50196 \n", "(0, 0, 1) 0 6.32287 -0.87718 -3.61371 12.64574 \n", "(0, 0, 1) 1 -6.32287 0.87718 176.38629 -12.64574\n", "(0, 0, 1) 2 -6.32287 179.12282 -3.61371 -12.64574\n", "(0, 0, 1) 3 6.32287 -179.12282 176.38629 12.64574 \n", "(0, 0, 1) 4 -173.67713 0.87718 176.38629 12.64574 \n", "(0, 0, 1) 5 -173.67713 179.12282 -3.61371 12.64574 \n", "========= ======== ========== ========== ========= =========\n", "\n" ] } ], "source": [ "print(fourc.forwardSolutionsTable(r, full=True))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For each of the reflections, six solutions were found possible.\n", "The first solution is taken as the default.\n", "To make a different choice, access the complete list, such as:" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(PosCalcE4CV(omega=-10.321012305373241, chi=-179.79155096044508, phi=86.38309742089963, tth=-20.642024610746482),\n", " PosCalcE4CV(omega=-10.321012305373241, chi=-0.20844903955490512, phi=-93.61690257910038, tth=-20.642024610746482),\n", " PosCalcE4CV(omega=10.321012305373241, chi=0.20844903955490512, phi=86.38309742089963, tth=20.642024610746482),\n", " PosCalcE4CV(omega=-169.67898769462678, chi=-179.79155096044508, phi=86.38309742089963, tth=20.642024610746482),\n", " PosCalcE4CV(omega=-169.67898769462678, chi=-0.20844903955490512, phi=-93.61690257910038, tth=20.642024610746482),\n", " PosCalcE4CV(omega=10.321012305373241, chi=179.79155096044508, phi=-93.61690257910038, tth=20.642024610746482))" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fourc.calc.forward((1,0,0))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Alternatively, apply one or more [*constraints*](#constraints) to\n", "restrict the range of allowed solutions." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If there are no solutions to the forward calculation,\n", "the *hkl* package raises a `ValueError` exception:\n", "\n", "```\n", "ValueError: Calculation failed (hkl-mode-auto-error-quark: none of the functions were solved !!! (0))\n", "```\n", "\n", "
\n", "detailed exception trace\n", "\n", "```ipython\n", "In [114]: fourc.calc.forward((5, 4, 35))\n", "---------------------------------------------------------------------------\n", "Error Traceback (most recent call last)\n", "~/.conda/envs/bluesky_2020_9/lib/python3.8/site-packages/hkl/engine.py in pseudo_positions(self, values)\n", " 212 try:\n", "--> 213 geometry_list = self._engine.pseudo_axis_values_set(values,\n", " 214 self._units)\n", "\n", "Error: hkl-mode-auto-error-quark: none of the functions were solved !!! (0)\n", "\n", "During handling of the above exception, another exception occurred:\n", "\n", "ValueError Traceback (most recent call last)\n", " in \n", "----> 1 fourc.calc.forward((5, 4, 35))\n", "\n", "~/.conda/envs/bluesky_2020_9/lib/python3.8/site-packages/hkl/calc.py in wrapped(self, *args, **kwargs)\n", " 42 initial_pos = self.physical_positions\n", " 43 try:\n", "---> 44 return func(self, *args, **kwargs)\n", " 45 finally:\n", " 46 self.physical_positions = initial_pos\n", "\n", "~/.conda/envs/bluesky_2020_9/lib/python3.8/site-packages/hkl/calc.py in forward(self, position, engine)\n", " 505 raise ValueError('Engine unset')\n", " 506\n", "--> 507 self.engine.pseudo_positions = position\n", " 508 return self.engine.solutions\n", " 509\n", "\n", "~/.conda/envs/bluesky_2020_9/lib/python3.8/site-packages/hkl/engine.py in pseudo_positions(self, values)\n", " 214 self._units)\n", " 215 except GLib.GError as ex:\n", "--> 216 raise ValueError('Calculation failed (%s)' % ex)\n", " 217\n", " 218 Position = self._calc.Position\n", "\n", "ValueError: Calculation failed (hkl-mode-auto-error-quark: none of the functions were solved !!! (0))\n", "```\n", "\n", "
\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `forwardSolutionsTable` does not raise an\n", "error but displays `none` for any *hkl* reflection with no\n", "solution in the real-space motor positions. To demonstrate,\n", "the (*5 4 35*) reflection is not available at this wavelength:" ] }, { "cell_type": "code", "execution_count": 37, "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "========== ======== ===== === === ===\n", "(hkl) solution omega chi phi tth\n", "========== ======== ===== === === ===\n", "(5, 4, 35) none \n", "========== ======== ===== === === ===\n", "\n" ] } ], "source": [ "print(fourc.forwardSolutionsTable( [ (5,4,35), ], full=True))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Constraints\n", "\n", "Constraints are applied to restrict the\n", "motor positions that are allowed to be solutions of the forward\n", "calculation from a reflection *hkl* to motor positions." ] }, { "cell_type": "code", "execution_count": 38, "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "===== ========= ========== ================== ====\n", "axis low_limit high_limit value fit \n", "===== ========= ========== ================== ====\n", "omega -180.0 180.0 -5.50832505964632 True\n", "chi -180.0 180.0 -90.00000003030587 True\n", "phi -180.0 180.0 0.0 True\n", "tth -180.0 180.0 -11.01665011929264 True\n", "===== ========= ========== ================== ====\n", "\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fourc.showConstraints()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Apply a constraint that only allows non-negative values for `omega`. Create a dictionary\n", "with the axis constraints to be applied. The dictionary key is the axis name (must\n", "be a name in the `fourc.calc.physical_axis_names` list).\n", "\n", "The names of the axes are available:" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['omega', 'chi', 'phi', 'tth']" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fourc.calc.physical_axis_names" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "The value is a\n", "[Constraints](https://blueskyproject.io/hklpy/constraints.html#constraints) object.\n", "\n", "`Constraints` Arguments\n", "\n", "* low_limit (*number*) :\n", " Limit solutions for this axis to no less than `low_limit` when `fit=True`.\n", "\n", "* high_limit (*number*) :\n", " Limit solutions for this axis to no greater than `high_limit` when `fit=True`.\n", "\n", "* value (*number*) :\n", " Calculate with axis = `value` when `fit=False`.\n", "\n", "* fit (*bool*) :\n", " Not used.\n", "\n", "In the dictionary, it is only necessary to define the axis constraints to be changed.\n", "The other (commented out) constraints will not be changed." ] }, { "cell_type": "code", "execution_count": 40, "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "===== ========= ========== ================== ====\n", "axis low_limit high_limit value fit \n", "===== ========= ========== ================== ====\n", "omega 0.0 180.0 0.0 True\n", "chi -180.0 180.0 -90.00000003030587 True\n", "phi -180.0 180.0 0.0 True\n", "tth -180.0 180.0 -11.01665011929264 True\n", "===== ========= ========== ================== ====\n", "\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ "my_constraints = {\n", " # axis: Constraint(lo_limit, hi_limit, value, fit)\n", " \"omega\": Constraint(0, 180, 0, True),\n", " # \"chi\": Constraint(-180, 180, 0, True),\n", " # \"phi\": Constraint(-180, 180, 0, True),\n", " # \"tth\": Constraint(-180, 180, 0, True),\n", "}\n", "fourc.applyConstraints(my_constraints)\n", "fourc.showConstraints()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Show all the possible solutions with these constraints (set keyword argument `full=True`):" ] }, { "cell_type": "code", "execution_count": 41, "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "========= ======== ======== ========= ========= ========\n", "(hkl) solution omega chi phi tth \n", "========= ======== ======== ========= ========= ========\n", "[1, 0, 0] 0 10.32101 0.20845 86.38310 20.64202\n", "[1, 0, 0] 1 10.32101 179.79155 -93.61690 20.64202\n", "[0, 1, 0] 0 2.75098 89.09839 -16.98335 5.50196 \n", "[0, 1, 0] 1 2.75098 90.90161 163.01665 5.50196 \n", "========= ======== ======== ========= ========= ========\n", "\n" ] } ], "source": [ "print(fourc.forwardSolutionsTable([[1,0,0],[0,1,0]], full=True))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Remove the constraint on `omega` and show the solutions:" ] }, { "cell_type": "code", "execution_count": 42, "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "===== ========= ========== ================== ====\n", "axis low_limit high_limit value fit \n", "===== ========= ========== ================== ====\n", "omega -180.0 180.0 -5.50832505964632 True\n", "chi -180.0 180.0 -90.00000003030587 True\n", "phi -180.0 180.0 0.0 True\n", "tth -180.0 180.0 -11.01665011929264 True\n", "===== ========= ========== ================== ====\n", "\n", "========= ======== ========== ========== ========= =========\n", "(hkl) solution omega chi phi tth \n", "========= ======== ========== ========== ========= =========\n", "[1, 0, 0] 0 -10.32101 -179.79155 86.38310 -20.64202\n", "[1, 0, 0] 1 -10.32101 -0.20845 -93.61690 -20.64202\n", "[1, 0, 0] 2 10.32101 0.20845 86.38310 20.64202 \n", "[1, 0, 0] 3 -169.67899 -179.79155 86.38310 20.64202 \n", "[1, 0, 0] 4 -169.67899 -0.20845 -93.61690 20.64202 \n", "[1, 0, 0] 5 10.32101 179.79155 -93.61690 20.64202 \n", "[0, 1, 0] 0 -2.75098 -90.90161 -16.98318 -5.50196 \n", "[0, 1, 0] 1 -2.75098 -89.09839 163.01682 -5.50196 \n", "[0, 1, 0] 2 -177.24902 -90.90161 -16.98318 5.50196 \n", "[0, 1, 0] 3 2.75098 89.09839 -16.98318 5.50196 \n", "[0, 1, 0] 4 -177.24902 -89.09839 163.01682 5.50196 \n", "[0, 1, 0] 5 2.75098 90.90161 163.01682 5.50196 \n", "========= ======== ========== ========== ========= =========\n", "\n", "\n", "\n", " Now, just the default solutions:\n", "========= ======== ========= ========== ========= =========\n", "(hkl) solution omega chi phi tth \n", "========= ======== ========= ========== ========= =========\n", "[1, 0, 0] 0 -10.32101 -179.79155 86.38310 -20.64202\n", "[0, 1, 0] 0 -2.75098 -90.90161 -16.98318 -5.50196 \n", "========= ======== ========= ========== ========= =========\n", "\n" ] } ], "source": [ "fourc.undoLastConstraints()\n", "fourc.showConstraints()\n", "print(fourc.forwardSolutionsTable([[1,0,0],[0,1,0]], full=True))\n", "print(\"\\n\\n Now, just the default solutions:\")\n", "print(fourc.forwardSolutionsTable([[1,0,0],[0,1,0]]))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Example - 4-circle with `LNO_LAO` sample\n", "\n", "We have some example information from a SPEC data file (collected at APS beamline 33BM).\n", "In summary, the sample and orientation information extracted is:\n", "\n", "term | value(s)\n", "--- | ---\n", "sample | LNO_LAO\n", "crystal | 3.781726143 3.791444574 3.79890313 90.2546203 90.01815424 89.89967858\n", "geometry | fourc\n", "mode | 0 (Omega equals zero)\n", "lambda | 1.239424258\n", "r1 | (0, 0, 2) 38.09875 19.1335 90.0135 0\n", "r2 | (1, 1, 3) 65.644 32.82125 115.23625 48.1315\n", "Q | (2, 2, 1.9) 67.78225 33.891 145.985 48.22875 -0.001 -0.16\n", "UB[0] | -1.658712442 0.09820024135 -0.000389705578\n", "UB[1] | -0.09554990312 -1.654278629 0.00242844486\n", "UB[2] | 0.0002629818914 0.009815746824 1.653961812\n", "\n", "**Note**: In SPEC's fourc geometry, the motors are reported\n", "in this order: `tth omega chi phi`\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### use 4-circle geometry\n", "\n", "Reset all the above changes by re-creating the `fourc` object." ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [], "source": [ "fourc = FourCircleDiffractometer('', name='fourc')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### define the sample" ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "HklSample(name='LNO_LAO', lattice=LatticeTuple(a=3.781726143, b=3.791444574, c=3.79890313, alpha=90.2546203, beta=90.01815424, gamma=89.89967858), ux=Parameter(name='None (internally: ux)', limits=(min=-180.0, max=180.0), value=0.0, fit=True, inverted=False, units='Degree'), uy=Parameter(name='None (internally: uy)', limits=(min=-180.0, max=180.0), value=0.0, fit=True, inverted=False, units='Degree'), uz=Parameter(name='None (internally: uz)', limits=(min=-180.0, max=180.0), value=0.0, fit=True, inverted=False, units='Degree'), U=array([[1., 0., 0.],\n", " [0., 1., 0.],\n", " [0., 0., 1.]]), UB=array([[ 1.66146225e+00, -2.89938471e-03, 5.11196668e-04],\n", " [ 0.00000000e+00, 1.65721725e+00, 7.34922202e-03],\n", " [ 0.00000000e+00, 0.00000000e+00, 1.65394723e+00]]), reflections=[])" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fourc.calc.new_sample('LNO_LAO',\n", " lattice=Lattice(\n", " a=3.781726143, b=3.791444574 , c=3.79890313,\n", " alpha=90.2546203, beta=90.01815424, gamma=89.89967858))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### set wavelength" ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [], "source": [ "fourc.calc.wavelength = 1.239424258" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### define two reflections" ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [], "source": [ "rp1 = fourc.calc.Position(omega=19.1335, chi=90.0135, phi=0, tth=38.09875)\n", "r1 = fourc.calc.sample.add_reflection(0, 0, 2, position=rp1)\n", "rp2 = fourc.calc.Position(omega=32.82125, chi=115.23625, phi=48.1315, tth=65.644)\n", "r2 = fourc.calc.sample.add_reflection(1, 1, 3, position=rp2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### calculate *UB* matrix" ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[-9.55499011e-02, -1.65427863e+00, 2.42844485e-03],\n", " [ 2.62981975e-04, 9.81483906e-03, 1.65396181e+00],\n", " [-1.65871244e+00, 9.82002396e-02, -3.89705577e-04]])" ] }, "execution_count": 47, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fourc.calc.sample.compute_UB(r1, r2)\n", "fourc.calc.sample.UB" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Compare this result with the *UB* matrix computed by SPEC:\n", "\n", "```\n", "-1.658712442 0.09820024135 -0.000389705578\n", "-0.09554990312 -1.654278629 0.00242844486\n", "0.0002629818914 0.009815746824 1.653961812\n", "```\n", "\n", "Same numbers, different row order, different order of real-space motors." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### calculate *(hkl)* given motor positions\n", "\n", "Given these motor positions, confirm this is the\n", "(2 2 1.9) reflection.\n", "\n", "axis | value\n", "--- | ---\n", "omega | 33.891\n", "chi | 145.985\n", "phi | 48.22875\n", "tth | 67.78225" ] }, { "cell_type": "code", "execution_count": 48, "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "===================== ================== =========\n", "term value axis_type\n", "===================== ================== =========\n", "diffractometer fourc \n", "sample name LNO_LAO \n", "energy (keV) 10.00337 \n", "wavelength (angstrom) 1.23942 \n", "calc engine hkl \n", "mode bissector \n", "h 1.9999956934724616 pseudo \n", "k 1.999999875673663 pseudo \n", "l 1.900000040364338 pseudo \n", "omega 33.891 real \n", "chi 145.985 real \n", "phi 48.22875 real \n", "tth 67.78225 real \n", "===================== ================== =========\n", "\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 48, "metadata": {}, "output_type": "execute_result" } ], "source": [ "%mov fourc.omega 33.891 fourc.chi 145.985 fourc.phi 48.22875 fourc.tth 67.78225\n", "fourc.wh()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### compute the motor positions of the (*2 2 1.9*) reflection\n", "\n", "Observe that `tth ~ 2*omega` which is consistent with `bissector` mode.\n", "The (*2 2 1.9*) reflection is not available in `constant_omega` mode with `omega=0`.\n", "Need to change modes." ] }, { "cell_type": "code", "execution_count": 49, "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "===== ========= ========== ======== ====\n", "axis low_limit high_limit value fit \n", "===== ========= ========== ======== ====\n", "omega -180.0 180.0 33.891 True\n", "chi -180.0 180.0 145.985 True\n", "phi -180.0 180.0 48.22875 True\n", "tth -180.0 180.0 67.78225 True\n", "===== ========= ========== ======== ====\n", "\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 49, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fourc.calc.engine.mode = \"bissector\"\n", "fourc.showConstraints()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The constraint on `omega` must be removed, then compute the default forward solution." ] }, { "cell_type": "code", "execution_count": 50, "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "=========== ======== ========== ========== ========== =========\n", "(hkl) solution omega chi phi tth \n", "=========== ======== ========== ========== ========== =========\n", "[2, 2, 1.9] 0 33.89115 145.98503 48.22884 67.78231 \n", "[2, 2, 1.9] 1 33.89115 34.01497 -131.77116 67.78231 \n", "[2, 2, 1.9] 2 -146.10885 -34.01497 48.22884 67.78231 \n", "[2, 2, 1.9] 3 -33.89115 -34.01497 48.22884 -67.78231\n", "[2, 2, 1.9] 4 -146.10885 -145.98503 -131.77116 67.78231 \n", "[2, 2, 1.9] 5 -33.89115 -145.98503 -131.77116 -67.78231\n", "=========== ======== ========== ========== ========== =========\n", "\n", "\n", " Now, just the default solution.\n", "=========== ======== ======== ========= ======== ========\n", "(hkl) solution omega chi phi tth \n", "=========== ======== ======== ========= ======== ========\n", "[2, 2, 1.9] 0 33.89115 145.98503 48.22884 67.78231\n", "=========== ======== ======== ========= ======== ========\n", "\n" ] } ], "source": [ "fourc.undoLastConstraints()\n", "print(fourc.forwardSolutionsTable(([2, 2, 1.9],), full=True))\n", "print(\"\\n Now, just the default solution.\")\n", "print(fourc.forwardSolutionsTable(([2, 2, 1.9],)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Apply constraints such that all motors are not negative, then recompute and show:" ] }, { "cell_type": "code", "execution_count": 51, "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "===== ========= ========== ===== ====\n", "axis low_limit high_limit value fit \n", "===== ========= ========== ===== ====\n", "omega 0.0 180.0 0.0 True\n", "chi 0.0 180.0 0.0 True\n", "phi 0.0 180.0 0.0 True\n", "tth 0.0 180.0 0.0 True\n", "===== ========= ========== ===== ====\n", "\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 51, "metadata": {}, "output_type": "execute_result" } ], "source": [ "my_constraints = {\n", " # axis: Constraint(lo_limit, hi_limit, value, fit)\n", " \"omega\": Constraint(0, 180, 0, True),\n", " \"chi\": Constraint(0, 180, 0, True),\n", " \"phi\": Constraint(0, 180, 0, True),\n", " \"tth\": Constraint(0, 180, 0, True),\n", "}\n", "fourc.applyConstraints(my_constraints)\n", "fourc.showConstraints()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Summarize the diffractometer settings." ] }, { "cell_type": "code", "execution_count": 52, "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "===================== ================== =========\n", "term value axis_type\n", "===================== ================== =========\n", "diffractometer fourc \n", "sample name LNO_LAO \n", "energy (keV) 10.00337 \n", "wavelength (angstrom) 1.23942 \n", "calc engine hkl \n", "mode bissector \n", "h 1.9999956934724616 pseudo \n", "k 1.999999875673663 pseudo \n", "l 1.900000040364338 pseudo \n", "omega 33.891 real \n", "chi 145.985 real \n", "phi 48.22875 real \n", "tth 67.78225 real \n", "===================== ================== =========\n", "\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 52, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fourc.wh()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Print the default solution for *(2 2 1.9)*." ] }, { "cell_type": "code", "execution_count": 53, "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "=========== ======== ======== ========= ======== ========\n", "(hkl) solution omega chi phi tth \n", "=========== ======== ======== ========= ======== ========\n", "[2, 2, 1.9] 0 33.89115 145.98503 48.22884 67.78231\n", "=========== ======== ======== ========= ======== ========\n", "\n" ] } ], "source": [ "print(\n", " fourc.forwardSolutionsTable(\n", " (\n", " [2, 2, 1.9],\n", " )\n", " )\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "These values match exactly the values from the SPEC data file." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### sample *(2k2)* scan, near `k=2`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Use the `fourc` object as the *detector* for the scans. Plotting is not necessary." ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [], "source": [ "from instrument.framework import bec\n", "bec.disable_plots()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next, scan *(2k2)* near `k=2`:" ] }, { "cell_type": "code", "execution_count": 55, "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "\n", "Transient Scan ID: 1 Time: 2020-12-16 17:24:56\n", "Persistent Unique Scan ID: '9a48a80e-deaa-4c5f-bd9c-2d4fe8d79c5e'\n", "New stream: 'primary'\n", "+-----------+------------+------------+------------+------------+-------------+------------+------------+------------+\n", "| seq_num | time | fourc_k | fourc_h | fourc_l | fourc_omega | fourc_chi | fourc_phi | fourc_tth |\n", "+-----------+------------+------------+------------+------------+-------------+------------+------------+------------+\n", "| 1 | 17:24:56.4 | 1.800 | 2.000 | 2.000 | 33.274 | 143.277 | 45.204 | 66.547 |\n", "| 2 | 17:24:56.4 | 1.850 | 2.000 | 2.000 | 33.578 | 143.613 | 45.988 | 67.157 |\n", "| 3 | 17:24:56.4 | 1.900 | 2.000 | 2.000 | 33.890 | 143.949 | 46.753 | 67.780 |\n", "| 4 | 17:24:56.4 | 1.950 | 2.000 | 2.000 | 34.208 | 144.284 | 47.499 | 68.417 |\n", "| 5 | 17:24:56.4 | 2.000 | 2.000 | 2.000 | 34.534 | 144.617 | 48.227 | 69.067 |\n", "| 6 | 17:24:56.4 | 2.050 | 2.000 | 2.000 | 34.866 | 144.950 | 48.936 | 69.732 |\n", "| 7 | 17:24:56.5 | 2.100 | 2.000 | 2.000 | 35.205 | 145.281 | 49.628 | 70.409 |\n", "| 8 | 17:24:56.5 | 2.150 | 2.000 | 2.000 | 35.550 | 145.610 | 50.303 | 71.100 |\n", "| 9 | 17:24:56.5 | 2.200 | 2.000 | 2.000 | 35.902 | 145.937 | 50.962 | 71.804 |\n", "+-----------+------------+------------+------------+------------+-------------+------------+------------+------------+\n", "generator rel_scan ['9a48a80e'] (scan num: 1)\n" ] }, { "data": { "text/plain": [ "('9a48a80e-deaa-4c5f-bd9c-2d4fe8d79c5e',)" ] }, "execution_count": 55, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fourc.move(2, 2, 2)\n", "RE(bp.rel_scan([fourc], fourc.k, -0.2, 0.2, 9))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Example - `epitaxial thin film on substrate`\n", "\n", "Found an example on the web from Rigaku.\n", "The sample is an epitaxial thin film of Mn3O4 on MgO substrate.\n", "\n", "ref: http://www.rigaku.com/downloads/journal/Vol16.1.1999/cguide.pdf\n", "\n", "Condense all the setup steps into one cell here." ] }, { "cell_type": "code", "execution_count": 56, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1" ] }, "execution_count": 56, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fourc = FourCircleDiffractometer('', name='fourc')\n", "fourc.calc.new_sample('Mn3O4/MgO thin film',\n", " lattice=Lattice(\n", " a=5.72, b=5.72, c=9.5, \n", " alpha=90.0, beta=90.0, gamma=90.0))\n", "fourc.calc.wavelength = 12.3984244 / 8.04 # Cu Kalpha\n", "fourc.calc.sample.compute_UB(\n", " fourc.calc.sample.add_reflection(\n", " -1.998, -1.994, 4.011,\n", " position=fourc.calc.Position(\n", " tth=80.8769, omega=40.6148, chi=0.647, phi=-121.717)), \n", " fourc.calc.sample.add_reflection(\n", " -0.997, -0.997, 2.009,\n", " position=fourc.calc.Position(\n", " tth=28.695, omega=14.4651, chi=-48.8860, phi=-88.758))\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Apply some constraints" ] }, { "cell_type": "code", "execution_count": 57, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "===== =================== ================== ===== ====\n", "axis low_limit high_limit value fit \n", "===== =================== ================== ===== ====\n", "omega -119.99999999999999 119.99999999999999 0.0 True\n", "chi -119.99999999999999 119.99999999999999 0.0 True\n", "phi -180.0 180.0 0.0 True\n", "tth -5.0 119.99999999999999 0.0 True\n", "===== =================== ================== ===== ====\n", "\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 57, "metadata": {}, "output_type": "execute_result" } ], "source": [ "my_constraints = {\n", " # axis: Constraint(lo_limit, hi_limit, value, fit)\n", " \"omega\": Constraint(-120, 120, 0, True),\n", " \"chi\": Constraint(-120, 120, 0, True),\n", " # \"phi\": Constraint(-180, 180, 0, True),\n", " \"tth\": Constraint(-5, 120, 0, True),\n", "}\n", "fourc.applyConstraints(my_constraints)\n", "fourc.showConstraints()" ] }, { "cell_type": "code", "execution_count": 58, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "=========== ======== ======== ======== ========== ========\n", "(hkl) solution omega chi phi tth \n", "=========== ======== ======== ======== ========== ========\n", "(-3, 0, 5) 0 34.95305 16.93669 -92.56666 69.90610\n", "(-2, -2, 4) 0 30.05045 0.68945 -121.67536 60.10091\n", "(-2, 1, 1) 0 18.18911 48.65405 -68.07899 36.37821\n", "(-1, -1, 2) 0 14.50007 0.68945 -121.67536 29.00014\n", "(0, 3, 0.5) 0 23.98052 14.97372 -2.28512 47.96104\n", "(0, 3, 1) 0 24.35942 12.23302 -7.33156 48.71883\n", "(0, 3, 1.5) 0 24.98135 9.51049 -12.08783 49.96270\n", "=========== ======== ======== ======== ========== ========\n", "\n" ] } ], "source": [ "r = [] # list of reflections - (hkl) tuples\n", "r.append((-3,0,5))\n", "r.append((-2,-2,4))\n", "r.append((-2,1,1))\n", "r.append((-1,-1,2))\n", "r.append((0,3,.5))\n", "r.append((0,3,1))\n", "r.append((0,3,1.5))\n", "print(fourc.forwardSolutionsTable(r))" ] }, { "cell_type": "code", "execution_count": 59, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "===================== =================== =========\n", "term value axis_type\n", "===================== =================== =========\n", "diffractometer fourc \n", "sample name Mn3O4/MgO thin film \n", "energy (keV) 8.04000 \n", "wavelength (angstrom) 1.54209 \n", "calc engine hkl \n", "mode bissector \n", "h 0.0 pseudo \n", "k 0.0 pseudo \n", "l 0.0 pseudo \n", "omega 0 real \n", "chi 0 real \n", "phi 0 real \n", "tth 0 real \n", "===================== =================== =========\n", "\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 59, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fourc.wh()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Scan along the *(0kl)* direction (down in *k*, up in *l*)." ] }, { "cell_type": "code", "execution_count": 60, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "\n", "Transient Scan ID: 2 Time: 2020-12-16 17:24:57\n", "Persistent Unique Scan ID: 'b5cff878-570f-4305-b5a1-db69f171b005'\n", "New stream: 'primary'\n", "+-----------+------------+------------+------------+------------+-------------+------------+------------+------------+\n", "| seq_num | time | fourc_k | fourc_l | fourc_h | fourc_omega | fourc_chi | fourc_phi | fourc_tth |\n", "+-----------+------------+------------+------------+------------+-------------+------------+------------+------------+\n", "| 1 | 17:24:57.4 | 3.200 | 0.500 | 0.000 | 25.675 | 15.144 | -1.961 | 51.349 |\n", "| 2 | 17:24:57.4 | 3.160 | 0.600 | -0.000 | 25.387 | 14.594 | -3.003 | 50.775 |\n", "| 3 | 17:24:57.4 | 3.120 | 0.700 | 0.000 | 25.112 | 14.028 | -4.062 | 50.224 |\n", "| 4 | 17:24:57.5 | 3.080 | 0.800 | -0.000 | 24.849 | 13.446 | -5.136 | 49.698 |\n", "| 5 | 17:24:57.5 | 3.040 | 0.900 | -0.000 | 24.598 | 12.847 | -6.226 | 49.196 |\n", "| 6 | 17:24:57.5 | 3.000 | 1.000 | -0.000 | 24.359 | 12.233 | -7.332 | 48.719 |\n", "| 7 | 17:24:57.5 | 2.960 | 1.100 | 0.000 | 24.134 | 11.603 | -8.452 | 48.268 |\n", "| 8 | 17:24:57.5 | 2.920 | 1.200 | -0.000 | 23.921 | 10.958 | -9.586 | 47.843 |\n", "| 9 | 17:24:57.5 | 2.880 | 1.300 | 0.000 | 23.722 | 10.298 | -10.733 | 47.444 |\n", "| 10 | 17:24:57.5 | 2.840 | 1.400 | -0.000 | 23.537 | 9.624 | -11.893 | 47.073 |\n", "| 11 | 17:24:57.5 | 2.800 | 1.500 | 0.000 | 23.365 | 8.936 | -13.066 | 46.730 |\n", "+-----------+------------+------------+------------+------------+-------------+------------+------------+------------+\n", "generator scan ['b5cff878'] (scan num: 2)\n" ] }, { "data": { "text/plain": [ "('b5cff878-570f-4305-b5a1-db69f171b005',)" ] }, "execution_count": 60, "metadata": {}, "output_type": "execute_result" } ], "source": [ "RE(bp.scan([fourc], fourc.k, 3.2, 2.8, fourc.l, 0.5, 1.5, 11))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Scan again, keeping `phi=0`." ] }, { "cell_type": "code", "execution_count": 61, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "===== =================== ================== ================== =====\n", "axis low_limit high_limit value fit \n", "===== =================== ================== ================== =====\n", "omega -119.99999999999999 119.99999999999999 23.364811487006858 True \n", "chi -119.99999999999999 119.99999999999999 8.936401718625467 True \n", "phi -180.0 180.0 0.0 False\n", "tth -5.0 119.99999999999999 46.729622974013715 True \n", "===== =================== ================== ================== =====\n", "\n", "\n", " Solutions:\n", "============= ======== ======== ======== ======= ========\n", "(hkl) solution omega chi phi tth \n", "============= ======== ======== ======== ======= ========\n", "[0, 3.2, 0.5] 0 23.78144 15.15228 0.00000 51.34916\n", "[0, 2.8, 1.5] 0 10.46066 9.16991 0.00000 46.72962\n", "============= ======== ======== ======== ======= ========\n", "\n", "\n", "\n", "Transient Scan ID: 3 Time: 2020-12-16 17:24:58\n", "Persistent Unique Scan ID: 'dc673022-3c4a-4b78-8a22-72e9a3a15e9c'\n", "New stream: 'primary'\n", "+-----------+------------+------------+------------+------------+-------------+------------+------------+------------+\n", "| seq_num | time | fourc_k | fourc_l | fourc_h | fourc_omega | fourc_chi | fourc_phi | fourc_tth |\n", "+-----------+------------+------------+------------+------------+-------------+------------+------------+------------+\n", "| 1 | 17:24:58.0 | 3.200 | 0.500 | -0.000 | 23.781 | 15.152 | 0.000 | 51.349 |\n", "| 2 | 17:24:58.1 | 3.160 | 0.600 | 0.000 | 22.481 | 14.613 | 0.000 | 50.775 |\n", "| 3 | 17:24:58.1 | 3.120 | 0.700 | -0.000 | 21.172 | 14.062 | 0.000 | 50.224 |\n", "| 4 | 17:24:58.1 | 3.080 | 0.800 | 0.000 | 19.854 | 13.498 | 0.000 | 49.698 |\n", "| 5 | 17:24:58.1 | 3.040 | 0.900 | -0.000 | 18.528 | 12.921 | 0.000 | 49.196 |\n", "| 6 | 17:24:58.1 | 3.000 | 1.000 | 0.000 | 17.195 | 12.331 | 0.000 | 48.719 |\n", "| 7 | 17:24:58.2 | 2.960 | 1.100 | 0.000 | 15.856 | 11.727 | 0.000 | 48.268 |\n", "| 8 | 17:24:58.2 | 2.920 | 1.200 | -0.000 | 14.512 | 11.110 | 0.000 | 47.843 |\n", "| 9 | 17:24:58.2 | 2.880 | 1.300 | -0.000 | 13.164 | 10.478 | 0.000 | 47.444 |\n", "| 10 | 17:24:58.2 | 2.840 | 1.400 | 0.000 | 11.813 | 9.831 | 0.000 | 47.073 |\n", "| 11 | 17:24:58.2 | 2.800 | 1.500 | -0.000 | 10.461 | 9.170 | 0.000 | 46.730 |\n", "+-----------+------------+------------+------------+------------+-------------+------------+------------+------------+\n", "generator scan ['dc673022'] (scan num: 3)\n" ] }, { "data": { "text/plain": [ "('dc673022-3c4a-4b78-8a22-72e9a3a15e9c',)" ] }, "execution_count": 61, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fourc.calc.engine.mode = 'constant_phi'\n", "my_constraints = {\n", " # add this one constraint\n", " \"phi\": Constraint(-180, 180, 0, False),\n", "}\n", "fourc.applyConstraints(my_constraints)\n", "fourc.showConstraints()\n", "print(\"\\n Solutions:\")\n", "print(fourc.forwardSolutionsTable((\n", " [0, 3.2, 0.5],\n", " [0, 2.8, 1.5],\n", ")))\n", "\n", "# VERY IMPORTANT, otherwise phi will stay at current position (-13.066 from previous scan)\n", "%mov fourc.phi 0\n", "\n", "RE(bp.scan([fourc], fourc.k, 3.2, 2.8, fourc.l, 0.5, 1.5, 11))" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3.8.2 64-bit (conda)", "language": "python", "name": "python38264bitcondaf8e76b08f7284c68a6b3de15f965a87a" }, "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.2-final" } }, "nbformat": 4, "nbformat_minor": 4 }