1 #+TITLE: Welcome to hkl's @VERSION@ documentation!
2 #+AUTHOR: Picca Frédéric-Emmanuel
3 #+EMAIL: picca at synchrotron dash soleil dot fr
5 #+HTML_MATHJAX: path:"/usr/share/javascript/mathjax/MathJax.js"
6 #+STYLE: <style>table.center {margin-left:auto; margin- right:auto;}</style>
8 #+HTML_HEAD: <link rel="stylesheet" type="text/css" href="http://www.pirilampo.org/styles/readtheorg/css/htmlize.css"/>
9 #+HTML_HEAD: <link rel="stylesheet" type="text/css" href="http://www.pirilampo.org/styles/readtheorg/css/readtheorg.css"/>
11 #+HTML_HEAD: <script src="http://code.jquery.com/jquery-2.2.0.min.js"></script>
12 #+HTML_HEAD: <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
13 #+HTML_HEAD: <script type="text/javascript" src="http://www.pirilampo.org/styles/lib/js/jquery.stickytableheaders.js"></script>
14 #+HTML_HEAD: <script type="text/javascript" src="http://www.pirilampo.org/styles/readtheorg/js/readtheorg.js"></script>
17 The purpose of the library is to factorize single crystal
18 diffraction angles computation for different kind of diffractometer
19 geometries. It is used at the SOLEIL, Desy and Alba synchrotron with
20 the Tango control system to pilot diffractometers.
22 - mode computation (aka PseudoAxis)
23 - item for different diffractometer geometries.
24 - UB matrix computation.
25 - busing & Levy with 2 reflections
26 - simplex computation with more than 2 reflections using the GSL
28 - Eulerians angles to pre-orientate your sample.
29 - Crystal lattice refinement
30 - with more than 2 reflections you can select which parameter must
33 - psi, eulerians, q, ...
35 In all this document the next convention will be used to describe
36 the diffractometers geometries.
37 - right handed convention for all the angles.
38 - direct space orthogonal base.
39 - description of the diffractometer geometries is done with all
40 axes values set to zero.
44 A periodic crystal is the association of a pattern and a lattice. The
45 pattern is located at each points of the lattice node. Positions of
46 those nodes are given by:
49 R_{uvw}=u\cdot\vec{a}+v\cdot\vec{b}+w\cdot\vec{c}
52 $\vec{a}$, $\vec{b}$, $\vec{c}$ are the former vector of a base of the
53 space. =u=, =v=, =w= are integers. The pattern contain atoms
54 associated to each lattice node. the purpose of diffraction is to study
55 the interaction of this crystal (pattern+lattice) with X-rays.
57 #+CAPTION: Crystal direct lattice.
58 [[./figures/crystal.png]]
60 this lattice is defined by $\vec{a}$, $\vec{b}$, $\vec{c}$ vectors, and
61 the angles $\alpha$, $\beta$, $\gamma$. In general cases this lattice is
64 Nevertheless to compute the interaction of this real space lattice and
65 the X-Rays, it is convenient to define another lattice called reciprocal
66 lattice defined like this:
69 \vec{a}^{\star} & = & \tau\frac{\vec{b}\wedge\vec{c}}{\vec{a}\cdot(\vec{b}\wedge\vec{c})}\\
70 \vec{b}^{\star} & = & \tau\frac{\vec{c}\wedge\vec{a}}{\vec{b}\cdot(\vec{c}\wedge\vec{a})}\\
71 \vec{c}^{\star} & = & \tau\frac{\vec{a}\wedge\vec{b}}{\vec{c}\cdot(\vec{a}\wedge\vec{b})}
74 $\tau=2\pi$ or $\tau=1$ depending on the conventions.
76 It is then possible to define theses orthogonal properties:
79 \vec{a}^{\star}\cdot\vec{a}=\tau & \vec{b}^{\star}\cdot\vec{a}=0 & \vec{c}^{\star}\cdot\vec{a}=0\\
80 \vec{a}^{\star}\cdot\vec{b}=0 & \vec{b}^{\star}\cdot\vec{b}=\tau & \vec{c}^{\star}\cdot\vec{b}=0\\
81 \vec{a}^{\star}\cdot\vec{c}=0 & \vec{b}^{\star}\cdot\vec{c}=0 & \vec{c}^{\star}\cdot\vec{c}=\tau
84 This reciprocal space lattice allow to write in a simpler form the
85 interaction between the crystal and the X-Rays. We often only know about
86 $\vec{a}$, $\vec{b}$, $\vec{c}$ vectors and the angles $\alpha$,
87 $\beta$, $\gamma$. Using the previous equations reciprocal, we can
88 compute the reciprocal lattice this way:
92 a^{\star} & = & \frac{\sin\alpha}{aD}\\
93 b^{\star} & = & \frac{\sin\beta}{bD}\\
94 c^{\star} & = & \frac{\sin\gamma}{cD}
100 D=\sqrt{1-\cos^{2}\alpha-\cos^{2}\beta-\cos^{2}\gamma+2\cos\alpha\cos\beta\cos\gamma}
103 To compute the angles between the reciprocal space vectors, it is once
104 again possible to use the previous equations reciprocal to obtain the
105 sines and cosines of the angles $\alpha^\star$, $\beta^\star$ and
109 \cos\alpha^{\star}=\frac{\cos\beta\cos\gamma-\cos\alpha}{\sin\beta\sin\gamma} & \, & \sin\alpha^{\star}=\frac{D}{\sin\beta\sin\gamma} \\
110 \cos\beta^{\star}=\frac{\cos\gamma\cos\alpha-\cos\beta}{\sin\gamma\sin\alpha} & \, & \sin\beta^{\star}=\frac{D}{\sin\gamma\sin\alpha}\\
111 \cos\gamma^{\star}=\frac{\cos\alpha\cos\beta-\cos\gamma}{\sin\alpha\sin\beta} & \, & \sin\gamma^{\star}=\frac{D}{\sin\alpha\sin\beta}
114 the volume of the lattice can be compute this way:
123 V = \vec{a} \dot (\vec{b} \wedge \vec{c}) = \vec{b} \dot (\vec{c} \wedge \vec{a}) = \vec{c} \dot (\vec{a} \wedge \vec{b})
129 Let the incoming X-rays beam whose wave vector is $\vec{k_{i}}$,
130 $|k_{i}|=\tau/\lambda$ where $\lambda$ is the wavelength of the signal.
131 The $\vec{k_{d}}$ vector wavelength of the diffracted beam. There is
132 diffusion if the diffusion vector $\vec{q}$ can be expressed as follows:
135 \vec{q}=\vec{k_{d}}-\vec{k_{i}}=h.\vec{a}^{*}+k.\vec{b}^{*}+l.\vec{c}^{*}
138 where $(h,k,l)\in\mathbb{N}^{3}$ and $(h,k,l)\neq(0,0,0)$. Theses
139 indices $(h,k,l)$ are named Miller indices.
141 Another way of looking at things has been given by Bragg and that famous
145 n\lambda=2d\sin\theta
148 where $d$ is the inter-plan distance and $n \in \mathbb{N}$.
150 The diffusion occurs for an unique $\theta$ angle. Then we got
151 $\vec{q}$ perpendicular to the diffraction plan.
153 The Ewald construction allow to represent this diffraction in the
159 The quaternions will be used to describe the diffractometers geometries.
160 Theses quaternions can represent 3D rotations. There is different way to
161 describe then like complex numbers.
173 To compute the quaternion's norm, we can proceed like for complex
177 \lvert q \rvert = \sqrt{a{{}^2}+b{{}^2}+c{{}^2}+d{{}^2}}
183 q^{*}=[a,-\vec{u}]=a-bi-cj-dk
188 The difference with the complex number algebra is about
197 ~ & 1 & i & j & k \cr
198 1 & 1 & i & j & k \cr
199 i & i & -1 & k & -j \cr
200 j & j & -k & -1 & i \cr
205 The product of two quaternions can be express by the Grassman product
206 Grassman product. So for two quaternions $p$ and $q$:
209 q &= a+\vec{u} = a+bi+cj+dk\\
210 p &= t+\vec{v} = t+xi+yj+zk
216 pq = at - \vec{u} \cdot \vec{v} + a \vec{v} + t \vec{u} + \vec{v} \times \vec{u}
222 pq = (at - bx - cy - dz) + (bt + ax + cz - dy) i + (ct + ay + dx - bz) j + (dt + az + by - cx) k
227 L'ensemble des quaternions unitaires (leur norme est égale à 1) est le
228 groupe qui représente les rotations dans l'espace 3D. Si on a un vecteur
229 unitaire $\vec{u}$ et un angle de rotation $\theta$ alors le quaternion
230 $[\cos\frac{\theta}{2},\sin\frac{\theta}{2}\vec{u]}$ représente la
231 rotation de $\theta$ autour de l'axe $\vec{u}$ dans le sens
232 trigonométrique. Nous allons donc utiliser ces quaternions unitaires
233 pour représenter les mouvements du diffractomètre.
235 Alors que dans le plan 2D une simple multiplication entre un nombre
236 complex et le nombre $e^{i\theta}$ permet de calculer simplement la
237 rotation d'angle $\theta$ autour de l'origine, dans l'espace 3D
238 l'expression équivalente est:
244 où $q$ est le quaternion de norme 1 représentant la rotation dans
245 l'espace et $z$ le quaternion représentant le vecteur qui subit la
246 rotation (sa partie réelle est nulle).
248 Dans le cas des quaternions de norme 1, il est très facile de calculer
249 $q^{-1}$. En effet l'inverse d'une rotation d'angle $\theta$ est la
250 rotation d'angle $-\theta$. On a donc directement:
253 q^{-1}=[\cos\frac{-\theta}{2},\sin\frac{-\theta}{2}\vec{u}]=[\cos\frac{\theta}{2},-\sin\frac{\theta}{2}\vec{u}]=q^{*}
256 Le passage aux matrices de rotation se fait par la formule suivante
261 a{{}^2}+b{{}^2}-c{{}^2}-d{{}^2} & 2bc-2ad & 2ac+2bd\\
262 2ad+2bc & a{{}^2}-b{{}^2}+c{{}^2}-d{{}^2} & 2cd-2ab\\
263 2bd-2ac & 2ab+2cd & a{{}^2}-b{{}^2}-c{{}^2}+d{{}^2}
267 La composition de rotation se fait simplement en multipliant les
268 quaternions entre eux. Si l'on à $q$
270 ** Modes de fonctionnement
271 ** Equations fondamentales
273 Le problème que nous devons résoudre est de calculer pour une famille de
274 plan $(h,k,l)$ donné, les angles de rotation du diffractomètre qui
275 permettent de le mettre en condition de diffraction. Il faut donc
276 exprimer les relations mathématiques qui lient les différents angles
277 entre eux lorsque la condition de Bragg est vérifiée. L'équation
278 fondamentale est la suivante:
281 \left(\prod_{i}S_{i}\right)\cdot U\cdot B\cdot\vec{h} & =\left(\prod_{j}D_{j}-I\right)\cdot\vec{k_{i}}\\
282 R\cdot U\cdot B\cdot\vec{h} & =\vec{Q}
285 ou $\vec{h}$ est le vecteur $(h,k,l)$, $\vec{k_{i}}$ est le vecteur
286 incident, $S_{i}$ les matrices de rotations des mouvements liés à
287 l'échantillon, $D_{j}$ les matrices de rotation des mouvements liés au
288 détecteur, $I$ la matrice identité, $U$ la matrice d'orientation du
289 cristal par rapport au repère de l'axe sur lequel ce dernier est monté
290 et $B$ la matrice de passage d'un repère non orthonormé ( celui du
291 crystal réciproque) à un repère orthonormé.
295 Si l'on connaît les paramètres cristallins du cristal étudié, il est
296 très simple de calculer $B$:
301 a^{\star} & b^{\star}\cos\gamma^{\star} & c^{\star}\cos\beta^{\star}\\
302 0 & b^{\star}\sin\gamma^{\star} & -c^{\star}\sin\beta^{\star}\cos\alpha\\
309 Il existe plusieurs façons de calculer $U$. Busing et Levy en a proposé
310 plusieurs. Nous allons présenter celle qui nécessite la mesure de
311 seulement deux réflections ainsi que la connaissance des paramètres
312 cristallins. Cette façon de calculer la matrice d'orientation $U$, peut
313 être généralisée à n'importe quel diffractomètre pour peu que la
314 description des axes de rotation permette d'obtenir la matrice de
315 rotation de la machine $R$ et le vecteur de diffusion $\vec{Q}$.
317 Il est également possible de calculer $U$ sans la connaîssance des
318 paramètres cristallins. il faut alors faire un affinement des
319 paramètres. Cela revient à minimiser une fonction. Nous allons utiliser
320 la méthode du simplex pour trouver ce minimum et donc ajuster l'ensemble
321 des paramètres cristallins ainsi que la matrice d'orientation.
323 *** Algorithme de Busing Levy
325 L'idée est de se placer dans le repère de l'axe sur lequel est monté
326 l'échantillon. On mesure deux réflections $(\vec{h}_{1},\vec{h}_{2})$
327 ainsi que leurs angles associés. Cela nous permet de calculer $R$ et
328 $\vec{Q}$ pour chacune de ces reflections. nous avons alors ce système:
331 U\cdot B\cdot\vec{h}_{1} & = & \tilde{R}_{1}\cdot\vec{Q}_{1}\\
332 U\cdot B\cdot\vec{h}_{2} & = & \tilde{R}_{2}\cdot\vec{Q}_{2}
335 De façon à calculer facilement $U$, il est intéressant de définir deux
336 trièdres orthonormé $T_{\vec{h}}$ et $T_{\vec{Q}}$ à partir des vecteurs
337 $(B\vec{h}_{1},B\vec{h}_{2})$ et
338 $(\tilde{R}_{1}\vec{Q}_{1},\tilde{R}_{2}\vec{Q}_{2})$. On a alors très
342 U \cdot T_{\vec{h}} = T_{\vec{Q}}
348 U = T_{\vec{Q}} \cdot \tilde{T}_{\vec{h}}
351 *** Affinement par la méthode du simplex
353 Dans ce cas nous ne connaissons pas la matrice $B$, il faut donc mesurer
354 plus que deux réflections pour ajuster les 9 paramètres. Six paramètres
355 pour le crystal et trois pour la matrice d'orientation $U$. Les trois
356 paramètres qui permennt de representer $U$ sont en fait les angles
357 d'euler. il faut donc être en mesure de passer d'une représentation
358 eulérien à cette matrice :math::U et réciproquement.
361 U = X \cdot Y \cdot Z
364 où $X$ est la matrice rotation suivant l'axe Ox et le premier angle
365 d'Euler, $Y$ la matrice de rotation suivant l'axe Oy et le deuxième
366 angle d'Euler et $Z$ la matrice du troisième angle d'Euler pour l'axe
369 #+ATTR_HTML: class="center"
371 | <10> | <10> | <10> |
372 | $\begin{bmatrix} 1 & 0 & 0\\ 0 & A & -B\\ 0 & B & A \end{bmatrix}$ | $\begin{bmatrix}C & 0 & D\\0 & 1 & 0\\-D & 0 & C\end{bmatrix}$ | $\begin{bmatrix}E & -F & 0\\F & E & 0\\0 & 0 & 1\end{bmatrix}$ |
380 BDE+AF & -BDF+AE & -BC\\
381 -ADE+BF & ADF+BE & AC
385 Il est donc facile de passer des angles d'Euler à la matrice
388 Il faut maintenant faire la transformation inverse de la matrice $U$
389 vers les angles d'euler.
392 This section describe the calculations done by the library for the
393 different kind of pseudo axes.
396 The hkl library use the gsl library in order to find the first
398 *** Multiplication of the solutions.
399 Once we have got the first solution different strategies are
400 applyed in order to generate more solutions.
401 **** Geometry Multiplication
402 For kappa diffractometers, once you have one solution it is
403 possible to générate another one using a property of this
404 geometry. (Left arm and right arm).
405 *** Restrains of the Solutions
406 We apply then some constrains to reduce these solutions to only a
407 bunch of acceptable ones. Usualy we take the axis range into
409 ** Eulerians to Kappa angles
414 \kappa_\omega & = & \omega - p + \frac{\pi}{2} \\
415 \kappa & = & 2 \arcsin\left(\frac{\sin\frac{\chi}{2}}{\sin\alpha}\right) \\
416 \kappa_\phi & = & \phi - p - \frac{\pi}{2}
422 \kappa_\omega & = & \omega - p - \frac{\pi}{2} \\
423 \kappa & = & -2 \arcsin\left(\frac{\sin\frac{\chi}{2}}{\sin\alpha}\right) \\
424 \kappa_\phi & = & \phi - p + \frac{\pi}{2}
430 p = \arcsin\left(\frac{\tan\frac{\chi}{2}}{\tan\alpha}\right)
433 and $\alpha$ is the angle of the kappa axis with the $\vec{y}$ axis.
435 ** Kappa to Eulerians angles
440 \omega & = & \kappa_\omega + p - \frac{\pi}{2} \\
441 \chi & = & 2 \arcsin\left(\sin\frac{\kappa}{2} \sin\alpha\right) \\
442 \phi & = & \kappa_\phi + p + \frac{\pi}{2}
448 \omega & = & \kappa_\omega + p + \frac{\pi}{2} \\
449 \chi & = & -2 \arcsin\left(\sin\frac{\kappa}{2} \sin\alpha\right) \\
450 \phi & = & \kappa_\phi + p - \frac{\pi}{2}
456 p = \arctan\left(\tan\frac{\kappa}{2} \cos\alpha\right)
459 #+CAPTION: $\omega = 0$, $\chi = 0$, $\phi = 0$, 1st solution
460 [[./figures/e2k_1.png]]
462 #+CAPTION: $\omega = 0$, $\chi = 0$, $\phi = 0$, 2nd solution
463 [[./figures/e2k_2.png]]
465 #+CAPTION: $\omega = 0$, $\chi = 90$, $\phi = 0$, 1st solution
466 [[./figures/e2k_3.png]]
468 #+CAPTION: $\omega = 0$, $\chi = 90$, $\phi = 0$, 2nd solution
469 [[./figures/e2k_4.png]]
472 [[./figures/qper_qpar.png]]
474 this pseudo axis engine compute the perpendicular
475 ($\left|\left|\vec{Q_\text{per}}\right|\right|$) and parallel
476 ($\left|\left|\vec{Q_\text{par}}\right|\right|$) contribution of
477 $\vec{Q}$ relatively to the surface of the sample defined by the
481 \vec{q} & = & \vec{k_\text{f}} - \vec{k_\text{i}} \\
482 \vec{q} & = & \vec{q_\text{per}} + \vec{q_\text{par}} \\
483 \vec{q_\text{per}} & = & \frac{\vec{q} \cdot \vec{n}}{\left|\left|\vec{n}\right|\right|} \frac{\vec{n}}{\left|\left|\vec{n}\right|\right|}
489 This section is automatically generating by introspecting the hkl library.
492 #+BEGIN_SRC python :exports results :results value raw
493 from gi.repository import Hkl
496 return ["\"*" + _ + "*\"" for _ in l]
498 def level(indent=1, s=None):
499 return " "*indent + s
501 diffractometers = Hkl.factories().iterkeys()
504 for diffractometer in sorted(diffractometers):
505 factory = Hkl.factories()[diffractometer]
506 output += "** " + diffractometer + "\n\n"
507 detector = Hkl.Detector.factory_new(Hkl.DetectorType(0))
508 sample = Hkl.Sample.new("toto")
509 geometry = factory.create_new_geometry()
510 engines = factory.create_new_engine_list()
511 engines.init(geometry, detector, sample)
513 output += "*** Axes: \n"
514 for axis in geometry.axis_names_get():
515 axis_v = geometry.axis_get(axis).axis_v_get().data
516 output += level(2, "+ \"*" + axis + "*\": rotation around the *" + repr(axis_v) + "* axis\n")
518 output += "*** Engines: \n"
519 for engine in engines.engines_get():
520 output += "**** \"*" + engine.name_get() + "*\":\n\n"
521 output += level(3, "* pseudo axes:\n")
522 for pseudo in engine.pseudo_axis_names_get():
523 p = engine.pseudo_axis_get(pseudo)
524 description = p.description_get()
525 output += level(4, "* \"*" + pseudo + "*\" : " + description + '\n\n')
527 for mode in engine.modes_names_get():
528 output += level(3, "+ mode: \"*" + mode + "*\"\n")
529 engine.current_mode_set(mode)
530 axes_r = engine.axis_names_get(Hkl.EngineAxisNamesGet.READ)
531 axes_w = engine.axis_names_get(Hkl.EngineAxisNamesGet.WRITE)
532 output += level(4, "+ axes (read) : " + ", ".join(bold(axes_r)) + "\n")
533 output += level(4, "+ axes (write): " + ", ".join(bold(axes_w)) + "\n")
534 parameters = engine.parameters_names_get()
535 output += level(4, "+ parameters: ")
538 for parameter in parameters:
539 p = engine.parameter_get(parameter)
540 description = p.description_get()
541 value = p.value_get(Hkl.UnitEnum.USER)
542 output += level(5, "+ *" + parameter + "* [" + str(value) + "]: " + description + "\n")
544 output += "No parameter\n"
551 To get hkl, you can download the last stable version from sourceforge or
552 if you want the latest development version use
553 [[http://git.or.cz/][git]] or
554 [[http://code.google.com/p/msysgit/downloads/list][msysgit]] on windows
558 git clone git://repo.or.cz/hkl.git
564 git clone http://repo.or.cz/r/hkl.git (slower)
567 then checkout the next branch like this:
571 git checkout -b next origin/next
576 To build hkl you need [[http://www.python.org][Python 2.3+]] the
577 [[http://www.gnu.org/software/gsl/][GNU Scientific Library 1.12]] and
578 [[https://developer.gnome.org/glib/][GLib-2.0 >= 2.3.4]]:
581 ./configure --disable-gui
586 you can also build a GUI interfaces which use
587 [[http://www.gtk.org][gtk]]:
595 optionnaly you can build an experimental /libhkl3d/ library (no public
596 API for now) which is used by the GUI to display and compute
597 diffractometer collisions (only the /K6C/ model). To build it you need
598 also [[https://projects.gnome.org/gtkglext/][gtkglext]] and
599 [[http://bulletphysics.org/wordpress/][bullet 2.82]]:
602 ./configure --enable-hkl3d
607 if you want to work on the documentation you need the extra
609 - [[http://www.gtk.org/gtk-doc/][gtk-doc]] for the api
610 - [[http://sphinx.pocoo.org/][sphinx]] for the html and latex doc.
611 - [[http://asymptote.sourceforge.net/][asymptote]] for the figures
612 - [[http://www.gnu.org/software/emacs/][emacs]] the well known editor
613 - [[https://github.com/emacsmirror/htmlize][htmlize]] used to highlight the source code
614 - [[http://orgmode.org][org-mode]] litteral programming
616 On Debian/Ubuntu you just need to install
619 sudo apt-get install emacs dvipng emacs-goodies-el org-mode
623 ./configure --enable-gtk-doc
628 nevertheless if you do not want to build the documentation you can do:
631 ./configure --disable-hkl-doc
637 You can find the bug tracker here
638 [[https://bugs.debian.org/cgi-bin/pkgreport.cgi?repeatmerged=no&src=hkl][libhkl]]
648 You just need to send an [[mailto:submit@bugs.debian.org?subject=%20My%20problem%20with%20hkl...&body=Package:%20hkl%0AVersion:%20@VERSION@%0A%0AI%20found%20this%20problem%20in%20hkl][email]]
650 *** Providing patches
652 you can send your patch to [[mailto:picca@synchrotron-soleil.fr][Picca Frédéric-Emmanuel]] using =git=
654 Here a minimalist example of the workflow to prepare and send
655 patches for integration into the hkl library. Suppose you wan to
656 add a new feature, you need first to create a new branch from the
660 git checkout -b my-next next
675 now that your new feature is ready, you can send by email your
676 work using =git format-patch= for review:
679 git format-patch origin/next
682 which will generate a bunch of ~0001\_xxx~, ~0002\_xxx~,
685 Then you can configure =git send-email= in order to send the
689 git config sendemail.to "picca@synchrotron-soleil.fr"
692 and send then with this command:
695 git send-email 0001-xxx.patch, 0002-xxx.patch, ...
698 If it does not work you can use your usually email software and
699 send these generated patches to the [[mailto:picca@synchrotron-soleil.fr][author]].
702 *** Add a diffractometer
703 To add a new diffractometer, you just need to copy the
704 ~hkl/hkl-engine-template.c~ into
705 ~hkl/hkl-engine-INSTITUT-BEAMLINE-INSTRUMENT.c~ where you replace
706 the upper case with the appropriate values.
708 The template file is compiled during the build process to ensure
709 that it is always valid.
711 Then you just need to follow the instruction found in the
712 template. If you need some precision about the process, do not
713 hesitate to contact the main author.
715 do not forgot also to add this new file into ~hkl/Makefile.am~
716 with other diffractometers in the hkl_c_sources variable (please
717 keep the alphabetic order).
718 *** Work on the documentation
719 The documentation system is written with [[http://orgmode.org/][org-mode]], and the [[http://orgmode.org/worg/org-contrib/babel/][babel]]
720 extension which allow to introspect the library and generate part
721 of the doc using the hkl library. Python code is executed during
722 the build process to generate the Diffractometer section of the
723 documentation. To work on the doc and test the embedded python
724 code it is necessary to setup a few environment variables and
725 start emacs with the right LD_LIBRARY_PATH. In order to simplify
726 the process a make target was written. You just need to type:
731 and start to contribute.
733 If you do not have emacs, you can nevertheless contribute by
734 editing the ~Documentation/hkl.org.in~ file which is text only.
736 The most expected contributions are for now:
737 * english correctness
741 The hkl library use the gobject-introspection to provide automatic
742 binding for a few languages.
746 You can test the binding directly from the source directory with
747 these commandes if ipython is installed.
754 then you have the Hkl module preloaded into the ipython environment.
758 has you can see there is 4 available solutions.
760 let's compute an hkl trajectory and select the first solution.
762 if we look at the 3 other solutions we can see that there is a problem
763 of continuity at the begining of the trajectory.
765 hey what's happend with theses solutions ! let's look closely to real
766 numbers. the last column is the distance to the diffractometer current
767 position. This distance is for now express like this:
769 $\sum_{axes} \left|\text{current position} - \text{target position}\right|$
772 [0.0, 119.99999999999999, 0.0, -90.0, 0.0, 59.99999999999999] 0.0
773 [0.0, -119.99999999999999, 0.0, -90.0, 0.0, -59.99999999999999] 6.28318530718
774 [0.0, -60.00000000000005, 0.0, 90.0, 0.0, 59.99999999999999] 6.28318530718
775 [0.0, 60.00000000000001, 0.0, 90.0, 0.0, -59.99999999999999] 6.28318530718
777 [0.0, 117.7665607657826, 7.456826294401656, -92.39856410531434, 0.0, 60.33024982425957] 0.216753826612
778 [0.0, -57.436310940366894, -7.456826294401656, 92.39856418853617, 0.0, 60.33024982425957] 6.41621345188
779 [0.0, 62.2334392342174, -7.456826294401656, 92.39856410531434, 0.0, -60.33024982425957] 6.42197739723
780 [0.0, -122.5636890596331, 7.456826294401656, -92.3985641885362, 0.0, -60.33024982425957] 6.50570308205
782 [0.0, 115.89125602137928, 14.781064139466098, -94.7660423112577, 0.0, 61.314597086440706] 0.219062698235
783 [0.0, -125.42334103772737, 14.781064139466098, -94.7660427050904, 0.0, -61.314597086440706] 6.53671995288
784 [0.0, -54.57665896227262, -14.781064139466098, 94.76604270509038, 0.0, 61.314597086440706] 6.67989976726
785 [0.0, 64.10874397862072, -14.781064139466098, 94.7660423112577, 0.0, -61.314597086440706] 6.71437170098
787 [0.0, 114.39338605351007, 21.85448296702796, -97.074145033719, 0.0, 62.93506298693471] 0.218163667981
788 [0.0, -128.54167683157993, 21.85448296702796, -97.07414574435087, 0.0, -62.93506298693471] 6.59846359365
789 [0.0, -51.45832316842005, -21.85448296702796, 97.07414574435087, 0.0, 62.93506298693471] 6.93673746356
790 [0.0, 65.60661394648993, -21.85448296702796, 97.074145033719, 0.0, -62.93506298693471] 7.03385205725
792 [0.0, 113.28316795475283, 28.583837575232764, -99.29953499008337, 0.0, 65.16540747008955] 0.21459359225
793 [0.0, -131.88223933078322, 28.583837575232764, -99.29953638594702, 0.0, -65.16540747008955] 6.69038531388
794 [0.0, -48.11776066921677, -28.583837575232764, 99.29953638594702, 0.0, 65.16540747008955] 7.18296350386
795 [0.0, 66.71683204524717, -28.583837575232764, 99.29953499008337, 0.0, -65.16540747008955] 7.37556986959
797 [0.0, 112.56286877075006, 34.90573305321372, -101.42496979586187, 0.0, 67.97568017857415] 0.209053830457
798 [0.0, -135.4128111996365, 34.90573305321372, -101.42497263302461, 0.0, -67.97568017857415] 6.81174779784
799 [0.0, -44.58718880036348, -34.90573305321372, 101.4249726330246, 0.0, 67.97568017857415] 7.41581162393
800 [0.0, 67.43713122924994, -34.90573305321372, 101.42496979586187, 0.0, -67.97568017857415] 7.7353201851
802 [0.0, 112.2291126083182, 40.78594007247402, -103.43941832567457, 0.0, 71.33706722449408] 0.202280147961
803 [0.0, -139.10795451001587, 40.78594007247402, -103.43942357602316, 0.0, -71.33706722449408] 6.96173845391
804 [0.0, -40.89204548998411, -40.78594007247402, 103.43942357602312, 0.0, 71.33706722449408] 7.63358787543
805 [0.0, 67.7708873916818, -40.78594007247402, 103.43941832567457, 0.0, -71.33706722449408] 8.10986069093
807 [0.0, 112.27578927291766, 46.214916130901734, -105.33741042812996, 0.0, 75.22640762217479] 0.196576175748
808 [0.0, -142.95061850160724, 46.214916130901734, -105.3374188005596, 0.0, -75.22640762217479] 7.13962155618
809 [0.0, -37.04938149839278, -46.214916130901734, 105.33741880055959, 0.0, 75.22640762217479] 7.83557762281
810 [0.0, 67.72421072708234, -46.214916130901734, 105.33741042812996, 0.0, -75.22640762217479] 8.49706672677
812 [0.0, 112.697137434232, 51.201667684695856, -107.11797492933192, 0.0, 79.63023536264535] 0.202327153157
813 [0.0, -146.9330984641471, 51.201667684695856, -107.11798610058318, 0.0, -79.63023536264535] 7.34491897177
814 [0.0, -33.0669015358529, -51.201667684695856, 107.11798610058317, 0.0, 79.63023536264535] 8.02185610877
815 [0.0, 67.30286256576798, -51.201667684695856, 107.11797492933192, 0.0, -79.63023536264535] 8.89597005568
817 [0.0, 113.49085964586432, 55.76762791023837, -108.78347437395287, 0.0, 84.54867879242364] 0.208455586312
818 [0.0, -151.05782007465257, 55.76762791023837, -108.78348605483542, 0.0, -84.54867879242364] 7.57761473366
819 [0.0, -28.942179925347414, -55.76762791023837, 108.78348605483538, 0.0, 84.54867879242364] 8.19307323084
820 [0.0, 66.50914035413568, -55.76762791023837, 108.78347437395287, 0.0, -84.54867879242364] 9.30675279514
822 [0.0, 114.6614608037443, 59.941489465646214, -110.3385360479293, 0.0, 90.00000081324956] 0.215562935229
823 [0.0, -155.33854118146962, 59.941489465646214, -110.33854432979601, 0.0, -89.99999918675044] 7.83839602383
824 [0.0, -24.661458818530395, -59.941489465646214, 110.33854432979601, 0.0, 90.00000081324956] 8.3502621071
825 [0.0, 65.3385391962557, -59.941489465646214, 110.3385360479293, 0.0, -89.99999918675044] 9.7307712883
828 as you can see for the first point of the trajectory, the 2nd, 3rd and
829 4th solutions have identical distances to the current position of the
830 diffractometer so they are un-ordered:
833 [0.0, 119.99999999999999, 0.0, -90.0, 0.0, 59.99999999999999] 0.0
834 [0.0, -119.99999999999999, 0.0, -90.0, 0.0, -59.99999999999999] 6.28318530718
835 [0.0, -60.00000000000005, 0.0, 90.0, 0.0, 59.99999999999999] 6.28318530718
836 [0.0, 60.00000000000001, 0.0, 90.0, 0.0, -59.99999999999999] 6.28318530718
839 then the problem arise with the second and third solution. you can see a
840 sort of reorganisation of the solution. 2 -> 3, 3 -> 4 and 4 -> 2 then
841 the order will stick unchanged until the end of the trajectory. this is
842 because the distance is computed relatively to the current position of
846 [0.0, 117.7665607657826, 7.456826294401656, -92.39856410531434, 0.0, 60.33024982425957] 0.216753826612
847 [0.0, -57.436310940366894, -7.456826294401656, 92.39856418853617, 0.0, 60.33024982425957] 6.41621345188
848 [0.0, 62.2334392342174, -7.456826294401656, 92.39856410531434, 0.0, -60.33024982425957] 6.42197739723
849 [0.0, -122.5636890596331, 7.456826294401656, -92.3985641885362, 0.0, -60.33024982425957] 6.50570308205
851 [0.0, 115.89125602137928, 14.781064139466098, -94.7660423112577, 0.0, 61.314597086440706] 0.219062698235
852 [0.0, -125.42334103772737, 14.781064139466098, -94.7660427050904, 0.0, -61.314597086440706] 6.53671995288
853 [0.0, -54.57665896227262, -14.781064139466098, 94.76604270509038, 0.0, 61.314597086440706] 6.67989976726
854 [0.0, 64.10874397862072, -14.781064139466098, 94.7660423112577, 0.0, -61.314597086440706] 6.71437170098
860 when you compute a trajectory, start from a valid position (the
861 starting point must be the real first point of your trajectory) then
862 use only the closest solution for the next points of the trajectory.
863 (first solution of the geometries list)
867 *** DONE Fix for multiarch (headers) <2016-05-04 mer.>
868 The =ccan_config.h= generated file is arch specific. It is then
869 necessary to install this file under /usr/include/<triplet> on
870 Debian like systems. This way it will be possible to co-installa
871 32/64 bit version of hkl, or to do cross-compilation (arm on
873 ** 5.0.0.2080 <2016-04-27 mer.>
874 *** DONE =HklEngine= <2016-01-20 mer.>
875 emergence_fixed for the SOLEIL SIX MED 2+2 geometry.
876 *** DONE =HklVector= <2016-02-09 mar.>
877 The hkl_vector_init method is now public.
878 *** DONE =HklParameter= <2016-02-25 Thu>
879 at the end of the computation all solutions are filtered in order
880 to check that they are valid (min < value < range). BUT for a
881 rotation axis this check was instead (min < value % 2pi < max).
882 *** DONE =HklGeometry= <2016-04-20 mer.>
883 Add hkl_geometry_[sample/detector]_rotation_get method. It is now
884 possible to get the sample or the detector rotation expressed as a
886 #+BEGIN_SRC python :export code
887 qr = geometry.sample_rotation_get(sample)
888 qd = geometry.detector_rotation_get(detector)
890 *** DONE =HklQuaternion= <2016-04-20 mer.>
891 Add hkl_quaternion_to_matrix in order to convert a =HklQuaternion=
892 into a =HklMatrix=. Then you just need to convert this HklMatrix
893 into a numpy array when used from the python binding
894 #+BEGIN_SRC python :export code
895 def hkl_matrix_to_numpy(m):
899 M[i, j] = m.get(i, j)
903 M = hkl_matrix_to_numpy(q.to_matrix())
905 *** DONE Soleil Sirius Turret <2016-04-26 mar.>
906 Add the =basepitch= axis which rotate around $\vec{y}$ in mrad.
907 ** 4.99.99.1955 <2015-07-15 mer.>
908 Add the ccan_config.h public header. This header is generated with
909 the ccan configurator program.
910 ** 4.99.99.1950 <2015-07-07 mar.>
911 Fix an FTBFS observed on the sparc arch
912 ** 4.99.99.1949 <2015-07-03 ven.>
913 *** DONE =HklInterval= <2015-07-03 ven.>
914 =hkl_interval_cmp= was wrong. Now the comparison is done between
915 =HKL_EPSILON= and the distance between minimum and maximum. This
916 problem was triggered first on ppc64el architecture.
917 *** DONE PATH_MAX <2015-07-03 ven.>
918 Replace getcwd called by get_current_dir_path instead in order to
919 avoid PATH_MAX which is not available on hurd.
920 ** 4.99.99.1946 <2015-06-30 mar.>
922 **** "emergence" <2015-06-22 lun.>
923 Add a new emergence engine which contain only one pseudo axis.
924 + =emergence= the outgoing beam emergence from the sample's surface.
925 + =azimuth= the sample's surface azimuth.
926 ** 4.99.99.1940 <2015-05-04 lun.>
927 *** DONE =HklLattice= add an =hkl_lattice_volume_get=
929 volume = hkl_lattice_volume_get(lattice);
932 **** "nrj, sample, ... dependencies" <2015-03-24 mar.>
933 Add the =hkl_engine_dependencies_get= method which return if the
934 =HklEngine= depends of the axes, the energy, or the sample. the
935 possible values are stored in the =HklEngineDependencies= enum.
938 dependencies = hkl_engine_dependencies_get(engine);
939 if (dependencies & HKL_ENGINE_DEPENDENCIES_ENERGY) {
942 if (dependencies & HKL_ENGINE_DEPENDENCIES_SAMPLE) {
947 **** "tth2" <2015-04-03 ven>
948 Add a new hkl engine which contain two pseudo axes.
949 + =tth= two times the diffraction angle $\theta$
950 + =alpha= the azimuth of q in the zOy plan.
951 **** "incidence" <2015-04-21 mar.>
952 Add a new incidence engine which contain only one pseudo axis.
953 + =incidence= the incoming beam incidence on the sample surface.
954 + =azimuth= the sample surface azimuth.
955 **** =hkl_engine_parameter_set= <2015-05-04 lun.>
956 Fix a bug and expose the method in the binding.
958 - use #define AXIS "axis_name" in all the code to set the axes
959 names at only one place. <2015-04-23 jeu.>
960 *** DONE =HklLattice= expose in the binding the _x_get/set methods <2015-03-24 mar.>
961 Now you can use hkl_lattice_x_get where x=a, b, c, alpha, beta,
962 gamma in the bindings.
963 #+BEGIN_SRC python :export code
967 *** DONE =HklSampleReflection= expose the flag_get/set and geometry_get/set method <2015-03-24 mar.>
968 It is now possible to change the geometry stored in a reflection
970 #+BEGIN_SRC python :export code
971 flag = reflection.flag_get()
972 reflection.flag_set(flag)
974 geometry = reflection.geometry_get()
975 geometry.axes_values_set([omega, chi, phi, ...])
976 reflection.geometry_set(geometry)
980 *** TODO [#A] =HklEngine= *q/q2*
981 Fix all these engines... This engine takes into account only the
982 *gamma* and *delta* axes. so diffractometers with 3 axes for the
983 detector are wrong. It would be nice to take into account all the
984 detector holder AND the position of the detecteor on the
985 diffractometer arms (for now the detector is always on the last
987 *** TODO [#A] HklSource
988 Create a parameter for the wavelength. This is just internally for
989 the futur trajectory system, so no need to change the signature of
990 hkl_geometry_vawelength get/set
991 *** TODO [0/2] PetraIII
992 **** TODO computation problem
995 Using the prruptest.txt ubmatrix I see that the value of psi is
996 offset by 45 degrees. I expect it to be 0 degrees when azimuth
997 reference vector is 0 0 1 that is along the beam. See below
998 thereturned numbers. This might have to do with the definition of
999 the beam axis in the controller. Otherwise now when I change
1000 reference vector by 90 degrees the computed value is changed by
1001 90 degrees. That is a progress. Can you contact Frederic and ask
1009 p09/door/haspp09.01 [9]: setaz 1 0 0
1011 p09/door/haspp09.01 [10]: wh
1015 Mode: psi_constant_vertical
1017 H K L = 0.00000 3.00605 -0.00000
1018 Ref = 1.00000 0.00000 0.00000
1019 Azimuth (Psi - calculated) = -45.00005
1020 Azimuth (Psi - set) = 0.00000
1021 Wavelength = 2.07957
1023 Delta Theta Chi Phi Mu Gamma
1024 45.77575 22.88783 90.00000 182.85400 0.00000 -0.00000
1026 p09/door/haspp09.01 [11]: setaz 0 0 1
1028 p09/door/haspp09.01 [12]: wh
1032 Mode: psi_constant_vertical
1034 H K L = 0.00000 3.00605 -0.00000
1035 Ref = 0.00000 0.00000 1.00000
1036 Azimuth (Psi - calculated) = -135.00005
1037 Azimuth (Psi - set) = 0.00000
1038 Wavelength = 2.07957
1040 Delta Theta Chi Phi Mu Gamma
1041 45.77575 22.88783 90.00000 182.85400 0.00000 -0.00000
1045 Azimuth (Psi - calculated) is the value of the pseudomotor psi.
1046 Azimuth (Psi - set) is the value set in the parameter psi of the current mode.
1050 This is the UB matrix:
1056 Created at 2015-01-21 12:35
1060 Wavelength 2.07957463938
1062 A 8.03656 B 8.03656 C 8.03656
1063 Alpha 90.0 Beta 90.0 Gamma 90.0
1065 R0 0 0.0 1.0 0.0 0 1 0.0 14.8979 90.0 182.854 0.0 29.7959
1066 R1 1 1.0 0.0 1.0 0 1 0.0 14.8979 0.0 182.854 0.0 29.7959
1068 Mode psi_constant_vertical
1072 U00 -0.580 U01 0.000 U02 0.525
1073 U10 0.000 U11 0.782 U12 -0.000
1074 U20 -0.525 U21 -0.000 U22 -0.580
1076 Ux 179.999952315 Uy 42.14605 Uz -179.999932647
1078 SaveDirectory /home/p09user/crystals/
1080 **** TODO another question
1081 J'ai un probleme avec la position que le controlleur calcule avec la
1082 matrice UB que nous t'avons envoye.
1083 See sequence of emails echanges avec Teresa.
1085 >>>> I am at 0 3.00605 0 with phi -182 and psi calculated is -135
1086 >>>> When I freeze psi at -135 and type ca 0 3.00605 0 the controller
1087 >> should return to me the positions at which I am. But no he tells me
1089 >> have to go to 178 degrees in phi that is turning by 360 degrees.
1091 Est-ce un probleme avec la trajectoire selectionnee ?
1092 Est-ce qu'il est possible de definir des cut-points comme dans spec avec
1094 *** TODO [2/4] HklParameter
1095 - [X] method to use min/max to check for the validity
1096 - [X] add a method to get the axis_v and quaternion of the HklAxis
1097 this method will return NULL if this is not relevant.
1098 hkl_parameter_axis_v_get and hkl_parameter_quaternion_get
1099 - [ ] degenerated an axis is degenerated if its position have no
1100 effect on the HklPseudoAxis calculus. Add a degenerated member
1101 to the axis. that way it would be possible to check a posteriori
1102 for this degenerescencence.
1103 - [ ] Add a description for each parameters.
1104 *** TODO This will help for the documentation and the gui.
1105 *** TODO HklGeometryList different method to help select a solution.
1106 this select solution can depend on the geometry
1107 for example the kappa axis must be in one side of the plane.
1108 *** TODO add a fit on the Hklaxis offsets.
1109 *** TODO API to put a detector and a sample on the Geometry.
1111 **** TODO [#B] unit test: hkl_sample_affine.
1113 lattice=1.540000;1.540000;1.540000;90.000000;90.000000;90.000000;0;0;0;0;0;0
1114 uxuyuz=0.000000;0.000000;0.000000
1115 reflection=1.540000;0.159010;1.256718;0.796660;1;0.000000;0.000000;0.000000;0.000000;0.000000
1116 reflection=1.540000;0.206208;0.342357;-0.080346;1;0.000000;0.000000;0.000000;0.000000;0.000000
1117 reflection=1.540000;0.206208;0.342357;-0.080346;1;0.000000;0.000000;0.000000;0.000000;0.000000
1119 A, B, C, Alpha, Beta, Gamma, Ux, Uy, Uy:
1120 17764892.133, 5793679.092, 15733785.198, 179.997, 179.999,452408725.23, -575727594.04, -1913661011.01 (affine) 1rst finetness
1122 all the reflections are non collinear the affine method should
1123 warn the user about this.
1124 *** TODO HklEngine "zone"
1125 *** TODO HklEngine "custom"
1126 for now this pseudoaxis let you select the axis you
1127 want to use for the computation.
1128 *** TODO HklEngine "q/q2" add a "reflectivity" mode
1129 This mode should have the surface as parameters and the incident
1130 angle is equal to the emergence angle.
1131 *** TODO create a macro to help compare two real the right way
1132 fabs(a-b) < epsilon * max(1, abs(a), abs(b))
1133 *** TODO add an hkl_sample_set_lattice_unit()
1134 *** TODO SOLEIL SIXS
1135 **** DONE find the right solutions. :zaxis:
1136 The cosinus and sinus properties are not enough to find the solution expected by the users.
1137 The idea is to use the Ewalds construction to generate a valid solution from the first one
1138 obtain numerically. The basic idea is to rotate the hkl vector around the last axis of the
1139 sample holder until it intersect again the Ewalds sphere. Then we just need to fit the
1140 detector position. This way the solution can be entirely generic (not geometry specific).
1141 Nevertheless it is necessary to propose this only for the hkl pseudo axes. I will add this
1142 special feature in the Mode. So it will be possible to add thoses special cases easily.
1143 **** TODO Add the DEP diffractometer geometry
1144 This diffractometer is a Newport one based on the kappa 6 circles ones.
1145 But instead of a kappa head, they use an Hexapod head.
1146 This head can be put horizontally or vertically.
1147 *** TODO generalisation of the z-axis hkl solver
1148 first we need the degenerated member of the Axis. thaht way it could be possible
1149 to find the last non degenerated axis for the detector fit.
1150 *** TODO investigate the prigo geometry.
1151 *** TODO augeas/elektra for the plugin configure part.
1153 **** TODO [1/2] add in a few methods.
1154 + [X] hkl_pseudo_axes_values_set
1155 + [ ] hkl_sample_affine
1156 **** TODO gir logging
1157 It would be nice to generate the library logging using the .gir
1158 information. So instead of writing the logging code for each
1159 method, it would be better to have a generic method for this
1161 **** TODO parsable logging information.
1162 A parsable logging format would help to setup some re-play unit
1163 test. This way it could help during the developpement process
1164 (modification of the hkl internals) to be confident that
1166 *** TODO performances
1167 + Investigate [[http://liboil.freedesktop.org/wiki/][liboil]] to speed calculation (in HklVector, HklMatrix
1169 + Avoid to call =hkl_engine_prepare_internal= at each computation.
1171 *** TODO [1/6] rewrite documentation in org-mode
1172 - [-] embedding code into the org file
1174 - [X] auto generation of the diffractometer descriptions
1175 - [ ] trajectories explanations
1176 - [ ] trajectories tests.
1177 - [ ] unit tests output ?
1179 - [X] need to check if templates could be generated using the hkl
1180 python binding for all diffractometer geometries.
1181 - [ ] need to add a description for the diffractometer, the mode, the parameters.
1182 - [ ] need a nice css for the generated doc.
1183 - [ ] check if org-info.js could be usefull
1184 - [ ] add documentation explaining the sector-cuts a la hkl
1186 - [ ] change the color of fitparameter cells if they differ from
1187 the current sample values
1188 - [ ] check if a [[https://github.com/jonathanslenders/python-prompt-toolkit/tree/master/examples/tutorial][REPL]] could be integrated to provide an autocad
1190 - [ ] add tooltips using hkl_parameter_description_get for the
1191 pseudo axes and the mode parameters.
1193 *** TODO add a method to find the 3D models in the right directories.
1196 *** TODO add a .spec file for rpm generation.