From e8053e5386146bf88b2b45d028774da9f4439069 Mon Sep 17 00:00:00 2001 From: Thomas White Date: Thu, 22 Sep 2022 14:07:34 +0200 Subject: Implement data_template_get_2d_detgeom_if_possible It is horrible. But it's contained inside the DataTemplate module. --- libcrystfel/src/datatemplate.c | 134 +++++++++++++++++++++++++++++++++++- libcrystfel/src/datatemplate_priv.h | 3 +- libcrystfel/src/image.c | 11 ++- libcrystfel/src/stream.c | 2 +- 4 files changed, 138 insertions(+), 12 deletions(-) diff --git a/libcrystfel/src/datatemplate.c b/libcrystfel/src/datatemplate.c index 8f909eb8..1075b349 100644 --- a/libcrystfel/src/datatemplate.c +++ b/libcrystfel/src/datatemplate.c @@ -1853,8 +1853,108 @@ static int im_get_length(struct image *image, const char *from, } +static int all_panels_reference_same_clen(const DataTemplate *dtempl) +{ + int i; + char *first_val = NULL; + char *first_units = NULL; + int fail = 0; + + for ( i=0; in_panels; i++ ) { + struct panel_template *p = &dtempl->panels[i]; + char *val; + char *units; + if ( separate_value_and_units(p->cnz_from, &val, &units) ) { + /* Parse error */ + return 0; + } + if ( i == 0 ) { + first_val = val; + first_units = units; + } else { + if ( strcmp(val, first_val) != 0 ) fail = 1; + if ( strcmp(units, first_units) != 0 ) fail = 1; + free(val); + free(units); + } + } + + free(first_val); + free(first_units); + return fail; +} + + +static int all_coffsets_small(const DataTemplate *dtempl) +{ + int i; + + for ( i=0; in_panels; i++ ) { + struct panel_template *p = &dtempl->panels[i]; + if ( p->cnz_offset > 10.0*p->pixel_pitch ) return 0; + } + + return 1; +} + + +static int all_panels_same_clen(const DataTemplate *dtempl) +{ + int i; + double *zvals; + double total = 0.0; + double mean; + + zvals = malloc(sizeof(double)*dtempl->n_panels); + if ( zvals == NULL ) return 0; + + for ( i=0; in_panels; i++ ) { + struct panel_template *p = &dtempl->panels[i]; + if ( im_get_length(NULL, p->cnz_from, 1e-3, &zvals[i]) ) { + /* Can't get length because it used a header reference */ + free(zvals); + return 0; + } + total += zvals[i]; + } + + mean = total/dtempl->n_panels; + for ( i=0; in_panels; i++ ) { + struct panel_template *p = &dtempl->panels[i]; + if ( fabs(zvals[i] - mean) > 10.0*p->pixel_pitch ) return 0; + } + + free(zvals); + + return 1; +} + + +static int all_panels_perpendicular_to_beam(const DataTemplate *dtempl) +{ + int i; + + for ( i=0; in_panels; i++ ) { + double z_diff; + struct panel_template *p = &dtempl->panels[i]; + z_diff = p->fsz*PANEL_WIDTH(p) + p->ssz*PANEL_HEIGHT(p); + if ( z_diff > 10.0*p->pixel_pitch ) return 0; + } + return 1; +} + + +static int detector_flat(const DataTemplate *dtempl) +{ + return all_panels_perpendicular_to_beam(dtempl) + && ( (all_panels_reference_same_clen(dtempl) && all_coffsets_small(dtempl)) + || all_panels_same_clen(dtempl) ); +} + + struct detgeom *create_detgeom(struct image *image, - const DataTemplate *dtempl) + const DataTemplate *dtempl, + int two_d_only) { struct detgeom *detgeom; int i; @@ -1875,6 +1975,12 @@ struct detgeom *create_detgeom(struct image *image, detgeom->n_panels = dtempl->n_panels; + if ( two_d_only ) { + if ( !detector_flat(dtempl) ) return NULL; + if ( dtempl->shift_x_from != NULL ) return NULL; + if ( dtempl->shift_y_from != NULL ) return NULL; + } + for ( i=0; in_panels; i++ ) { struct detgeom_panel *p = &detgeom->panels[i]; @@ -1888,10 +1994,15 @@ struct detgeom *create_detgeom(struct image *image, /* NB cnx,cny are in pixels, cnz is in m */ p->cnx = tmpl->cnx; p->cny = tmpl->cny; + if ( im_get_length(image, tmpl->cnz_from, 1e-3, &p->cnz) ) { - ERROR("Failed to read length from '%s'\n", tmpl->cnz_from); - return NULL; + if ( two_d_only ) { + p->cnz = NAN; + } else { + ERROR("Failed to read length from '%s'\n", tmpl->cnz_from); + return NULL; + } } /* Apply offset (in m) and then convert cnz from @@ -1959,4 +2070,21 @@ struct detgeom *create_detgeom(struct image *image, return detgeom; } + +/** + * Create a detgeom structure from the DataTemplate, if possible, and ignoring + * 3D information. + * + * This procedure will create a detgeom structure provided that the detector + * is close to lying in a single flat plane perpendicular to the beam + * direction. If certain things (e.g. panel z-positions) refer to headers, + * it might not be possible to determine that the detector is really flat + * until an image is loaded. Therefore you must gracefully handle a NULL + * return value from this routine. + * + * \returns the detgeom structure, or NULL if impossible. + */ +struct detgeom *data_template_get_2d_detgeom_if_possible(const DataTemplate *dt) +{ + return create_detgeom(NULL, dt, 1); } diff --git a/libcrystfel/src/datatemplate_priv.h b/libcrystfel/src/datatemplate_priv.h index 3e61f216..26b90d6b 100644 --- a/libcrystfel/src/datatemplate_priv.h +++ b/libcrystfel/src/datatemplate_priv.h @@ -237,6 +237,7 @@ struct _datatemplate extern double convert_to_m(double val, int units); extern struct detgeom *create_detgeom(struct image *image, - const DataTemplate *dtempl); + const DataTemplate *dtempl, + int two_d_only); #endif /* DATATEMPLATE_PRIV_H */ diff --git a/libcrystfel/src/image.c b/libcrystfel/src/image.c index 45b61bec..84088ead 100644 --- a/libcrystfel/src/image.c +++ b/libcrystfel/src/image.c @@ -412,11 +412,6 @@ static struct header_cache_entry *cached_header(struct image *image, const char { struct header_cache_entry *ce; - if ( image == NULL ) { - ERROR("Attempt to retrieve a header value without an image\n"); - return NULL; - } - ce = find_cache_entry(image, from); if ( ce != NULL ) return ce; @@ -434,6 +429,8 @@ int image_read_header_float(struct image *image, const char *from, double *val) { struct header_cache_entry *ce; + if ( image == NULL ) return 1; + ce = cached_header(image, from); if ( ce == NULL ) return 1; @@ -1074,7 +1071,7 @@ struct image *image_create_for_simulation(const DataTemplate *dtempl) return NULL; } - image->detgeom = create_detgeom(image, dtempl); + image->detgeom = create_detgeom(image, dtempl, 0); if ( image->detgeom == NULL ) { image_free(image); return NULL; @@ -1126,7 +1123,7 @@ static int do_image_read(struct image *image, const DataTemplate *dtempl, } profile_start("create-detgeom"); - image->detgeom = create_detgeom(image, dtempl); + image->detgeom = create_detgeom(image, dtempl, 0); profile_end("create-detgeom"); if ( image->detgeom == NULL ) { ERROR("Failed to read geometry information\n"); diff --git a/libcrystfel/src/stream.c b/libcrystfel/src/stream.c index 3a4f5dae..0195e0ff 100644 --- a/libcrystfel/src/stream.c +++ b/libcrystfel/src/stream.c @@ -897,7 +897,7 @@ struct image *stream_read_chunk(Stream *st, StreamFlags srf) if ( have_filename && have_ev ) { /* Success */ if ( srf & STREAM_DATA_DETGEOM ) { - image->detgeom = create_detgeom(image, st->dtempl_read); + image->detgeom = create_detgeom(image, st->dtempl_read, 0); if ( image->detgeom == NULL ) { image_free(image); return NULL; -- cgit v1.2.3