[hkl] fix a bug in the hkl_engine_parameter_set method
[hkl.git] / hkl / hkl-pseudoaxis.c
blobaf63c4a4fca9ef9961259329e8574f80121362dd
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-2015 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 unsigned int i;
51 HklParameter **parameter;
52 const char **axis;
54 fprintf(f, "mode: \"%s\"\n", self->info->name);
55 fprintf(f, "initialized_get: %p\n", self->ops->initialized_get);
56 fprintf(f, "initialized_set: %p\n", self->ops->initialized_set);
57 fprintf(f, "get: %p\n", self->ops->get);
58 fprintf(f, "set: %p\n", self->ops->set);
60 darray_foreach(parameter, self->parameters){
61 fprintf(f, "\n ");
62 hkl_parameter_fprintf(f, *parameter);
65 fprintf(f, "axes (read) names:");
66 darray_foreach(axis, self->info->axes_r)
67 fprintf(f, " %s", *axis);
68 fprintf(f, "\n");
70 fprintf(f, "axes (write) names:");
71 darray_foreach(axis, self->info->axes_w)
72 fprintf(f, " %s", *axis);
73 fprintf(f, "\n");
76 /*************/
77 /* HklEngine */
78 /*************/
80 /**
81 * hkl_engine_name_get:
82 * @self: the this ptr
84 * Return value: the name of the HklEngine
85 **/
86 const char *hkl_engine_name_get(const HklEngine *self)
88 return self->info->name;
91 /**
92 * hkl_engine_len: (skip)
93 * @self: the this ptr
95 * Return value: the len of the pseudo axes of the HklEngine
96 **/
97 unsigned int hkl_engine_len(const HklEngine *self)
99 return darray_size(self->info->pseudo_axes);
103 * hkl_engine_pseudo_axis_names_get:
104 * @self: the this ptr
106 * Return value: (type gpointer): the pseudo_axes managed by this #HklEngine
108 const darray_string *hkl_engine_pseudo_axis_names_get(HklEngine *self)
110 return &self->pseudo_axis_names;
114 * hkl_engine_pseudo_axis_values_get:
115 * @self: the this ptr
116 * @values: (array length=n_values): the values to get
117 * @n_values: the size of the values array.
118 * @unit_type: the unit type (default or user) of the returned value
120 * Get the engine pseudo axes values
122 * return value: TRUE if succeded or FALSE otherwise.
124 int hkl_engine_pseudo_axis_values_get(HklEngine *self,
125 double values[], size_t n_values,
126 HklUnitEnum unit_type, GError **error)
128 hkl_error(error == NULL ||*error == NULL);
130 if(n_values != darray_size(self->info->pseudo_axes)){
131 g_set_error(error,
132 HKL_ENGINE_ERROR,
133 HKL_ENGINE_ERROR_PSEUDO_AXIS_VALUES_GET,
134 "cannot get engine pseudo axes, wrong number of parameter (%d) given, (%d) expected\n",
135 n_values, darray_size(self->info->pseudo_axes));
136 return FALSE;
139 if(!hkl_engine_get(self, error)){
140 g_assert(error == NULL || *error != NULL);
141 return FALSE;
143 g_assert(error == NULL || *error == NULL);
145 for(size_t i=0; i<n_values; ++i){
146 values[i] = hkl_parameter_value_get(darray_item(self->pseudo_axes, i),
147 unit_type);
149 return TRUE;
153 * hkl_engine_pseudo_axis_values_set:
154 * @self: the this ptr
155 * @values: (array length=n_values): the values to set
156 * @n_values: the size of the values array.
157 * @unit_type: the unit type (default or user) of the returned value
158 * @error: return location for a GError, or NULL
160 * Set the engine pseudo axes values
162 * Return value: #HklGeometryList or NULL if no solution was found,
163 * use hkl_geometry_list_free to release the memory once done.
165 HklGeometryList *hkl_engine_pseudo_axis_values_set(HklEngine *self,
166 double values[], size_t n_values,
167 HklUnitEnum unit_type, GError **error)
169 char *msg;
170 size_t msg_size;
171 FILE *stream;
172 HklGeometryList *solutions = NULL;
174 hkl_error(error == NULL ||*error == NULL);
176 if(n_values != darray_size(self->info->pseudo_axes)){
177 g_set_error(error,
178 HKL_ENGINE_ERROR,
179 HKL_ENGINE_ERROR_PSEUDO_AXIS_VALUES_SET,
180 "cannot set engine pseudo axes, wrong number of parameter (%d) given, (%d) expected\n",
181 n_values, darray_size(self->info->pseudo_axes));
182 goto out;
185 #if LOGGING
186 stream = open_memstream(&msg, &msg_size);
188 fprintf(stream, "%s(", __func__);
189 fprintf(stream, "self: %s, values: [", hkl_engine_name_get(self));
190 for(size_t i=0; i<n_values; ++i)
191 fprintf(stream, " %f", values[i]);
192 fprintf(stream, "], n_values: %d unit_type: %d, error: %p)", n_values, unit_type, error);
194 hkl_geometry_fprintf(stream, self->geometry);
195 hkl_sample_fprintf(stream, self->sample);
196 hkl_engine_fprintf(stream, self);
197 #endif
198 for(size_t i=0; i<n_values; ++i){
199 if(!hkl_parameter_value_set(darray_item(self->pseudo_axes, i),
200 values[i],
201 unit_type, error)){
202 goto clean_stream_out;
206 if(!hkl_engine_set(self, error)){
207 #if LOGGING
208 fflush(stream);
209 g_message(msg);
210 if(error && *error != NULL)
211 g_warning("%s", (*error)->message);
212 #endif
213 goto clean_stream_out;
216 solutions = hkl_geometry_list_new_copy(self->engines->geometries);
218 clean_stream_out:
219 #if LOGGING
220 fclose(stream);
221 free(msg);
222 #endif
223 out:
224 return solutions;
228 * hkl_engine_pseudo_axis_get:
229 * @self: the this ptr
230 * @name: the name of the expected pseudo_axis
231 * @error: return location for a GError, or NULL
233 * get the #HklParameter with the given @name.
235 * Returns: (allow-none): retun the parameter or NULL if the engine
236 * does not contain this pseudo_axis.
237 * TODO: unit test
239 const HklParameter *hkl_engine_pseudo_axis_get(const HklEngine *self,
240 const char *name,
241 GError **error)
243 HklParameter **parameter;
245 hkl_error (error == NULL || *error == NULL);
247 darray_foreach(parameter, self->pseudo_axes)
248 if(!strcmp((*parameter)->name, name))
249 return *parameter;
251 g_set_error(error,
252 HKL_ENGINE_ERROR,
253 HKL_ENGINE_ERROR_PSEUDO_AXIS_SET,
254 "This pseudo axis doesn not contain this pseudo axis \"%s\"\n",
255 name);
257 return NULL;
261 * hkl_engine_pseudo_axis_set: (skip)
262 * @self: the this ptr
263 * @name: the name of the pseudo_axis to set
264 * @parameter: the parameter to set.
265 * @error: return location for a GError, or NULL
267 * set a parameter of the #HklEngine
269 * Return value: #HklGeometryList or NULL if no solution was found,
270 * use hkl_geometry_list_free to release the memory once done.
272 HklGeometryList *hkl_engine_pseudo_axis_set(HklEngine *self,
273 const char *name,
274 const HklParameter *parameter,
275 GError **error)
277 HklParameter **p;
279 hkl_error (error == NULL || *error == NULL);
280 hkl_error (strcmp(name, parameter->name) == 0);
282 darray_foreach(p, self->pseudo_axes)
283 if(!strcmp((*p)->name, parameter->name)){
284 /* todo save the previous value to restore this value */
285 hkl_parameter_init_copy(*p, parameter, NULL);
286 if(!hkl_engine_set(self, error)){
287 g_assert(error == NULL || *error != NULL);
288 return NULL;
290 g_assert(error == NULL || *error == NULL);
292 return hkl_geometry_list_new_copy(self->engines->geometries);
295 g_set_error(error,
296 HKL_ENGINE_ERROR,
297 HKL_ENGINE_ERROR_PSEUDO_AXIS_SET,
298 "Can not find the pseudo axis \"%s\" in the \"%s\" engine\n",
299 parameter->name, self->info->name);
301 return NULL;
305 * hkl_engine_capabilities_get:
306 * @self: the this ptr
308 * return the capabilities of the engine. Theses capabilities can
309 * change, from on mode to the other. for now there is three kind of
310 * capabilities.
312 * HKL_ENGINE_CAP_READABLE: pseudo axes values can be read from the HklEngine
314 * HKL_ENGINE_CAP_WRITABLE: pseudo axes values can be set for this #HklEngine
316 * HKL_ENGINE_CAP_INITIALISABLE: this pseudo axes must be initialized
317 * with hkl_engine_initialize before
318 * reading or writing on it.
320 * Returns:
322 unsigned int hkl_engine_capabilities_get(const HklEngine *self)
324 return self->mode->ops->capabilities;
329 * hkl_engine_modes_names_get:
330 * @self: the this ptr
332 * Return value: (type gpointer): All the modes supported by the #HklEngine
334 const darray_string *hkl_engine_modes_names_get(const HklEngine *self)
336 return &self->mode_names;
340 * hkl_engine_parameters_names_get:
341 * @self: the this ptr
343 * Return value: (type gpointer): All the parameters of #HklEngine.
345 const darray_string *hkl_engine_parameters_names_get(const HklEngine *self)
347 return &self->mode->parameters_names;
351 * hkl_engine_parameters_values_get: (skip)
352 * @self: the this ptr
353 * @values: (array length=n_values): the values to get
354 * @n_values: the size of the values array.
355 * @unit_type: the unit type (default or user) of the returned value
357 * Get the engine parameters values
359 * return value: TRUE if succeded or FALSE otherwise.
361 void hkl_engine_parameters_values_get(const HklEngine *self,
362 double values[], size_t n_values,
363 HklUnitEnum unit_type)
365 g_return_if_fail (n_values == darray_size(self->mode->parameters));
367 for(size_t i=0; i<n_values; ++i)
368 values[i] = hkl_parameter_value_get(darray_item(self->mode->parameters, i),
369 unit_type);
373 * hkl_engine_parameters_values_set:
374 * @self: the this ptr
375 * @values: (array length=n_values): the values to set
376 * @n_values: the size of the values array.
377 * @unit_type: the unit type (default or user) of the returned value
378 * @error: return location for a GError, or NULL
380 * Set the engine parameters values
382 * return value: TRUE if succeded or FALSE otherwise.
384 int hkl_engine_parameters_values_set(HklEngine *self,
385 double values[], size_t n_values,
386 HklUnitEnum unit_type, GError **error)
388 hkl_error (error == NULL || *error == NULL && n_values == darray_size(self->mode->parameters));
390 for(size_t i=0; i<n_values; ++i){
391 if(!hkl_parameter_value_set(darray_item(self->mode->parameters, i),
392 values[i], unit_type, error)){
393 g_assert (error == NULL || *error != NULL);
394 return FALSE;
397 g_assert (error == NULL || *error == NULL);
399 return TRUE;
403 * hkl_engine_parameter_get:
404 * @self: the this ptr
405 * @name: the name of the expected parameter
406 * @error: return location for a GError, or NULL
408 * get the #HklParameter with the given @name.
410 * Returns: (allow-none): return the parameter or NULL if the engine
411 * does not contain this parameter.
413 const HklParameter *hkl_engine_parameter_get(const HklEngine *self,
414 const char *name,
415 GError **error)
417 HklParameter **parameter;
419 hkl_error (error == NULL || *error == NULL);
421 darray_foreach(parameter, self->mode->parameters)
422 if(!strcmp((*parameter)->name, name))
423 return *parameter;
425 g_set_error(error,
426 HKL_ENGINE_ERROR,
427 HKL_ENGINE_ERROR_PARAMETER_GET,
428 "this engine does not contain this parameter \"%s\"\n",
429 name);
431 return NULL;
435 * hkl_engine_parameter_set:
436 * @self: the this ptr
437 * @name: the name of the parameter to set.
438 * @parameter: the parameter to set.
439 * @error: return location for a GError, or NULL
441 * set a parameter of the #HklEngine
442 * TODO add an error
444 * return value: TRUE if succeded or FALSE otherwise.
446 int hkl_engine_parameter_set(HklEngine *self,
447 const char *name,
448 const HklParameter *parameter,
449 GError **error)
451 HklParameter **p;
453 hkl_error (error == NULL || *error == NULL);
455 darray_foreach(p, self->mode->parameters)
456 if(!strcmp(name, (*p)->name)){
457 const char *old_name = (*p)->name;
458 hkl_parameter_init_copy(*p, parameter, NULL);
459 /* we do not check if the name is identical so force the right name */
460 /* TODO rethink this HklParameter assignement */
461 (*p)->name = old_name;
462 return TRUE;
465 g_set_error(error,
466 HKL_ENGINE_ERROR,
467 HKL_ENGINE_ERROR_PARAMETER_SET,
468 "this engine does not contain this parameter \"%s\"\n",
469 parameter->name);
471 return FALSE;
475 * hkl_engine_current_mode_get:
476 * @self: the this ptr
478 * Returns: the current HklEngine mode
480 const char *hkl_engine_current_mode_get(const HklEngine *self)
482 return self->mode->info->name;
486 * hkl_engine_current_mode_set:
487 * @self: the HklEngine
488 * @name: the mode to select
489 * @error: return location for a GError, or NULL
491 * This method also populate the self->axes from the mode->axis_names.
492 * this is to speed the computation of the numerical axes.
494 * return value: TRUE if succeded or FALSE otherwise.
496 int hkl_engine_current_mode_set(HklEngine *self, const char *name,
497 GError **error)
499 HklMode **mode;
501 hkl_error (error == NULL || *error == NULL);
503 darray_foreach(mode, self->modes)
504 if(!strcmp((*mode)->info->name, name)){
505 hkl_engine_mode_set(self, *mode);
506 return TRUE;
509 g_set_error(error,
510 HKL_ENGINE_ERROR,
511 HKL_ENGINE_ERROR_CURRENT_MODE_SET,
512 "this engine does not contain this mode \"%s\"\n",
513 name);
515 return FALSE;
519 * hkl_engine_axis_names_get:
520 * @self: the this ptr
521 * @mode:
523 * return a list of axes relevant when reading or writing on the
524 * #HklEngine.
526 * exemple, for a K6C diffractometer in "lifting detector" mode, your
527 * Engine control only 3 motors when writing, but the hkl values
528 * depends on the 6 motors when reading.
530 * Returns: (type gpointer):
532 const darray_string *hkl_engine_axis_names_get(const HklEngine *self,
533 HklEngineAxisNamesGet mode)
535 switch(mode){
536 case HKL_ENGINE_AXIS_NAMES_GET_READ:
537 return &self->mode->info->axes_r;
538 case HKL_ENGINE_AXIS_NAMES_GET_WRITE:
539 return &self->mode->info->axes_w;
543 int hkl_engine_initialized_get(const HklEngine *self)
545 return hkl_mode_initialized_get(self->mode);
549 * hkl_engine_initialized_set:
550 * @self: the HklEngine
551 * @initialized: TRUE or FALSE to activated or deactivate the HklEngine
552 * @error: return location for a GError, or NULL
554 * initialize the HklEngine
556 * return value: TRUE if succeded or FALSE otherwise.
558 int hkl_engine_initialized_set(HklEngine *self, int initialized, GError **error)
560 hkl_error (error == NULL || *error == NULL);
562 if(!self->geometry || !self->detector || !self->sample
563 || !self->mode) {
564 g_set_error(error,
565 HKL_ENGINE_ERROR,
566 HKL_ENGINE_ERROR_INITIALIZE,
567 "Internal error");
568 return FALSE;
571 return hkl_mode_initialized_set(self->mode,
572 self,
573 self->engines->geometry,
574 self->engines->detector,
575 self->engines->sample,
576 initialized,
577 error);
581 * hkl_engine_dependencies_get:
582 * @self: the this ptr
584 * return all dependencies of the engine which are not mode parameters
585 * or axes. The possible combination of values are defined in
586 * #HklEngineDependencies enum.
588 * return value:
590 unsigned int hkl_engine_dependencies_get(const HklEngine *self)
592 return self->info->dependencies;
596 * hkl_engine_fprintf: (skip)
597 * @f: the FILE
598 * @self: the HklEngine
600 * print to a FILE the HklEngine
602 void hkl_engine_fprintf(FILE *f, const HklEngine *self)
604 HklParameter **pseudo_axis;
606 fprintf(f, "\nPseudoAxesEngine : \"%s\"", self->info->name);
608 /* mode */
609 if (self->mode) {
610 fprintf(f, " %s", self->mode->info->name);
611 for(uint i=0; i<darray_size(self->mode->parameters); ++i){
612 fprintf(f, "\n ");
613 hkl_parameter_fprintf(
615 darray_item(self->mode->parameters, i));
617 fprintf(f, "\n");
620 /* the pseudoAxes part */
621 darray_foreach(pseudo_axis, self->pseudo_axes){
622 fprintf(f, "\n ");
623 hkl_parameter_fprintf(f, *pseudo_axis);
626 if(self->engines->geometries->n_items != 0){
627 fprintf(f, "\n ");
628 hkl_geometry_list_fprintf(f, self->engines->geometries);
630 fprintf(f, "\n");
633 /*****************/
634 /* HklEngineList */
635 /*****************/
638 * hkl_engine_list_free: (skip)
639 * @self: the #HklEngineList to destroy
641 * destructor
643 void hkl_engine_list_free(HklEngineList *self)
645 hkl_engine_list_clear(self);
646 hkl_geometry_list_free(self->geometries);
647 free(self);
651 * hkl_engine_list_engines_get: (skip)
652 * @self: the this ptr
654 * Return: a pointer on the engine array
656 darray_engine *hkl_engine_list_engines_get(HklEngineList *self)
658 return (darray_engine *)self;
662 * hkl_engine_list_geometry_get: (skip)
663 * @self: the this ptr
665 * Return: a pointer on the geometry member
667 HklGeometry *hkl_engine_list_geometry_get(HklEngineList *self)
669 return self->geometry;
672 int hkl_engine_list_geometry_set(HklEngineList *self, const HklGeometry *geometry)
674 if(!hkl_geometry_set(self->geometry, geometry))
675 return FALSE;
677 hkl_engine_list_get(self);
679 return TRUE;
683 * hkl_engine_list_select_solution:
684 * @self: the this ptr
685 * @item: the #HklGeoemtryListItem selected.
687 * this method set the geometry member with the selected solution.
689 * return value: TRUE if succeded or FALSE otherwise.
691 int hkl_engine_list_select_solution(HklEngineList *self,
692 const HklGeometryListItem *item)
694 return hkl_geometry_init_geometry(self->geometry, item->geometry);
698 * hkl_engine_list_engine_get_by_name:
699 * @self: the this ptr
700 * @name: the name of the requested #HklPseudoAxisEngin
701 * @error: return location for a GError, or NULL
703 * get the #HklEngine by its name from the list.
705 * Returns: (transfer none) (allow-none): the requested engine
707 HklEngine *hkl_engine_list_engine_get_by_name(HklEngineList *self,
708 const char *name,
709 GError **error)
711 HklEngine **engine;
713 hkl_error (error == NULL || *error == NULL);
715 darray_foreach(engine, *self){
716 if (!strcmp((*engine)->info->name, name))
717 return *engine;
720 g_set_error(error,
721 HKL_ENGINE_LIST_ERROR,
722 HKL_ENGINE_LIST_ERROR_ENGINE_GET_BY_NAME,
723 "this engine list does not contain this engine \"%s\"",
724 name);
726 return NULL;
730 * hkl_engine_list_init:
731 * @self: the engine list
732 * @geometry: the associated #HklGeometry
733 * @detector: the associated #HklDetector
734 * @sample: the associated #HklSample
736 * before using an engine list you must associate all engines to a
737 * Geometry, a detector and a sample.
739 void hkl_engine_list_init(HklEngineList *self,
740 HklGeometry *geometry,
741 HklDetector *detector,
742 HklSample *sample)
744 HklEngine **engine;
746 self->geometry = geometry;
747 self->detector = detector;
748 self->sample = sample;
750 darray_foreach(engine, *self){
751 hkl_engine_prepare_internal(*engine);
756 * hkl_engine_list_get:
757 * @self: the list of #HklEngine
759 * apply the get method to all the #HklEngine of the list
760 * after this it is possible to retrive all the #HklPseudoAxis values.
762 * Returns: HKL_SUCCESS or HKL_FAIL if one of the #HklEngine
763 * get method failed.
765 int hkl_engine_list_get(HklEngineList *self)
767 HklEngine **engine;
768 int res = TRUE;
770 darray_foreach(engine, *self){
771 res &= hkl_engine_get(*engine, NULL);
774 return res;
778 * hkl_engine_list_fprintf: (skip)
779 * @f: the File
780 * @self: the list
782 * print to a FILE the #HklEngineList
784 void hkl_engine_list_fprintf(FILE *f,
785 const HklEngineList *self)
787 HklEngine **engine;
789 darray_foreach(engine, *self){
790 hkl_engine_fprintf(f, *engine);