[binoculars-ng] start to work on the cirpad
[hkl.git] / hkl / hkl-pseudoaxis-private.h
blob21a69b6ffa39f57c69f25c57ff5f4829a1d1588c
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-2019, 2021, 2022, 2023 Synchrotron SOLEIL
17 * L'Orme des Merisiers Saint-Aubin
18 * BP 48 91192 GIF-sur-YVETTE CEDEX
20 * Authors: Picca Frédéric-Emmanuel <picca@synchrotron-soleil.fr>
22 #ifndef __HKL_PSEUDOAXIS_PRIVATE_H__
23 #define __HKL_PSEUDOAXIS_PRIVATE_H__
25 #include <gsl/gsl_sf_trig.h> // for gsl_sf_angle_restrict_symm
26 #include <stddef.h> // for size_t
27 #include <stdlib.h> // for free
28 #include <string.h> // for NULL
29 #include <sys/types.h> // for uint
30 #include "hkl-detector-private.h"
31 #include "hkl-geometry-private.h" // for hkl_geometry_update, etc
32 #include "hkl-macros-private.h" // for HKL_MALLOC
33 #include "hkl-parameter-private.h" // for hkl_parameter_list_free, etc
34 #include "hkl.h" // for HklEngine, HklMode, etc
35 #include "hkl/ccan/array_size/array_size.h"
36 #include "hkl/ccan/darray/darray.h" // for darray_foreach, etc
38 G_BEGIN_DECLS
40 typedef struct _HklModeOperations HklModeOperations;
41 typedef struct _HklModeInfo HklModeInfo;
42 typedef struct _HklMode HklMode;
43 typedef struct _HklEngineInfo HklEngineInfo;
44 typedef struct _HklEngineOperations HklEngineOperations;
45 typedef struct _HklEngineListInfo HklEngineListInfo;
46 typedef struct _HklEngineListOperations HklEngineListOperations;
48 typedef darray(HklMode *) darray_mode;
50 /***********/
51 /* HklMode */
52 /***********/
54 struct _HklModeInfo {
55 const char *name;
56 const darray_string axes_r;
57 const darray_string axes_w;
58 const darray(const HklParameter) parameters;
61 #define HKL_MODE_INFO_RO(_name, _axes) .name=_name, .axes_r=DARRAY(_axes)
62 #define HKL_MODE_INFO(_name, _axes_r, _axes_w) HKL_MODE_INFO_RO((_name), (_axes_r)), .axes_w=DARRAY((_axes_w))
64 #define HKL_MODE_INFO_RO_WITH_PARAMS(_name, _axes, _parameters) HKL_MODE_INFO_RO((_name), (_axes)), .parameters=DARRAY(_parameters)
65 #define HKL_MODE_INFO_WITH_PARAMS(_name, _axes_r, _axes_w, _parameters) \
66 HKL_MODE_INFO(_name, _axes_r, _axes_w), .parameters=DARRAY(_parameters)
68 struct _HklModeOperations
70 unsigned long capabilities;
72 void (* free)(HklMode *self);
73 int (* initialized_get)(const HklMode *self);
74 int (* initialized_set)(HklMode *self,
75 HklEngine *engine,
76 HklGeometry *geometry,
77 HklDetector *detector,
78 HklSample *sample,
79 int initialized,
80 GError **error);
81 int (* get)(HklMode *self,
82 HklEngine *engine,
83 HklGeometry *geometry,
84 HklDetector *detector,
85 HklSample *sample,
86 GError **error);
87 int (* set)(HklMode *self,
88 HklEngine *engine,
89 HklGeometry *geometry,
90 HklDetector *detector,
91 HklSample *sample,
92 GError **error);
96 #define HKL_MODE_OPERATIONS_DEFAULTS .capabilities=HKL_ENGINE_CAPABILITIES_READABLE | HKL_ENGINE_CAPABILITIES_WRITABLE, \
97 .free=hkl_mode_free_real, \
98 .initialized_get=hkl_mode_initialized_get_real, \
99 .initialized_set=hkl_mode_initialized_set_real, \
100 .get=hkl_mode_get_real, \
101 .set=hkl_mode_set_real
104 struct _HklMode
106 const HklModeInfo *info;
107 const HklModeOperations *ops;
108 darray_parameter parameters;
109 darray_string parameters_names;
110 int initialized;
114 static inline void hkl_mode_free_real(HklMode *self)
116 HklParameter **parameter;
118 darray_foreach(parameter, self->parameters){
119 hkl_parameter_free(*parameter);
121 darray_free(self->parameters);
123 darray_free(self->parameters_names);
125 free(self);
129 static inline int hkl_mode_initialized_get_real(const HklMode *self)
131 return self->initialized;
135 static inline int hkl_mode_initialized_get(const HklMode *self)
137 return self->ops->initialized_get(self);
141 static inline int hkl_mode_initialized_set_real(UNUSED HklMode *self,
142 UNUSED HklEngine *engine,
143 UNUSED HklGeometry *geometry,
144 UNUSED HklDetector *detector,
145 UNUSED HklSample *sample,
146 UNUSED int initialized,
147 UNUSED GError **error)
149 /* by default do nothing and no error */
150 return TRUE;
154 static inline int hkl_mode_initialized_set(HklMode *self,
155 HklEngine *engine,
156 HklGeometry *geometry,
157 HklDetector *detector,
158 HklSample *sample,
159 int initialized,
160 GError **error)
162 return self->ops->initialized_set(self,
163 engine, geometry, detector, sample,
164 initialized, error);
168 static inline int hkl_mode_get_real(UNUSED HklMode *self,
169 UNUSED HklEngine *engine,
170 UNUSED HklGeometry *geometry,
171 UNUSED HklDetector *detector,
172 UNUSED HklSample *sample,
173 UNUSED GError **error)
175 /* by default do nothing and no error */
176 return FALSE;
180 static inline int hkl_mode_set_real(UNUSED HklMode *self,
181 UNUSED HklEngine *engine,
182 UNUSED HklGeometry *geometry,
183 UNUSED HklDetector *detector,
184 UNUSED HklSample *sample,
185 UNUSED GError **error)
187 /* by default do nothing and no error */
188 return FALSE;
192 static inline int hkl_mode_init(HklMode *self,
193 const HklModeInfo *info,
194 const HklModeOperations *ops,
195 int initialized) HKL_ARG_NONNULL(1, 2, 3) HKL_WARN_UNUSED_RESULT;
196 static inline int hkl_mode_init(HklMode *self,
197 const HklModeInfo *info,
198 const HklModeOperations *ops,
199 int initialized)
201 const HklParameter *parameter;
202 HklParameter *p;
204 self->info = info;
205 self->ops = ops;
207 /* parameters */
208 darray_init(self->parameters) ;
209 darray_init(self->parameters_names);
210 darray_foreach(parameter, self->info->parameters){
211 if(NULL == (p = hkl_parameter_new_copy(parameter)))
212 break;
214 darray_append(self->parameters, p);
215 darray_append(self->parameters_names, parameter->name);
218 self->initialized = initialized;
220 return TRUE;
224 static inline HklMode *hkl_mode_new(const HklModeInfo *info,
225 const HklModeOperations *op,
226 int initialized)
228 HklMode *self = g_new(HklMode, 1);
230 hkl_mode_init(self, info, op, initialized);
232 return self;
237 * hkl_mode_free: (skip)
238 * @self:
240 * delete an HklMode
242 static inline void hkl_mode_free(HklMode *self)
244 self->ops->free(self);
247 /*************/
248 /* HklEngine */
249 /*************/
252 struct _HklEngineInfo {
253 const char *name;
254 const darray(const HklParameter *) pseudo_axes;
255 unsigned int dependencies;
258 #define HKL_ENGINE_INFO(_name, _pseudo_axes, _dependencies) .name = (_name), \
259 .pseudo_axes = DARRAY(_pseudo_axes), \
260 .dependencies = (_dependencies)
262 struct _HklEngine
264 const HklEngineInfo *info;
265 const HklEngineOperations *ops;
266 HklGeometry *geometry;
267 HklDetector *detector;
268 HklSample *sample;
269 HklMode *mode; /* not owned */
270 HklEngineList *engines; /* not owned */
271 darray_parameter axes;
272 darray_parameter pseudo_axes;
273 darray_string pseudo_axis_names;
274 darray_mode modes;
275 darray_string mode_names;
279 struct _HklEngineListInfo {
280 const darray(const HklParameter *) parameters;
283 #define HKL_ENGINE_LIST_INFO_DEFAULTS .parameters = darray_new()
284 #define HKL_ENGINE_LIST_INFO(_parameters) .parameters = DARRAY(_parameters)
286 struct _HklEngineListOperations
288 void (* free)(HklEngineList *self);
289 int (* post_engine_set)(HklEngineList *self);
292 #define HKL_ENGINE_LIST_OPERATIONS_DEFAULTS .free=hkl_engine_list_free_real, \
293 .post_engine_set=hkl_engine_list_post_engine_set_real
295 struct _HklEngineList
297 _darray(HklEngine *); /* must be the first memeber */
298 const HklEngineListInfo *info;
299 const HklEngineListOperations *ops;
300 HklGeometryList *geometries;
301 HklGeometry *geometry;
302 HklDetector *detector;
303 HklSample *sample;
304 darray_parameter pseudo_axes;
305 darray_parameter parameters;
306 darray_string parameters_names;
309 #define HKL_ENGINE_ERROR hkl_engine_error_quark ()
312 static GQuark hkl_engine_error_quark (void)
314 return g_quark_from_static_string ("hkl-engine-error-quark");
318 typedef enum {
319 HKL_ENGINE_ERROR_PSEUDO_AXIS_VALUES_GET, /* can not get the engine pseudo axes values */
320 HKL_ENGINE_ERROR_PSEUDO_AXIS_VALUES_SET, /* can not set the engine pseudo axes values */
321 HKL_ENGINE_ERROR_PSEUDO_AXIS_SET, /* can not set the pseudo axis */
322 HKL_ENGINE_ERROR_INITIALIZE, /* can not initialize the engine */
323 HKL_ENGINE_ERROR_SET, /* can not set the engine */
324 HKL_ENGINE_ERROR_GET, /* can not get the engine */
325 HKL_ENGINE_ERROR_PARAMETER_GET, /* can not get the parameter */
326 HKL_ENGINE_ERROR_PARAMETER_SET, /* can not set the parameter */
327 HKL_ENGINE_ERROR_CURRENT_MODE_SET, /* can not select the mode */
328 } HklEngineError;
331 static inline void set_geometry_axes(HklEngine *engine, const double values[])
333 HklParameter **axis;
334 uint i = 0;
336 darray_foreach(axis, engine->axes){
337 hkl_parameter_value_set(*axis, values[i++], HKL_UNIT_DEFAULT, NULL);
339 hkl_geometry_update(engine->geometry);
343 static inline void hkl_engine_release(HklEngine *self)
345 HklMode **mode;
347 if(self->geometry)
348 hkl_geometry_free(self->geometry);
350 if(self->detector)
351 hkl_detector_free(self->detector);
353 if(self->sample)
354 hkl_sample_free(self->sample);
356 /* release the mode added */
357 darray_foreach(mode, self->modes){
358 hkl_mode_free(*mode);
360 darray_free(self->modes);
362 darray_free(self->axes);
363 darray_free(self->pseudo_axes);
364 darray_free(self->pseudo_axis_names);
365 darray_free(self->mode_names);
369 struct _HklEngineOperations
371 void (*free)(HklEngine *self);
375 #define HKL_ENGINE_OPERATIONS_DEFAULTS .free=hkl_engine_free_real
378 static inline void hkl_engine_free_real(UNUSED HklEngine *self)
383 static inline void hkl_engine_free(HklEngine *self)
385 self->ops->free(self);
389 static inline void hkl_engine_init(HklEngine *self,
390 const HklEngineInfo *info,
391 const HklEngineOperations *ops,
392 HklEngineList *engines)
394 self->info = info;
395 self->ops = ops;
396 self->geometry = NULL;
397 self->detector = NULL;
398 self->sample = NULL;
399 self->engines = engines;
400 darray_init(self->axes);
401 darray_init(self->pseudo_axes);
402 darray_init(self->pseudo_axis_names);
403 darray_init(self->modes);
404 darray_init(self->mode_names);
406 darray_append(*engines, self);
409 static inline HklParameter *register_mode_parameter(HklMode *mode, unsigned int index)
411 if(index < darray_size(mode->parameters))
412 return darray_item(mode->parameters, index);
413 else
414 abort();
417 static inline HklParameter *register_pseudo_axis(HklEngine *self,
418 HklEngineList *engines,
419 const HklParameter *pseudo_axis)
421 HklParameter **param;
422 HklParameter *parameter;
424 /* try to find an already existing pseudo axis in the list. */
425 darray_foreach(param, engines->pseudo_axes){
426 if(!strcmp(pseudo_axis->name, (*param)->name)){
427 parameter = *param;
428 goto out;
432 parameter = hkl_parameter_new_copy(pseudo_axis);
433 darray_append(engines->pseudo_axes, parameter);
434 out:
435 darray_append(self->pseudo_axes, parameter);
436 darray_append(self->pseudo_axis_names, parameter->name);
438 return parameter;
442 * hkl_engine_add_mode: (skip)
443 * @self:
444 * @mode: the mode to add
446 * add an HklMode to the self HklEngine
448 static inline void hkl_engine_add_mode(HklEngine *self, HklMode *mode) HKL_ARG_NONNULL(1, 2);
449 static inline void hkl_engine_add_mode(HklEngine *self, HklMode *mode)
451 darray_append(self->modes, mode);
452 darray_append(self->mode_names, mode->info->name);
456 * hkl_engine_add_geometry: (skip)
457 * @self: the current PseudoAxeEngine
458 * @x: x A vector of double with the axes values to put in the geometry.
460 * This method try to be clever by allocating memory only if the
461 * current length of the geometries is not large enought. Then it just
462 * set the geometry axes and copy it to the right geometries. We do
463 * not gives the x len as it is equal to the self->axes_len.
466 static inline void hkl_engine_add_geometry(HklEngine *self,
467 double const x[])
469 HklParameter **axis;
470 uint i = 0;
472 /* copy the axes configuration into the engine->geometry */
473 darray_foreach(axis, self->axes){
474 hkl_parameter_value_set(*axis,
475 gsl_sf_angle_restrict_symm(x[i++]),
476 HKL_UNIT_DEFAULT,
477 NULL);
480 hkl_geometry_list_add(self->engines->geometries, self->geometry);
484 static inline void hkl_engine_prepare_internal(HklEngine *self)
486 if(!self || !self->engines)
487 return;
489 /* set */
490 if(self->geometry)
491 hkl_geometry_free(self->geometry);
492 self->geometry = hkl_geometry_new_copy(self->engines->geometry);
494 if(self->detector)
495 hkl_detector_free(self->detector);
496 self->detector = hkl_detector_new_copy(self->engines->detector);
498 if(self->sample)
499 hkl_sample_free(self->sample);
500 self->sample = hkl_sample_new_copy(self->engines->sample);
502 /* fill the axes member from the function */
503 if(self->mode){
504 const char **axis_name;
506 darray_free(self->axes);
507 darray_init(self->axes);
508 darray_foreach(axis_name, self->mode->info->axes_w){
509 HklParameter *axis = hkl_geometry_get_axis_by_name(self->geometry,
510 *axis_name);
511 darray_append(self->axes, axis);
515 /* reset the geometries len */
516 hkl_geometry_list_reset(self->engines->geometries);
520 * hkl_engine_mode_set: (skip)
521 * @self: the HklEngine
522 * @name: the mode to select
524 * This method also populate the self->axes from the mode->axis_names.
525 * this is to speed the computation of the numerical axes.
527 static inline void hkl_engine_mode_set(HklEngine *self, HklMode *mode)
529 self->mode = mode;
533 static inline int hkl_engine_get(HklEngine *self,
534 GError **error) HKL_ARG_NONNULL(1);
536 * hkl_engine_get: (skip)
537 * @self: The HklEngine
538 * @error: return location for a GError, or NULL
540 * get the values of the pseudo-axes from the real-axes values
542 * return value: TRUE if succeded or FALSE otherwise.
544 static inline int hkl_engine_get(HklEngine *self, GError **error)
546 hkl_error (error == NULL || *error == NULL);
548 if(!self->engines || !self->engines->geometry || !self->engines->detector
549 || !self->engines->sample || !self->mode || !self->mode->ops->get){
550 g_set_error(error,
551 HKL_ENGINE_ERROR,
552 HKL_ENGINE_ERROR_GET,
553 "Internal error");
554 return FALSE;
557 if (!self->mode->ops->get(self->mode,
558 self,
559 self->engines->geometry,
560 self->engines->detector,
561 self->engines->sample,
562 error)){
563 hkl_assert(error == NULL || *error != NULL);
564 return FALSE;
566 hkl_assert(error == NULL || *error == NULL);
568 return TRUE;
573 * hkl_engine_list_post_process_free: (skip)
574 * @self: the #HklEngineList to modify
576 * apply a post set method.
578 static int hkl_engine_list_post_engine_set(HklEngineList *self)
580 return self->ops->post_engine_set(self);
586 * hkl_engine_set: (skip)
587 * @self: the HklEngine
588 * @error: return location for a GError, or NULL
590 * use the HklPseudoaxisEngine values to compute the real axes values.
592 * return value: TRUE if succeded or FALSE otherwise.
594 static inline int hkl_engine_set(HklEngine *self, GError **error)
596 hkl_error (error == NULL || *error == NULL);
598 if(!self->geometry || !self->detector || !self->sample
599 || !self->mode || !self->mode->ops->set){
600 g_set_error(error,
601 HKL_ENGINE_ERROR,
602 HKL_ENGINE_ERROR_SET,
603 "Internal error");
604 return FALSE;
607 hkl_engine_prepare_internal(self);
609 if (!self->mode->ops->set(self->mode, self,
610 self->geometry,
611 self->detector,
612 self->sample,
613 error)){
614 hkl_assert(error == NULL || *error != NULL);
615 return FALSE;
617 hkl_assert(error == NULL || *error == NULL);
619 hkl_geometry_list_multiply(self->engines->geometries);
620 hkl_engine_list_post_engine_set(self->engines);
621 hkl_geometry_list_multiply_from_range(self->engines->geometries);
622 hkl_geometry_list_remove_invalid(self->engines->geometries);
623 hkl_geometry_list_sort(self->engines->geometries, self->engines->geometry);
625 if(self->engines->geometries->n_items == 0){
626 g_set_error(error,
627 HKL_ENGINE_ERROR,
628 HKL_ENGINE_ERROR_SET,
629 "no remaining solutions");
630 return FALSE;
633 return TRUE;
636 /* HklEngineList */
639 #define HKL_ENGINE_LIST_ERROR hkl_engine_list_error_quark ()
642 static inline GQuark hkl_engine_list_error_quark (void)
644 return g_quark_from_static_string ("hkl-engine-list-error-quark");
648 typedef enum {
649 HKL_ENGINE_LIST_ERROR_ENGINE_GET_BY_NAME, /* can not set this geometry */
650 HKL_ENGINE_LIST_ERROR_PSEUDO_AXIS_GET_BY_NAME, /* can not set this geometry */
651 HKL_ENGINE_LIST_ERROR_PARAMETER_GET, /* can not get the parameter */
652 HKL_ENGINE_LIST_ERROR_PARAMETER_SET, /* can not set the parameter */
653 } HklEngineListError;
656 * hkl_engine_list_clear: (skip)
657 * @self: the engine list to clear
659 * remove all engine from the engine list
661 static inline void hkl_engine_list_clear(HklEngineList *self)
663 HklEngine **engine;
664 HklParameter **parameter;
666 darray_foreach(engine, *self){
667 hkl_engine_free(*engine);
669 darray_free(*self);
671 darray_foreach(parameter, self->pseudo_axes){
672 hkl_parameter_free(*parameter);
674 darray_free(self->pseudo_axes);
676 darray_foreach(parameter, self->parameters){
677 hkl_parameter_free(*parameter);
679 darray_free(self->parameters);
680 darray_free(self->parameters_names);
684 * hkl_engine_list_free_real: (skip)
685 * @self: the #HklEngineList to destroy
687 * destructor
689 static inline void hkl_engine_list_free_real(HklEngineList *self)
691 hkl_engine_list_clear(self);
692 hkl_geometry_list_free(self->geometries);
693 free(self);
697 * hkl_engine_list_post_process_real: (skip)
698 * @self: the #HklEngineList to destroy
700 * destructor
702 static inline int hkl_engine_list_post_engine_set_real(UNUSED HklEngineList *self)
704 return FALSE;
708 * hkl_engine_list_new_with_info: (skip)
709 * @info: the info part of the HklEngineList
711 * default constructor with info part
713 * Returns:
715 static inline HklEngineList *hkl_engine_list_new_with_info(const HklEngineListInfo *info,
716 const HklEngineListOperations *ops)
718 const HklParameter **parameter;
719 HklEngineList *self = g_new(HklEngineList, 1);
721 /* This code needs _darray to be at start of HklEngineList */
722 BUILD_ASSERT(offsetof(HklEngineList, item) == 0);
723 darray_init(*self);
725 self->info = info;
726 self->ops = ops;
728 self->geometries = hkl_geometry_list_new();
730 self->geometry = NULL;
731 self->detector = NULL;
732 self->sample = NULL;
734 darray_init(self->pseudo_axes);
736 darray_init(self->parameters);
737 darray_init(self->parameters_names);
738 darray_foreach(parameter, info->parameters){
739 darray_append(self->parameters, hkl_parameter_new_copy(*parameter));
740 darray_append(self->parameters_names, (*parameter)->name);
743 return self;
747 * hkl_engine_list_new: (skip)
749 * default constructor
751 * Returns:
753 static inline HklEngineList *hkl_engine_list_new(void)
755 static const HklEngineListInfo info = {HKL_ENGINE_LIST_INFO_DEFAULTS};
756 static const HklEngineListOperations ops = {HKL_ENGINE_LIST_OPERATIONS_DEFAULTS};
758 return hkl_engine_list_new_with_info(&info, &ops);
763 * hkl_engine_list_new_copy: (skip)
764 * @self:
766 * dummy copy constructor for the binding
768 * Returns: (transfer none): NULL all the time the structure is non-copyable
770 static inline HklEngineList *hkl_engine_list_new_copy(UNUSED const HklEngineList *self)
772 return NULL;
775 G_END_DECLS
777 #endif /* __HKL_PSEUDOAXIS_PRIVATE_H__ */