pre-release
[hkl.git] / hkl / hkl-engine-petra3-p08-lisa.c
blob160f7d0d8bde53bf634662f10cd5fa2d5f639878
1 /* This file is part of the hkl library.
3 * The hkl library is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
8 * The hkl library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with the hkl library. If not, see <http://www.gnu.org/licenses/>.
16 * Copyright (C) 2003-2017 Synchrotron SOLEIL
17 * L'Orme des Merisiers Saint-Aubin
18 * BP 48 91192 GIF-sur-YVETTE CEDEX
19 * Copyright (C) 2017 DESY
21 * Authors: Picca Frédéric-Emmanuel <picca@synchrotron-soleil.fr>
22 * Teresa Núñez <tnunez@mail.desy.de>
24 #include "hkl.h"
25 #include <gsl/gsl_sys.h> // for gsl_isnan
26 #include "hkl-axis-private.h"
27 #include "hkl-factory-private.h" // for autodata_factories_, etc
28 #include "hkl-matrix-private.h"
29 #include "hkl-pseudoaxis-common-hkl-private.h" // for hkl_mode_operations, etc
30 #include "hkl-pseudoaxis-common-psi-private.h" // for hkl_engine_psi_new, etc
31 #include "hkl-pseudoaxis-common-q-private.h" // for hkl_engine_q2_new, etc
32 #include "hkl-pseudoaxis-common-tth-private.h" // for hkl_engine_tth2_new, etc
33 #include "hkl-pseudoaxis-common-readonly-private.h"
34 #include "hkl-sample-private.h"
36 /***********************
38 Description
40 There are 5 real motors:
42 mchi (monochromator rotation) -> rotation y axis +1
43 sphi (sample rotation) -> rotation z axis +1
44 dtth (detector table rotation) -> rotation z axis -1
45 dh (detector height) -> translation z axis +1
46 drot (detector rotation) -> rotation x axis +1
48 There are 4 pseudo motors related to them:
50 alpha (incident angle - kin with xy plane)
51 beta (outgoing angle - kout with xy plane)
52 sth (angle between the kin projection and the vector defined via sphi)
53 stth (angle between kin and kout projections in the xy plane)
55 sth and stth has to be independently as pseudomotors.
57 For a given energy, E, one can compute mchi, sphi, dtth, dh and drot
58 from alpha, beta, th and tth and viceversa. The solutions are not
59 unique, for fixing them one has to set:
61 FRED: reading this and looking at the schema, it seems that you need a
62 pseudo motor engine with the four pseudo motors. something which takes
63 alpha, beta, sth and stth in order to compute the 5 real motors
64 positions. So maybe the right things to do is to create a pm with all
65 the pseudo motors and not only stth and sth.
67 Teresa: I agree. The users told me only about stth and sth, as the manual
68 also says, but it is better to have the four ones.
70 Maybe the right things to do is to create for now, only pseudo motors
71 with the read part. So once we have this setup it will be easier for
72 us to understand what is going on.
74 - Detector rotation tracking -> the detector table rotation, dtth,
75 follows the monochromator rotation, mchi, so that the position of
76 stth stays constant. For stth = 0 the detector is in diffraction
77 plane.
79 - mchi rotation direction -> if set to '+' the mchi angle goes from 0
80 to pi, set to '-' it goes from 0 to -pi.
82 - allow rotation sample -> if 'yes' the sample will be rotated with
83 the monochromator, so that sth will stay constant. If 'no' the
84 sample will not be rotated.
86 The following geometry constants have to be set:
88 - distance sample center to detector = 500
89 - distance first crystal (mono1) to sample center = 650
90 - distance first crystal (mono1) to second one (mono2) = 25
91 - first crystal diffraction parameter
92 - second crystal diffraction parameter
94 lambda = hc_over_e/Energy
95 bragg1 = g_tau1 * lambda * 1/(4*pi)
96 bragg2 = g_tau2 * lambda * 1/(4*pi)
98 where
100 the crystals used are Si111 and Si220.
102 g_tau1 = 2*PI/d111
103 g_tau2 = 2*PI/d220
105 where d111 and d220 are the lattice plane distances (in Amstrong) of the
106 crystals.
108 d111 = 3.136 A
109 d220 = 1.920 A
111 FRED: Do you want to set these parameters in the code or do you want
112 to add these parameters to the geometry dynamiquely ? So the user can
113 change this during the experimenta ? I would prefer a static
114 declaration for now in the code.
116 For a alpha, beta, th and tth set there are different possibilities of
117 choosing the position of the real motors for getting a given
118 h,k,l. Four possible geometry modes have to be implemented, each mode
119 gives an unique solution for the real computers computed from the
120 angles. These modes are:
122 - mode 0 -> K axis from reciprocal space parallel to incident beam.
123 - mode 1 -> alpha = beta
124 - mode 2 -> th = tth/2
125 - mode 3 -> K axis from reciprocal space parallel to outgoing beam.
127 There are some corrections (motor movements) that have to be done if
128 the energy is changed, in order to correct the shifts in the position
129 of the beam on the sample.
131 *******************/
134 /**************/
135 /* Axes names */
136 /**************/
138 #define SPHI "sphi"
139 #define DTTH "dtth"
140 #define DH "dh"
141 #define DROT "drot"
142 #define MCHI "mchi"
144 #define D_SD 0.5 /* meter */
145 #define D_Si111 3.136 /* Si111 of mono1 Angstöm */
146 #define D_Si220 1.920 /* Si220 ok mono2 Angstöm */
148 #define PETRA3_P08_LISA_SOURCE_HOLDER_IDX 0
149 #define PETRA3_P08_LISA_SAMPLE_HOLDER_IDX 1
150 #define PETRA3_P08_LISA_DETECTOR_HOLDER_IDX 2
152 #define HKL_GEOMETRY_PETRA3_P08_LISA_DESCRIPTION \
153 "+ xrays source fix along the :math:`\\vec{x}` direction (1, 0, 0)\n" \
154 "+ 1 axes for the monochromator\n" \
155 "\n" \
156 " + **" MCHI "** : rotation around the :math:`\\vec{x}` direction (1, 0, 0)\n" \
157 "\n" \
158 "+ 1 axis for the sample\n" \
159 "\n" \
160 " + **" SPHI "** : rotating around the :math:`\\vec{z}` direction (0, 0, 1)\n" \
161 "\n" \
162 "+ 2 axes for the detector\n" \
163 "\n" \
164 " + **" DTTH "** : rotation around the :math:`-\\vec{z}` direction (0, 0, -1)\n" \
165 " + **" DH "** : translation along the :math:`\\vec{z}` direction (0, 0, 1)\n" \
166 " + **" DROT "** : rotation around the :math:`-\\vec{y}` direction (0, -1, 0)\n"
168 static double _alpha_max(double wavelength, double d1, double d2)
170 double theta1 = asin(wavelength / (2 * d1));
171 double theta2 = asin(wavelength / (2 * d2));
172 return 2 * (theta2 - theta1);
175 static int hkl_mode_hkl_petra3_p08_lisa_get_real(HklMode *self,
176 HklEngine *engine,
177 HklGeometry *geometry,
178 HklDetector *detector,
179 HklSample *sample,
180 GError **error)
182 HklHolder *holder;
183 HklMatrix RUB;
184 HklVector hkl;
185 HklVector ki;
186 HklVector Q;
187 HklEngineHkl *engine_hkl = container_of(engine, HklEngineHkl, engine);
189 /* update the geometry internals */
190 hkl_geometry_update(geometry);
192 /* R * UB */
193 /* for the lisa geometry the holder 1 is the sample holder. */
194 holder = hkl_geometry_sample_holder_get(geometry, sample);
195 hkl_quaternion_to_matrix(&holder->q, &RUB);
196 hkl_matrix_times_matrix(&RUB, &sample->UB);
198 /* kf - ki = Q */
199 ki = hkl_geometry_ki_get(geometry);
201 Q = hkl_geometry_kf_get(geometry, detector);
203 hkl_vector_minus_vector(&Q, &ki);
205 /* compute hkl */
207 hkl_matrix_solve(&RUB, &hkl, &Q);
209 engine_hkl->h->_value = hkl.data[0];
210 engine_hkl->k->_value = hkl.data[1];
211 engine_hkl->l->_value = hkl.data[2];
213 return TRUE;
216 int hkl_mode_hkl_petra3_p08_lisa_set_real(HklMode *self,
217 HklEngine *engine,
218 HklGeometry *geometry,
219 HklDetector *detector,
220 HklSample *sample,
221 GError **error)
223 /* FRED: to implement */
224 /* int last_axis; */
226 /* hkl_error (error == NULL || *error == NULL); */
228 /* /\* check the input parameters *\/ */
229 /* if(!hkl_is_reachable(engine, geometry->source.wave_length, */
230 /* error)){ */
231 /* hkl_assert(error == NULL || *error != NULL); */
232 /* return FALSE; */
233 /* } */
234 /* hkl_assert(error == NULL || *error == NULL); */
236 /* /\* compute the mode *\/ */
237 /* if(!hkl_mode_auto_set_real(self, engine, */
238 /* geometry, detector, sample, */
239 /* error)){ */
240 /* hkl_assert(error == NULL || *error != NULL); */
241 /* //fprintf(stdout, "message :%s\n", (*error)->message); */
242 /* return FALSE; */
243 /* } */
244 /* hkl_assert(error == NULL || *error == NULL); */
246 /* /\* check that the mode allow to move a sample axis *\/ */
247 /* /\* FIXME for now the sample holder is the first one *\/ */
248 /* last_axis = get_last_axis_idx(geometry, 0, &self->info->axes_w); */
249 /* if(last_axis >= 0){ */
250 /* uint i; */
251 /* const HklGeometryListItem *item; */
252 /* uint len = engine->engines->geometries->n_items; */
254 /* /\* For each solution already found we will generate another one *\/ */
255 /* /\* using the Ewalds construction by rotating Q around the last sample *\/ */
256 /* /\* axis of the mode until it intersect again the Ewald sphere. *\/ */
257 /* /\* FIXME do not work if ki is colinear with the axis. *\/ */
259 /* /\* for this we needs : *\/ */
260 /* /\* - the coordinates of the end of the Q vector (q) *\/ */
261 /* /\* - the last sample axis orientation of the mode (axis_v) *\/ */
262 /* /\* - the coordinates of the center of the ewalds sphere (c) *\/ */
263 /* /\* - the coordinates of the center of rotation of the sample (o = 0, 0, 0) *\/ */
265 /* /\* then we can : *\/ */
266 /* /\* - project the origin in plane of normal axis_v containing q (o') *\/ */
267 /* /\* - project the center of the ewalds sphere into the same plan (c') *\/ */
268 /* /\* - rotate q around this (o', c') line of 180° to find the (q2) solution *\/ */
269 /* /\* - compute the (kf2) corresponding to this q2 solution *\/ */
270 /* /\* at the end we just need to solve numerically the position of the detector *\/ */
272 /* /\* we will add solution to the geometries so save its length before *\/ */
273 /* for(i=0, item=list_top(&engine->engines->geometries->items, HklGeometryListItem, list); */
274 /* i<len; */
275 /* ++i, item=list_next(&engine->engines->geometries->items, item, list)){ */
276 /* int j; */
277 /* HklVector ki; */
278 /* HklVector kf2; */
279 /* HklVector q; */
280 /* HklVector axis_v; */
281 /* HklQuaternion qr; */
282 /* HklAxis *axis; */
283 /* HklVector cp = {{0}}; */
284 /* HklVector op = {{0}}; */
285 /* double angle; */
286 /* HklGeometry *geom; */
288 /* geom = hkl_geometry_new_copy(item->geometry); */
290 /* /\* get the Q vector kf - ki *\/ */
291 /* hkl_detector_compute_kf(detector, geom, &q); */
292 /* hkl_source_compute_ki(&geom->source, &ki); */
293 /* hkl_vector_minus_vector(&q, &ki); */
295 /* /\* compute the current orientation of the last axis *\/ */
296 /* axis = container_of(darray_item(geom->axes, */
297 /* darray_item(geom->holders, 0)->config->idx[last_axis]), */
298 /* HklAxis, parameter); */
299 /* axis_v = axis->axis_v; */
300 /* hkl_quaternion_init(&qr, 1, 0, 0, 0); */
301 /* for(j=0; j<last_axis; ++j) */
302 /* hkl_quaternion_times_quaternion( */
303 /* &qr, */
304 /* &container_of(darray_item(geom->axes, */
305 /* darray_item(geom->holders, 0)->config->idx[j]), */
306 /* HklAxis, parameter)->q); */
307 /* hkl_vector_rotated_quaternion(&axis_v, &qr); */
309 /* /\* - project the center of the ewalds sphere into the same plan (c') *\/ */
310 /* hkl_vector_minus_vector(&cp, &ki); */
311 /* hkl_vector_project_on_plan_with_point(&cp, &axis_v, &q); */
312 /* hkl_vector_project_on_plan_with_point(&op, &axis_v, &q); */
314 /* /\* - rotate q around this (o', c') line of 180° to find the (q2) solution *\/ */
315 /* kf2 = q; */
316 /* hkl_vector_rotated_around_line(&kf2, M_PI, &cp, &op); */
317 /* angle = hkl_vector_oriented_angle_points(&q, &op, &kf2, &axis_v); */
318 /* /\* TODO parameter list for geometry *\/ */
319 /* if(!hkl_parameter_value_set(&axis->parameter, */
320 /* hkl_parameter_value_get(&axis->parameter, HKL_UNIT_DEFAULT) + angle, */
321 /* HKL_UNIT_DEFAULT, error)) */
322 /* return FALSE; */
323 /* hkl_geometry_update(geom); */
324 /* #ifdef DEBUG */
325 /* fprintf(stdout, "\n- try to add a solution by rotating Q <%f, %f, %f> around the \"%s\" axis <%f, %f, %f> of %f radian", */
326 /* q.data[0], q.data[1], q.data[2], */
327 /* ((HklParameter *)axis)->name, */
328 /* axis_v.data[0], axis_v.data[1], axis_v.data[2], */
329 /* angle); */
330 /* fprintf(stdout, "\n op: <%f, %f, %f>", op.data[0], op.data[1], op.data[2]); */
331 /* fprintf(stdout, "\n q2: <%f, %f, %f>", kf2.data[0], kf2.data[1], kf2.data[2]); */
332 /* #endif */
333 /* hkl_vector_add_vector(&kf2, &ki); */
335 /* /\* at the end we just need to solve numerically the position of the detector *\/ */
336 /* if(fit_detector_position(self, geom, detector, &kf2)) */
337 /* hkl_geometry_list_add(engine->engines->geometries, */
338 /* geom); */
340 /* hkl_geometry_free(geom); */
341 /* } */
342 /* } */
343 return TRUE;
346 #define HKL_MODE_HKL_PETRA3_P08_LISA_OPERATIONS_DEFAULTS \
347 HKL_MODE_OPERATIONS_AUTO_DEFAULTS, \
348 .get = hkl_mode_hkl_petra3_p08_lisa_get_real, \
349 .set = hkl_mode_hkl_petra3_p08_lisa_set_real
351 static const HklModeOperations hkl_mode_hkl_petra3_p08_lisa_operations = {
352 HKL_MODE_HKL_PETRA3_P08_LISA_OPERATIONS_DEFAULTS,
355 static const char* hkl_geometry_petra3_p08_lisa_axes[] = {MCHI, SPHI, DTTH, DH, DROT};
357 static HklHolder *hkl_geometry_petra3_p08_lisa_sample_holder_get_real(const HklGeometry *geometry,
358 const HklSample *sample)
360 return darray_item(geometry->holders, PETRA3_P08_LISA_SAMPLE_HOLDER_IDX);
363 static HklHolder *hkl_geometry_petra3_p08_lisa_detector_holder_get_real(const HklGeometry *geometry,
364 const HklDetector *detector)
366 return darray_item(geometry->holders, PETRA3_P08_LISA_DETECTOR_HOLDER_IDX);
369 static HklVector hkl_geometry_petra3_p08_lisa_ki_get_real(const HklGeometry *geometry)
371 double alpha_max = _alpha_max(geometry->source.wave_length, D_Si111, D_Si220);
372 HklHolder *holder;
373 HklVector ki = {{cos(alpha_max), 0, -sin(alpha_max)}};
375 holder = darray_item(geometry->holders, PETRA3_P08_LISA_SOURCE_HOLDER_IDX);
376 ki = hkl_holder_transformation_apply(holder, &ki);
377 hkl_vector_times_double(&ki, HKL_TAU / geometry->source.wave_length);
379 return ki;
382 static HklVector hkl_geometry_petra3_p08_lisa_kf_get_real(const HklGeometry *geometry,
383 const HklDetector *detector)
385 HklHolder *holder;
386 HklVector kf = {{D_SD, 0, 0}};
388 holder = hkl_geometry_detector_holder_get(geometry, detector);
389 kf = hkl_holder_transformation_apply(holder, &kf);
390 hkl_vector_normalize(&kf);
391 hkl_vector_times_double(&kf, HKL_TAU / geometry->source.wave_length);
393 return kf;
396 #define HKL_GEOMETRY_PETRA3_P08_LISA_OPERATIONS_DEFAULTS \
397 HKL_GEOMETRY_OPERATIONS_DEFAULTS, \
398 .sample_holder_get = hkl_geometry_petra3_p08_lisa_sample_holder_get_real, \
399 .detector_holder_get = hkl_geometry_petra3_p08_lisa_detector_holder_get_real, \
400 .ki_get = hkl_geometry_petra3_p08_lisa_ki_get_real, \
401 .kf_get = hkl_geometry_petra3_p08_lisa_kf_get_real
403 static HklGeometry *hkl_geometry_new_petra3_p08_lisa(const HklFactory *factory)
405 static HklGeometryOperations ops = {HKL_GEOMETRY_PETRA3_P08_LISA_OPERATIONS_DEFAULTS};
406 HklGeometry *self = hkl_geometry_new(factory, &ops);
407 HklHolder *h;
409 /* source */
410 h = hkl_geometry_add_holder(self);
411 hkl_holder_add_rotation(h, MCHI, 1, 0, 0, &hkl_unit_angle_deg);
413 /* sample */
414 h = hkl_geometry_add_holder(self);
415 hkl_holder_add_rotation(h, SPHI, 0, 0, 1, &hkl_unit_angle_deg);
417 /* detector */
418 h = hkl_geometry_add_holder(self);
419 hkl_holder_add_rotation(h, DTTH, 0, 0, -1, &hkl_unit_angle_deg);
420 hkl_holder_add_translation(h, DH, 0, 0, 1, &hkl_unit_length_mm);
421 hkl_holder_add_rotation_with_origin(h, DROT, 0, -1, 0, D_SD, 0, 0, &hkl_unit_angle_deg);
423 return self;
426 /*********/
427 /* Modes */
428 /********/
430 /* hkl modes */
432 static HklMode *k_parallel_incident(void)
434 /* TODO: check if the axes are correct, add the functions and implement them */
436 static const char* axes_r[] = {MCHI, SPHI, DTTH, DROT};
438 static const char* axes_w[] = {MCHI, SPHI, DTTH, DROT};
440 static const HklFunction *functions[] = {};
442 /* here just the description of the mode: name, axes_r, axes_w, functions */
443 static const HklModeAutoInfo info = {
444 HKL_MODE_AUTO_INFO(__func__, axes_r, axes_w, functions),
447 /* instantiate a new mode */
448 return hkl_mode_auto_new(&info,
449 &hkl_mode_hkl_petra3_p08_lisa_operations,
450 TRUE);
454 static HklMode *alpha_eq_beta(void)
456 /* TODO: check if the axes are correct, add the functions and implement them */
458 static const char* axes_r[] = {MCHI, SPHI, DTTH, DROT};
460 static const char* axes_w[] = {MCHI, SPHI, DTTH, DROT};
462 static const HklFunction *functions[] = {};
464 /* here just the description of the mode: name, axes_r, axes_w, functions */
465 static const HklModeAutoInfo info = {
466 HKL_MODE_AUTO_INFO(__func__, axes_r, axes_w, functions),
469 /* instantiate a new mode */
470 return hkl_mode_auto_new(&info,
471 &hkl_mode_hkl_petra3_p08_lisa_operations,
472 TRUE);
474 static HklMode *th_eq_tth2(void)
476 /* TODO: check if the axes are correct, add the functions and implement them */
478 static const char* axes_r[] = {MCHI, SPHI, DTTH, DROT};
480 static const char* axes_w[] = {MCHI, SPHI, DTTH, DROT};
482 static const HklFunction *functions[] = {};
484 /* here just the description of the mode: name, axes_r, axes_w, functions */
485 static const HklModeAutoInfo info = {
486 HKL_MODE_AUTO_INFO(__func__, axes_r, axes_w, functions),
489 /* instantiate a new mode */
490 return hkl_mode_auto_new(&info,
491 &hkl_mode_hkl_petra3_p08_lisa_operations,
492 TRUE);
494 static HklMode *k_parallel_outgoing(void)
496 /* TODO: check if the axes are correct, add the functions and implement them */
498 static const char* axes_r[] = {MCHI, SPHI, DTTH, DROT};
500 static const char* axes_w[] = {MCHI, SPHI, DTTH, DROT};
502 static const HklFunction *functions[] = {};
504 /* here just the description of the mode: name, axes_r, axes_w, functions */
505 static const HklModeAutoInfo info = {
506 HKL_MODE_AUTO_INFO(__func__, axes_r, axes_w, functions),
509 /* instantiate a new mode */
510 return hkl_mode_auto_new(&info,
511 &hkl_mode_hkl_petra3_p08_lisa_operations,
512 TRUE);
515 /* lisapm modes */
518 static const HklParameter mode_lisa_pm_parameters[] = {
520 HKL_PARAMETER_DEFAULTS, .name = "det_rot_tracking", ._value = 0,
521 .description = "if 1, the detector table will be rotated with the monochromator, so that stth stays constant",
522 .range = { .min=0, .max=1 },
525 HKL_PARAMETER_DEFAULTS, .name = "mchi_rot_dir", ._value = 1,
526 .description = "if 1 mchi angle goes from 0 to pi, if -1 from 0 to -pi",
527 .range = { .min=-1, .max=1 },
530 HKL_PARAMETER_DEFAULTS, .name = "sample_rot", ._value = 0,
531 .description = "if 1, the sample will be rotated with the monochromator, so that sth stays constant.",
532 .range = { .min=0, .max=1 },
536 static int _mode_lisa_pm_m_to_pm_func(const gsl_vector *x, void *params, gsl_vector *f)
538 /* TODO: implement it */
540 return GSL_SUCCESS;
543 static const HklFunction mode_lisa_pm_m_to_pm_func = {
544 .function = _mode_lisa_pm_m_to_pm_func,
545 .size = 3,
548 static int _mode_lisa_pm_pm_to_m_func(const gsl_vector *x, void *params, gsl_vector *f)
550 /* TODO: implement it */
552 return GSL_SUCCESS;
555 static const HklFunction mode_lisa_pm_pm_to_m_func = {
556 .function = _mode_lisa_pm_pm_to_m_func,
557 .size = 3,
560 static HklMode *mode_lisa_pm(void)
563 static const char* axes_r[] = {MCHI, SPHI, DTTH}; /* QUESTION: these are the two motors I need for computing sth and stth positions, is this right ??? */
565 static const char* axes_w[] = {MCHI, SPHI, DTTH}; /* QUESTION: these are the motors I move if I write to the pseudomotor sth or stth, is this right ??? */
568 /* here a list of functions use to solve the mode */ /* QUESTION: which functions should be here ???, I need one for computing motor positions from pseudomotor and one for computing pseudonmotor from motor positions. Why in the other diffractometers there is only one function here ??? */
569 /* FRED this are not the functions in order to do get and set but only to do the set. the get/set is done in the hkl_mode_operations. */
570 static const HklFunction *functions[] = {&mode_lisa_pm_m_to_pm_func, &mode_lisa_pm_pm_to_m_func};
572 /* here just the description of the mode: name, axes_r, axes_w, functions */
573 static const HklModeAutoInfo info = {
574 HKL_MODE_AUTO_INFO_WITH_PARAMS(__func__, axes_r, axes_w, functions, mode_lisa_pm_parameters),
577 /* instantiate a new mode */
578 return hkl_mode_auto_new(&info,
579 &hkl_mode_operations, /* FRED these operation must be specifique to the pseudo motors look at the read_only emergence pseudo in hkl-pseudoaxis-common-readonly code. */
580 TRUE);
583 /******************/
584 /* LisaPM Engine */
585 /*****************/
587 struct _HklEngineLisaPM
589 HklEngine engine;
590 HklParameter *sth;
591 HklParameter *stth;
594 typedef struct _HklEngineLisaPM HklEngineLisaPM;
596 static void hkl_engine_lisapm_free_real(HklEngine *base)
598 HklEngineLisaPM *self = container_of(base, HklEngineLisaPM, engine);
599 hkl_engine_release(&self->engine);
600 free(self);
603 HklEngine *hkl_engine_lisa_pm_new(HklEngineList *engines)
605 HklEngineLisaPM *self;
607 static const HklParameter sth = {
608 HKL_PARAMETER_DEFAULTS_ANGLE, .name="sth",
609 .description = "angle of the projection of $\\vec{ki}$ in the $xy$ and the sample table rotation",
612 static const HklParameter stth = {
613 HKL_PARAMETER_DEFAULTS_ANGLE, .name="stth",
614 .description = "angle of the projection of $\\vec{ki}$ in the $xy$ and the detector arm",
617 static const HklParameter *pseudo_axes[] = {&sth, &stth};
618 static const HklEngineInfo info = {
619 HKL_ENGINE_INFO("LisaPM",
620 pseudo_axes,
621 HKL_ENGINE_DEPENDENCIES_AXES),
623 static const HklEngineOperations operations = {
624 HKL_ENGINE_OPERATIONS_DEFAULTS,
625 .free=hkl_engine_lisapm_free_real,
628 self = HKL_MALLOC(HklEngineLisaPM);
630 hkl_engine_init(&self->engine, &info, &operations, engines);
631 self->sth = register_pseudo_axis(&self->engine, engines, &sth);
632 self->stth = register_pseudo_axis(&self->engine, engines, &stth);
634 return &self->engine;
640 /***********/
641 /* Engines */
642 /***********/
644 static HklEngine *hkl_engine_petra3_p08_lisa_hkl_new(HklEngineList *engines)
646 HklEngine *self;
647 HklMode *default_mode;
649 self = hkl_engine_hkl_new(engines);
651 default_mode = k_parallel_incident();
652 hkl_engine_add_mode(self, default_mode);
653 hkl_engine_mode_set(self, default_mode);
655 hkl_engine_add_mode(self, alpha_eq_beta());
656 hkl_engine_add_mode(self, th_eq_tth2());
657 hkl_engine_add_mode(self, k_parallel_outgoing());
659 return self;
662 static HklEngine *hkl_engine_petra3_p08_lisa_pm_new(HklEngineList *engines)
664 HklEngine *self;
665 HklMode *default_mode;
667 self = hkl_engine_lisa_pm_new(engines);
669 default_mode = mode_lisa_pm();
670 hkl_engine_add_mode(self, default_mode);
671 hkl_engine_mode_set(self, default_mode);
673 return self;
677 /***************/
678 /* Engine list */
679 /***************/
681 static HklEngineList *hkl_engine_list_new_petra3_p08_lisa(const HklFactory *factory)
684 HklEngineList *self = hkl_engine_list_new();
686 hkl_engine_petra3_p08_lisa_hkl_new(self);
687 /* hkl_engine_petra3_p08_lisa_pm_new(self); */
689 return self;
692 /* Register the diffractometer into the factory */
693 REGISTER_DIFFRACTOMETER(petra3_p08_lisa, "PETRA3 P08 LISA", HKL_GEOMETRY_PETRA3_P08_LISA_DESCRIPTION);