{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# UB matrix : Set directly\n", "\n", "$UB$ is the 3x3 orientation matrix used to transform coordinates between\n", "reciprocal space directions (of the crystal lattice planes) and the rotational\n", "axes of the diffractometer.\n", "\n", "It is possible to set $UB$ directly, as shown below.\n", "\n", "Alternatively, $UB$ can be [calculated](./demo_UB_calc.ipynb) from two non-parallel reflections, using\n", "the method of Busing and Levy (*Acta Cryst* **22** (1967) 457)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Quick example\n", "\n", "In **hklpy2**, the $UB$ matrix is a property of the *solver*. For a\n", "diffractometer object named `diffractometer`, set $UB$ such as:\n", "\n", "```py\n", "diffractometer.operator.solver.UB = [\n", " [0.5, 6.24, -0.5],\n", " [-0.5, -0.5, 6.24],\n", " [-6.24, -0.5, -0.5],\n", "]\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Create a diffractometer object\n", "\n", "First, create a diffractometer object that uses the `\"hkl_soleil\"` solver with\n", "the `\"hkl\"` computation engine. This solver provides support for many\n", "diffractometer geometries. This example will use the simulated 4-circle\n", "geometry from the solver's `\"E4CV\"`." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from hklpy2 import SimulatedE4CV\n", "\n", "diffractometer = SimulatedE4CV(name=\"diffractometer\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Defaults\n", "\n", "The diffractometer object starts with a default sample. The structure is cubic ($a=b=c$, 90 degree corners)." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Sample(name='sample', lattice=Lattice(a=1, system='cubic'))" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "diffractometer.sample" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This is the sample the solver will be using.\n", "\n", "$U$ is the orientation of the sample's crystal lattice as mounted on the diffractometer\n", "sample holder. The default is to assume $U=I$, where $I$ is the 3x3 identity\n", "matrix. \n", "\n", "$U$ is provided by the *solver*, in this case `\"hkl_soleil\"`. From the\n", "diffractometer object, the solver's default sample $U$ is accessed through a\n", "couple software layers:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]]" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "diffractometer.operator.solver.U" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The default $UB$ (without knowing how the crystal planes are oriented with\n", "respect to the diffractometer) of this cubic crystal is $(2\\pi/a) I$ where $I$\n", "is the 3x3 identity matrix and $a$ is the lattice parameter. Like $U$, this is\n", "provided by the *solver*, in this case `\"hkl_soleil\"`." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[[6.28318530718, -0.0, -0.0],\n", " [0.0, 6.28318530718, -0.0],\n", " [0.0, 0.0, 6.28318530718]]" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "diffractometer.operator.solver.UB" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "$UB$ is used to transform *(hkl)* to angles (method: `forward()`) and angles to\n", "*(hkl)* (method: `inverse()`). These transformations are fundamental to\n", "diffractometer operations, so they are provided to the diffractometer object\n", "directly.\n", "\n", "Here, we compute the angles for the (111) orientation:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "SimulatedE4CVRealPos(omega=60.000000002716, chi=35.264389682252, phi=44.999999999738, tth=120.000000005433)" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "diffractometer.forward(1, 1, 1)" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'bissector'" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "diffractometer.operator.solver.mode" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, convert *(hkl)* from these angles. Because we have truncated the numerical\n", "precision, we should not expect the precise values of (1.0, 1.0, 1.0)." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "SimulatedE4CVPseudoPos(h=-1.003252265133, k=0.993463529784, l=-1.003252265133)" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "diffractometer.inverse(-60, -35, 45, -120)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Set UB to new matrix\n", "\n", "The solver's $UB$ matrix can be re-defined by providing a new Python matrix.\n", "Here is a matrix for a cubic sample, oriented previously:\n", "\n", "```\n", "[[0.545455316412, -6.239788968842, -0.495930309978],\n", " [-0.547615630691, -0.543471652084, 6.235639164201],\n", " [-6.235463558747, -0.498103654451, -0.591011669061]]\n", "```" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[[0.5454561359, -6.239786441844, -0.49593056545],\n", " [-0.547617660448, -0.543473530637, 6.235639727849],\n", " [-6.235461050162, -0.498101063505, -0.591009918402]]" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "diffractometer.operator.solver.UB = [\n", " [0.545455316412, -6.239788968842, -0.495930309978],\n", " [-0.547615630691, -0.543471652084, 6.235639164201],\n", " [-6.235463558747, -0.498103654451, -0.591011669061]\n", "]\n", "diffractometer.operator.solver.UB" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[[0.086812079408, -0.993092986426, -0.078930242493],\n", " [-0.087156096879, -0.086496568538, 0.992432445262],\n", " [-0.992404896021, -0.079275872384, -0.094063055512]]" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "diffractometer.operator.solver.U" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Try it out\n", "\n", "First, compute $(hkl)$ from a set of *reals*." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "SimulatedE4CVPseudoPos(h=0.821953663396, k=0.989926119534, l=1.159500990198)" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "diffractometer.inverse(-60, -35, 45, -120)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There can be more than one solution to the `forward()` transformation; many combinations of *reals* can be represented by the same set of *pseudos*. A *solver*'s geometry provides one or *modes* which provide additional constraints or relationships to limit the `forward()` computation.\n", "\n", "The E4CV geometry's `\"bissector\"` mode adds this relationship: `tth = 2 * omega`." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'bissector'" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "diffractometer.operator.solver.mode" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Still, there can be more than one solution returned by the *solver*. In **hklpy2**, the default is to pick the first solution in the list returned from the *solver*, as shown next:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "diffractometer._forward_solution" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Show the first computed solution in `\"bissector\"` mode for the $(1,1,1)$ reflection:" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "SimulatedE4CVRealPos(omega=-59.999921375969, chi=-28.211225311916, phi=40.202361982144, tth=-119.999842751938)" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "diffractometer.forward(1, 1, 1)" ] } ], "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 }