Merge branch 'maint' into next
[hkl.git] / hkl / hkl-pseudoaxis.c
blobf78e40ccc5edb8a9400c92a33c18f10e63dc22b3
1 /*
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-2016 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
37 /***********/
38 /* HklMode */
39 /***********/
41 /**
42 * hkl_mode_fprintf: (skip)
43 * @f:
44 * @self:
46 * print to a FILE the HklPSeudoAxisEngineMode members
47 **/
48 void hkl_mode_fprintf(FILE *f, const HklMode *self)
50 HklParameter **parameter;
51 const char **axis;
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){
60 fprintf(f, "\n ");
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);
67 fprintf(f, "\n");
69 fprintf(f, "axes (write) names:");
70 darray_foreach(axis, self->info->axes_w)
71 fprintf(f, " %s", *axis);
72 fprintf(f, "\n");
75 /*************/
76 /* HklEngine */
77 /*************/
79 /**
80 * hkl_engine_name_get:
81 * @self: the this ptr
83 * Return value: the name of the HklEngine
84 **/
85 const char *hkl_engine_name_get(const HklEngine *self)
87 return self->info->name;
90 /**
91 * hkl_engine_len: (skip)
92 * @self: the this ptr
94 * Return value: the len of the pseudo axes of the HklEngine
95 **/
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)){
130 g_set_error(error,
131 HKL_ENGINE_ERROR,
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));
135 return FALSE;
138 if(!hkl_engine_get(self, error)){
139 g_assert(error == NULL || *error != NULL);
140 return FALSE;
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),
146 unit_type);
148 return TRUE;
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)
168 #if LOGGING
169 char *msg;
170 size_t msg_size;
171 FILE *stream;
172 #endif
173 HklGeometryList *solutions = NULL;
175 hkl_error(error == NULL ||*error == NULL);
177 if(n_values != darray_size(self->info->pseudo_axes)){
178 g_set_error(error,
179 HKL_ENGINE_ERROR,
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));
183 goto out;
186 #if LOGGING
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->geometry);
196 hkl_sample_fprintf(stream, self->sample);
197 hkl_engine_fprintf(stream, self);
198 #endif
199 for(size_t i=0; i<n_values; ++i){
200 if(!hkl_parameter_value_set(darray_item(self->pseudo_axes, i),
201 values[i],
202 unit_type, error)){
203 goto clean_stream_out;
207 if(!hkl_engine_set(self, error)){
208 #if LOGGING
209 fflush(stream);
210 g_message(msg);
211 if(error && *error != NULL)
212 g_warning("%s", (*error)->message);
213 #endif
214 goto clean_stream_out;
217 solutions = hkl_geometry_list_new_copy(self->engines->geometries);
219 #if LOGGING
220 hkl_geometry_list_fprintf(stream, solutions);
221 fflush(stream);
222 g_message(msg);
223 #endif
225 clean_stream_out:
226 #if LOGGING
227 fclose(stream);
228 free(msg);
229 #endif
230 out:
231 return 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.
244 * TODO: unit test
246 const HklParameter *hkl_engine_pseudo_axis_get(const HklEngine *self,
247 const char *name,
248 GError **error)
250 HklParameter **parameter;
252 hkl_error (error == NULL || *error == NULL);
254 darray_foreach(parameter, self->pseudo_axes)
255 if(!strcmp((*parameter)->name, name))
256 return *parameter;
258 g_set_error(error,
259 HKL_ENGINE_ERROR,
260 HKL_ENGINE_ERROR_PSEUDO_AXIS_SET,
261 "This pseudo axis doesn not contain this pseudo axis \"%s\"\n",
262 name);
264 return NULL;
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,
280 const char *name,
281 const HklParameter *parameter,
282 GError **error)
284 HklParameter **p;
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);
295 return NULL;
297 g_assert(error == NULL || *error == NULL);
299 return hkl_geometry_list_new_copy(self->engines->geometries);
302 g_set_error(error,
303 HKL_ENGINE_ERROR,
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);
308 return NULL;
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
317 * capabilities.
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.
327 * Returns:
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 * return value: TRUE if succeded or FALSE otherwise.
368 void hkl_engine_parameters_values_get(const HklEngine *self,
369 double values[], size_t n_values,
370 HklUnitEnum unit_type)
372 g_return_if_fail (n_values == darray_size(self->mode->parameters));
374 for(size_t i=0; i<n_values; ++i)
375 values[i] = hkl_parameter_value_get(darray_item(self->mode->parameters, i),
376 unit_type);
380 * hkl_engine_parameters_values_set:
381 * @self: the this ptr
382 * @values: (array length=n_values): the values to set
383 * @n_values: the size of the values array.
384 * @unit_type: the unit type (default or user) of the returned value
385 * @error: return location for a GError, or NULL
387 * Set the engine parameters values
389 * return value: TRUE if succeded or FALSE otherwise.
391 int hkl_engine_parameters_values_set(HklEngine *self,
392 double values[], size_t n_values,
393 HklUnitEnum unit_type, GError **error)
395 hkl_error (error == NULL || *error == NULL || n_values == darray_size(self->mode->parameters));
397 for(size_t i=0; i<n_values; ++i){
398 if(!hkl_parameter_value_set(darray_item(self->mode->parameters, i),
399 values[i], unit_type, error)){
400 g_assert (error == NULL || *error != NULL);
401 return FALSE;
404 g_assert (error == NULL || *error == NULL);
406 return TRUE;
410 * hkl_engine_parameter_get:
411 * @self: the this ptr
412 * @name: the name of the expected parameter
413 * @error: return location for a GError, or NULL
415 * get the #HklParameter with the given @name.
417 * Returns: (allow-none): return the parameter or NULL if the engine
418 * does not contain this parameter.
420 const HklParameter *hkl_engine_parameter_get(const HklEngine *self,
421 const char *name,
422 GError **error)
424 HklParameter **parameter;
426 hkl_error (error == NULL || *error == NULL);
428 darray_foreach(parameter, self->mode->parameters)
429 if(!strcmp((*parameter)->name, name))
430 return *parameter;
432 g_set_error(error,
433 HKL_ENGINE_ERROR,
434 HKL_ENGINE_ERROR_PARAMETER_GET,
435 "this engine does not contain this parameter \"%s\"\n",
436 name);
438 return NULL;
442 * hkl_engine_parameter_set:
443 * @self: the this ptr
444 * @name: the name of the parameter to set.
445 * @parameter: the parameter to set.
446 * @error: return location for a GError, or NULL
448 * set a parameter of the #HklEngine
449 * TODO add an error
451 * return value: TRUE if succeded or FALSE otherwise.
453 int hkl_engine_parameter_set(HklEngine *self,
454 const char *name,
455 const HklParameter *parameter,
456 GError **error)
458 HklParameter **p;
460 hkl_error (error == NULL || *error == NULL);
462 darray_foreach(p, self->mode->parameters)
463 if(!strcmp(name, (*p)->name)){
464 const char *old_name = (*p)->name;
465 hkl_parameter_init_copy(*p, parameter, NULL);
466 /* we do not check if the name is identical so force the right name */
467 /* TODO rethink this HklParameter assignement */
468 (*p)->name = old_name;
469 return TRUE;
472 g_set_error(error,
473 HKL_ENGINE_ERROR,
474 HKL_ENGINE_ERROR_PARAMETER_SET,
475 "this engine does not contain this parameter \"%s\"\n",
476 parameter->name);
478 return FALSE;
482 * hkl_engine_current_mode_get:
483 * @self: the this ptr
485 * Returns: the current HklEngine mode
487 const char *hkl_engine_current_mode_get(const HklEngine *self)
489 return self->mode->info->name;
493 * hkl_engine_current_mode_set:
494 * @self: the HklEngine
495 * @name: the mode to select
496 * @error: return location for a GError, or NULL
498 * This method also populate the self->axes from the mode->axis_names.
499 * this is to speed the computation of the numerical axes.
501 * return value: TRUE if succeded or FALSE otherwise.
503 int hkl_engine_current_mode_set(HklEngine *self, const char *name,
504 GError **error)
506 HklMode **mode;
508 hkl_error (error == NULL || *error == NULL);
510 darray_foreach(mode, self->modes)
511 if(!strcmp((*mode)->info->name, name)){
512 hkl_engine_mode_set(self, *mode);
513 return TRUE;
516 g_set_error(error,
517 HKL_ENGINE_ERROR,
518 HKL_ENGINE_ERROR_CURRENT_MODE_SET,
519 "this engine does not contain this mode \"%s\"\n",
520 name);
522 return FALSE;
526 * hkl_engine_axis_names_get:
527 * @self: the this ptr
528 * @mode:
530 * return a list of axes relevant when reading or writing on the
531 * #HklEngine.
533 * exemple, for a K6C diffractometer in "lifting detector" mode, your
534 * Engine control only 3 motors when writing, but the hkl values
535 * depends on the 6 motors when reading.
537 * Returns: (type gpointer):
539 const darray_string *hkl_engine_axis_names_get(const HklEngine *self,
540 HklEngineAxisNamesGet mode)
542 switch(mode){
543 case HKL_ENGINE_AXIS_NAMES_GET_READ:
544 return &self->mode->info->axes_r;
545 case HKL_ENGINE_AXIS_NAMES_GET_WRITE:
546 return &self->mode->info->axes_w;
547 default:
548 return NULL;
552 int hkl_engine_initialized_get(const HklEngine *self)
554 return hkl_mode_initialized_get(self->mode);
558 * hkl_engine_initialized_set:
559 * @self: the HklEngine
560 * @initialized: TRUE or FALSE to activated or deactivate the HklEngine
561 * @error: return location for a GError, or NULL
563 * initialize the HklEngine
565 * return value: TRUE if succeded or FALSE otherwise.
567 int hkl_engine_initialized_set(HklEngine *self, int initialized, GError **error)
569 hkl_error (error == NULL || *error == NULL);
571 if(!self->geometry || !self->detector || !self->sample
572 || !self->mode) {
573 g_set_error(error,
574 HKL_ENGINE_ERROR,
575 HKL_ENGINE_ERROR_INITIALIZE,
576 "Internal error");
577 return FALSE;
580 return hkl_mode_initialized_set(self->mode,
581 self,
582 self->engines->geometry,
583 self->engines->detector,
584 self->engines->sample,
585 initialized,
586 error);
590 * hkl_engine_dependencies_get:
591 * @self: the this ptr
593 * return all dependencies of the engine which are not mode parameters
594 * or axes. The possible combination of values are defined in
595 * #HklEngineDependencies enum.
597 * return value:
599 unsigned int hkl_engine_dependencies_get(const HklEngine *self)
601 return self->info->dependencies;
605 * hkl_engine_fprintf: (skip)
606 * @f: the FILE
607 * @self: the HklEngine
609 * print to a FILE the HklEngine
611 void hkl_engine_fprintf(FILE *f, const HklEngine *self)
613 HklParameter **pseudo_axis;
615 fprintf(f, "\nPseudoAxesEngine : \"%s\"", self->info->name);
617 /* mode */
618 if (self->mode) {
619 fprintf(f, " %s", self->mode->info->name);
620 for(uint i=0; i<darray_size(self->mode->parameters); ++i){
621 fprintf(f, "\n ");
622 hkl_parameter_fprintf(
624 darray_item(self->mode->parameters, i));
626 fprintf(f, "\n");
629 /* the pseudoAxes part */
630 darray_foreach(pseudo_axis, self->pseudo_axes){
631 fprintf(f, "\n ");
632 hkl_parameter_fprintf(f, *pseudo_axis);
635 if(self->engines->geometries->n_items != 0){
636 fprintf(f, "\n ");
637 hkl_geometry_list_fprintf(f, self->engines->geometries);
639 fprintf(f, "\n");
642 /*****************/
643 /* HklEngineList */
644 /*****************/
647 * hkl_engine_list_free: (skip)
648 * @self: the #HklEngineList to destroy
650 * destructor
652 void hkl_engine_list_free(HklEngineList *self)
654 hkl_engine_list_clear(self);
655 hkl_geometry_list_free(self->geometries);
656 free(self);
660 * hkl_engine_list_engines_get: (skip)
661 * @self: the this ptr
663 * Return: a pointer on the engine array
665 darray_engine *hkl_engine_list_engines_get(HklEngineList *self)
667 return (darray_engine *)self;
671 * hkl_engine_list_geometry_get: (skip)
672 * @self: the this ptr
674 * Return: a pointer on the geometry member
676 HklGeometry *hkl_engine_list_geometry_get(HklEngineList *self)
678 return self->geometry;
681 int hkl_engine_list_geometry_set(HklEngineList *self, const HklGeometry *geometry)
683 if(!hkl_geometry_set(self->geometry, geometry))
684 return FALSE;
686 hkl_engine_list_get(self);
688 return TRUE;
692 * hkl_engine_list_select_solution:
693 * @self: the this ptr
694 * @item: the #HklGeoemtryListItem selected.
696 * this method set the geometry member with the selected solution.
698 * return value: TRUE if succeded or FALSE otherwise.
700 int hkl_engine_list_select_solution(HklEngineList *self,
701 const HklGeometryListItem *item)
703 return hkl_geometry_init_geometry(self->geometry, item->geometry);
707 * hkl_engine_list_engine_get_by_name:
708 * @self: the this ptr
709 * @name: the name of the requested #HklPseudoAxisEngin
710 * @error: return location for a GError, or NULL
712 * get the #HklEngine by its name from the list.
714 * Returns: (transfer none) (allow-none): the requested engine
716 HklEngine *hkl_engine_list_engine_get_by_name(HklEngineList *self,
717 const char *name,
718 GError **error)
720 HklEngine **engine;
722 hkl_error (error == NULL || *error == NULL);
724 darray_foreach(engine, *self){
725 if (!strcmp((*engine)->info->name, name))
726 return *engine;
729 g_set_error(error,
730 HKL_ENGINE_LIST_ERROR,
731 HKL_ENGINE_LIST_ERROR_ENGINE_GET_BY_NAME,
732 "this engine list does not contain this engine \"%s\"",
733 name);
735 return NULL;
739 * hkl_engine_list_init:
740 * @self: the engine list
741 * @geometry: the associated #HklGeometry
742 * @detector: the associated #HklDetector
743 * @sample: the associated #HklSample
745 * before using an engine list you must associate all engines to a
746 * Geometry, a detector and a sample.
748 void hkl_engine_list_init(HklEngineList *self,
749 HklGeometry *geometry,
750 HklDetector *detector,
751 HklSample *sample)
753 HklEngine **engine;
755 self->geometry = geometry;
756 self->detector = detector;
757 self->sample = sample;
759 darray_foreach(engine, *self){
760 hkl_engine_prepare_internal(*engine);
765 * hkl_engine_list_get:
766 * @self: the list of #HklEngine
768 * apply the get method to all the #HklEngine of the list
769 * after this it is possible to retrive all the #HklPseudoAxis values.
771 * Returns: HKL_SUCCESS or HKL_FAIL if one of the #HklEngine
772 * get method failed.
774 int hkl_engine_list_get(HklEngineList *self)
776 HklEngine **engine;
777 int res = TRUE;
779 darray_foreach(engine, *self){
780 res &= hkl_engine_get(*engine, NULL);
783 return res;
787 * hkl_engine_list_fprintf: (skip)
788 * @f: the File
789 * @self: the list
791 * print to a FILE the #HklEngineList
793 void hkl_engine_list_fprintf(FILE *f,
794 const HklEngineList *self)
796 HklEngine **engine;
798 darray_foreach(engine, *self){
799 hkl_engine_fprintf(f, *engine);