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>
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"
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))); \
51 #define fill_row(row, shape, val) do{ \
52 for(int i_=0; i_<(shape).width; ++i_){ \
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_]; \
65 #define fill_column(col, shape, val) do { \
66 for(int i_=0; i_<shape_size(shape); i_=i_+(shape).width){ \
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)]
84 #define SHAPE(width_, height_) (struct shape_t) \
85 {.width=width_, .height=height_}
91 #define SQUARE(pixel_size_) (struct square_t) \
92 {.pixel_size=pixel_size_}
95 struct square_t square
;
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_}
104 struct square_t square
;
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_}
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
)
127 const struct shape_t shape
;
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
[] = {
138 SHAPE(560, 240), IMXPAD(130e-6, 80, 120)),
139 DETECTOR(XpadFlatCorrected
,
140 SHAPE(576, 1154), SQUARE(130e-6)),
142 SHAPE(560, 120), IMXPAD(130e-6, 80, 120)),
144 SHAPE(1030, 1065), TILING(1030, 514, 10, 37, 75e-6)),
146 SHAPE(257, 256), SQUARE(75e-6)),
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 */
159 /***********************/
160 /* specific operations */
161 /***********************/
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
);
178 return s
* 3.0 / 2.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);
192 static inline double *coordinates_get_imxpad(const struct shape_t
*shape
,
193 const struct imxpad_t
*imxpad
)
196 double *arr
= coordinates_new(shape
);
200 row
= y_coordinates(arr
, *shape
);
201 for(i
=0; i
<shape
->width
; ++i
){
202 row
[i
] = - imxpad_coordinates_pattern(i
,
204 imxpad
->square
.pixel_size
);
206 replicate_row(row
, *shape
, shape
->height
);
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
,
215 imxpad
->square
.pixel_size
));
221 static inline double *coordinates_rectangle(const struct shape_t
*shape
,
222 double p_w
, double p_h
)
225 double *arr
= coordinates_new(shape
);
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
);
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
);
245 static inline void flip_z(const struct shape_t
*shape
, double *arr
)
248 double *z
= z_coordinates(arr
, *shape
);
250 for(i
=0; i
<shape_size(*shape
); ++i
)
254 static inline double *coordinates_get_square(const struct shape_t
*shape
,
255 const struct square_t
*square
)
257 return coordinates_rectangle(shape
,
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
){
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
){
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);
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);
326 static inline uint8_t *mask_get_tiling(const struct shape_t
*shape
,
327 const struct tiling_t
*tiling
)
330 uint8_t *arr
= no_mask(shape
);
333 for(i
=tiling
->module_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
);
342 for(i
=tiling
->module_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
);
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
){
372 static inline void rotate_coordinates(double *arr
,
373 const struct shape_t shape
,
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
}};
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
);
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
]);
413 void hkl_binoculars_detector_2d_sixs_calibration(HklBinocularsDetectorEnum n
,
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
);
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);
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
);
463 match(detector
.type
){
464 of(ImXpadS70
, imxpad
){
465 arr
= coordinates_get_imxpad(&detector
.shape
,
468 of(ImXpadS140
, imxpad
){
469 arr
= coordinates_get_imxpad(&detector
.shape
,
472 of(XpadFlatCorrected
, square
){
473 arr
= coordinates_get_square(&detector
.shape
,
477 arr
= coordinates_get_square(&detector
.shape
,
479 flip_z(&detector
.shape
, arr
);
482 arr
= coordinates_get_square(&detector
.shape
,
486 arr
= coordinates_get_square(&detector
.shape
,
489 of(MerlinMedipix3RXQuad
, tiling
){
490 arr
= coordinates_get_square(&detector
.shape
,
497 void hkl_binoculars_detector_2d_coordinates_save(HklBinocularsDetectorEnum n
,
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
);
517 uint8_t *hkl_binoculars_detector_2d_mask_get(HklBinocularsDetectorEnum n
)
519 const struct detector_t detector
= get_detector(n
);
522 match(detector
.type
){
523 of(ImXpadS70
, imxpad
){
524 arr
= mask_get_imxpad(&detector
.shape
,
527 of(ImXpadS140
, imxpad
){
528 arr
= mask_get_imxpad(&detector
.shape
,
531 of(XpadFlatCorrected
){
532 arr
= mask_get_xpad_flat_corrected(&detector
.shape
);
535 arr
= mask_get_tiling(&detector
.shape
,
539 arr
= no_mask(&detector
.shape
);
542 arr
= no_mask(&detector
.shape
);
544 of(MerlinMedipix3RXQuad
, tiling
){
545 arr
= mask_get_tiling(&detector
.shape
,
549 arr
= no_mask(&detector
.shape
);
556 uint8_t *hkl_binoculars_detector_2d_mask_load(HklBinocularsDetectorEnum n
,
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
);
573 void hkl_binoculars_detector_2d_mask_save(HklBinocularsDetectorEnum n
,
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
);
591 uint32_t *hkl_binoculars_detector_2d_fake_image_uint32(HklBinocularsDetectorEnum n
,
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
){