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
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
;
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
,
76 HklGeometry
*geometry
,
77 HklDetector
*detector
,
81 int (* get
)(HklMode
*self
,
83 HklGeometry
*geometry
,
84 HklDetector
*detector
,
87 int (* set
)(HklMode
*self
,
89 HklGeometry
*geometry
,
90 HklDetector
*detector
,
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
106 const HklModeInfo
*info
;
107 const HklModeOperations
*ops
;
108 darray_parameter parameters
;
109 darray_string parameters_names
;
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
);
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 */
154 static inline int hkl_mode_initialized_set(HklMode
*self
,
156 HklGeometry
*geometry
,
157 HklDetector
*detector
,
162 return self
->ops
->initialized_set(self
,
163 engine
, geometry
, detector
, sample
,
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 */
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 */
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
,
201 const HklParameter
*parameter
;
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
)))
214 darray_append(self
->parameters
, p
);
215 darray_append(self
->parameters_names
, parameter
->name
);
218 self
->initialized
= initialized
;
224 static inline HklMode
*hkl_mode_new(const HklModeInfo
*info
,
225 const HklModeOperations
*op
,
228 HklMode
*self
= g_new(HklMode
, 1);
230 hkl_mode_init(self
, info
, op
, initialized
);
237 * hkl_mode_free: (skip)
242 static inline void hkl_mode_free(HklMode
*self
)
244 self
->ops
->free(self
);
252 struct _HklEngineInfo
{
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)
264 const HklEngineInfo
*info
;
265 const HklEngineOperations
*ops
;
266 HklGeometry
*geometry
;
267 HklDetector
*detector
;
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
;
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
;
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");
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 */
331 static inline void set_geometry_axes(HklEngine
*engine
, const double values
[])
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
)
348 hkl_geometry_free(self
->geometry
);
351 hkl_detector_free(self
->detector
);
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
)
396 self
->geometry
= NULL
;
397 self
->detector
= 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
);
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
)){
432 parameter
= hkl_parameter_new_copy(pseudo_axis
);
433 darray_append(engines
->pseudo_axes
, parameter
);
435 darray_append(self
->pseudo_axes
, parameter
);
436 darray_append(self
->pseudo_axis_names
, parameter
->name
);
442 * hkl_engine_add_mode: (skip)
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
,
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
++]),
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
)
491 hkl_geometry_free(self
->geometry
);
492 self
->geometry
= hkl_geometry_new_copy(self
->engines
->geometry
);
495 hkl_detector_free(self
->detector
);
496 self
->detector
= hkl_detector_new_copy(self
->engines
->detector
);
499 hkl_sample_free(self
->sample
);
500 self
->sample
= hkl_sample_new_copy(self
->engines
->sample
);
502 /* fill the axes member from the function */
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
,
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
)
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
){
552 HKL_ENGINE_ERROR_GET
,
557 if (!self
->mode
->ops
->get(self
->mode
,
559 self
->engines
->geometry
,
560 self
->engines
->detector
,
561 self
->engines
->sample
,
563 hkl_assert(error
== NULL
|| *error
!= NULL
);
566 hkl_assert(error
== NULL
|| *error
== NULL
);
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
){
602 HKL_ENGINE_ERROR_SET
,
607 hkl_engine_prepare_internal(self
);
609 if (!self
->mode
->ops
->set(self
->mode
, self
,
614 hkl_assert(error
== NULL
|| *error
!= NULL
);
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){
628 HKL_ENGINE_ERROR_SET
,
629 "no remaining solutions");
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");
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
)
664 HklParameter
**parameter
;
666 darray_foreach(engine
, *self
){
667 hkl_engine_free(*engine
);
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
689 static inline void hkl_engine_list_free_real(HklEngineList
*self
)
691 hkl_engine_list_clear(self
);
692 hkl_geometry_list_free(self
->geometries
);
697 * hkl_engine_list_post_process_real: (skip)
698 * @self: the #HklEngineList to destroy
702 static inline int hkl_engine_list_post_engine_set_real(UNUSED HklEngineList
*self
)
708 * hkl_engine_list_new_with_info: (skip)
709 * @info: the info part of the HklEngineList
711 * default constructor with info part
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);
728 self
->geometries
= hkl_geometry_list_new();
730 self
->geometry
= NULL
;
731 self
->detector
= 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
);
747 * hkl_engine_list_new: (skip)
749 * default constructor
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)
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
)
777 #endif /* __HKL_PSEUDOAXIS_PRIVATE_H__ */