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 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>
25 #include <tap/basic.h>
26 #include <tap/hkl-tap.h>
30 typedef int (* test_func
) (HklEngine
*engine
, HklEngineList
*engine_list
, unsigned int n
);
32 static int __test(unsigned int nb_iter
, test_func f
, int foreach_mode
)
34 HklFactory
**factories
;
36 HklGeometry
*geometry
= NULL
;
37 HklDetector
*detector
= hkl_detector_factory_new(HKL_DETECTOR_TYPE_0D
);
38 struct Sample cu
= CU
;
39 HklSample
*sample
= newSample(cu
);
40 HklEngineList
*engines
;
44 factories
= hkl_factory_get_all(&n
);
45 for(i
=0; i
<n
&& TRUE
== res
; i
++){
48 geometry
= hkl_factory_create_new_geometry(factories
[i
]);
49 engines
= hkl_factory_create_new_engine_list(factories
[i
]);
50 hkl_engine_list_init(engines
, geometry
, detector
, sample
);
51 darray_foreach(engine
, *hkl_engine_list_engines_get(engines
)){
52 const darray_string
*modes
= hkl_engine_modes_names_get(*engine
);
54 darray_foreach(mode
, *modes
){
55 res
&= DIAG(hkl_engine_current_mode_set(*engine
, *mode
, NULL
));
56 for(j
=0; j
<nb_iter
; ++j
){
57 res
&= DIAG(f(*engine
, engines
, nb_iter
));
59 diag("failed at factory: \"%s\" engine: \"%s\" mode: \"%s\"",
60 hkl_geometry_name_get(geometry
),
61 hkl_engine_name_get(*engine
), *mode
);
69 for(j
=0; j
<nb_iter
; ++j
){
70 res
&= DIAG(f(*engine
, engines
, nb_iter
));
78 hkl_geometry_free(geometry
);
79 hkl_engine_list_free(engines
);
81 hkl_detector_free(detector
);
82 hkl_sample_free(sample
);
87 #define TEST_FOREACH_ENGINE(_nb_iter, _f) __test(_nb_iter, _f, 0)
88 #define TEST_FOREACH_MODE(_nb_iter, _f) __test(_nb_iter, _f, 1)
90 static void factories(void)
94 HklEngineList
*engines
;
95 HklFactory
**factories
;
97 factories
= hkl_factory_get_all(&n
);
99 engines
= hkl_factory_create_new_engine_list(factories
[i
]);
100 hkl_engine_list_free(engines
);
103 ok(res
== TRUE
, "factories");
106 static void parameters(void)
110 HklEngineList
*engines
;
111 HklFactory
**factories
;
112 const darray_string
*parameters_names
;
114 factories
= hkl_factory_get_all(&n
);
119 engines
= hkl_factory_create_new_engine_list(factories
[i
]);
121 /* check parameters names */
122 parameters_names
= hkl_engine_list_parameters_names_get(engines
);
123 size
= darray_size(*parameters_names
);
124 if(!strcmp("SOLEIL SIXS MED2+3 v2", hkl_factory_name_get(factories
[i
]))){
125 const HklParameter
*p
;
128 res
&= DIAG(size
== 1);
129 p
= hkl_engine_list_parameter_get(engines
, "eta_a_rotation", NULL
);
130 res
&= DIAG(p
!= NULL
);
133 res
&= DIAG(hkl_engine_list_parameter_set(engines
, "eta_a_rotation", p
, NULL
));
136 hkl_engine_list_parameters_values_get(engines
,
137 values
, ARRAY_SIZE(values
),
139 res
&= DIAG(values
[0] == 0.0);
143 res
&= DIAG(hkl_engine_list_parameters_values_set(engines
,
144 values
, ARRAY_SIZE(values
),
145 HKL_UNIT_USER
, NULL
));
146 hkl_engine_list_parameters_values_get(engines
,
147 values
, ARRAY_SIZE(values
),
149 res
&= DIAG(values
[0] == 1.0);
151 res
&= DIAG(size
== 0);
154 hkl_engine_list_free(engines
);
157 ok(res
== TRUE
, "parameters");
161 static int _get(HklEngine
*engine
, HklEngineList
*engine_list
, UNUSED
unsigned int n
)
166 HklGeometry
*geometry
= hkl_engine_list_geometry_get(engine_list
);
167 const darray_string
*pseudo_axes
= hkl_engine_pseudo_axis_names_get(engine
);
168 const size_t n_pseudo_axes
= darray_size(*pseudo_axes
);
169 double targets
[n_pseudo_axes
];
170 double currents
[n_pseudo_axes
];
172 /* randomize the geometry */
173 hkl_geometry_randomize(geometry
);
175 /* randomize the pseudoAxes values */
176 hkl_tap_engine_pseudo_axes_randomize(engine
,
177 targets
, n_pseudo_axes
,
180 /* randomize the parameters */
181 hkl_tap_engine_parameters_randomize(engine
);
183 /* pseudo -> geometry */
184 if(HKL_ENGINE_CAPABILITIES_INITIALIZABLE
& hkl_engine_capabilities_get(engine
))
185 res
&= DIAG(hkl_engine_initialized_set(engine
, TRUE
, NULL
));
186 res
&= DIAG(hkl_engine_pseudo_axis_values_get(engine
, currents
, n_pseudo_axes
,
187 HKL_UNIT_DEFAULT
, NULL
));
189 /* idem with error management */
191 res
&= DIAG(hkl_engine_pseudo_axis_values_get(engine
, currents
, n_pseudo_axes
,
192 HKL_UNIT_DEFAULT
, &error
));
193 res
&= DIAG(NULL
== error
);
194 for(i
=0; i
<n_pseudo_axes
; ++i
)
195 res
&= DIAG(targets
[i
] != currents
[i
]); /* TODO this test is almost true, need a real check */
202 ok(TRUE
== TEST_FOREACH_MODE(1, _get
), __func__
);
205 static int _set(HklEngine
*engine
, HklEngineList
*engine_list
, UNUSED
unsigned int n
)
207 GError
*error
= NULL
;
210 HklGeometry
*geometry
= hkl_engine_list_geometry_get(engine_list
);
211 const darray_string
*pseudo_axes
= hkl_engine_pseudo_axis_names_get(engine
);
212 const size_t n_pseudo_axes
= darray_size(*pseudo_axes
);
213 double targets
[n_pseudo_axes
];
214 double currents
[n_pseudo_axes
];
216 /* randomize the geometry */
217 hkl_geometry_randomize(geometry
);
219 /* for now skip the eulerians check */
220 if(!strcmp(hkl_engine_current_mode_get(engine
), "eulerians"))
224 HklGeometryList
*solutions
;
226 /* randomize the pseudoAxes values */
227 hkl_tap_engine_pseudo_axes_randomize(engine
,
228 targets
, n_pseudo_axes
,
231 /* randomize the parameters */
232 hkl_tap_engine_parameters_randomize(engine
);
234 /* pseudo -> geometry */
235 res
&= DIAG(hkl_engine_initialized_set(engine
, TRUE
, &error
));
237 /* geometry -> pseudo */
238 solutions
= hkl_engine_pseudo_axis_values_set(engine
,
239 targets
, n_pseudo_axes
,
240 HKL_UNIT_DEFAULT
, &error
);
242 const HklGeometryListItem
*item
;
244 HKL_GEOMETRY_LIST_FOREACH(item
, solutions
){
245 hkl_geometry_set(geometry
,
246 hkl_geometry_list_item_geometry_get(item
));
248 res
&= DIAG(hkl_engine_pseudo_axis_values_get(engine
, currents
, n_pseudo_axes
, HKL_UNIT_DEFAULT
, &error
));
249 for(j
=0; j
<n_pseudo_axes
; ++j
)
250 res
&= DIAG(fabs(targets
[j
] - currents
[j
]) < HKL_EPSILON
);
252 hkl_geometry_list_free(solutions
);
254 res
&= DIAG(error
!= NULL
);
255 g_clear_error(&error
);
259 fprintf(stderr
, " unreachable : %d/%d", unreachable
, i
);
261 fprintf(stderr
, " ko");
262 /* print the hkl internals if the test failed */
263 fprintf(stderr
, "\n expected : ");
264 for(uint j
=0; j
<n_pseudo_axes
; ++j
)
265 fprintf(stderr
, " %f", targets
[j
]);
266 fprintf(stderr
, " obtained : ");
267 for(uint j
=0; j
<n_pseudo_axes
; ++j
)
268 fprintf(stderr
, " %f", currents
[j
]);
269 hkl_engine_fprintf(stderr
, engine
);
272 fprintf(stderr
, " ok");
280 static void set(int nb_iter
)
282 ok(TRUE
== TEST_FOREACH_MODE(nb_iter
, _set
), __func__
);
286 static int _pseudo_axis_get(HklEngine
*engine
, UNUSED HklEngineList
*engine_list
, UNUSED
unsigned int n
)
288 static const char *bad
= "_bad_name_";
289 const darray_string
*pseudo_axis_names
= hkl_engine_pseudo_axis_names_get(engine
);
290 const char **pseudo_axis_name
;
291 const HklParameter
*pseudo_axis
;
295 darray_foreach(pseudo_axis_name
, *pseudo_axis_names
){
296 pseudo_axis
= hkl_engine_pseudo_axis_get(engine
, *pseudo_axis_name
, NULL
);
297 res
&= DIAG(NULL
!= pseudo_axis
);
300 pseudo_axis
= hkl_engine_pseudo_axis_get(engine
, *pseudo_axis_name
, &error
);
301 res
&= DIAG(NULL
!= pseudo_axis
);
302 res
&= DIAG(NULL
== error
);
306 pseudo_axis
= hkl_engine_pseudo_axis_get(engine
, bad
, NULL
);
307 res
&= DIAG(NULL
== pseudo_axis
);
310 pseudo_axis
= hkl_engine_pseudo_axis_get(engine
, bad
, &error
);
311 res
&= DIAG(NULL
== pseudo_axis
);
312 res
&= DIAG(error
!= NULL
);
313 g_clear_error(&error
);
318 static void pseudo_axis_get(void)
320 ok(TRUE
== TEST_FOREACH_ENGINE(1, _pseudo_axis_get
), __func__
);
323 static int _capabilities(HklEngine
*engine
, UNUSED HklEngineList
*engine_list
, UNUSED
unsigned int n
)
326 const unsigned long capabilities
= hkl_engine_capabilities_get(engine
);
328 /* all motors must have the read capabilities */
329 res
&= DIAG((capabilities
& HKL_ENGINE_CAPABILITIES_READABLE
) != 0);
331 /* all engines except the readonly (incidence, emergence) are writable */
332 if(strcmp("incidence", hkl_engine_name_get(engine
))
333 && strcmp("emergence", hkl_engine_name_get(engine
)))
334 res
&= DIAG((capabilities
& HKL_ENGINE_CAPABILITIES_WRITABLE
) != 0);
336 /* all psi engines must be initialisable */
337 if(!strcmp("psi", hkl_engine_name_get(engine
)))
338 res
&= DIAG((capabilities
& HKL_ENGINE_CAPABILITIES_INITIALIZABLE
) != 0);
343 static void capabilities(void)
345 ok(TRUE
== TEST_FOREACH_MODE(1, _capabilities
), __func__
);
348 static int _initialized(HklEngine
*engine
, UNUSED HklEngineList
*engine_list
, UNUSED
unsigned int n
)
351 GError
*error
= NULL
;
352 const unsigned long capabilities
= hkl_engine_capabilities_get(engine
);
354 if(HKL_ENGINE_CAPABILITIES_INITIALIZABLE
& capabilities
){
357 res
&= DIAG(TRUE
== hkl_engine_initialized_set(engine
, FALSE
, NULL
));
358 res
&= DIAG(FALSE
== hkl_engine_initialized_get(engine
));
359 tmp
= hkl_engine_initialized_set(engine
, TRUE
, NULL
);
360 res
&= DIAG(tmp
== hkl_engine_initialized_get(engine
));
362 res
&= DIAG(TRUE
== hkl_engine_initialized_set(engine
, FALSE
, &error
));
363 res
&= DIAG(FALSE
== hkl_engine_initialized_get(engine
));
364 res
&= DIAG(NULL
== error
);
365 tmp
= hkl_engine_initialized_set(engine
, TRUE
, &error
);
366 res
&= DIAG(tmp
== hkl_engine_initialized_get(engine
));
368 res
&= DIAG(NULL
== error
);
370 res
&= DIAG(NULL
!= error
);
371 g_clear_error(&error
);
374 /* non-initializable engine should not produce an error */
375 res
&= DIAG(TRUE
== hkl_engine_initialized_get(engine
));
376 res
&= DIAG(TRUE
== hkl_engine_initialized_set(engine
, TRUE
, NULL
));
377 res
&= DIAG(TRUE
== hkl_engine_initialized_get(engine
));
378 res
&= DIAG(TRUE
== hkl_engine_initialized_set(engine
, FALSE
, NULL
));
379 res
&= DIAG(TRUE
== hkl_engine_initialized_get(engine
));
381 res
&= DIAG(TRUE
== hkl_engine_initialized_set(engine
, TRUE
, &error
));
382 res
&= DIAG(TRUE
== hkl_engine_initialized_get(engine
));
383 res
&= DIAG(NULL
== error
);
384 res
&= DIAG(TRUE
== hkl_engine_initialized_set(engine
, FALSE
, &error
));
385 res
&= DIAG(TRUE
== hkl_engine_initialized_get(engine
));
386 res
&= DIAG(NULL
== error
);
392 static void initialized(void)
394 ok(TRUE
== TEST_FOREACH_MODE(1, _initialized
), __func__
);
397 HKLAPI
int hkl_engine_initialized_set(HklEngine
*self
, int initialized
,
398 GError
**error
) HKL_ARG_NONNULL(1) HKL_WARN_UNUSED_RESULT
;
401 static int _modes(HklEngine
*engine
, UNUSED HklEngineList
*engine_list
, UNUSED
unsigned int n
)
403 static const char *bad
= "__bad_mode_name__";
406 const darray_string
*modes
;
408 const char *current_mode
;
409 GError
*error
= NULL
;
411 modes
= hkl_engine_modes_names_get(engine
);
413 /* check that the current mode is available in the mode list. */
414 current_mode
= hkl_engine_current_mode_get(engine
);
416 darray_foreach(mode
, *modes
){
417 if(!strcmp(current_mode
, *mode
))
420 res
&= DIAG(TRUE
== ok
);
422 /* check that all modes can be set */
423 darray_foreach(mode
, *modes
){
424 res
&= DIAG(TRUE
== hkl_engine_current_mode_set(engine
, *mode
, NULL
));
426 res
&= DIAG(TRUE
== hkl_engine_current_mode_set(engine
, *mode
, &error
));
427 res
&= DIAG(NULL
== error
);
430 /* check for bad mode name */
431 res
&= DIAG(FALSE
== hkl_engine_current_mode_set(engine
, bad
, NULL
));
433 res
&= DIAG(FALSE
== hkl_engine_current_mode_set(engine
, bad
, &error
));
434 res
&= DIAG(NULL
!= error
);
435 g_clear_error(&error
);
440 static void modes(void)
442 ok(TRUE
== TEST_FOREACH_ENGINE(1, _modes
), __func__
);
445 static int _check_axes(const darray_string
*axes
, const darray_string
*refs
)
451 darray_foreach(axis
, *axes
){
452 darray_foreach(ref
, *refs
){
453 if(!strcmp(*axis
, *ref
))
463 static int _axis_names(HklEngine
*engine
, HklEngineList
*engine_list
, UNUSED
unsigned int n
)
466 HklGeometry
*geometry
;
467 const darray_string
*all_axes
;
468 const darray_string
*axes_r
;
469 const darray_string
*axes_w
;
471 geometry
= hkl_engine_list_geometry_get(engine_list
);
472 all_axes
= hkl_geometry_axis_names_get(geometry
);
474 /* check consistency of the engines, all axes should be in the
475 * list of the geometry axes */
476 axes_r
= hkl_engine_axis_names_get(engine
,
477 HKL_ENGINE_AXIS_NAMES_GET_READ
);
479 axes_w
= hkl_engine_axis_names_get(engine
,
480 HKL_ENGINE_AXIS_NAMES_GET_WRITE
);
482 res
&= DIAG(axes_r
!= NULL
);
483 res
&= DIAG(axes_w
!= NULL
);
484 res
&= DIAG(_check_axes(axes_r
, all_axes
));
485 res
&= DIAG(_check_axes(axes_w
, all_axes
));
490 static void axis_names(void)
492 ok(TRUE
== TEST_FOREACH_MODE(1, _axis_names
), __func__
);
496 static int _mode_parameters(HklEngine
*engine
, UNUSED HklEngineList
*engine_list
, UNUSED
unsigned int n
)
498 static const char *bad
= "__bad_parameter_name__";
500 GError
*error
= NULL
;
501 const char **parameter
;
502 const darray_string
*parameters
= hkl_engine_parameters_names_get(engine
);
503 const HklParameter
*param
;
504 int n_values
= darray_size(*parameters
);
505 double values
[n_values
];
507 /* can not get a bad parameter */
508 param
= hkl_engine_parameter_get(engine
, bad
, NULL
);
509 res
&= DIAG(NULL
== param
);
511 param
= hkl_engine_parameter_get(engine
, bad
, &error
);
512 res
&= DIAG(NULL
== param
);
513 res
&= DIAG(NULL
!= error
);
514 g_clear_error(&error
);
516 /* it is possible to get and set all the parameters */
517 darray_foreach(parameter
, *parameters
){
519 param
= hkl_engine_parameter_get(engine
, *parameter
, NULL
);
520 res
&= DIAG(NULL
!= param
);
522 param
= hkl_engine_parameter_get(engine
, *parameter
, &error
);
523 res
&= DIAG(NULL
!= param
);
524 res
&= DIAG(NULL
== error
);
527 res
&= DIAG(TRUE
== hkl_engine_parameter_set(engine
, *parameter
, param
, NULL
));
528 res
&= DIAG(TRUE
== hkl_engine_parameter_set(engine
, *parameter
, param
, &error
));
529 res
&= DIAG(NULL
== error
);
531 res
&= DIAG(FALSE
== hkl_engine_parameter_set(engine
, bad
, param
, &error
));
532 res
&= DIAG(NULL
!= error
);
533 g_clear_error(&error
);
536 hkl_engine_parameters_values_get(engine
, values
, n_values
, HKL_UNIT_USER
);
538 res
&= DIAG(TRUE
== hkl_engine_parameters_values_set(engine
, values
, n_values
, HKL_UNIT_DEFAULT
, NULL
));
539 res
&= DIAG(TRUE
== hkl_engine_parameters_values_set(engine
, values
, n_values
, HKL_UNIT_DEFAULT
, &error
));
540 res
&= DIAG(NULL
== error
);
542 res
&= DIAG(TRUE
== hkl_engine_parameters_values_set(engine
, values
, n_values
, HKL_UNIT_USER
, NULL
));
543 res
&= DIAG(TRUE
== hkl_engine_parameters_values_set(engine
, values
, n_values
, HKL_UNIT_USER
, &error
));
544 res
&= DIAG(NULL
== error
);
549 static void mode_parameters(void)
551 ok(TRUE
== TEST_FOREACH_MODE(1, _mode_parameters
), __func__
);
554 static int _depends(HklEngine
*engine
, UNUSED HklEngineList
*engine_list
, UNUSED
unsigned int n
)
557 const char *name
= hkl_engine_name_get(engine
);
558 const unsigned int depends
= hkl_engine_dependencies_get(engine
);
560 if(!strcmp("hkl", name
))
561 res
&= DIAG((depends
& (HKL_ENGINE_DEPENDENCIES_AXES
| HKL_ENGINE_DEPENDENCIES_ENERGY
| HKL_ENGINE_DEPENDENCIES_SAMPLE
)) != 0);
562 if(!strcmp("eulerians", hkl_engine_name_get(engine
))){
563 res
&= DIAG((depends
& HKL_ENGINE_DEPENDENCIES_AXES
) != 0);
564 res
&= DIAG((depends
& HKL_ENGINE_DEPENDENCIES_ENERGY
) == 0);
565 res
&= DIAG((depends
& HKL_ENGINE_DEPENDENCIES_SAMPLE
) == 0);
567 if(!strcmp("q", name
)){
568 res
&= DIAG((depends
&(HKL_ENGINE_DEPENDENCIES_AXES
| HKL_ENGINE_DEPENDENCIES_ENERGY
)) != 0);
569 res
&= DIAG((depends
& HKL_ENGINE_DEPENDENCIES_SAMPLE
) == 0);
571 if(!strcmp("q2", name
)){
572 res
&= DIAG((depends
&(HKL_ENGINE_DEPENDENCIES_AXES
| HKL_ENGINE_DEPENDENCIES_ENERGY
)) != 0);
573 res
&= DIAG((depends
& HKL_ENGINE_DEPENDENCIES_SAMPLE
) == 0);
575 if(!strcmp("qper_qpar", name
)){
576 res
&= DIAG((depends
& (HKL_ENGINE_DEPENDENCIES_AXES
| HKL_ENGINE_DEPENDENCIES_ENERGY
)) != 0);
577 res
&= DIAG((depends
& HKL_ENGINE_DEPENDENCIES_SAMPLE
) == 0);
579 if(!strcmp("psi", name
))
580 res
&= DIAG((depends
& (HKL_ENGINE_DEPENDENCIES_AXES
| HKL_ENGINE_DEPENDENCIES_ENERGY
| HKL_ENGINE_DEPENDENCIES_SAMPLE
)) != 0);
585 static void depends(void)
587 ok(TRUE
== TEST_FOREACH_ENGINE(1, _depends
), __func__
);
590 int main(int argc
, char** argv
)