[haskell] use the right version of the hkl library >= 5.0.0.3381-1~
[hkl.git] / binoculars / hkl-binoculars-detectors-2d.c
blob93db89f373a673a5f61b377beb7586cee18a1d17
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-2023 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>
22 #include <stdlib.h>
24 #include "datatype99.h"
26 #include "ccan/array_size/array_size.h"
28 #include "hkl-binoculars.h"
29 #include "hkl-binoculars-cnpy-private.h"
30 #include "hkl-quaternion-private.h"
31 #include "hkl-vector-private.h"
33 /**********/
34 /* macros */
35 /**********/
37 #define wrong_detector(n) fprintf(stderr, "You requested a non existing detector %d the maximum number available is %d", n, HKL_BINOCULARS_DETECTOR_NUM_DETECTORS)
39 #define shape_size(shape) (shape).width * (shape).height
40 #define flat_index(shape, i, j) i + j * (shape).width
42 #define get_row(arr, shape, i) &arr[(i) * (shape).width]
43 #define get_col(arr, i) &arr[i]
45 #define replicate_row(row, shape, n) do{ \
46 for(int i_=1; i_<(n); ++i_){ \
47 memcpy(&(row)[i_ * (shape).width], (row), (shape).width * sizeof(*(row))); \
48 } \
49 } while(0)
51 #define fill_row(row, shape, val) do{ \
52 for(int i_=0; i_<(shape).width; ++i_){ \
53 (row)[i_] = (val); \
54 } \
55 } while(0)
57 #define replicate_column(col, shape, n) do{ \
58 for(int i_=0; i_<shape_size(shape); i_=i_+(shape).width){ \
59 for(int j_=1; j_<(n); ++j_){ \
60 (col[i_+j_]) = col[i_]; \
61 } \
62 } \
63 } while(0)
65 #define fill_column(col, shape, val) do { \
66 for(int i_=0; i_<shape_size(shape); i_=i_+(shape).width){ \
67 (col)[i_] = (val); \
68 } \
69 } while(0)
71 #define x_coordinates(arr, shape) &arr[0 * shape_size(shape)]
72 #define y_coordinates(arr, shape) &arr[1 * shape_size(shape)]
73 #define z_coordinates(arr, shape) &arr[2 * shape_size(shape)]
75 /*************/
76 /* detectors */
77 /************/
79 struct shape_t {
80 int width;
81 int height;
84 #define SHAPE(width_, height_) (struct shape_t) \
85 {.width=width_, .height=height_}
87 struct square_t {
88 double pixel_size;
91 #define SQUARE(pixel_size_) (struct square_t) \
92 {.pixel_size=pixel_size_}
94 struct imxpad_t {
95 struct square_t square;
96 int chip_w;
97 int chip_h;
100 #define IMXPAD(pixel_size_, chip_w_, chip_h_) (struct imxpad_t) \
101 {.square=SQUARE(pixel_size_), .chip_w=chip_w_, .chip_h=chip_h_}
103 struct tiling_t {
104 struct square_t square;
105 int module_width;
106 int module_height;
107 int gap_width;
108 int gap_height;
111 #define TILING(module_width_, module_height_, gap_width_, gap_height_, pixel_size_) (struct tiling_t) \
112 {.square=SQUARE(pixel_size_), .module_width=module_width_, .module_height=module_height_, .gap_width=gap_width_, .gap_height=gap_height_}
114 datatype(
115 DetectorType,
116 (ImXpadS70, struct imxpad_t),
117 (ImXpadS140, struct imxpad_t),
118 (XpadFlatCorrected, struct square_t),
119 (Eiger1M, struct tiling_t),
120 (Ufxc, struct square_t),
121 (Merlin, struct square_t),
122 (MerlinMedipix3RXQuad, struct tiling_t)
125 struct detector_t {
126 const char *name;
127 const struct shape_t shape;
128 DetectorType type;
131 #define DETECTOR(name_, shape_, type_) (struct detector_t) \
132 {.name=#name_, .shape=shape_, .type=name_(type_)}
134 static inline struct detector_t get_detector(HklBinocularsDetectorEnum n)
136 struct detector_t detectors[] = {
137 DETECTOR(ImXpadS140,
138 SHAPE(560, 240), IMXPAD(130e-6, 80, 120)),
139 DETECTOR(XpadFlatCorrected,
140 SHAPE(576, 1154), SQUARE(130e-6)),
141 DETECTOR(ImXpadS70,
142 SHAPE(560, 120), IMXPAD(130e-6, 80, 120)),
143 DETECTOR(Eiger1M,
144 SHAPE(1030, 1065), TILING(1030, 514, 10, 37, 75e-6)),
145 DETECTOR(Ufxc,
146 SHAPE(257, 256), SQUARE(75e-6)),
147 DETECTOR(Merlin,
148 SHAPE(256, 256), SQUARE(55e-6)),
149 DETECTOR(MerlinMedipix3RXQuad,
150 SHAPE(515, 515), TILING(256, 256, 3, 3, 55e-6)),
153 if (n > ARRAY_SIZE(detectors))
154 n = 0; /* use the first detector as default */
156 return detectors[n];
159 /***********************/
160 /* specific operations */
161 /***********************/
163 /* coordinates */
165 static inline double *coordinates_new(const struct shape_t *shape)
167 return g_new0(double, 3 * shape_size(*shape));
170 static inline double imxpad_coordinates_pattern(int i, int chip, double s)
172 div_t q = div(i, chip);
174 if (i == 0){
175 return s / 2;
177 if (i == 1){
178 return s * 3.0 / 2.0;
180 if (q.rem == 0){
181 return s * (i + 3 * q.quot - 0.25);
183 if (q.rem <= (chip - 2)) {
184 return s * (i + 3 * q.quot + 0.5);
186 if (q.rem <= (chip - 1)) {
187 return s * (i + 3 * q.quot + 2.5);
189 return NAN;
192 static inline double *coordinates_get_imxpad(const struct shape_t *shape,
193 const struct imxpad_t *imxpad)
195 int i;
196 double *arr = coordinates_new(shape);
197 double *z, *row;
199 /* y */
200 row = y_coordinates(arr, *shape);
201 for(i=0; i<shape->width; ++i){
202 row[i] = - imxpad_coordinates_pattern(i,
203 imxpad->chip_w,
204 imxpad->square.pixel_size);
206 replicate_row(row, *shape, shape->height);
208 /* z */
209 z = z_coordinates(arr, *shape);
210 for(i=0; i<shape->height; ++i){
211 row = get_row(z, *shape, i);
212 fill_row(row, *shape,
213 imxpad_coordinates_pattern(i,
214 imxpad->chip_h,
215 imxpad->square.pixel_size));
218 return arr;
221 static inline double *coordinates_rectangle(const struct shape_t *shape,
222 double p_w, double p_h)
224 int i;
225 double *arr = coordinates_new(shape);
226 double *y, *z;
228 /* y */
229 y = y_coordinates(arr, *shape);
230 for(i=0; i<shape->width; ++i)
231 y[i] = - (0.5 + i) * p_w;
232 replicate_row(y, *shape, shape->height);
234 /* z */
235 z = z_coordinates(arr, *shape);
236 for(i=0; i<shape->height; ++i){
237 double *row = get_row(z, *shape, i);
238 fill_row(row, *shape, (0.5 + i) * p_h);
241 return arr;
245 static inline void flip_z(const struct shape_t *shape, double *arr)
247 int i;
248 double *z = z_coordinates(arr, *shape);
250 for(i=0; i<shape_size(*shape); ++i)
251 z[i] *= -1;
254 static inline double *coordinates_get_square(const struct shape_t *shape,
255 const struct square_t *square)
257 return coordinates_rectangle(shape,
258 square->pixel_size,
259 square->pixel_size);
262 /* masks */
264 static inline uint8_t *no_mask(const struct shape_t *shape)
266 return g_new0(uint8_t, shape_size(*shape));
269 static inline uint8_t *mask_get_imxpad(const struct shape_t *shape,
270 const struct imxpad_t *imxpad)
272 uint8_t *arr = no_mask(shape);
274 /* now mask all the strange row */
276 div_t q = div(shape->width, imxpad->chip_w);
277 int n_chips = q.quot;
279 for(int chip=0; chip<n_chips; ++chip){
280 if (chip != 0){
281 uint8_t *first = get_col(arr, chip * imxpad->chip_w);
282 fill_column(first, *shape, 1);
285 if (chip != (n_chips - 1)){
286 uint8_t *last = get_col(arr, (chip + 1) * imxpad->chip_w - 1);
287 fill_column(last, *shape, 1);
291 q = div(shape->height, imxpad->chip_h);
292 int n_modules = q.quot;
294 for(int module=0; module<n_modules; ++module){
295 if (module != 0){
296 uint8_t *first = get_row(arr, *shape,
297 module * imxpad->chip_h);
298 fill_row(first, *shape, 1);
301 if (module != (n_modules - 1)){
302 uint8_t *last = get_row(arr, *shape,
303 (module + 1) * imxpad->chip_h - 1);
304 fill_row(last, *shape, 1);
308 return arr;
311 static inline uint8_t *mask_get_xpad_flat_corrected(const struct shape_t *shape)
313 uint8_t *arr = no_mask(shape);
315 /* now mask all the strange row */
316 for(int i=118; i<=1006; i=i+148){
317 uint8_t *row = get_row(arr, *shape, i);
319 fill_row(row, *shape, 1);
320 replicate_row(row, *shape, 30);
323 return arr;
326 static inline uint8_t *mask_get_tiling(const struct shape_t *shape,
327 const struct tiling_t *tiling)
329 int i;
330 uint8_t *arr = no_mask(shape);
332 /* columns */
333 for(i=tiling->module_width;
334 i<shape->width;
335 i=i+tiling->module_width + tiling->gap_width){
336 uint8_t *col = get_col(arr, i);
337 fill_column(col, *shape, 1);
338 replicate_column(col, *shape, tiling->gap_width);
341 /* rows */
342 for(i=tiling->module_height;
343 i<shape->height;
344 i=i+tiling->module_height + tiling->gap_height){
345 uint8_t *row = get_row(arr, *shape, i);
346 fill_row(row, *shape, 1);
347 replicate_row(row, *shape, tiling->gap_height);
350 return arr;
353 /***************/
354 /* Calibration */
355 /***************/
357 static inline void translate_coordinates(double *arr,
358 const struct shape_t shape,
359 double dx, double dy, double dz)
361 double *x = x_coordinates(arr, shape);
362 double *y = y_coordinates(arr, shape);
363 double *z = z_coordinates(arr, shape);
365 for(int i=0; i<shape_size(shape); ++i){
366 x[i] += dx;
367 y[i] += dy;
368 z[i] += dz;
372 static inline void rotate_coordinates(double *arr,
373 const struct shape_t shape,
374 double angle,
375 double axis_x, double axis_y, double axis_z)
377 double *x = x_coordinates(arr, shape);
378 double *y = y_coordinates(arr, shape);
379 double *z = z_coordinates(arr, shape);
381 HklVector axis = {{axis_x, axis_y, axis_z}};
382 HklQuaternion q;
384 hkl_quaternion_init_from_angle_and_axe(&q, angle, &axis);
386 for(int i=0; i<shape_size(shape); ++i){
387 HklVector v= {{x[i], y[i], z[i]}};
389 hkl_vector_rotated_quaternion(&v, &q);
390 x[i] = v.data[0];
391 y[i] = v.data[1];
392 z[i] = v.data[2];
396 static inline void normalize_coordinates(double *arr, const struct shape_t shape)
398 double *x = x_coordinates(arr, shape);
399 double *y = y_coordinates(arr, shape);
400 double *z = z_coordinates(arr, shape);
402 for(int i=0; i<shape_size(shape); ++i)
404 double n = sqrt(x[i] * x[i] + y[i] * y[i] + z[i] * z[i]);
405 if (n != 0.0){
406 x[i] = x[i] / n;
407 y[i] = y[i] / n;
408 z[i] = z[i] / n;
413 void hkl_binoculars_detector_2d_sixs_calibration(HklBinocularsDetectorEnum n,
414 double *arr,
415 int width, int height,
416 int ix0, int iy0, double sdd,
417 double detrot, int normalize_flag)
419 struct shape_t shape = SHAPE(width, height);
420 double *y = y_coordinates(arr, shape);
421 double *z = z_coordinates(arr, shape);
423 double dx = sdd;
424 double dy = -y[flat_index(shape, ix0, iy0)];
425 double dz = -z[flat_index(shape, ix0, iy0)];
427 translate_coordinates(arr, shape, dx, dy, dz);
428 rotate_coordinates(arr, shape, detrot, 1, 0, 0);
429 if(normalize_flag)
430 normalize_coordinates(arr, shape);
433 /*****************************/
434 /* public API implementation */
435 /*****************************/
437 int hkl_binoculars_detector_2d_number_of_detectors(void)
439 return HKL_BINOCULARS_DETECTOR_NUM_DETECTORS;
442 const char *hkl_binoculars_detector_2d_name_get(HklBinocularsDetectorEnum n)
444 const struct detector_t detector = get_detector(n);
446 return detector.name;
449 void hkl_binoculars_detector_2d_shape_get(HklBinocularsDetectorEnum n,
450 int *width, int *height)
452 const struct detector_t detector = get_detector(n);
454 *width = detector.shape.width;
455 *height = detector.shape.height;
458 double *hkl_binoculars_detector_2d_coordinates_get(HklBinocularsDetectorEnum n)
460 const struct detector_t detector = get_detector(n);
461 double *arr = NULL;
463 match(detector.type){
464 of(ImXpadS70, imxpad){
465 arr = coordinates_get_imxpad(&detector.shape,
466 imxpad);
468 of(ImXpadS140, imxpad){
469 arr = coordinates_get_imxpad(&detector.shape,
470 imxpad);
472 of(XpadFlatCorrected, square){
473 arr = coordinates_get_square(&detector.shape,
474 square);
476 of(Eiger1M, tiling){
477 arr = coordinates_get_square(&detector.shape,
478 &tiling->square);
479 flip_z(&detector.shape, arr);
481 of(Ufxc, square){
482 arr = coordinates_get_square(&detector.shape,
483 square);
485 of(Merlin, square){
486 arr = coordinates_get_square(&detector.shape,
487 square);
489 of(MerlinMedipix3RXQuad, tiling){
490 arr = coordinates_get_square(&detector.shape,
491 &tiling->square);
494 return arr;
497 void hkl_binoculars_detector_2d_coordinates_save(HklBinocularsDetectorEnum n,
498 const char *fname)
500 double *arr = NULL;
501 const struct detector_t detector = get_detector(n);
503 darray_int shape = darray_new();
505 darray_append(shape, 3);
506 darray_append(shape, detector.shape.height);
507 darray_append(shape, detector.shape.width);
509 arr = hkl_binoculars_detector_2d_coordinates_get(n);
511 npy_save(fname, arr, HklBinocularsNpyDouble(), &shape);
513 free(arr);
514 darray_free(shape);
517 uint8_t *hkl_binoculars_detector_2d_mask_get(HklBinocularsDetectorEnum n)
519 const struct detector_t detector = get_detector(n);
520 uint8_t *arr;
522 match(detector.type){
523 of(ImXpadS70, imxpad){
524 arr = mask_get_imxpad(&detector.shape,
525 imxpad);
527 of(ImXpadS140, imxpad){
528 arr = mask_get_imxpad(&detector.shape,
529 imxpad);
531 of(XpadFlatCorrected){
532 arr = mask_get_xpad_flat_corrected(&detector.shape);
534 of(Eiger1M, tiling){
535 arr = mask_get_tiling(&detector.shape,
536 tiling);
538 of(Ufxc){
539 arr = no_mask(&detector.shape);
541 of(Merlin){
542 arr = no_mask(&detector.shape);
544 of(MerlinMedipix3RXQuad, tiling){
545 arr = mask_get_tiling(&detector.shape,
546 tiling);
548 otherwise {
549 arr = no_mask(&detector.shape);
553 return arr;
556 uint8_t *hkl_binoculars_detector_2d_mask_load(HklBinocularsDetectorEnum n,
557 const char *fname)
559 uint8_t *arr = NULL;
560 const struct detector_t detector = get_detector(n);
561 darray_int shape = darray_new();
563 darray_append(shape, detector.shape.height);
564 darray_append(shape, detector.shape.width);
566 arr = npy_load(fname, HklBinocularsNpyBool(), &shape);
568 darray_free(shape);
570 return arr;
573 void hkl_binoculars_detector_2d_mask_save(HklBinocularsDetectorEnum n,
574 const char *fname)
576 uint8_t *arr = NULL;
577 const struct detector_t detector = get_detector(n);
578 darray_int shape = darray_new();
580 darray_append(shape, detector.shape.height);
581 darray_append(shape, detector.shape.width);
583 arr = hkl_binoculars_detector_2d_mask_get(n);
584 npy_save(fname, arr, HklBinocularsNpyBool(), &shape);
586 darray_free(shape);
587 free(arr);
591 uint32_t *hkl_binoculars_detector_2d_fake_image_uint32(HklBinocularsDetectorEnum n,
592 size_t *n_pixels)
594 size_t i;
595 uint32_t *arr;
596 const struct detector_t detector = get_detector(n);
598 *n_pixels = detector.shape.width * detector.shape.height;
599 arr = g_new(uint32_t, *n_pixels);
600 for(i=0; i<*n_pixels; ++i){
601 arr[i] = rand();
604 return arr;