[contrib] create a transformation type
[hkl.git] / hkl / hkl-pseudoaxis.c
blob008967c8df8f1f80f86ad3fd2b334854d6505083
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-2014 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 /* HklPseudoAxis */
39 /*****************/
42 /***********/
43 /* HklMode */
44 /***********/
46 /**
47 * hkl_mode_fprintf: (skip)
48 * @f:
49 * @self:
51 * print to a FILE the HklPSeudoAxisEngineMode members
52 **/
53 void hkl_mode_fprintf(FILE *f, const HklMode *self)
55 unsigned int i;
56 HklParameter **parameter;
57 const char **axis;
59 fprintf(f, "mode: \"%s\"\n", self->info->name);
60 fprintf(f, "initialized_get: %p\n", self->ops->initialized_get);
61 fprintf(f, "initialized_set: %p\n", self->ops->initialized_set);
62 fprintf(f, "get: %p\n", self->ops->get);
63 fprintf(f, "set: %p\n", self->ops->set);
65 darray_foreach(parameter, self->parameters){
66 fprintf(f, "\n ");
67 hkl_parameter_fprintf(f, *parameter);
70 fprintf(f, "axes (read) names:");
71 darray_foreach(axis, self->info->axes_r)
72 fprintf(f, " %s", *axis);
73 fprintf(f, "\n");
75 fprintf(f, "axes (write) names:");
76 darray_foreach(axis, self->info->axes_w)
77 fprintf(f, " %s", *axis);
78 fprintf(f, "\n");
81 /*************/
82 /* HklEngine */
83 /*************/
85 /**
86 * hkl_engine_name_get:
87 * @self: the this ptr
89 * Return value: the name of the HklEngine
90 **/
91 const char *hkl_engine_name_get(const HklEngine *self)
93 return self->info->name;
96 /**
97 * hkl_engine_len: (skip)
98 * @self: the this ptr
100 * Return value: the len of the pseudo axes of the HklEngine
102 unsigned int hkl_engine_len(const HklEngine *self)
104 return darray_size(self->info->pseudo_axes);
108 * hkl_engine_pseudo_axis_names_get:
109 * @self: the this ptr
111 * Return value: (type gpointer): the pseudo_axes managed by this #HklEngine
113 const darray_string *hkl_engine_pseudo_axis_names_get(HklEngine *self)
115 return &self->pseudo_axis_names;
119 * hkl_engine_pseudo_axis_values_get:
120 * @self: the this ptr
121 * @values: (array length=n_values): the values to get
122 * @n_values: the size of the values array.
123 * @unit_type: the unit type (default or user) of the returned value
125 * Get the engine pseudo axes values
127 * return value: TRUE if succeded or FALSE otherwise.
129 int hkl_engine_pseudo_axis_values_get(HklEngine *self,
130 double values[], size_t n_values,
131 HklUnitEnum unit_type, GError **error)
133 hkl_error(error == NULL ||*error == NULL);
135 if(n_values != darray_size(self->info->pseudo_axes)){
136 g_set_error(error,
137 HKL_ENGINE_ERROR,
138 HKL_ENGINE_ERROR_PSEUDO_AXIS_VALUES_GET,
139 "cannot get engine pseudo axes, wrong number of parameter (%d) given, (%d) expected\n",
140 n_values, darray_size(self->info->pseudo_axes));
141 return FALSE;
144 if(!hkl_engine_get(self, error)){
145 g_assert(error == NULL || *error != NULL);
146 return FALSE;
148 g_assert(error == NULL || *error == NULL);
150 for(size_t i=0; i<n_values; ++i){
151 values[i] = hkl_parameter_value_get(darray_item(self->pseudo_axes, i),
152 unit_type);
154 return TRUE;
158 * hkl_engine_pseudo_axis_values_set:
159 * @self: the this ptr
160 * @values: (array length=n_values): the values to set
161 * @n_values: the size of the values array.
162 * @unit_type: the unit type (default or user) of the returned value
163 * @error: return location for a GError, or NULL
165 * Set the engine pseudo axes values
167 * Return value: #HklGeometryList or NULL if no solution was found,
168 * use hkl_geometry_list_free to release the memory once done.
170 HklGeometryList *hkl_engine_pseudo_axis_values_set(HklEngine *self,
171 double values[], size_t n_values,
172 HklUnitEnum unit_type, GError **error)
174 char *msg;
175 size_t msg_size;
176 FILE *stream;
177 HklGeometryList *solutions = NULL;
179 hkl_error(error == NULL ||*error == NULL);
181 if(n_values != darray_size(self->info->pseudo_axes)){
182 g_set_error(error,
183 HKL_ENGINE_ERROR,
184 HKL_ENGINE_ERROR_PSEUDO_AXIS_VALUES_SET,
185 "cannot set engine pseudo axes, wrong number of parameter (%d) given, (%d) expected\n",
186 n_values, darray_size(self->info->pseudo_axes));
187 goto out;
190 #if LOGGING
191 stream = open_memstream(&msg, &msg_size);
193 fprintf(stream, "%s(", __func__);
194 fprintf(stream, "self: %s, values: [", hkl_engine_name_get(self));
195 for(size_t i=0; i<n_values; ++i)
196 fprintf(stream, " %f", values[i]);
197 fprintf(stream, "], n_values: %d unit_type: %d, error: %p)", n_values, unit_type, error);
199 hkl_geometry_fprintf(stream, self->geometry);
200 hkl_sample_fprintf(stream, self->sample);
201 hkl_engine_fprintf(stream, self);
202 #endif
203 for(size_t i=0; i<n_values; ++i){
204 if(!hkl_parameter_value_set(darray_item(self->pseudo_axes, i),
205 values[i],
206 unit_type, error)){
207 goto clean_stream_out;
211 if(!hkl_engine_set(self, error)){
212 #if LOGGING
213 fflush(stream);
214 g_message(msg);
215 if(error && *error != NULL)
216 g_warning("%s", (*error)->message);
217 #endif
218 goto clean_stream_out;
221 solutions = hkl_geometry_list_new_copy(self->engines->geometries);
223 clean_stream_out:
224 #if LOGGING
225 fclose(stream);
226 free(msg);
227 #endif
228 out:
229 return solutions;
233 * hkl_engine_pseudo_axis_get:
234 * @self: the this ptr
235 * @name: the name of the expected psudo_axis
236 * @error: return location for a GError, or NULL
238 * get the #HklParameter with the given @name.
240 * Returns: (allow-none): retun the parameter or NULL if the engine
241 * does not contain this pseudo_axis.
242 * TODO: unit test
244 const HklParameter *hkl_engine_pseudo_axis_get(const HklEngine *self,
245 const char *name,
246 GError **error)
248 HklParameter **parameter;
250 hkl_error (error == NULL || *error == NULL);
252 darray_foreach(parameter, self->pseudo_axes)
253 if(!strcmp((*parameter)->name, name))
254 return *parameter;
256 g_set_error(error,
257 HKL_ENGINE_ERROR,
258 HKL_ENGINE_ERROR_PSEUDO_AXIS_SET,
259 "This pseudo axis doesn not contain this pseudo axis \"%s\"\n",
260 name);
262 return NULL;
266 * hkl_engine_pseudo_axis_set: (skip)
267 * @self: the this ptr
268 * @name: the name of the pseudo_axis to set
269 * @parameter: the parameter to set.
270 * @error: return location for a GError, or NULL
272 * set a parameter of the #HklEngine
274 * Return value: #HklGeometryList or NULL if no solution was found,
275 * use hkl_geometry_list_free to release the memory once done.
277 HklGeometryList *hkl_engine_pseudo_axis_set(HklEngine *self,
278 const char *name,
279 const HklParameter *parameter,
280 GError **error)
282 HklParameter **p;
284 hkl_error (error == NULL || *error == NULL);
285 hkl_error (strcmp(name, parameter->name) == 0);
287 darray_foreach(p, self->pseudo_axes)
288 if(!strcmp((*p)->name, parameter->name)){
289 /* todo save the previous value to restore this value */
290 hkl_parameter_init_copy(*p, parameter, NULL);
291 if(!hkl_engine_set(self, error)){
292 g_assert(error == NULL || *error != NULL);
293 return NULL;
295 g_assert(error == NULL || *error == NULL);
297 return hkl_geometry_list_new_copy(self->engines->geometries);
300 g_set_error(error,
301 HKL_ENGINE_ERROR,
302 HKL_ENGINE_ERROR_PSEUDO_AXIS_SET,
303 "Can not find the pseudo axis \"%s\" in the \"%s\" engine\n",
304 parameter->name, self->info->name);
306 return NULL;
310 * hkl_engine_capabilities_get:
311 * @self: the this ptr
313 * return the capabilities of the engine. Theses capabilities can
314 * change, from on mode to the other. for now there is three kind of
315 * capabilities.
317 * HKL_ENGINE_CAP_READABLE: pseudo axes values can be read from the HklEngine
319 * HKL_ENGINE_CAP_WRITABLE: pseudo axes values can be set for this #HklEngine
321 * HKL_ENGINE_CAP_INITIALISABLE: this pseudo axes must be initialized
322 * with hkl_engine_initialize before
323 * reading or writing on it.
325 * Returns:
327 unsigned int hkl_engine_capabilities_get(const HklEngine *self)
329 return self->mode->ops->capabilities;
334 * hkl_engine_modes_names_get:
335 * @self: the this ptr
337 * Return value: (type gpointer): All the modes supported by the #HklEngine
339 const darray_string *hkl_engine_modes_names_get(const HklEngine *self)
341 return &self->mode_names;
345 * hkl_engine_parameters_names_get:
346 * @self: the this ptr
348 * Return value: (type gpointer): All the parameters of #HklEngine.
350 const darray_string *hkl_engine_parameters_names_get(const HklEngine *self)
352 return &self->mode->parameters_names;
356 * hkl_engine_parameters_values_get: (skip)
357 * @self: the this ptr
358 * @values: (array length=n_values): the values to get
359 * @n_values: the size of the values array.
360 * @unit_type: the unit type (default or user) of the returned value
362 * Get the engine parameters values
364 * return value: TRUE if succeded or FALSE otherwise.
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),
374 unit_type);
378 * hkl_engine_parameters_values_set: (skip)
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);
399 return FALSE;
402 g_assert (error == NULL || *error == NULL);
404 return TRUE;
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,
419 const char *name,
420 GError **error)
422 HklParameter **parameter;
424 hkl_error (error == NULL || *error == NULL);
426 darray_foreach(parameter, self->mode->parameters)
427 if(!strcmp((*parameter)->name, name))
428 return *parameter;
430 g_set_error(error,
431 HKL_ENGINE_ERROR,
432 HKL_ENGINE_ERROR_PARAMETER_GET,
433 "this engine does not contain this parameter \"%s\"\n",
434 name);
436 return NULL;
440 * hkl_engine_parameter_set: (skip)
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
447 * TODO add an error
449 * return value: TRUE if succeded or FALSE otherwise.
451 int hkl_engine_parameter_set(HklEngine *self,
452 const char *name,
453 const HklParameter *parameter,
454 GError **error)
456 HklParameter **p;
458 hkl_error (error == NULL || *error == NULL);
460 darray_foreach(p, self->mode->parameters)
461 if(!strcmp(name, (*p)->name)){
462 hkl_parameter_init_copy(*p, parameter, NULL);
463 /* we do not check if the name is identical so force the right name */
464 /* TODO rethink this HklParameter assignement */
465 (*p)->name = name;
466 return TRUE;
469 g_set_error(error,
470 HKL_ENGINE_ERROR,
471 HKL_ENGINE_ERROR_PARAMETER_SET,
472 "this engine does not contain this parameter \"%s\"\n",
473 parameter->name);
475 return FALSE;
479 * hkl_engine_current_mode_get:
480 * @self: the this ptr
482 * Returns: the current HklEngine mode
484 const char *hkl_engine_current_mode_get(const HklEngine *self)
486 return self->mode->info->name;
490 * hkl_engine_current_mode_set:
491 * @self: the HklEngine
492 * @name: the mode to select
493 * @error: return location for a GError, or NULL
495 * This method also populate the self->axes from the mode->axis_names.
496 * this is to speed the computation of the numerical axes.
498 * return value: TRUE if succeded or FALSE otherwise.
500 int hkl_engine_current_mode_set(HklEngine *self, const char *name,
501 GError **error)
503 HklMode **mode;
505 hkl_error (error == NULL || *error == NULL);
507 darray_foreach(mode, self->modes)
508 if(!strcmp((*mode)->info->name, name)){
509 hkl_engine_mode_set(self, *mode);
510 return TRUE;
513 g_set_error(error,
514 HKL_ENGINE_ERROR,
515 HKL_ENGINE_ERROR_CURRENT_MODE_SET,
516 "this engine does not contain this mode \"%s\"\n",
517 name);
519 return FALSE;
523 * hkl_engine_axis_names_get:
524 * @self: the this ptr
525 * @mode:
527 * return a list of axes relevant when reading or writing on the
528 * #HklEngine.
530 * exemple, for a K6C diffractometer in "lifting detector" mode, your
531 * Engine control only 3 motors when writing, but the hkl values
532 * depends on the 6 motors when reading.
534 * Returns: (type gpointer):
536 const darray_string *hkl_engine_axis_names_get(const HklEngine *self,
537 HklEngineAxisNamesGet mode)
539 switch(mode){
540 case HKL_ENGINE_AXIS_NAMES_GET_READ:
541 return &self->mode->info->axes_r;
542 case HKL_ENGINE_AXIS_NAMES_GET_WRITE:
543 return &self->mode->info->axes_w;
547 int hkl_engine_initialized_get(const HklEngine *self)
549 return hkl_mode_initialized_get(self->mode);
553 * hkl_engine_initialized_set:
554 * @self: the HklEngine
555 * @initialized: TRUE or FALSE to activated or deactivate the HklEngine
556 * @error: return location for a GError, or NULL
558 * initialize the HklEngine
560 * return value: TRUE if succeded or FALSE otherwise.
562 int hkl_engine_initialized_set(HklEngine *self, int initialized, GError **error)
564 hkl_error (error == NULL || *error == NULL);
566 if(!self->geometry || !self->detector || !self->sample
567 || !self->mode) {
568 g_set_error(error,
569 HKL_ENGINE_ERROR,
570 HKL_ENGINE_ERROR_INITIALIZE,
571 "Internal error");
572 return FALSE;
575 return hkl_mode_initialized_set(self->mode,
576 self,
577 self->engines->geometry,
578 self->engines->detector,
579 self->engines->sample,
580 initialized,
581 error);
585 * hkl_engine_fprintf: (skip)
586 * @f: the FILE
587 * @self: the HklEngine
589 * print to a FILE the HklEngine
591 void hkl_engine_fprintf(FILE *f, const HklEngine *self)
593 HklParameter **pseudo_axis;
595 fprintf(f, "\nPseudoAxesEngine : \"%s\"", self->info->name);
597 /* mode */
598 if (self->mode) {
599 fprintf(f, " %s", self->mode->info->name);
600 for(uint i=0; i<darray_size(self->mode->parameters); ++i){
601 fprintf(f, "\n ");
602 hkl_parameter_fprintf(
604 darray_item(self->mode->parameters, i));
606 fprintf(f, "\n");
609 /* the pseudoAxes part */
610 darray_foreach(pseudo_axis, self->pseudo_axes){
611 fprintf(f, "\n ");
612 hkl_parameter_fprintf(f, *pseudo_axis);
615 if(self->engines->geometries->n_items != 0){
616 fprintf(f, "\n ");
617 hkl_geometry_list_fprintf(f, self->engines->geometries);
619 fprintf(f, "\n");
622 /*****************/
623 /* HklEngineList */
624 /*****************/
627 * hkl_engine_list_free: (skip)
628 * @self: the #HklEngineList to destroy
630 * destructor
632 void hkl_engine_list_free(HklEngineList *self)
634 hkl_engine_list_clear(self);
635 hkl_geometry_list_free(self->geometries);
636 free(self);
640 * hkl_engine_list_engines_get: (skip)
641 * @self: the this ptr
643 * Return: a pointer on the engine array
645 darray_engine *hkl_engine_list_engines_get(HklEngineList *self)
647 return (darray_engine *)self;
651 * hkl_engine_list_geometry_get: (skip)
652 * @self: the this ptr
654 * Return: a pointer on the geometry member
656 HklGeometry *hkl_engine_list_geometry_get(HklEngineList *self)
658 return self->geometry;
661 int hkl_engine_list_geometry_set(HklEngineList *self, const HklGeometry *geometry)
663 if(!hkl_geometry_set(self->geometry, geometry))
664 return FALSE;
666 hkl_engine_list_get(self);
668 return TRUE;
672 * hkl_engine_list_select_solution:
673 * @self: the this ptr
674 * @item: the #HklGeoemtryListItem selected.
676 * this method set the geometry member with the selected solution.
678 * return value: TRUE if succeded or FALSE otherwise.
680 int hkl_engine_list_select_solution(HklEngineList *self,
681 const HklGeometryListItem *item)
683 return hkl_geometry_init_geometry(self->geometry, item->geometry);
687 * hkl_engine_list_engine_get_by_name:
688 * @self: the this ptr
689 * @name: the name of the requested #HklPseudoAxisEngin
690 * @error: return location for a GError, or NULL
692 * get the #HklEngine by its name from the list.
694 * Returns: (transfer none) (allow-none): the requested engine
696 HklEngine *hkl_engine_list_engine_get_by_name(HklEngineList *self,
697 const char *name,
698 GError **error)
700 HklEngine **engine;
702 hkl_error (error == NULL || *error == NULL);
704 darray_foreach(engine, *self){
705 if (!strcmp((*engine)->info->name, name))
706 return *engine;
709 g_set_error(error,
710 HKL_ENGINE_LIST_ERROR,
711 HKL_ENGINE_LIST_ERROR_ENGINE_GET_BY_NAME,
712 "this engine list does not contain this engine \"%s\"",
713 name);
715 return NULL;
719 * hkl_engine_list_init:
720 * @self: the engine list
721 * @geometry: the associated #HklGeometry
722 * @detector: the associated #HklDetector
723 * @sample: the associated #HklSample
725 * before using an engine list you must associate all engines to a
726 * Geometry, a detector and a sample.
728 void hkl_engine_list_init(HklEngineList *self,
729 HklGeometry *geometry,
730 HklDetector *detector,
731 HklSample *sample)
733 HklEngine **engine;
735 self->geometry = geometry;
736 self->detector = detector;
737 self->sample = sample;
739 darray_foreach(engine, *self){
740 hkl_engine_prepare_internal(*engine);
745 * hkl_engine_list_get:
746 * @self: the list of #HklEngine
748 * apply the get method to all the #HklEngine of the list
749 * after this it is possible to retrive all the #HklPseudoAxis values.
751 * Returns: HKL_SUCCESS or HKL_FAIL if one of the #HklEngine
752 * get method failed.
754 int hkl_engine_list_get(HklEngineList *self)
756 HklEngine **engine;
757 int res = TRUE;
759 darray_foreach(engine, *self){
760 res &= hkl_engine_get(*engine, NULL);
763 return res;
767 * hkl_engine_list_fprintf: (skip)
768 * @f: the File
769 * @self: the list
771 * print to a FILE the #HklEngineList
773 void hkl_engine_list_fprintf(FILE *f,
774 const HklEngineList *self)
776 HklEngine **engine;
778 darray_foreach(engine, *self){
779 hkl_engine_fprintf(f, *engine);