2 * This file is part of the hkl library.
4 * The hkl library is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * The hkl library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with the hkl library. If not, see <http://www.gnu.org/licenses/>.
17 * Copyright (C) 2003-2017 Synchrotron SOLEIL
18 * L'Orme des Merisiers Saint-Aubin
19 * BP 48 91192 GIF-sur-YVETTE CEDEX
21 * Authors: Picca Frédéric-Emmanuel <picca@synchrotron-soleil.fr>
23 #include <stdio.h> // for fprintf, FILE
24 #include <stdlib.h> // for free
25 #include <string.h> // for NULL, strcmp
26 #include <sys/types.h> // for uint
27 #include "hkl-detector-private.h" // for hkl_detector_new_copy
28 #include "hkl-geometry-private.h" // for _HklGeometryList, etc
29 #include "hkl-macros-private.h" // for hkl_assert, HKL_MALLOC, etc
30 #include "hkl-parameter-private.h" // for hkl_parameter_list_fprintf, etc
31 #include "hkl-pseudoaxis-private.h" // for _HklEngine, _HklEngineList, etc
32 #include "hkl-sample-private.h"
33 #include "hkl.h" // for HklEngine, HklEngineList, etc
34 #include "hkl/ccan/container_of/container_of.h" // for container_of
35 #include "hkl/ccan/darray/darray.h" // for darray_foreach, darray_init, etc
42 * hkl_mode_fprintf: (skip)
46 * print to a FILE the HklPSeudoAxisEngineMode members
48 void hkl_mode_fprintf(FILE *f
, const HklMode
*self
)
50 HklParameter
**parameter
;
53 fprintf(f
, "mode: \"%s\"\n", self
->info
->name
);
54 fprintf(f
, "initialized_get: %p\n", self
->ops
->initialized_get
);
55 fprintf(f
, "initialized_set: %p\n", self
->ops
->initialized_set
);
56 fprintf(f
, "get: %p\n", self
->ops
->get
);
57 fprintf(f
, "set: %p\n", self
->ops
->set
);
59 darray_foreach(parameter
, self
->parameters
){
61 hkl_parameter_fprintf(f
, *parameter
);
64 fprintf(f
, "axes (read) names:");
65 darray_foreach(axis
, self
->info
->axes_r
)
66 fprintf(f
, " %s", *axis
);
69 fprintf(f
, "axes (write) names:");
70 darray_foreach(axis
, self
->info
->axes_w
)
71 fprintf(f
, " %s", *axis
);
80 * hkl_engine_name_get:
83 * Return value: the name of the HklEngine
85 const char *hkl_engine_name_get(const HklEngine
*self
)
87 return self
->info
->name
;
91 * hkl_engine_len: (skip)
94 * Return value: the len of the pseudo axes of the HklEngine
96 unsigned int hkl_engine_len(const HklEngine
*self
)
98 return darray_size(self
->info
->pseudo_axes
);
102 * hkl_engine_pseudo_axis_names_get:
103 * @self: the this ptr
105 * Return value: (type gpointer): the pseudo_axes managed by this #HklEngine
107 const darray_string
*hkl_engine_pseudo_axis_names_get(HklEngine
*self
)
109 return &self
->pseudo_axis_names
;
113 * hkl_engine_pseudo_axis_values_get:
114 * @self: the this ptr
115 * @values: (array length=n_values): the values to get
116 * @n_values: the size of the values array.
117 * @unit_type: the unit type (default or user) of the returned value
119 * Get the engine pseudo axes values
121 * return value: TRUE if succeded or FALSE otherwise.
123 int hkl_engine_pseudo_axis_values_get(HklEngine
*self
,
124 double values
[], size_t n_values
,
125 HklUnitEnum unit_type
, GError
**error
)
127 hkl_error(error
== NULL
||*error
== NULL
);
129 if(n_values
!= darray_size(self
->info
->pseudo_axes
)){
132 HKL_ENGINE_ERROR_PSEUDO_AXIS_VALUES_GET
,
133 "cannot get engine pseudo axes, wrong number of parameter (%d) given, (%d) expected\n",
134 n_values
, darray_size(self
->info
->pseudo_axes
));
138 if(!hkl_engine_get(self
, error
)){
139 g_assert(error
== NULL
|| *error
!= NULL
);
142 g_assert(error
== NULL
|| *error
== NULL
);
144 for(size_t i
=0; i
<n_values
; ++i
){
145 values
[i
] = hkl_parameter_value_get(darray_item(self
->pseudo_axes
, i
),
152 * hkl_engine_pseudo_axis_values_set:
153 * @self: the this ptr
154 * @values: (array length=n_values): the values to set
155 * @n_values: the size of the values array.
156 * @unit_type: the unit type (default or user) of the returned value
157 * @error: return location for a GError, or NULL
159 * Set the engine pseudo axes values
161 * Return value: #HklGeometryList or NULL if no solution was found,
162 * use hkl_geometry_list_free to release the memory once done.
164 HklGeometryList
*hkl_engine_pseudo_axis_values_set(HklEngine
*self
,
165 double values
[], size_t n_values
,
166 HklUnitEnum unit_type
, GError
**error
)
173 HklGeometryList
*solutions
= NULL
;
175 hkl_error(error
== NULL
||*error
== NULL
);
177 if(n_values
!= darray_size(self
->info
->pseudo_axes
)){
180 HKL_ENGINE_ERROR_PSEUDO_AXIS_VALUES_SET
,
181 "cannot set engine pseudo axes, wrong number of parameter (%d) given, (%d) expected\n",
182 n_values
, darray_size(self
->info
->pseudo_axes
));
187 stream
= open_memstream(&msg
, &msg_size
);
189 fprintf(stream
, "%s(", __func__
);
190 fprintf(stream
, "self: %s, values: [", hkl_engine_name_get(self
));
191 for(size_t i
=0; i
<n_values
; ++i
)
192 fprintf(stream
, " %f", values
[i
]);
193 fprintf(stream
, "], n_values: %d unit_type: %d, error: %p)", n_values
, unit_type
, error
);
195 hkl_geometry_fprintf(stream
, self
->engines
->geometry
);
196 hkl_sample_fprintf(stream
, self
->engines
->sample
);
197 hkl_engine_fprintf(stream
, self
);
199 for(size_t i
=0; i
<n_values
; ++i
){
200 if(!hkl_parameter_value_set(darray_item(self
->pseudo_axes
, i
),
203 goto clean_stream_out
;
207 if(!hkl_engine_set(self
, error
)){
211 if(error
&& *error
!= NULL
)
212 g_warning("%s", (*error
)->message
);
214 goto clean_stream_out
;
217 solutions
= hkl_geometry_list_new_copy(self
->engines
->geometries
);
220 hkl_geometry_list_fprintf(stream
, solutions
);
235 * hkl_engine_pseudo_axis_get:
236 * @self: the this ptr
237 * @name: the name of the expected pseudo_axis
238 * @error: return location for a GError, or NULL
240 * get the #HklParameter with the given @name.
242 * Returns: (allow-none): retun the parameter or NULL if the engine
243 * does not contain this pseudo_axis.
246 const HklParameter
*hkl_engine_pseudo_axis_get(const HklEngine
*self
,
250 HklParameter
**parameter
;
252 hkl_error (error
== NULL
|| *error
== NULL
);
254 darray_foreach(parameter
, self
->pseudo_axes
)
255 if(!strcmp((*parameter
)->name
, name
))
260 HKL_ENGINE_ERROR_PSEUDO_AXIS_SET
,
261 "This pseudo axis doesn not contain this pseudo axis \"%s\"\n",
268 * hkl_engine_pseudo_axis_set: (skip)
269 * @self: the this ptr
270 * @name: the name of the pseudo_axis to set
271 * @parameter: the parameter to set.
272 * @error: return location for a GError, or NULL
274 * set a parameter of the #HklEngine
276 * Return value: #HklGeometryList or NULL if no solution was found,
277 * use hkl_geometry_list_free to release the memory once done.
279 HklGeometryList
*hkl_engine_pseudo_axis_set(HklEngine
*self
,
281 const HklParameter
*parameter
,
286 hkl_error (error
== NULL
|| *error
== NULL
);
287 hkl_error (strcmp(name
, parameter
->name
) == 0);
289 darray_foreach(p
, self
->pseudo_axes
)
290 if(!strcmp((*p
)->name
, parameter
->name
)){
291 /* todo save the previous value to restore this value */
292 hkl_parameter_init_copy(*p
, parameter
, NULL
);
293 if(!hkl_engine_set(self
, error
)){
294 g_assert(error
== NULL
|| *error
!= NULL
);
297 g_assert(error
== NULL
|| *error
== NULL
);
299 return hkl_geometry_list_new_copy(self
->engines
->geometries
);
304 HKL_ENGINE_ERROR_PSEUDO_AXIS_SET
,
305 "Can not find the pseudo axis \"%s\" in the \"%s\" engine\n",
306 parameter
->name
, self
->info
->name
);
312 * hkl_engine_capabilities_get:
313 * @self: the this ptr
315 * return the capabilities of the engine. Theses capabilities can
316 * change, from on mode to the other. for now there is three kind of
319 * HKL_ENGINE_CAP_READABLE: pseudo axes values can be read from the HklEngine
321 * HKL_ENGINE_CAP_WRITABLE: pseudo axes values can be set for this #HklEngine
323 * HKL_ENGINE_CAP_INITIALISABLE: this pseudo axes must be initialized
324 * with hkl_engine_initialize before
325 * reading or writing on it.
329 unsigned int hkl_engine_capabilities_get(const HklEngine
*self
)
331 return self
->mode
->ops
->capabilities
;
336 * hkl_engine_modes_names_get:
337 * @self: the this ptr
339 * Return value: (type gpointer): All the modes supported by the #HklEngine
341 const darray_string
*hkl_engine_modes_names_get(const HklEngine
*self
)
343 return &self
->mode_names
;
347 * hkl_engine_parameters_names_get:
348 * @self: the this ptr
350 * Return value: (type gpointer): All the parameters of #HklEngine.
352 const darray_string
*hkl_engine_parameters_names_get(const HklEngine
*self
)
354 return &self
->mode
->parameters_names
;
358 * hkl_engine_parameters_values_get: (skip)
359 * @self: the this ptr
360 * @values: (array length=n_values): the values to get
361 * @n_values: the size of the values array.
362 * @unit_type: the unit type (default or user) of the returned value
364 * Get the engine parameters values
366 void hkl_engine_parameters_values_get(const HklEngine
*self
,
367 double values
[], size_t n_values
,
368 HklUnitEnum unit_type
)
370 g_return_if_fail (n_values
== darray_size(self
->mode
->parameters
));
372 for(size_t i
=0; i
<n_values
; ++i
)
373 values
[i
] = hkl_parameter_value_get(darray_item(self
->mode
->parameters
, i
),
378 * hkl_engine_parameters_values_set:
379 * @self: the this ptr
380 * @values: (array length=n_values): the values to set
381 * @n_values: the size of the values array.
382 * @unit_type: the unit type (default or user) of the returned value
383 * @error: return location for a GError, or NULL
385 * Set the engine parameters values
387 * return value: TRUE if succeded or FALSE otherwise.
389 int hkl_engine_parameters_values_set(HklEngine
*self
,
390 double values
[], size_t n_values
,
391 HklUnitEnum unit_type
, GError
**error
)
393 hkl_error (error
== NULL
|| *error
== NULL
|| n_values
== darray_size(self
->mode
->parameters
));
395 for(size_t i
=0; i
<n_values
; ++i
){
396 if(!hkl_parameter_value_set(darray_item(self
->mode
->parameters
, i
),
397 values
[i
], unit_type
, error
)){
398 g_assert (error
== NULL
|| *error
!= NULL
);
402 g_assert (error
== NULL
|| *error
== NULL
);
408 * hkl_engine_parameter_get:
409 * @self: the this ptr
410 * @name: the name of the expected parameter
411 * @error: return location for a GError, or NULL
413 * get the #HklParameter with the given @name.
415 * Returns: (allow-none): return the parameter or NULL if the engine
416 * does not contain this parameter.
418 const HklParameter
*hkl_engine_parameter_get(const HklEngine
*self
,
422 HklParameter
**parameter
;
424 hkl_error (error
== NULL
|| *error
== NULL
);
426 darray_foreach(parameter
, self
->mode
->parameters
)
427 if(!strcmp((*parameter
)->name
, name
))
432 HKL_ENGINE_ERROR_PARAMETER_GET
,
433 "this engine does not contain this parameter \"%s\"\n",
440 * hkl_engine_parameter_set:
441 * @self: the this ptr
442 * @name: the name of the parameter to set.
443 * @parameter: the parameter to set.
444 * @error: return location for a GError, or NULL
446 * set a parameter of the #HklEngine
449 * return value: TRUE if succeded or FALSE otherwise.
451 int hkl_engine_parameter_set(HklEngine
*self
,
453 const HklParameter
*parameter
,
458 hkl_error (error
== NULL
|| *error
== NULL
);
460 darray_foreach(p
, self
->mode
->parameters
)
461 if(!strcmp(name
, (*p
)->name
)){
462 const char *old_name
= (*p
)->name
;
463 hkl_parameter_init_copy(*p
, parameter
, NULL
);
464 /* we do not check if the name is identical so force the right name */
465 /* TODO rethink this HklParameter assignement */
466 (*p
)->name
= old_name
;
472 HKL_ENGINE_ERROR_PARAMETER_SET
,
473 "this engine does not contain this parameter \"%s\"\n",
480 * hkl_engine_current_mode_get:
481 * @self: the this ptr
483 * Returns: the current HklEngine mode
485 const char *hkl_engine_current_mode_get(const HklEngine
*self
)
487 return self
->mode
->info
->name
;
491 * hkl_engine_current_mode_set:
492 * @self: the HklEngine
493 * @name: the mode to select
494 * @error: return location for a GError, or NULL
496 * This method also populate the self->axes from the mode->axis_names.
497 * this is to speed the computation of the numerical axes.
499 * return value: TRUE if succeded or FALSE otherwise.
501 int hkl_engine_current_mode_set(HklEngine
*self
, const char *name
,
506 hkl_error (error
== NULL
|| *error
== NULL
);
508 darray_foreach(mode
, self
->modes
)
509 if(!strcmp((*mode
)->info
->name
, name
)){
510 hkl_engine_mode_set(self
, *mode
);
516 HKL_ENGINE_ERROR_CURRENT_MODE_SET
,
517 "this engine does not contain this mode \"%s\"\n",
524 * hkl_engine_axis_names_get:
525 * @self: the this ptr
528 * return a list of axes relevant when reading or writing on the
531 * exemple, for a K6C diffractometer in "lifting detector" mode, your
532 * Engine control only 3 motors when writing, but the hkl values
533 * depends on the 6 motors when reading.
535 * Returns: (type gpointer):
537 const darray_string
*hkl_engine_axis_names_get(const HklEngine
*self
,
538 HklEngineAxisNamesGet mode
)
541 case HKL_ENGINE_AXIS_NAMES_GET_READ
:
542 return &self
->mode
->info
->axes_r
;
543 case HKL_ENGINE_AXIS_NAMES_GET_WRITE
:
544 return &self
->mode
->info
->axes_w
;
550 int hkl_engine_initialized_get(const HklEngine
*self
)
552 return hkl_mode_initialized_get(self
->mode
);
556 * hkl_engine_initialized_set:
557 * @self: the HklEngine
558 * @initialized: TRUE or FALSE to activated or deactivate the HklEngine
559 * @error: return location for a GError, or NULL
561 * initialize the HklEngine
563 * return value: TRUE if succeded or FALSE otherwise.
565 int hkl_engine_initialized_set(HklEngine
*self
, int initialized
, GError
**error
)
567 hkl_error (error
== NULL
|| *error
== NULL
);
569 if(!self
->geometry
|| !self
->detector
|| !self
->sample
573 HKL_ENGINE_ERROR_INITIALIZE
,
578 return hkl_mode_initialized_set(self
->mode
,
580 self
->engines
->geometry
,
581 self
->engines
->detector
,
582 self
->engines
->sample
,
588 * hkl_engine_dependencies_get:
589 * @self: the this ptr
591 * return all dependencies of the engine which are not mode parameters
592 * or axes. The possible combination of values are defined in
593 * #HklEngineDependencies enum.
597 unsigned int hkl_engine_dependencies_get(const HklEngine
*self
)
599 return self
->info
->dependencies
;
603 * hkl_engine_fprintf: (skip)
605 * @self: the HklEngine
607 * print to a FILE the HklEngine
609 void hkl_engine_fprintf(FILE *f
, const HklEngine
*self
)
611 HklParameter
**pseudo_axis
;
613 fprintf(f
, "\nPseudoAxesEngine : \"%s\"", self
->info
->name
);
617 fprintf(f
, " %s", self
->mode
->info
->name
);
618 for(uint i
=0; i
<darray_size(self
->mode
->parameters
); ++i
){
620 hkl_parameter_fprintf(
622 darray_item(self
->mode
->parameters
, i
));
627 /* the pseudoAxes part */
628 darray_foreach(pseudo_axis
, self
->pseudo_axes
){
630 hkl_parameter_fprintf(f
, *pseudo_axis
);
633 if(self
->engines
->geometries
->n_items
!= 0){
635 hkl_geometry_list_fprintf(f
, self
->engines
->geometries
);
645 * hkl_engine_list_free: (skip)
646 * @self: the #HklEngineList to destroy
650 void hkl_engine_list_free(HklEngineList
*self
)
652 hkl_engine_list_clear(self
);
653 hkl_geometry_list_free(self
->geometries
);
658 * hkl_engine_list_engines_get: (skip)
659 * @self: the this ptr
661 * Return: a pointer on the engine array
663 darray_engine
*hkl_engine_list_engines_get(HklEngineList
*self
)
665 return (darray_engine
*)self
;
669 * hkl_engine_list_geometry_get: (skip)
670 * @self: the this ptr
672 * Return: a pointer on the geometry member
674 HklGeometry
*hkl_engine_list_geometry_get(HklEngineList
*self
)
676 return self
->geometry
;
679 int hkl_engine_list_geometry_set(HklEngineList
*self
, const HklGeometry
*geometry
)
681 if(!hkl_geometry_set(self
->geometry
, geometry
))
684 hkl_engine_list_get(self
);
690 * hkl_engine_list_select_solution:
691 * @self: the this ptr
692 * @item: the #HklGeoemtryListItem selected.
694 * this method set the geometry member with the selected solution.
696 * return value: TRUE if succeded or FALSE otherwise.
698 int hkl_engine_list_select_solution(HklEngineList
*self
,
699 const HklGeometryListItem
*item
)
701 return hkl_geometry_init_geometry(self
->geometry
, item
->geometry
);
705 * hkl_engine_list_engine_get_by_name:
706 * @self: the this ptr
707 * @name: the name of the requested #HklPseudoAxisEngin
708 * @error: return location for a GError, or NULL
710 * get the #HklEngine by its name from the list.
712 * Returns: (transfer none) (allow-none): the requested engine
714 HklEngine
*hkl_engine_list_engine_get_by_name(HklEngineList
*self
,
720 hkl_error (error
== NULL
|| *error
== NULL
);
722 darray_foreach(engine
, *self
){
723 if (!strcmp((*engine
)->info
->name
, name
))
728 HKL_ENGINE_LIST_ERROR
,
729 HKL_ENGINE_LIST_ERROR_ENGINE_GET_BY_NAME
,
730 "this engine list does not contain this engine \"%s\"",
737 * hkl_engine_list_init:
738 * @self: the engine list
739 * @geometry: the associated #HklGeometry
740 * @detector: the associated #HklDetector
741 * @sample: the associated #HklSample
743 * before using an engine list you must associate all engines to a
744 * Geometry, a detector and a sample.
746 void hkl_engine_list_init(HklEngineList
*self
,
747 HklGeometry
*geometry
,
748 HklDetector
*detector
,
753 self
->geometry
= geometry
;
754 self
->detector
= detector
;
755 self
->sample
= sample
;
757 darray_foreach(engine
, *self
){
758 hkl_engine_prepare_internal(*engine
);
763 * hkl_engine_list_get:
764 * @self: the list of #HklEngine
766 * apply the get method to all the #HklEngine of the list
767 * after this it is possible to retrive all the #HklPseudoAxis values.
769 * Returns: HKL_SUCCESS or HKL_FAIL if one of the #HklEngine
772 int hkl_engine_list_get(HklEngineList
*self
)
777 darray_foreach(engine
, *self
){
778 res
&= hkl_engine_get(*engine
, NULL
);
785 * hkl_engine_list_fprintf: (skip)
789 * print to a FILE the #HklEngineList
791 void hkl_engine_list_fprintf(FILE *f
,
792 const HklEngineList
*self
)
796 darray_foreach(engine
, *self
){
797 hkl_engine_fprintf(f
, *engine
);