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 ** 5.0.0.2080 <2016-04-27 mer.>
868 *** DONE =HklEngine= <2016-01-20 mer.>
869 emergence_fixed for the SOLEIL SIX MED 2+2 geometry.
870 *** DONE =HklVector= <2016-02-09 mar.>
871 The hkl_vector_init method is now public.
872 *** DONE =HklParameter= <2016-02-25 Thu>
873 at the end of the computation all solutions are filtered in order
874 to check that they are valid (min < value < range). BUT for a
875 rotation axis this check was instead (min < value % 2pi < max).
876 *** DONE =HklGeometry= <2016-04-20 mer.>
877 Add hkl_geometry_[sample/detector]_rotation_get method. It is now
878 possible to get the sample or the detector rotation expressed as a
880 #+BEGIN_SRC python :export code
881 qr = geometry.sample_rotation_get(sample)
882 qd = geometry.detector_rotation_get(detector)
884 *** DONE =HklQuaternion= <2016-04-20 mer.>
885 Add hkl_quaternion_to_matrix in order to convert a =HklQuaternion=
886 into a =HklMatrix=. Then you just need to convert this HklMatrix
887 into a numpy array when used from the python binding
888 #+BEGIN_SRC python :export code
889 def hkl_matrix_to_numpy(m):
893 M[i, j] = m.get(i, j)
897 M = hkl_matrix_to_numpy(q.to_matrix())
899 *** DONE Soleil Sirius Turret <2016-04-26 mar.>
900 Add the =basepitch= axis which rotate around $\vec{y}$ in mrad.
901 ** 4.99.99.1955 <2015-07-15 mer.>
902 Add the ccan_config.h public header. This header is generated with
903 the ccan configurator program.
904 ** 4.99.99.1950 <2015-07-07 mar.>
905 Fix an FTBFS observed on the sparc arch
906 ** 4.99.99.1949 <2015-07-03 ven.>
907 *** DONE =HklInterval= <2015-07-03 ven.>
908 =hkl_interval_cmp= was wrong. Now the comparison is done between
909 =HKL_EPSILON= and the distance between minimum and maximum. This
910 problem was triggered first on ppc64el architecture.
911 *** DONE PATH_MAX <2015-07-03 ven.>
912 Replace getcwd called by get_current_dir_path instead in order to
913 avoid PATH_MAX which is not available on hurd.
914 ** 4.99.99.1946 <2015-06-30 mar.>
916 **** "emergence" <2015-06-22 lun.>
917 Add a new emergence engine which contain only one pseudo axis.
918 + =emergence= the outgoing beam emergence from the sample's surface.
919 + =azimuth= the sample's surface azimuth.
920 ** 4.99.99.1940 <2015-05-04 lun.>
921 *** DONE =HklLattice= add an =hkl_lattice_volume_get=
923 volume = hkl_lattice_volume_get(lattice);
926 **** "nrj, sample, ... dependencies" <2015-03-24 mar.>
927 Add the =hkl_engine_dependencies_get= method which return if the
928 =HklEngine= depends of the axes, the energy, or the sample. the
929 possible values are stored in the =HklEngineDependencies= enum.
932 dependencies = hkl_engine_dependencies_get(engine);
933 if (dependencies & HKL_ENGINE_DEPENDENCIES_ENERGY) {
936 if (dependencies & HKL_ENGINE_DEPENDENCIES_SAMPLE) {
941 **** "tth2" <2015-04-03 ven>
942 Add a new hkl engine which contain two pseudo axes.
943 + =tth= two times the diffraction angle $\theta$
944 + =alpha= the azimuth of q in the zOy plan.
945 **** "incidence" <2015-04-21 mar.>
946 Add a new incidence engine which contain only one pseudo axis.
947 + =incidence= the incoming beam incidence on the sample surface.
948 + =azimuth= the sample surface azimuth.
949 **** =hkl_engine_parameter_set= <2015-05-04 lun.>
950 Fix a bug and expose the method in the binding.
952 - use #define AXIS "axis_name" in all the code to set the axes
953 names at only one place. <2015-04-23 jeu.>
954 *** DONE =HklLattice= expose in the binding the _x_get/set methods <2015-03-24 mar.>
955 Now you can use hkl_lattice_x_get where x=a, b, c, alpha, beta,
956 gamma in the bindings.
957 #+BEGIN_SRC python :export code
961 *** DONE =HklSampleReflection= expose the flag_get/set and geometry_get/set method <2015-03-24 mar.>
962 It is now possible to change the geometry stored in a reflection
964 #+BEGIN_SRC python :export code
965 flag = reflection.flag_get()
966 reflection.flag_set(flag)
968 geometry = reflection.geometry_get()
969 geometry.axes_values_set([omega, chi, phi, ...])
970 reflection.geometry_set(geometry)
974 *** TODO [#A] =HklEngine= *q/q2*
975 Fix all these engines... This engine takes into account only the
976 *gamma* and *delta* axes. so diffractometers with 3 axes for the
977 detector are wrong. It would be nice to take into account all the
978 detector holder AND the position of the detecteor on the
979 diffractometer arms (for now the detector is always on the last
981 *** TODO [#A] HklSource
982 Create a parameter for the wavelength. This is just internally for
983 the futur trajectory system, so no need to change the signature of
984 hkl_geometry_vawelength get/set
985 *** TODO [0/2] PetraIII
986 **** TODO computation problem
989 Using the prruptest.txt ubmatrix I see that the value of psi is
990 offset by 45 degrees. I expect it to be 0 degrees when azimuth
991 reference vector is 0 0 1 that is along the beam. See below
992 thereturned numbers. This might have to do with the definition of
993 the beam axis in the controller. Otherwise now when I change
994 reference vector by 90 degrees the computed value is changed by
995 90 degrees. That is a progress. Can you contact Frederic and ask
1003 p09/door/haspp09.01 [9]: setaz 1 0 0
1005 p09/door/haspp09.01 [10]: wh
1009 Mode: psi_constant_vertical
1011 H K L = 0.00000 3.00605 -0.00000
1012 Ref = 1.00000 0.00000 0.00000
1013 Azimuth (Psi - calculated) = -45.00005
1014 Azimuth (Psi - set) = 0.00000
1015 Wavelength = 2.07957
1017 Delta Theta Chi Phi Mu Gamma
1018 45.77575 22.88783 90.00000 182.85400 0.00000 -0.00000
1020 p09/door/haspp09.01 [11]: setaz 0 0 1
1022 p09/door/haspp09.01 [12]: wh
1026 Mode: psi_constant_vertical
1028 H K L = 0.00000 3.00605 -0.00000
1029 Ref = 0.00000 0.00000 1.00000
1030 Azimuth (Psi - calculated) = -135.00005
1031 Azimuth (Psi - set) = 0.00000
1032 Wavelength = 2.07957
1034 Delta Theta Chi Phi Mu Gamma
1035 45.77575 22.88783 90.00000 182.85400 0.00000 -0.00000
1039 Azimuth (Psi - calculated) is the value of the pseudomotor psi.
1040 Azimuth (Psi - set) is the value set in the parameter psi of the current mode.
1044 This is the UB matrix:
1050 Created at 2015-01-21 12:35
1054 Wavelength 2.07957463938
1056 A 8.03656 B 8.03656 C 8.03656
1057 Alpha 90.0 Beta 90.0 Gamma 90.0
1059 R0 0 0.0 1.0 0.0 0 1 0.0 14.8979 90.0 182.854 0.0 29.7959
1060 R1 1 1.0 0.0 1.0 0 1 0.0 14.8979 0.0 182.854 0.0 29.7959
1062 Mode psi_constant_vertical
1066 U00 -0.580 U01 0.000 U02 0.525
1067 U10 0.000 U11 0.782 U12 -0.000
1068 U20 -0.525 U21 -0.000 U22 -0.580
1070 Ux 179.999952315 Uy 42.14605 Uz -179.999932647
1072 SaveDirectory /home/p09user/crystals/
1074 **** TODO another question
1075 J'ai un probleme avec la position que le controlleur calcule avec la
1076 matrice UB que nous t'avons envoye.
1077 See sequence of emails echanges avec Teresa.
1079 >>>> I am at 0 3.00605 0 with phi -182 and psi calculated is -135
1080 >>>> When I freeze psi at -135 and type ca 0 3.00605 0 the controller
1081 >> should return to me the positions at which I am. But no he tells me
1083 >> have to go to 178 degrees in phi that is turning by 360 degrees.
1085 Est-ce un probleme avec la trajectoire selectionnee ?
1086 Est-ce qu'il est possible de definir des cut-points comme dans spec avec
1088 *** TODO [2/4] HklParameter
1089 - [X] method to use min/max to check for the validity
1090 - [X] add a method to get the axis_v and quaternion of the HklAxis
1091 this method will return NULL if this is not relevant.
1092 hkl_parameter_axis_v_get and hkl_parameter_quaternion_get
1093 - [ ] degenerated an axis is degenerated if its position have no
1094 effect on the HklPseudoAxis calculus. Add a degenerated member
1095 to the axis. that way it would be possible to check a posteriori
1096 for this degenerescencence.
1097 - [ ] Add a description for each parameters.
1098 *** TODO This will help for the documentation and the gui.
1099 *** TODO HklGeometryList different method to help select a solution.
1100 this select solution can depend on the geometry
1101 for example the kappa axis must be in one side of the plane.
1102 *** TODO add a fit on the Hklaxis offsets.
1103 *** TODO API to put a detector and a sample on the Geometry.
1105 **** TODO [#B] unit test: hkl_sample_affine.
1107 lattice=1.540000;1.540000;1.540000;90.000000;90.000000;90.000000;0;0;0;0;0;0
1108 uxuyuz=0.000000;0.000000;0.000000
1109 reflection=1.540000;0.159010;1.256718;0.796660;1;0.000000;0.000000;0.000000;0.000000;0.000000
1110 reflection=1.540000;0.206208;0.342357;-0.080346;1;0.000000;0.000000;0.000000;0.000000;0.000000
1111 reflection=1.540000;0.206208;0.342357;-0.080346;1;0.000000;0.000000;0.000000;0.000000;0.000000
1113 A, B, C, Alpha, Beta, Gamma, Ux, Uy, Uy:
1114 17764892.133, 5793679.092, 15733785.198, 179.997, 179.999,452408725.23, -575727594.04, -1913661011.01 (affine) 1rst finetness
1116 all the reflections are non collinear the affine method should
1117 warn the user about this.
1118 *** TODO HklEngine "zone"
1119 *** TODO HklEngine "custom"
1120 for now this pseudoaxis let you select the axis you
1121 want to use for the computation.
1122 *** TODO HklEngine "q/q2" add a "reflectivity" mode
1123 This mode should have the surface as parameters and the incident
1124 angle is equal to the emergence angle.
1125 *** TODO create a macro to help compare two real the right way
1126 fabs(a-b) < epsilon * max(1, abs(a), abs(b))
1127 *** TODO add an hkl_sample_set_lattice_unit()
1128 *** TODO SOLEIL SIXS
1129 **** DONE find the right solutions. :zaxis:
1130 The cosinus and sinus properties are not enough to find the solution expected by the users.
1131 The idea is to use the Ewalds construction to generate a valid solution from the first one
1132 obtain numerically. The basic idea is to rotate the hkl vector around the last axis of the
1133 sample holder until it intersect again the Ewalds sphere. Then we just need to fit the
1134 detector position. This way the solution can be entirely generic (not geometry specific).
1135 Nevertheless it is necessary to propose this only for the hkl pseudo axes. I will add this
1136 special feature in the Mode. So it will be possible to add thoses special cases easily.
1137 **** TODO Add the DEP diffractometer geometry
1138 This diffractometer is a Newport one based on the kappa 6 circles ones.
1139 But instead of a kappa head, they use an Hexapod head.
1140 This head can be put horizontally or vertically.
1141 *** TODO generalisation of the z-axis hkl solver
1142 first we need the degenerated member of the Axis. thaht way it could be possible
1143 to find the last non degenerated axis for the detector fit.
1144 *** TODO investigate the prigo geometry.
1145 *** TODO augeas/elektra for the plugin configure part.
1147 **** TODO [1/2] add in a few methods.
1148 + [X] hkl_pseudo_axes_values_set
1149 + [ ] hkl_sample_affine
1150 **** TODO gir logging
1151 It would be nice to generate the library logging using the .gir
1152 information. So instead of writing the logging code for each
1153 method, it would be better to have a generic method for this
1155 **** TODO parsable logging information.
1156 A parsable logging format would help to setup some re-play unit
1157 test. This way it could help during the developpement process
1158 (modification of the hkl internals) to be confident that
1160 *** TODO performances
1161 + Investigate [[http://liboil.freedesktop.org/wiki/][liboil]] to speed calculation (in HklVector, HklMatrix
1163 + Avoid to call =hkl_engine_prepare_internal= at each computation.
1165 *** TODO [1/6] rewrite documentation in org-mode
1166 - [-] embedding code into the org file
1168 - [X] auto generation of the diffractometer descriptions
1169 - [ ] trajectories explanations
1170 - [ ] trajectories tests.
1171 - [ ] unit tests output ?
1173 - [X] need to check if templates could be generated using the hkl
1174 python binding for all diffractometer geometries.
1175 - [ ] need to add a description for the diffractometer, the mode, the parameters.
1176 - [ ] need a nice css for the generated doc.
1177 - [ ] check if org-info.js could be usefull
1178 - [ ] add documentation explaining the sector-cuts a la hkl
1180 - [ ] change the color of fitparameter cells if they differ from
1181 the current sample values
1182 - [ ] check if a [[https://github.com/jonathanslenders/python-prompt-toolkit/tree/master/examples/tutorial][REPL]] could be integrated to provide an autocad
1184 - [ ] add tooltips using hkl_parameter_description_get for the
1185 pseudo axes and the mode parameters.
1187 *** TODO add a method to find the 3D models in the right directories.
1190 *** TODO add a .spec file for rpm generation.