diff options
author | Thomas White <taw@physics.org> | 2019-09-20 16:02:59 +0200 |
---|---|---|
committer | Thomas White <taw@physics.org> | 2019-09-20 17:04:17 +0200 |
commit | ac669f51d502369b635cf9447abfd0bb94af1700 (patch) | |
tree | 47d4ddc6f5c00f052dee780bfa9b6f37536eab25 | |
parent | f901c64ce6ce7b0acfdef5051af350e4b65f8590 (diff) |
Delegate option processing for indexing methods
Involves switching from getopt_long to argp. A big improvement!
-rw-r--r-- | libcrystfel/src/felix.c | 176 | ||||
-rw-r--r-- | libcrystfel/src/felix.h | 17 | ||||
-rw-r--r-- | libcrystfel/src/taketwo.c | 104 | ||||
-rw-r--r-- | libcrystfel/src/taketwo.h | 12 | ||||
-rw-r--r-- | libcrystfel/src/utils.c | 2 | ||||
-rw-r--r-- | libcrystfel/src/xgandalf.c | 159 | ||||
-rw-r--r-- | libcrystfel/src/xgandalf.h | 12 | ||||
-rw-r--r-- | src/indexamajig.c | 1836 | ||||
-rw-r--r-- | src/process_image.h | 7 |
9 files changed, 1241 insertions, 1084 deletions
diff --git a/libcrystfel/src/felix.c b/libcrystfel/src/felix.c index ea27093a..cac12410 100644 --- a/libcrystfel/src/felix.c +++ b/libcrystfel/src/felix.c @@ -70,6 +70,21 @@ #define FELIX_VERBOSE 0 +struct felix_options +{ + double ttmin; /* radians */ + double ttmax; /* radians */ + int min_visits; + double min_completeness; + double max_uniqueness; + int n_voxels; + double fraction_max_visits; + double sigma; + double domega; + double max_internal_angle; +}; + + /* Global private data, prepared once */ struct felix_private { @@ -789,3 +804,164 @@ const char *felix_probe(UnitCell *cell) if ( ok ) return "felix"; return NULL; } + + +static void show_help() +{ + printf("Parameters for the Felix indexing algorithm:\n" +" --felix-domega Degree range of omega (moscaicity) to consider.\n" +" Default: 2\n" +" --felix-fraction-max-visits\n" +" Cutoff for minimum fraction of the max visits.\n" +" Default: 0.75\n" +" --felix-max-internal-angle\n" +" Cutoff for maximum internal angle between observed\n" +" spots and predicted spots. Default: 0.25\n" +" --felix-max-uniqueness\n" +" Cutoff for maximum fraction of found spots which\n" +" can belong to other crystallites. Default: 0.5\n" +" --felix-min-completeness\n" +" Cutoff for minimum fraction of projected spots\n" +" found in the pattern. Default: 0.001\n" +" --felix-min-visits\n" +" Cutoff for minimum number of voxel visits.\n" +" Default: 15\n" +" --felix-num-voxels Number of voxels for Rodrigues space search\n" +" Default: 100\n" +" --felix-sigma The sigma of the 2theta, eta and omega angles.\n" +" Default: 0.2\n" +" --felix-tthrange-max Maximum 2theta to consider for indexing (degrees)\n" +" Default: 30\n" +" --felix-tthrange-min Minimum 2theta to consider for indexing (degrees)\n" +" Default: 0\n" +); +} + + +static error_t parse_arg(int key, char *arg, struct argp_state *state) +{ + struct felix_options **opts_ptr = state->input; + float tmp; + + switch ( key ) { + + case ARGP_KEY_INIT : + *opts_ptr = malloc(sizeof(struct felix_options)); + if ( *opts_ptr == NULL ) return ENOMEM; + (*opts_ptr)->ttmin = -1.0; + (*opts_ptr)->ttmax = -1.0; + (*opts_ptr)->min_visits = 0; + (*opts_ptr)->min_completeness = -1.0; + (*opts_ptr)->max_uniqueness = -1.0; + (*opts_ptr)->n_voxels = 0; + (*opts_ptr)->fraction_max_visits = -1.0; + (*opts_ptr)->sigma = -1.0; + (*opts_ptr)->domega = -1.0; + (*opts_ptr)->max_internal_angle = -1.0; + break; + + case 1 : + show_help(); + return EINVAL; + + case 2 : + if ( sscanf(arg, "%f", &tmp) != 1 ) { + ERROR("Invalid value for --felix-tthrange-min\n"); + return EINVAL; + } + (*opts_ptr)->ttmin = deg2rad(tmp); + break; + + case 3 : + if ( sscanf(arg, "%f", &tmp) != 1 ) { + ERROR("Invalid value for --felix-tthrange-max\n"); + return EINVAL; + } + (*opts_ptr)->ttmax = deg2rad(tmp); + break; + + case 4 : + if ( sscanf(arg, "%d", &(*opts_ptr)->min_visits) != 1 ) { + ERROR("Invalid value for --felix-min-visits\n"); + return EINVAL; + } + break; + + case 5 : + if ( sscanf(arg, "%lf", &(*opts_ptr)->min_completeness) != 1 ) { + ERROR("Invalid value for --felix-min-completeness\n"); + return EINVAL; + } + break; + + case 6 : + if ( sscanf(arg, "%lf", &(*opts_ptr)->max_uniqueness) != 1 ) { + ERROR("Invalid value for --felix-max-uniqueness\n"); + return EINVAL; + } + break; + + case 7 : + if ( sscanf(arg, "%d", &(*opts_ptr)->n_voxels) != 1 ) { + ERROR("Invalid value for --felix-num-voxels\n"); + return EINVAL; + } + break; + + case 8 : + if ( sscanf(arg, "%lf", &(*opts_ptr)->fraction_max_visits) != 1 ) { + ERROR("Invalid value for --felix-fraction-max-visits\n"); + return EINVAL; + } + break; + + case 9 : + if ( sscanf(arg, "%lf", &(*opts_ptr)->sigma) != 1 ) { + ERROR("Invalid value for --felix-sigma\n"); + return EINVAL; + } + break; + + case 10 : + if ( sscanf(arg, "%lf", &(*opts_ptr)->domega) != 1 ) { + ERROR("Invalid value for --felix-domega\n"); + return EINVAL; + } + break; + + case 11 : + if ( sscanf(arg, "%lf", &(*opts_ptr)->max_internal_angle) != 1 ) { + ERROR("Invalid value for --felix-max-internal-angle\n"); + return EINVAL; + } + break; + + default : + return ARGP_ERR_UNKNOWN; + + } + + return 0; +} + + +static struct argp_option options[] = { + + {"help-felix", 1, NULL, OPTION_NO_USAGE, + "Show options for Felix indexing algorithm", 99}, + {"felix-tthrange-min", 2, "2theta", OPTION_HIDDEN, NULL}, + {"felix-tthrange-max", 3, "2theta", OPTION_HIDDEN, NULL}, + {"felix-min-visits", 4, "n", OPTION_HIDDEN, NULL}, + {"felix-min-completeness", 5, "frac", OPTION_HIDDEN, NULL}, + {"felix-max-uniqueness", 6, "n", OPTION_HIDDEN, NULL}, + {"felix-num-voxels", 7, "n", OPTION_HIDDEN, NULL}, + {"felix-fraction-max-visits", 8, "n", OPTION_HIDDEN, NULL}, + {"felix-sigma", 9, "n", OPTION_HIDDEN, NULL}, + {"felix-domega", 10, "n", OPTION_HIDDEN, NULL}, + {"felix-max-internal-angle", 11, "ang", OPTION_HIDDEN, NULL}, + + {0} +}; + + +struct argp felix_argp = { options, parse_arg, NULL, NULL, NULL, NULL, NULL }; diff --git a/libcrystfel/src/felix.h b/libcrystfel/src/felix.h index 645adaeb..8cec9754 100644 --- a/libcrystfel/src/felix.h +++ b/libcrystfel/src/felix.h @@ -34,6 +34,8 @@ #include <config.h> #endif +#include <argp.h> + #include "cell.h" /** @@ -41,19 +43,8 @@ * Felix indexer interface */ -struct felix_options -{ - double ttmin; /* radians */ - double ttmax; /* radians */ - int min_visits; - double min_completeness; - double max_uniqueness; - int n_voxels; - double fraction_max_visits; - double sigma; - double domega; - double max_internal_angle; -}; +typedef struct felix_options FelixOptions; +extern struct argp felix_argp; extern void *felix_prepare(IndexingMethod *indm, UnitCell *cell, struct felix_options *opts); diff --git a/libcrystfel/src/taketwo.c b/libcrystfel/src/taketwo.c index ddbfe173..893791e4 100644 --- a/libcrystfel/src/taketwo.c +++ b/libcrystfel/src/taketwo.c @@ -100,6 +100,14 @@ #include "peaks.h" #include "symmetry.h" +struct taketwo_options +{ + int member_thresh; + double len_tol; + double angle_tol; + double trace_tol; +}; + /** * \param obsvec an observed vector between two spots * \param matches array of matching theoretical vectors from unit cell @@ -2241,6 +2249,7 @@ void *taketwo_prepare(IndexingMethod *indm, UnitCell *cell) return tp; } + void taketwo_cleanup(IndexingPrivate *pp) { struct taketwo_private *tp = (struct taketwo_private *)pp; @@ -2257,3 +2266,98 @@ const char *taketwo_probe(UnitCell *cell) if ( cell_has_parameters(cell) ) return "taketwo"; return NULL; } + + +static void show_help() +{ + printf("Parameters for the TakeTwo indexing algorithm:\n" +" --taketwo-member-threshold\n" +" Minimum number of members in network\n" +" --taketwo-len-tolerance\n" +" Reciprocal space length tolerance (1/A)\n" +" --taketwo-angle-tolerance\n" +" Reciprocal space angle tolerance (in degrees)\n" +" --taketwo-trace-tolerance\n" +" Rotation matrix equivalence tolerance (in degrees)\n" +); +} + + +static error_t parse_arg(int key, char *arg, struct argp_state *state) +{ + struct taketwo_options **opts_ptr = state->input; + float tmp; + + switch ( key ) { + + case ARGP_KEY_INIT : + *opts_ptr = malloc(sizeof(struct taketwo_options)); + if ( *opts_ptr == NULL ) return ENOMEM; + (*opts_ptr)->member_thresh = -1.0; + (*opts_ptr)->len_tol = -1.0; + (*opts_ptr)->angle_tol = -1.0; + (*opts_ptr)->trace_tol = -1.0; + break; + + case 1 : + show_help(); + return EINVAL; + + case 2 : + if ( sscanf(arg, "%i", &(*opts_ptr)->member_thresh) != 1 ) + { + ERROR("Invalid value for --taketwo-member-threshold\n"); + return EINVAL; + } + break; + + case 3 : + if ( sscanf(arg, "%f", &tmp) != 1 ) + { + ERROR("Invalid value for --taketwo-len-tol\n"); + return EINVAL; + } + (*opts_ptr)->len_tol = tmp * 1e10; /* Convert to m^-1 */ + break; + + case 4 : + if ( sscanf(arg, "%f", &tmp) != 1 ) + { + ERROR("Invalid value for --taketwo-angle-tol\n"); + return EINVAL; + } + (*opts_ptr)->angle_tol = deg2rad(tmp); + break; + + case 5 : + if ( sscanf(arg, "%f", &tmp) != 1 ) + { + ERROR("Invalid value for --taketwo-trace-tol\n"); + return EINVAL; + } + (*opts_ptr)->trace_tol = deg2rad(tmp); + break; + + default : + return ARGP_ERR_UNKNOWN; + + } + + return 0; +} + + +static struct argp_option options[] = { + + {"help-taketwo", 1, NULL, OPTION_NO_USAGE, + "Show options for TakeTwo indexing algorithm", 99}, + + {"taketwo-member-threshold", 2, "n", OPTION_HIDDEN, NULL}, + {"taketwo-len-tolerance", 3, "one_over_A", OPTION_HIDDEN, NULL}, + {"taketwo-angle-tolerance", 4, "deg", OPTION_HIDDEN, NULL}, + {"taketwo-trace-tolerance", 5, "deg", OPTION_HIDDEN, NULL}, + {0} +}; + + +struct argp taketwo_argp = { options, parse_arg, NULL, NULL, NULL, NULL, NULL }; diff --git a/libcrystfel/src/taketwo.h b/libcrystfel/src/taketwo.h index 6960446d..c489228f 100644 --- a/libcrystfel/src/taketwo.h +++ b/libcrystfel/src/taketwo.h @@ -31,19 +31,15 @@ #ifndef TAKETWO_H #define TAKETWO_H +#include <argp.h> + #include "cell.h" #include "index.h" /** \file taketwo.h */ -struct taketwo_options -{ - int member_thresh; - double len_tol; - double angle_tol; - double trace_tol; -}; - +typedef struct taketwo_options TakeTwoOptions; +extern struct argp taketwo_argp; extern void *taketwo_prepare(IndexingMethod *indm, UnitCell *cell); extern const char *taketwo_probe(UnitCell *cell); diff --git a/libcrystfel/src/utils.c b/libcrystfel/src/utils.c index a2ba2c60..ba6f44c3 100644 --- a/libcrystfel/src/utils.c +++ b/libcrystfel/src/utils.c @@ -469,6 +469,8 @@ char *check_prefix(char *prefix) char *new; size_t len; + if ( prefix[0] == '\0' ) return prefix; + /* Is "prefix" a directory? */ r = stat(prefix, &statbuf); if ( r != 0 ) { diff --git a/libcrystfel/src/xgandalf.c b/libcrystfel/src/xgandalf.c index 6a8ba4d5..2b5bd512 100644 --- a/libcrystfel/src/xgandalf.c +++ b/libcrystfel/src/xgandalf.c @@ -28,19 +28,32 @@ #include "xgandalf.h" -#ifdef HAVE_XGANDALF #include <stdlib.h> #include "utils.h" #include "cell-utils.h" #include "peaks.h" +#ifdef HAVE_XGANDALF #include "xgandalf/adaptions/crystfel/Lattice.h" #include "xgandalf/adaptions/crystfel/ExperimentSettings.h" #include "xgandalf/adaptions/crystfel/IndexerPlain.h" +#endif /** \file xgandalf.h */ +struct xgandalf_options { + unsigned int sampling_pitch; + unsigned int grad_desc_iterations; + float tolerance; + unsigned int no_deviation_from_provided_cell; + float minLatticeVectorLength_A; + float maxLatticeVectorLength_A; + int maxPeaksForIndexing; +}; + +#ifdef HAVE_XGANDALF + struct xgandalf_private_data { IndexerPlain *indexer; reciprocalPeaks_1_per_A_t reciprocalPeaks_1_per_A; @@ -332,3 +345,147 @@ const char *xgandalf_probe(UnitCell *cell) } #endif // HAVE_XGANDALF + +static void show_help() +{ + printf("Parameters for the TakeTwo indexing algorithm:\n" +" --xgandalf-sampling-pitch\n" +" Sampling pitch: 0 (loosest) to 4 (most dense)\n" +" or with secondary Miller indices: 5 (loosest) to\n" +" 7 (most dense). Default: 6\n" +" --xgandalf-grad-desc-iterations\n" +" Gradient descent iterations: 0 (few) to 5 (many)\n" +" Default: 4\n" +" --xgandalf-fast-execution Shortcut to set\n" +" --xgandalf-sampling-pitch=2\n" +" --xgandalf-grad-desc-iterations=3\n" +" --xgandalf-tolerance Relative tolerance of the lattice vectors.\n" +" Default is 0.02\n" +" --xgandalf-no-deviation-from-provided-cell\n" +" Force the fitted cell to have the same lattice\n" +" parameters as the provided one\n" +" --xgandalf-min-lattice-vector-length\n" +" Minimum possible lattice vector length in A.\n" +" Default: 30 A\n" +" --xgandalf-max-lattice-vector-length\n" +" Maximum possible lattice vector length in A.\n" +" Default: 250 A\n" +" --xgandalf-max-peaks\n" +" Maximum number of peaks used for indexing.\n" +" All peaks are used for refinement.\n" +" Default: 250\n" +); +} + + +static error_t parse_arg(int key, char *arg, struct argp_state *state) +{ + struct xgandalf_options **opts_ptr = state->input; + + switch ( key ) { + + case ARGP_KEY_INIT : + *opts_ptr = malloc(sizeof(struct xgandalf_options)); + if ( *opts_ptr == NULL ) return ENOMEM; + (*opts_ptr)->sampling_pitch = 6; + (*opts_ptr)->grad_desc_iterations = 4; + (*opts_ptr)->tolerance = 0.02; + (*opts_ptr)->no_deviation_from_provided_cell = 0; + (*opts_ptr)->minLatticeVectorLength_A = 30; + (*opts_ptr)->maxLatticeVectorLength_A = 250; + (*opts_ptr)->maxPeaksForIndexing = 250; + break; + + case 1 : + show_help(); + return EINVAL; + + case 2 : + if (sscanf(arg, "%u", &(*opts_ptr)->sampling_pitch) != 1) { + ERROR("Invalid value for --xgandalf-sampling-pitch\n"); + return EINVAL; + } + break; + + case 3 : + if (sscanf(arg, "%u", &(*opts_ptr)->grad_desc_iterations) != 1) { + ERROR("Invalid value for --xgandalf-grad-desc-iterations\n"); + return EINVAL; + } + break; + + case 4 : + if (sscanf(arg, "%f", &(*opts_ptr)->tolerance) != 1) { + ERROR("Invalid value for --xgandalf-tolerance\n"); + return EINVAL; + } + break; + + case 5 : + (*opts_ptr)->no_deviation_from_provided_cell = 1; + break; + + case 6 : + if (sscanf(arg, "%f", &(*opts_ptr)->minLatticeVectorLength_A) != 1) { + ERROR("Invalid value for --xgandalf-min-lattice-vector-length\n"); + return EINVAL; + } + break; + + case 7 : + if (sscanf(arg, "%f", &(*opts_ptr)->maxLatticeVectorLength_A) != 1) { + ERROR("Invalid value for --xgandalf-max-lattice-vector-length\n"); + return EINVAL; + } + break; + + case 8 : + (*opts_ptr)->sampling_pitch = 2; + (*opts_ptr)->grad_desc_iterations = 3; + break; + + case 9 : + if (sscanf(arg, "%i", &(*opts_ptr)->maxPeaksForIndexing) != 1) { + ERROR("Invalid value for --xgandalf-max-peaks\n"); + return EINVAL; + } + break; + + } + + return 0; +} + + +static struct argp_option options[] = { + + {"help-xgandalf", 1, NULL, OPTION_NO_USAGE, + "Show options for XGANDALF indexing algorithm", 99}, + + {"xgandalf-sampling-pitch", 2, "pitch", OPTION_HIDDEN, NULL}, + {"xgandalf-sps", 2, "pitch", OPTION_HIDDEN, NULL}, + + {"xgandalf-grad-desc-iterations", 3, "n", OPTION_HIDDEN, NULL}, + {"xgandalf-gdis", 3, "n", OPTION_HIDDEN, NULL}, + + {"xgandalf-tolerance", 4, "t", OPTION_HIDDEN, NULL}, + {"xgandalf-tol", 4, "t", OPTION_HIDDEN, NULL}, + + {"xgandalf-no-deviation-from-provided-cell", 5, NULL, OPTION_HIDDEN, NULL}, + {"xgandalf-ndfpc", 5, NULL, OPTION_HIDDEN, NULL}, + + {"xgandalf-min-lattice-vector-length", 6, "len", OPTION_HIDDEN, NULL}, + {"xgandalf-min-lvl", 6, "len", OPTION_HIDDEN, NULL}, + + {"xgandalf-max-lattice-vector-length", 7, "len", OPTION_HIDDEN, NULL}, + {"xgandalf-max-lvl", 7, "len", OPTION_HIDDEN, NULL}, + + {"xgandalf-fast-execution", 8, NULL, OPTION_HIDDEN, NULL}, + + {"xgandalf-max-peaks", 9, "n", OPTION_HIDDEN, NULL}, + + {0} +}; + + +struct argp xgandalf_argp = { options, parse_arg, NULL, NULL, NULL, NULL, NULL }; diff --git a/libcrystfel/src/xgandalf.h b/libcrystfel/src/xgandalf.h index 23c5c1b0..7cc85388 100644 --- a/libcrystfel/src/xgandalf.h +++ b/libcrystfel/src/xgandalf.h @@ -34,21 +34,15 @@ #endif #include <stddef.h> +#include <argp.h> /** * \file xgandalf.h * XGANDALF indexer interface */ -struct xgandalf_options { - unsigned int sampling_pitch; - unsigned int grad_desc_iterations; - float tolerance; - unsigned int no_deviation_from_provided_cell; - float minLatticeVectorLength_A; - float maxLatticeVectorLength_A; - int maxPeaksForIndexing; -}; +typedef struct xgandalf_options XGandalfOptions; +extern struct argp xgandalf_argp; #include "index.h" diff --git a/src/indexamajig.c b/src/indexamajig.c index b50858ab..fdf32b22 100644 --- a/src/indexamajig.c +++ b/src/indexamajig.c @@ -3,13 +3,13 @@ * * Index patterns, output hkl+intensity etc. * - * Copyright © 2012-2018 Deutsches Elektronen-Synchrotron DESY, + * Copyright © 2012-2019 Deutsches Elektronen-Synchrotron DESY, * a research centre of the Helmholtz Association. * Copyright © 2012 Richard Kirian * Copyright © 2012 Lorenzo Galli * * Authors: - * 2010-2017 Thomas White <taw@physics.org> + * 2010-2019 Thomas White <taw@physics.org> * 2011 Richard Kirian * 2012 Lorenzo Galli * 2012 Chunhong Yoon @@ -43,7 +43,7 @@ #include <stdio.h> #include <string.h> #include <unistd.h> -#include <getopt.h> +#include <argp.h> #include <hdf5.h> #include <gsl/gsl_errno.h> #include <sys/types.h> @@ -67,168 +67,6 @@ #include "image.h" -static void show_help(const char *s) -{ - printf("Syntax: %s [options]\n\n", s); - printf( -"Index and integrate snapshot diffraction images.\n\n" -" -h, --help Display this help message\n" -" --version Print CrystFEL version number and exit\n" -"\nBasic options:\n\n" -" -i, --input=<filename> List of images to process.\n" -" -o, --output=<filename> Output stream filename\n" -" -g --geometry=<file> Detector geometry filename\n" -" --basename Remove the directory parts of the filenames\n" -" -x, --prefix=<p> Prefix filenames from input file with <p>\n" -" --no-check-prefix Don't attempt to correct the --prefix\n" -" -j <n> Run <n> analyses in parallel Default 1\n" -" --highres=<n> Absolute resolution cutoff in Angstroms\n" -" --profile Show timing data for performance monitoring\n" -" --temp-dir=<path> Put the temporary folder under <path>\n" -" --wait-for-file=<n> Time to wait for each file before processing\n" -" --zmq-msgpack Receive data in MessagePack format over ZMQ\n" -" --no-image-data Do not load image data (from ZMQ)\n" -"\nPeak search options:\n\n" -" --peaks=<method> Peak search method. Default: zaef\n" -" (zaef,peakfinder8,peakfinder9,hdf5,cxi,msgpack)\n" -" --peak-radius=<r> Integration radii for peak search\n" -" --min-peaks=<n> Minimum number of peaks for indexing\n" -" --hdf5-peaks=<p> Find peaks table in HDF5 file here\n" -" Default: /processing/hitfinder/peakinfo\n" -" --median-filter=<n> Apply a median filter to the image data\n" -" Default: 0 (no filter)\n" -" --filter-noise Apply noise filter to image data\n" -" --threshold=<n> Threshold for peak detection\n" -" (zaef,peakfinder8 only) Default: 800\n" -" --min-squared-gradient=<n>\n" -" Minimum squared gradient\n" -" (zaef only) Default: 100,000\n" -" --min-snr=<n> Minimum signal/noise ratio for peaks\n" -" (zaef,peakfinder8, peakfinder9 only) Default: 5\n" -" --min-pix-count=<n> Minimum number of pixels per peak\n" -" (peakfinder8 only) Default: 2\n" -" --max-pix-count=<n> Maximum number of pixels per peak\n" -" (peakfinder8 only) Default: 200\n" -" --local-bg-radius=<n> Radius (pixels) for local background estimation\n" -" (peakfinder8, peakfinder9 only) Default: 3\n" -" --min-res=<n> Minimum resolution for peak search (in pixels)\n" -" (peakfinder8 only) Default: 0\n" -" --max-res=<n> Maximum resolution for peak search (in pixels)\n" -" (peakfinder8 only) Default: 1200\n" -" --min-snr-biggest-pix=<n>\n" -" Minimum snr of the biggest pixel in the peak\n" -" (peakfinder9 only)\n" -" --min-snr-peak-pix=<n>\n" -" Minimum snr of a peak pixel (peakfinder9 only)\n" -" --min-sig=<n> Minimum standard deviation of the background\n" -" (peakfinder9 only)\n" -" --min-peak-over-neighbour=<n>\n" -" Just for speed. Biggest pixel in peak must be n\n" -" higher than this (peakfinder9 only).\n" -" --no-use-saturated Reject saturated peaks\n" -" --no-revalidate Don't re-integrate and check HDF5 peaks\n" -" --no-half-pixel-shift\n" -" Don't offset the HDF5 peak locations by 0.5 px\n" -" --check-hdf5-snr Check SNR for peaks from hdf5 or cxi (see --min-snr)\n" -"\nIndexing options:\n\n" -" --indexing=<methods> Indexing method list, comma separated\n" -" -p, --pdb=<file> Unit cell file (PDB or CrystFEL unit cell format)\n" -" Default: 'molecule.pdb'\n" -" --tolerance=<tol> Tolerances for cell comparison\n" -" Default: 5,5,5,1.5,1.5,1.5\n" -" --no-check-cell Don't check lattice parameters against input cell\n" -" --multi Repeat indexing to index multiple hits\n" -" --no-retry Don't repeat indexing to increase indexing rate\n" -" --no-refine Skip the prediction refinement step\n" -" --no-check-peaks Don't check that most of the peaks can be accounted\n" -" for by the indexing solution\n" -"\n" -" --taketwo-member-threshold\n" -" Minimum number of members in network\n" -" --taketwo-len-tolerance\n" -" Reciprocal space length tolerance (1/A)\n" -" --taketwo-angle-tolerance\n" -" Reciprocal space angle tolerance (in degrees)\n" -" --taketwo-trace-tolerance\n" -" Rotation matrix equivalence tolerance (in degrees)\n" -"\n" -" --felix-domega Degree range of omega (moscaicity) to consider.\n" -" Default: 2\n" -" --felix-fraction-max-visits\n" -" Cutoff for minimum fraction of the max visits.\n" -" Default: 0.75\n" -" --felix-max-internal-angle\n" -" Cutoff for maximum internal angle between observed\n" -" spots and predicted spots. Default: 0.25\n" -" --felix-max-uniqueness\n" -" Cutoff for maximum fraction of found spots which\n" -" can belong to other crystallites. Default: 0.5\n" -" --felix-min-completeness\n" -" Cutoff for minimum fraction of projected spots\n" -" found in the pattern. Default: 0.001\n" -" --felix-min-visits\n" -" Cutoff for minimum number of voxel visits.\n" -" Default: 15\n" -" --felix-num-voxels Number of voxels for Rodrigues space search\n" -" Default: 100\n" -" --felix-sigma The sigma of the 2theta, eta and omega angles.\n" -" Default: 0.2\n" -" --felix-tthrange-max Maximum 2theta to consider for indexing (degrees)\n" -" Default: 30\n" -" --felix-tthrange-min Minimum 2theta to consider for indexing (degrees)\n" -" Default: 0\n" -"\n" -" --xgandalf-sampling-pitch\n" -" Sampling pitch: 0 (loosest) to 4 (most dense)\n" -" or with secondary Miller indices: 5 (loosest) to\n" -" 7 (most dense). Default: 6\n" -" --xgandalf-grad-desc-iterations\n" -" Gradient descent iterations: 0 (few) to 5 (many)\n" -" Default: 4\n" -" --xgandalf-fast-execution Shortcut to set\n" -" --xgandalf-sampling-pitch=2\n" -" --xgandalf-grad-desc-iterations=3\n" -" --xgandalf-tolerance Relative tolerance of the lattice vectors.\n" -" Default is 0.02\n" -" --xgandalf-no-deviation-from-provided-cell\n" -" Force the fitted cell to have the same lattice\n" -" parameters as the provided one\n" -" --xgandalf-min-lattice-vector-length\n" -" Minimum possible lattice vector length in A.\n" -" Default: 30 A\n" -" --xgandalf-max-lattice-vector-length\n" -" Maximum possible lattice vector length in A.\n" -" Default: 250 A\n" -" --xgandalf-max-peaks\n" -" Maximum number of peaks used for indexing.\n" -" All peaks are used for refinement.\n" -" Default: 250\n" -"\n" -"\nIntegration options:\n\n" -" --integration=<meth> Integration method (rings,prof2d)-(cen,nocen)\n" -" Default: rings-nocen\n" -" --fix-profile-radius Fix the reciprocal space profile radius for spot\n" -" prediction (default: automatically determine\n" -" --fix-bandwidth Set the bandwidth for spot prediction\n" -" --fix-divergence Set the divergence (full angle) for spot prediction\n" -" --int-radius=<r> Set the integration radii. Default: 4,5,7.\n" -" --int-diag=<cond> Show debugging information about reflections\n" -" --push-res=<n> Integrate higher than apparent resolution cutoff\n" -" --overpredict Over-predict reflections (for post-refinement)\n" -"\nOutput options:\n\n" -" --no-non-hits-in-stream\n" -" Do not include non-hit frames in the stream\n" -" (see --min-peaks)\n" -" --copy-hdf5-field=<f> Copy the value of HDF5 field <f> into the stream\n" -" --no-peaks-in-stream Do not record peak search results in the stream\n" -" --no-refls-in-stream Do not record integrated reflections in the stream\n" -" --serial-start Start the serial numbers in the stream here\n" -"\nHistorical options:\n\n" -" --no-sat-corr Don't correct values of saturated peaks\n" -); -} - - static void add_geom_beam_stuff_to_field_list(struct imagefile_field_list *copyme, struct detector *det, struct beam_params *beam) @@ -250,946 +88,850 @@ static void add_geom_beam_stuff_to_field_list(struct imagefile_field_list *copym } -int main(int argc, char *argv[]) +struct indexamajig_arguments { - int c; - char *filename = NULL; - char *outfile = NULL; - FILE *fh; - Stream *st; - int config_checkprefix = 1; - int config_basename = 0; - int integrate_saturated = 0; - char *indm_str = NULL; - char *cellfile = NULL; - char *prefix = NULL; - char *speaks = NULL; - char *toler = NULL; - int n_proc = 1; - struct index_args iargs; - char *intrad = NULL; - char *pkrad = NULL; - char *int_str = NULL; - char *temp_location = NULL; /* e.g. /tmp */ - char *tmpdir; /* e.g. /tmp/indexamajig.12345 */ - char *rn; /* e.g. /home/taw/indexing */ + struct index_args iargs; /* These are the options that will be + * given to process_image */ + char *filename; + char *geom_filename; + char *outfile; + char *prefix; + int check_prefix; + int n_proc; + char *cellfile; + char *spectrum_fn; + char *indm_str; + int basename; + int zmq; + int no_image_data; + int serial_start; + char *temp_location; + char *command_line_peak_path; + int if_refine; + int if_checkcell; + int if_peaks; + int if_multi; + int if_retry; + + TakeTwoOptions **taketwo_opts_ptr; + FelixOptions **felix_opts_ptr; + XGandalfOptions **xgandalf_opts_ptr; +}; + + +static void show_version(FILE *fh, struct argp_state *state) +{ + printf("CrystFEL: " CRYSTFEL_VERSIONSTRING "\n"); + printf(CRYSTFEL_BOILERPLATE"\n"); +} + + +static error_t parse_arg(int key, char *arg, struct argp_state *state) +{ + float tmp; int r; - char *int_diag = NULL; - char *geom_filename = NULL; - struct beam_params beam; - int have_push_res = 0; - char *command_line_peak_path = NULL; - int if_refine = 1; - int if_nocomb_unused = 0; - int if_nocheck = 0; - int if_peaks = 1; - int if_multi = 0; - int if_retry = 1; - int serial_start = 1; - char *spectrum_fn = NULL; - int zmq = 0; - char *zmq_address = NULL; + struct indexamajig_arguments *args = state->input; - /* Defaults */ - iargs.cell = NULL; - iargs.noisefilter = 0; - iargs.median_filter = 0; - iargs.satcorr = 1; - iargs.tols[0] = 0.05; - iargs.tols[1] = 0.05; - iargs.tols[2] = 0.05; - iargs.tols[3] = 1.5; - iargs.tols[4] = 1.5; - iargs.tols[5] = 1.5; - iargs.threshold = 800.0; - iargs.min_sq_gradient = 100000.0; - iargs.min_snr = 5.0; - iargs.min_pix_count = 2; - iargs.max_pix_count = 200; - iargs.min_res = 0; - iargs.max_res = 1200; - iargs.local_bg_radius = 3; - iargs.min_snr_biggest_pix = 7.0; /* peak finder 9 */ - iargs.min_snr_peak_pix = 6.0; - iargs.min_sig = 11.0; - iargs.min_peak_over_neighbour = -INFINITY; - iargs.check_hdf5_snr = 0; - iargs.det = NULL; - iargs.peaks = PEAK_ZAEF; - iargs.beam = &beam; - iargs.hdf5_peak_path = NULL; - iargs.half_pixel_shift = 1; - iargs.copyme = NULL; - iargs.pk_inn = -1.0; - iargs.pk_mid = -1.0; - iargs.pk_out = -1.0; - iargs.ir_inn = 4.0; - iargs.ir_mid = 5.0; - iargs.ir_out = 7.0; - iargs.use_saturated = 1; - iargs.no_revalidate = 0; - iargs.stream_peaks = 1; - iargs.stream_refls = 1; - iargs.stream_nonhits = 1; - iargs.int_diag = INTDIAG_NONE; - iargs.copyme = new_imagefile_field_list(); - iargs.min_peaks = 0; - iargs.overpredict = 0; - iargs.wait_for_file = 0; - if ( iargs.copyme == NULL ) { - ERROR("Couldn't allocate HDF5 field list.\n"); - return 1; - } - iargs.ipriv = NULL; /* No default */ - iargs.int_meth = integration_method("rings-nocen-nosat-nograd", NULL); - iargs.push_res = 0.0; - iargs.highres = +INFINITY; - iargs.fix_profile_r = -1.0; - iargs.fix_bandwidth = -1.0; - iargs.fix_divergence = -1.0; - iargs.profile = 0; - iargs.no_image_data = 0; - iargs.taketwo_opts.member_thresh = -1; - iargs.taketwo_opts.len_tol = -1.0; - iargs.taketwo_opts.angle_tol = -1.0; - iargs.taketwo_opts.trace_tol = -1.0; - iargs.xgandalf_opts.sampling_pitch = 6; - iargs.xgandalf_opts.grad_desc_iterations = 4; - iargs.xgandalf_opts.tolerance = 0.02; - iargs.xgandalf_opts.no_deviation_from_provided_cell = 0; - iargs.xgandalf_opts.minLatticeVectorLength_A = 30; - iargs.xgandalf_opts.maxLatticeVectorLength_A = 250; - iargs.xgandalf_opts.maxPeaksForIndexing = 250; - iargs.felix_opts.ttmin = -1.0; - iargs.felix_opts.ttmax = -1.0; - iargs.felix_opts.min_visits = 0; - iargs.felix_opts.min_completeness = -1.0; - iargs.felix_opts.max_uniqueness = -1.0; - iargs.felix_opts.n_voxels = 0; - iargs.felix_opts.fraction_max_visits = -1.0; - iargs.felix_opts.sigma = -1.0; - iargs.felix_opts.domega = -1.0; - iargs.felix_opts.max_internal_angle = -1.0; - - /* Long options */ - const struct option longopts[] = { - - /* Options with long and short versions */ - {"help", 0, NULL, 'h'}, - {"version", 0, NULL, 'v'}, - {"input", 1, NULL, 'i'}, - {"output", 1, NULL, 'o'}, - {"indexing", 1, NULL, 'z'}, - {"geometry", 1, NULL, 'g'}, - {"pdb", 1, NULL, 'p'}, - {"prefix", 1, NULL, 'x'}, - {"threshold", 1, NULL, 't'}, - {"beam", 1, NULL, 'b'}, - - /* Long-only options with no arguments */ - {"filter-noise", 0, &iargs.noisefilter, 1}, - {"no-check-prefix", 0, &config_checkprefix, 0}, - {"basename", 0, &config_basename, 1}, - {"no-peaks-in-stream", 0, &iargs.stream_peaks, 0}, - {"no-refls-in-stream", 0, &iargs.stream_refls, 0}, - {"no-non-hits-in-stream", 0, &iargs.stream_nonhits, 0}, - {"integrate-saturated",0, &integrate_saturated, 1}, - {"no-use-saturated", 0, &iargs.use_saturated, 0}, - {"no-revalidate", 0, &iargs.no_revalidate, 1}, - {"check-hdf5-snr", 0, &iargs.check_hdf5_snr, 1}, - {"profile", 0, &iargs.profile, 1}, - {"no-half-pixel-shift",0, &iargs.half_pixel_shift, 0}, - {"no-refine", 0, &if_refine, 0}, - {"no-cell-combinations",0,&if_nocomb_unused, 1}, - {"no-check-cell", 0, &if_nocheck, 1}, - {"no-cell-check", 0, &if_nocheck, 1}, - {"check-peaks", 0, &if_peaks, 1}, - {"no-check-peaks", 0, &if_peaks, 0}, - {"no-retry", 0, &if_retry, 0}, - {"retry", 0, &if_retry, 1}, - {"no-multi", 0, &if_multi, 0}, - {"multi", 0, &if_multi, 1}, - {"overpredict", 0, &iargs.overpredict, 1}, - {"zmq-msgpack", 0, &zmq, 1}, - {"no-image-data", 0, &iargs.no_image_data, 1}, - - /* Long-only options which don't actually do anything */ - {"no-sat-corr", 0, &iargs.satcorr, 0}, - {"sat-corr", 0, &iargs.satcorr, 1}, - {"no-check-hdf5-snr", 0, &iargs.check_hdf5_snr, 0}, - {"use-saturated", 0, &iargs.use_saturated, 1}, - - /* Long-only options with arguments */ - {"peaks", 1, NULL, 302}, - {"cell-reduction", 1, NULL, 303}, - {"min-gradient", 1, NULL, 304}, - {"record", 1, NULL, 305}, - {"cpus", 1, NULL, 306}, - {"cpugroup", 1, NULL, 307}, - {"cpuoffset", 1, NULL, 308}, - {"hdf5-peaks", 1, NULL, 309}, - {"copy-hdf5-field", 1, NULL, 310}, - {"min-snr", 1, NULL, 311}, - {"tolerance", 1, NULL, 313}, - {"int-radius", 1, NULL, 314}, - {"median-filter", 1, NULL, 315}, - {"integration", 1, NULL, 316}, - {"temp-dir", 1, NULL, 317}, - {"int-diag", 1, NULL, 318}, - {"push-res", 1, NULL, 319}, - {"res-push", 1, NULL, 319}, /* compat */ - {"peak-radius", 1, NULL, 320}, - {"highres", 1, NULL, 321}, - {"fix-profile-radius", 1, NULL, 322}, - {"fix-bandwidth", 1, NULL, 323}, - {"fix-divergence", 1, NULL, 324}, - {"felix-options", 1, NULL, 325}, - {"min-pix-count", 1, NULL, 326}, - {"max-pix-count", 1, NULL, 327}, - {"local-bg-radius", 1, NULL, 328}, - {"min-res", 1, NULL, 329}, - {"max-res", 1, NULL, 330}, - {"min-peaks", 1, NULL, 331}, - {"taketwo-member-threshold", 1, NULL, 332}, - {"taketwo-member-thresh", 1, NULL, 332}, /* compat */ - {"taketwo-len-tolerance", 1, NULL, 333}, - {"taketwo-len-tol", 1, NULL, 333}, /* compat */ - {"taketwo-angle-tolerance", 1, NULL, 334}, - {"taketwo-angle-tol", 1, NULL, 334}, /* compat */ - {"taketwo-trace-tolerance", 1, NULL, 335}, - {"taketwo-trace-tol", 1, NULL, 335}, /* compat */ - {"felix-tthrange-min", 1, NULL, 336}, - {"felix-tthrange-max", 1, NULL, 337}, - {"felix-min-visits", 1, NULL, 338}, - {"felix-min-completeness", 1, NULL, 339}, - {"felix-max-uniqueness", 1, NULL, 340}, - {"felix-num-voxels", 1, NULL, 341}, - {"felix-fraction-max-visits",1, NULL, 342}, - {"felix-sigma", 1, NULL, 343}, - {"serial-start", 1, NULL, 344}, - {"felix-domega", 1, NULL, 345}, - {"felix-max-internal-angle", 1, NULL, 346}, - {"min-snr-biggest-pix", 1, NULL, 347}, - {"min-snr-peak-pix", 1, NULL, 348}, - {"min-sig", 1, NULL, 349}, - {"min-peak-over-neighbour", 1, NULL, 350}, - {"xgandalf-sampling-pitch", 1, NULL, 351}, - {"xgandalf-sps", 1, NULL, 351}, - {"xgandalf-grad-desc-iterations", 1, NULL, 352}, - {"xgandalf-gdis", 1, NULL, 352}, - {"xgandalf-tolerance", 1, NULL, 353}, - {"xgandalf-tol", 1, NULL, 353}, - {"xgandalf-no-deviation-from-provided-cell", 0, NULL, 354}, - {"xgandalf-ndfpc", 0, NULL, 354}, - {"xgandalf-min-lattice-vector-length", 1, NULL, 355}, - {"xgandalf-min-lvl", 1, NULL, 355}, - {"xgandalf-max-lattice-vector-length", 1, NULL, 356}, - {"xgandalf-max-lvl", 1, NULL, 356}, - {"spectrum-file", 1, NULL, 357}, - {"wait-for-file", 1, NULL, 358}, - {"min-squared-gradient",1,NULL, 359}, - {"min-sq-gradient", 1, NULL, 359}, /* compat */ - {"xgandalf-fast-execution", 0, NULL, 360}, - {"xgandalf-max-peaks", 1, NULL, 361}, - - {0, 0, NULL, 0} - }; + switch ( key ) { - /* Short options */ - while ((c = getopt_long(argc, argv, "hi:o:z:p:x:j:g:t:vb:", - longopts, NULL)) != -1) - { - switch (c) { - - case 'h' : - show_help(argv[0]); - return 0; - - case 'v' : - printf("CrystFEL: " CRYSTFEL_VERSIONSTRING "\n"); - printf(CRYSTFEL_BOILERPLATE"\n"); - return 0; - - case 'b' : - ERROR("WARNING: This version of CrystFEL no longer " - "uses beam files. Please remove the beam file " - "from your indexamajig command line.\n"); - return 1; + case ARGP_KEY_INIT : + state->child_inputs[0] = args->taketwo_opts_ptr; + state->child_inputs[1] = args->felix_opts_ptr; + state->child_inputs[2] = args->xgandalf_opts_ptr; + break; - case 'i' : - filename = strdup(optarg); - break; - - case 'o' : - outfile = strdup(optarg); - break; - - case 'z' : - indm_str = strdup(optarg); - break; - - case 'p' : - cellfile = strdup(optarg); - break; - - case 'x' : - prefix = strdup(optarg); - break; - - case 'j' : - n_proc = atoi(optarg); - break; - - case 'g' : - geom_filename = optarg; - break; - - case 't' : - iargs.threshold = strtof(optarg, NULL); - break; - - case 302 : - speaks = strdup(optarg); - break; - - case 303 : - ERROR("The option '--cell-reduction' is no longer " - "used.\n" - "The complete indexing behaviour is now " - "controlled using '--indexing'.\n" - "See 'man indexamajig' for details of the " - "available methods.\n"); - return 1; + case 'h' : + argp_state_help(state, stdout, ARGP_HELP_STD_HELP); + break; /* argp_state_help doesn't return */ - case 304 : - iargs.min_sq_gradient = strtof(optarg, NULL); - ERROR("Recommend using --min-squared-gradient instead " - "of --min-gradient.\n"); - break; - - case 305 : - ERROR("The option '--record' is no longer used.\n" - "Use '--no-peaks-in-stream' and" - "'--no-refls-in-stream' if you need to control" - "the contents of the stream.\n"); - return 1; + case 'v' : + show_version(stdout, state); + exit(0); - case 306 : - case 307 : - case 308 : - ERROR("The options --cpus, --cpugroup and --cpuoffset" - " are no longer used by indexamajig.\n"); - break; - - case 309 : - free(command_line_peak_path); - command_line_peak_path = strdup(optarg); - break; - - case 310 : - add_imagefile_field(iargs.copyme, optarg); - break; - - case 311 : - iargs.min_snr = strtof(optarg, NULL); - break; - - case 313 : - toler = strdup(optarg); - break; - - case 314 : - intrad = strdup(optarg); - break; - - case 315 : - iargs.median_filter = atoi(optarg); - break; - - case 316 : - int_str = strdup(optarg); - break; - - case 317 : - temp_location = strdup(optarg); - break; - - case 318 : - int_diag = strdup(optarg); - break; - - case 319 : - if ( sscanf(optarg, "%f", &iargs.push_res) != 1 ) { - ERROR("Invalid value for --push-res\n"); - return 1; - } - iargs.push_res *= 1e9; /* nm^-1 -> m^-1 */ - have_push_res = 1; - break; - - case 320 : - pkrad = strdup(optarg); - break; - - case 321 : - if ( sscanf(optarg, "%f", &iargs.highres) != 1 ) { - ERROR("Invalid value for --highres\n"); - return 1; - } - /* A -> m^-1 */ - iargs.highres = 1.0 / (iargs.highres/1e10); - break; - - case 322 : - if ( sscanf(optarg, "%f", &iargs.fix_profile_r) != 1 ) { - ERROR("Invalid value for " - "--fix-profile-radius\n"); - return 1; - } - break; + case 'i' : + args->filename = strdup(arg); + break; - case 323 : - if ( sscanf(optarg, "%f", &iargs.fix_bandwidth) != 1 ) { - ERROR("Invalid value for --fix-bandwidth\n"); - return 1; - } - break; + case 'o' : + args->outfile = strdup(arg); + break; - case 324 : - if ( sscanf(optarg, "%f", &iargs.fix_divergence) != 1 ) { - ERROR("Invalid value for --fix-divergence\n"); - return 1; - } - break; + case 'x' : + args->prefix = strdup(arg); + break; - case 325 : - ERROR("--felix-options is no longer used.\n"); - ERROR("See --help for the new Felix options.\n"); - return 1; + case 'j' : + args->n_proc = atoi(arg); + break; - case 326: - iargs.min_pix_count = atoi(optarg); - break; + case 'g' : + args->geom_filename = arg; + break; - case 327: - iargs.max_pix_count = atoi(optarg); - break; + case 201 : + args->basename = 1; + break; - case 328: - iargs.local_bg_radius = atoi(optarg); - break; + case 202 : + args->check_prefix = 0; + break; - case 329: - iargs.min_res = atoi(optarg); - break; + case 203 : + if ( sscanf(arg, "%f", &tmp) != 1 ) { + ERROR("Invalid value for --highres\n"); + return EINVAL; + } + args->iargs.highres = 1.0 / (tmp/1e10); /* A -> m^-1 */ + break; + + case 204 : + args->iargs.profile = 1; + break; + + case 205 : + args->temp_location = strdup(arg); + break; + + case 206 : + if (sscanf(arg, "%d", &args->iargs.wait_for_file) != 1) + { + ERROR("Invalid value for --wait-for-file\n"); + return EINVAL; + } + break; + + case 207 : + args->zmq = 1; + break; + + case 208 : + args->no_image_data = 1; + break; + + case 209 : + args->spectrum_fn = strdup(arg); + break; + + /* ---------- Peak search ---------- */ + + case 't' : + args->iargs.threshold = strtof(arg, NULL); + break; + + case 301 : + if ( strcmp(arg, "zaef") == 0 ) { + args->iargs.peaks = PEAK_ZAEF; + } else if ( strcmp(arg, "peakfinder8") == 0 ) { + args->iargs.peaks = PEAK_PEAKFINDER8; + } else if ( strcmp(arg, "hdf5") == 0 ) { + args->iargs.peaks = PEAK_HDF5; + } else if ( strcmp(arg, "cxi") == 0 ) { + args->iargs.peaks = PEAK_CXI; + } else if ( strcmp(arg, "peakfinder9") == 0 ) { + args->iargs.peaks = PEAK_PEAKFINDER9; + } else if ( strcmp(arg, "msgpack") == 0 ) { + args->iargs.peaks = PEAK_MSGPACK; + } else if ( strcmp(arg, "none") == 0 ) { + args->iargs.peaks = PEAK_NONE; + } else { + ERROR("Unrecognised peak detection method '%s'\n", arg); + return EINVAL; + } + break; - case 330: - iargs.max_res = atoi(optarg); - break; + case 302 : + r = sscanf(arg, "%f,%f,%f", &args->iargs.pk_inn, + &args->iargs.pk_mid, &args->iargs.pk_out); + if ( (r != 3) || (args->iargs.pk_inn < 0) ) { + ERROR("Invalid parameters for '--peak-radius'\n"); + return EINVAL; + } + break; - case 331: - iargs.min_peaks = atoi(optarg); - break; + case 303 : + if (sscanf(arg, "%d", &args->iargs.min_peaks) != 1) + { + ERROR("Invalid value for --min-peaks\n"); + return EINVAL; + } + break; + + case 304 : + free(args->command_line_peak_path); + args->command_line_peak_path = strdup(arg); + break; + + case 305 : + if (sscanf(arg, "%d", &args->iargs.median_filter) != 1) + { + ERROR("Invalid value for --median-filter\n"); + return EINVAL; + } + break; - case 332: - if ( sscanf(optarg, "%i", &iargs.taketwo_opts.member_thresh) != 1 ) - { - ERROR("Invalid value for --taketwo-member-threshold\n"); - return 1; - } - break; + case 306 : + args->iargs.noisefilter = 1; + break; - case 333: - if ( sscanf(optarg, "%lf", &iargs.taketwo_opts.len_tol) != 1 ) - { - ERROR("Invalid value for --taketwo-len-tolerance\n"); - return 1; - } - /* Convert to m^-1 */ - iargs.taketwo_opts.len_tol *= 1e10; - break; - - case 334: - if ( sscanf(optarg, "%lf", &iargs.taketwo_opts.angle_tol) != 1 ) - { - ERROR("Invalid value for --taketwo-angle-tolerance\n"); - return 1; - } - /* Convert to radians */ - iargs.taketwo_opts.angle_tol = deg2rad(iargs.taketwo_opts.angle_tol); - break; - - case 335: - if ( sscanf(optarg, "%lf", &iargs.taketwo_opts.trace_tol) != 1 ) - { - ERROR("Invalid value for --taketwo-trace-tolerance\n"); - return 1; - } - /* Convert to radians */ - iargs.taketwo_opts.trace_tol = deg2rad(iargs.taketwo_opts.trace_tol); - break; - - case 336: - if ( sscanf(optarg, "%lf", &iargs.felix_opts.ttmin) != 1 ) - { - ERROR("Invalid value for --felix-tthrange-min\n"); - return 1; - } - iargs.felix_opts.ttmin = deg2rad(iargs.felix_opts.ttmin); - break; - - case 337: - if ( sscanf(optarg, "%lf", &iargs.felix_opts.ttmax) != 1 ) - { - ERROR("Invalid value for --felix-tthrange-max\n"); - return 1; - } - iargs.felix_opts.ttmax = deg2rad(iargs.felix_opts.ttmax); - break; - - case 338: - if ( sscanf(optarg, "%i", - &iargs.felix_opts.min_visits) != 1 ) - { - ERROR("Invalid value for --felix-min-visits\n"); - return 1; - } - break; - - case 339: - if ( sscanf(optarg, "%lf", - &iargs.felix_opts.min_completeness) != 1 ) - { - ERROR("Invalid value for --felix-min-completeness\n"); - return 1; - } - break; - - case 340: - if ( sscanf(optarg, "%lf", - &iargs.felix_opts.max_uniqueness) != 1 ) - { - ERROR("Invalid value for --felix-max-uniqueness\n"); - return 1; - } - break; - - case 341: - if ( sscanf(optarg, "%i", - &iargs.felix_opts.n_voxels) != 1 ) - { - ERROR("Invalid value for --felix-num-voxels\n"); - return 1; - } - break; - - case 342: - if ( sscanf(optarg, "%lf", - &iargs.felix_opts.fraction_max_visits) != 1 ) - { - ERROR("Invalid value for --felix-fraction-max-visits\n"); - return 1; - } - break; - - case 343: - if ( sscanf(optarg, "%lf", - &iargs.felix_opts.sigma) != 1 ) - { - ERROR("Invalid value for --felix-sigma\n"); - return 1; - } - break; + case 307 : + if (sscanf(arg, "%f", &args->iargs.min_sq_gradient) != 1) + { + ERROR("Invalid value for --min-squared-gradient\n"); + return EINVAL; + } + break; - case 344: - if ( sscanf(optarg, "%i", &serial_start) != 1 ) - { - ERROR("Invalid value for --serial-start\n"); - return 1; - } - break; + case 308 : + if (sscanf(arg, "%f", &args->iargs.min_snr) != 1) + { + ERROR("Invalid value for --min-snr\n"); + return EINVAL; + } + break; - case 345: - if ( sscanf(optarg, "%lf", &iargs.felix_opts.domega) != 1 ) - { - ERROR("Invalid value for --felix-domega\n"); - return 1; - } - break; + case 309 : + if (sscanf(arg, "%d", &args->iargs.min_pix_count) != 1) + { + ERROR("Invalid value for --min-pix-count\n"); + return EINVAL; + } + break; - case 346: - if ( sscanf(optarg, "%lf", &iargs.felix_opts.max_internal_angle) != 1 ) - { - ERROR("Invalid value for --felix-max-internal-angle\n"); - return 1; - } - break; - - case 347: - iargs.min_snr_biggest_pix = strtof(optarg, NULL); - break; - - case 348: - iargs.min_snr_peak_pix = strtof(optarg, NULL); - break; - - case 349: - iargs.min_sig = strtof(optarg, NULL); - break; - - case 350: - iargs.min_peak_over_neighbour = strtof(optarg, NULL); - break; - - case 351: - if (sscanf(optarg, "%u", - &iargs.xgandalf_opts.sampling_pitch) != 1) - { - ERROR("Invalid value for --xgandalf-sampling-pitch\n"); - return 1; - } - break; - - case 352: - if (sscanf(optarg, "%u", - &iargs.xgandalf_opts.grad_desc_iterations) != 1) - { - ERROR("Invalid value for --xgandalf-grad-desc-iterations\n"); - return 1; - } - break; - - case 353: - if (sscanf(optarg, "%f", - &iargs.xgandalf_opts.tolerance) != 1) - { - ERROR("Invalid value for --xgandalf-tolerance\n"); - return 1; - } - break; - - case 354: - iargs.xgandalf_opts.no_deviation_from_provided_cell = 1; - break; - - case 355: - if (sscanf(optarg, "%f", - &iargs.xgandalf_opts.minLatticeVectorLength_A) != 1) - { - ERROR("Invalid value for " - "--xgandalf-min-lattice-vector-length\n"); - return 1; - } - break; - - case 356: - if (sscanf(optarg, "%f", - &iargs.xgandalf_opts.maxLatticeVectorLength_A) != 1) - { - ERROR("Invalid value for " - "--xgandalf-max-lattice-vector-length\n"); - return 1; - } - break; + case 310 : + if (sscanf(arg, "%d", &args->iargs.max_pix_count) != 1) + { + ERROR("Invalid value for --max-pix-count\n"); + return EINVAL; + } + break; + + case 311 : + if (sscanf(arg, "%d", &args->iargs.local_bg_radius) != 1) + { + ERROR("Invalid value for --local-bg-radius\n"); + return EINVAL; + } + break; - case 357: - spectrum_fn = strdup(optarg); - break; + case 312 : + if (sscanf(arg, "%d", &args->iargs.min_res) != 1) + { + ERROR("Invalid value for --min-res\n"); + return EINVAL; + } + break; - case 358: - if (sscanf(optarg, "%d", &iargs.wait_for_file) != 1) - { - ERROR("Invalid value for --wait-for-file\n"); - return 1; - } - break; - - case 359 : - iargs.min_sq_gradient = strtof(optarg, NULL); - break; - - case 360: - iargs.xgandalf_opts.sampling_pitch = 2; - iargs.xgandalf_opts.grad_desc_iterations = 3; - break; - - case 361: - if (sscanf(optarg, "%i", - &iargs.xgandalf_opts.maxPeaksForIndexing) != 1) - { - ERROR("Invalid value for --xgandalf-max-peaks\n"); - return 1; + case 313 : + if (sscanf(arg, "%d", &args->iargs.max_res) != 1) + { + ERROR("Invalid value for --max-res\n"); + return EINVAL; + } + break; + + case 314 : + if (sscanf(arg, "%f", &args->iargs.min_snr_biggest_pix) != 1) + { + ERROR("Invalid value for --max-snr-biggest-pix\n"); + return EINVAL; + } + break; + + case 315 : + if (sscanf(arg, "%f", &args->iargs.min_snr_peak_pix) != 1) + { + ERROR("Invalid value for --max-snr-peak-pix\n"); + return EINVAL; + } + break; + + case 316 : + if (sscanf(arg, "%f", &args->iargs.min_sig) != 1) + { + ERROR("Invalid value for --max-ssig\n"); + return EINVAL; + } + break; + + case 317 : + if (sscanf(arg, "%f", &args->iargs.min_peak_over_neighbour) != 1) + { + ERROR("Invalid value for --max-peak-over-neighbour\n"); + return EINVAL; + } + break; + + case 318 : + args->iargs.use_saturated = 0; + break; + + case 319 : + args->iargs.no_revalidate = 1; + break; + + case 320 : + args->iargs.half_pixel_shift = 0; + break; + + case 321 : + args->iargs.check_hdf5_snr = 1; + break; + + /* ---------- Indexing ---------- */ + + case 400 : + case 'z' : + args->indm_str = strdup(arg); + break; + + case 'p' : + args->cellfile = strdup(arg); + break; + + case 401 : + r = sscanf(arg, "%f,%f,%f,%f,%f,%f", + &args->iargs.tols[0], &args->iargs.tols[1], &args->iargs.tols[2], + &args->iargs.tols[3], &args->iargs.tols[4], &args->iargs.tols[5]); + if ( r != 6 ) { + /* Try old format */ + r = sscanf(arg, "%f,%f,%f,%f", + &args->iargs.tols[0], &args->iargs.tols[1], + &args->iargs.tols[2], &args->iargs.tols[3]); + if ( r != 4 ) { + ERROR("Invalid parameters for '--tolerance'\n"); + return EINVAL; } - break; + args->iargs.tols[4] = args->iargs.tols[3]; + args->iargs.tols[5] = args->iargs.tols[3]; + } + + /* Percent to fraction */ + args->iargs.tols[0] /= 100.0; + args->iargs.tols[1] /= 100.0; + args->iargs.tols[2] /= 100.0; + args->iargs.tols[3] = deg2rad(args->iargs.tols[3]); + args->iargs.tols[4] = deg2rad(args->iargs.tols[4]); + args->iargs.tols[5] = deg2rad(args->iargs.tols[5]); + break; + + case 402 : + args->if_checkcell = 0; + break; + + case 403 : + args->if_checkcell = 1; /* This is the default */ + break; + + case 404 : + args->if_multi = 1; + break; + + case 405 : + args->if_multi = 0; /* This is the default */ + break; + + case 406 : + args->if_retry = 0; + break; + + case 407 : + args->if_retry = 1; /* This is the default */ + break; + + case 408 : + args->if_refine = 0; + break; + + case 409 : + args->if_refine = 1; /* This is the default */ + break; + + case 410 : + args->if_peaks = 0; + break; + + case 411 : + args->if_peaks = 1; /* This is the default */ + break; + + case 412 : + ERROR("The option --no-cell-combinations is no longer used.\n"); + /* .. but we can still carry on. Results will probably be + * better than the user expected. */ + break; + + /* ---------- Integration ---------- */ + + case 501 : + args->iargs.int_meth = integration_method(arg, &r); + if ( r ) { + ERROR("Invalid integration method '%s'\n", arg); + return EINVAL; + } + break; + + case 502 : + if ( sscanf(arg, "%f", &args->iargs.fix_profile_r) != 1 ) { + ERROR("Invalid value for --fix-profile-radius\n"); + return EINVAL; + } + break; + + case 503 : + if ( sscanf(arg, "%f", &args->iargs.fix_bandwidth) != 1 ) { + ERROR("Invalid value for --fix-bandwidth\n"); + return EINVAL; + } + break; + + case 504 : + if ( sscanf(arg, "%f", &args->iargs.fix_divergence) != 1 ) { + ERROR("Invalid value for --fix-divergence\n"); + return EINVAL; + } + break; + + case 505 : + r = sscanf(arg, "%f,%f,%f", &args->iargs.ir_inn, + &args->iargs.ir_mid, &args->iargs.ir_out); + if ( r != 3 ) { + ERROR("Invalid parameters for '--int-radius'\n"); + return EINVAL; + } + break; + + case 506 : + if ( strcmp(arg, "random") == 0 ) { + args->iargs.int_diag = INTDIAG_RANDOM; + } + + if ( strcmp(arg, "all") == 0 ) { + args->iargs.int_diag = INTDIAG_ALL; + } - case 0 : - break; + if ( strcmp(arg, "negative") == 0 ) { + args->iargs.int_diag = INTDIAG_NEGATIVE; + } + + if ( strcmp(arg, "implausible") == 0 ) { + args->iargs.int_diag = INTDIAG_IMPLAUSIBLE; + } + + if ( strcmp(arg, "strong") == 0 ) { + args->iargs.int_diag = INTDIAG_STRONG; + } + + r = sscanf(arg, "%i,%i,%i", &args->iargs.int_diag_h, + &args->iargs.int_diag_k, &args->iargs.int_diag_l); + if ( r == 3 ) { + args->iargs.int_diag = INTDIAG_INDICES; + } + + if ( (args->iargs.int_diag == INTDIAG_NONE) + && (strcmp(arg, "none") != 0) ) + { + ERROR("Invalid value for --int-diag.\n"); + return EINVAL; + } + + break; - case '?' : - break; + case 507 : + if ( sscanf(arg, "%f", &args->iargs.push_res) != 1 ) { + ERROR("Invalid value for --push-res\n"); + return EINVAL; + } + args->iargs.push_res *= 1e9; /* nm^-1 -> m^-1 */ + break; + + case 508 : + args->iargs.overpredict = 1; + break; + + /* ---------- Output ---------- */ + + case 601 : + args->iargs.stream_nonhits = 0; + break; + + case 602 : + add_imagefile_field(args->iargs.copyme, arg); + break; + + case 603 : + args->iargs.stream_peaks = 0; + break; - default : - ERROR("Unhandled option '%c'\n", c); - break; + case 604 : + args->iargs.stream_refls = 0; + break; + case 605 : + if ( sscanf(arg, "%d", &args->serial_start) != 1 ) { + ERROR("Invalid value for --serial-start\n"); + return EINVAL; } + default : + return ARGP_ERR_UNKNOWN; + } - if ( if_nocomb_unused ) { - ERROR("WARNING: --no-cell-combinations is no longer used, " - "and has been ignored.\n"); + return 0; +} + + +int main(int argc, char *argv[]) +{ + FILE *fh; + Stream *st; + struct indexamajig_arguments args; + char *tmpdir; /* e.g. /tmp/indexamajig.12345 */ + char *rn; /* e.g. /home/taw/indexing */ + int r; + struct beam_params beam; + char *zmq_address = NULL; + TakeTwoOptions *taketwo_opts = NULL; + FelixOptions *felix_opts = NULL; + XGandalfOptions *xgandalf_opts = NULL; + + /* Defaults for "top level" arguments */ + args.filename = NULL; + args.geom_filename = NULL; + args.outfile = NULL; + args.temp_location = strdup("."); + args.prefix = strdup(""); + args.check_prefix = 1; + args.n_proc = 1; + args.cellfile = NULL; + args.spectrum_fn = NULL; + args.indm_str = NULL; + args.basename = 0; + args.zmq = 0; + args.serial_start = 1; + args.command_line_peak_path = NULL; + args.if_peaks = 1; + args.if_multi = 0; + args.if_retry = 1; + args.if_checkcell = 1; + args.taketwo_opts_ptr = &taketwo_opts; + args.felix_opts_ptr = &felix_opts; + args.xgandalf_opts_ptr = &xgandalf_opts; + + /* Defaults for process_image arguments */ + args.iargs.cell = NULL; + args.iargs.noisefilter = 0; + args.iargs.median_filter = 0; + args.iargs.tols[0] = 0.05; + args.iargs.tols[1] = 0.05; + args.iargs.tols[2] = 0.05; + args.iargs.tols[3] = 1.5; + args.iargs.tols[4] = 1.5; + args.iargs.tols[5] = 1.5; + args.iargs.threshold = 800.0; + args.iargs.min_sq_gradient = 100000.0; + args.iargs.min_snr = 5.0; + args.iargs.min_pix_count = 2; + args.iargs.max_pix_count = 200; + args.iargs.min_res = 0; + args.iargs.max_res = 1200; + args.iargs.local_bg_radius = 3; + args.iargs.min_snr_biggest_pix = 7.0; /* peak finder 9 */ + args.iargs.min_snr_peak_pix = 6.0; + args.iargs.min_sig = 11.0; + args.iargs.min_peak_over_neighbour = -INFINITY; + args.iargs.check_hdf5_snr = 0; + args.iargs.det = NULL; + args.iargs.peaks = PEAK_ZAEF; + args.iargs.beam = &beam; + args.iargs.hdf5_peak_path = NULL; + args.iargs.half_pixel_shift = 1; + args.iargs.copyme = NULL; + args.iargs.pk_inn = -1.0; + args.iargs.pk_mid = -1.0; + args.iargs.pk_out = -1.0; + args.iargs.ir_inn = -1.0; + args.iargs.ir_mid = -1.0; + args.iargs.ir_out = -1.0; + args.iargs.use_saturated = 1; + args.iargs.no_revalidate = 0; + args.iargs.stream_peaks = 1; + args.iargs.stream_refls = 1; + args.iargs.stream_nonhits = 1; + args.iargs.int_diag = INTDIAG_NONE; + args.iargs.min_peaks = 0; + args.iargs.overpredict = 0; + args.iargs.wait_for_file = 0; + args.iargs.copyme = new_imagefile_field_list(); + if ( args.iargs.copyme == NULL ) { + ERROR("Couldn't allocate HDF5 field list.\n"); + return 1; } + args.iargs.ipriv = NULL; /* No default */ + args.iargs.int_meth = integration_method("rings-nocen-nosat-nograd", NULL); + args.iargs.push_res = -1.0; + args.iargs.highres = +INFINITY; + args.iargs.fix_profile_r = -1.0; + args.iargs.fix_bandwidth = -1.0; + args.iargs.fix_divergence = -1.0; + args.iargs.profile = 0; + args.iargs.no_image_data = 0; + + argp_program_version_hook = show_version; + + static char doc[] = "Index and integrate snapshot diffraction images.\v" + "For more information including a tutorial, visit " + "https://www.desy.de/~twhite/crystfel"; + + static struct argp_option options[] = { + + {NULL, 0, 0, OPTION_DOC, "Basic options:", 2}, + + {NULL, 'h', NULL, OPTION_HIDDEN, NULL}, + {NULL, 'v', NULL, OPTION_HIDDEN, NULL}, + + {"input", 'i', "infile", 0, "List of input image filenames"}, + {"output", 'o', "filename.stream", 0, "Output stream filename"}, + {"geometry",'g', "experiment.geom", 0, "Detector geometry filename"}, + {"prefix", 'x', "/path/to/images/", OPTION_NO_USAGE, "Prefix filenames from input " + "file"}, + {NULL, 'j', "nproc", 0, "Run this many analyses in parallel, default 1"}, + {"basename", 201, NULL, OPTION_NO_USAGE, "Remove director parts from the " + "filenames"}, + {"no-check-prefix", 202, NULL, OPTION_NO_USAGE, "Don't attempt to correct the " + "--prefix"}, + {"highres", 203, "res", OPTION_NO_USAGE, "Absolute resolution cutoff in Angstroms"}, + {"profile", 204, NULL, OPTION_NO_USAGE, "Show timing data for performance " + "monitoring"}, + {"temp-dir", 205, "path", OPTION_NO_USAGE, "Location for temporary folder"}, + {"wait-for-file", 206, "seconds", OPTION_NO_USAGE, "Wait for each file before " + "processing"}, + {"zmq-msgpack", 207, NULL, OPTION_NO_USAGE, "Receive data in MessagePack format " + "over ZMQ"}, + {"no-image-data", 208, NULL, OPTION_NO_USAGE, "Do not load image data (from ZMQ)"}, + {"spectrum-file", 209, "fn", OPTION_NO_USAGE, "File containing radiation spectrum"}, + + {NULL, 0, 0, OPTION_DOC, "Peak search options:", 3}, + {"peaks", 301, "method", 0, "Peak search method. Default: zaef"}, + {"peak-radius", 302, "r1,r2,r3", OPTION_NO_USAGE, "Radii for peak search"}, + {"min-peaks", 303, "n", OPTION_NO_USAGE, "Minimum number of peaks for indexing"}, + {"hdf5-peaks", 304, "p", OPTION_NO_USAGE, "Location of peak table in HDF5 file"}, + {"median-filter", 305, "n", OPTION_NO_USAGE, "Apply median filter to image data"}, + {"filter-noise", 306, NULL, OPTION_NO_USAGE, "Apply noise filter to image data"}, + {"threshold", 't', "adu", OPTION_NO_USAGE, "Threshold for peak detection " + "(zaef only, default 800)"}, + {"min-squared-gradient", 307, "n", OPTION_NO_USAGE, "Minimum squared gradient " + "(zaef only, default 100000)"}, + {"min-snr", 308, "n", OPTION_NO_USAGE, "Minimum signal/noise ratio for peaks " + "(zaef,peakfinder8,peakfinder9 only, default 5)"}, + {"min-pix-count", 309, "n", OPTION_NO_USAGE, "Minimum number of pixels per peak " + "(peakfinder8 only, default 2)"}, + {"max-pix-count", 310, "n", OPTION_NO_USAGE, "Maximum number of pixels per peak " + "(peakfinder8 only, default 2)"}, + {"local-bg-radius", 311, "n", OPTION_NO_USAGE, "Radius (pixels) for local " + "background estimation (peakfinder8/9 only, default 3)"}, + {"min-res", 312, "n", OPTION_NO_USAGE, "Minimum resoultion (pixels) for peak " + "search (peakfinder8 only, default 0)"}, + {"max-res", 313, "n", OPTION_NO_USAGE, "Maximum resoultion (pixels) for peak " + "search (peakfinder8 only, default 1200)"}, + {"min-snr-biggest-peak", 314, "n", OPTION_NO_USAGE, "Minimum SNR of the biggest " + "pixel in the peak (peakfinder9 only)"}, + {"min-snr-peak-pix", 315, "n", OPTION_NO_USAGE, "Minimum SNR of peak pixel " + "(peakfinder9 only)"}, + {"min-sig", 316, "n", OPTION_NO_USAGE, "Minimum standard deviation of the " + "background (peakfinder9 only)"}, + {"min-peak-over-neighbour", 317, "n", OPTION_NO_USAGE, "Minimum difference between " + "highest pixel and neighbours (peakfinder9 only, just for speed)"}, + {"no-use-saturated", 318, NULL, OPTION_NO_USAGE, "Reject saturated peaks"}, + {"no-revalidate", 319, NULL, OPTION_NO_USAGE, "Don't re-integrate and check HDF5 " + "peaks"}, + {"no-half-pixel-shift", 320, NULL, OPTION_NO_USAGE, "Don't offset HDF5 peak " + "locations by 0.5 pixels"}, + {"check-hdf5-snr", 321, NULL, OPTION_NO_USAGE, "Check SNR for peaks from HDF5 or " + "CXI (see --min-snr)"}, + + {NULL, 0, 0, OPTION_DOC, "Indexing options:", 4}, + {"indexing", 400, "method", 0, "List of indexing methods"}, + {NULL, 'z', "method", OPTION_HIDDEN | OPTION_ALIAS, NULL}, + {"pdb", 'p', "parameters.cell", 0, "PDB or CrystFEL Unit Cell File"}, + {"tolerance", 401, "a,b,c,al,be,ga", OPTION_NO_USAGE, "Tolerances for cell " + "comparison in percent and degrees, default 5,5,5,1.5,1.5,1.5"}, + {"no-check-cell", 402, NULL, OPTION_NO_USAGE, "Don't check cell parameters " + "against target cell"}, + {"check-cell", 403, NULL, OPTION_HIDDEN, NULL}, + {"multi", 404, NULL, OPTION_NO_USAGE, "Repeat indexing to index multiple hits"}, + {"no-multi", 405, NULL, OPTION_HIDDEN, NULL}, + {"no-retry", 406, NULL, OPTION_NO_USAGE, "Don't repeat indexing to increase " + "indexing rate"}, + {"retry", 407, NULL, OPTION_HIDDEN, NULL}, + {"no-refine", 408, NULL, OPTION_NO_USAGE, "Skip prediction refinement"}, + {"refine", 409, NULL, OPTION_HIDDEN, NULL}, + {"no-check-peaks", 410, NULL, OPTION_NO_USAGE, "Don't check that most peaks can be " + "accounted for by the indexing solution"}, + {"check-peaks", 411, NULL, OPTION_HIDDEN, NULL}, + {"no-cell-combinations", 412, NULL, OPTION_HIDDEN, NULL}, + + {NULL, 0, 0, OPTION_DOC, "Integration options:", 5}, + {"integration", 501, "method", OPTION_NO_USAGE, "Integration method"}, + {"fix-profile-radius", 502, "r", OPTION_NO_USAGE, "Fix profile radius for spot " + "prediction, instead of automatically determining"}, + {"fix-bandwidth", 503, "bw", OPTION_NO_USAGE, "Set the bandwidth for spot " + "prediction"}, + {"fix-divergence", 504, "deg", OPTION_NO_USAGE, "Set the divergence (full angle) " + "for spot prediction"}, + {"int-radius", 505, "r1,r2,r3", 0, "Set the integration radii (inner,mid,outer)"}, + {"int-diag", 506, "condition", 0, "Show debugging information about reflections"}, + {"push-res", 507, "dist", 0, "Integrate higher than apparent resolution cutoff (m^-1)"}, + {"overpredict", 508, NULL, 0, "Over-predict reflections"}, + + {NULL, 0, 0, OPTION_DOC, "Output options:", 6}, + {"no-non-hits-in-stream", 601, NULL, OPTION_NO_USAGE, "Don't include non-hits in " + "stream (see --min-peaks)"}, + {"copy-hdf5-field", 602, "f", OPTION_NO_USAGE, "Put the value of this HDF5 field " + "into the stream"}, + {"no-peaks-in-stream", 603, NULL, OPTION_NO_USAGE, "Don't put peak search results " + "in stream"}, + {"no-refls-in-stream", 604, NULL, OPTION_NO_USAGE, "Don't put integration results " + "in stream"}, + {"serial-start", 605, "n", OPTION_NO_USAGE, "Start the serial numbers in the stream " + "here"}, + + {NULL, 0, 0, OPTION_DOC, "More information:", 99}, + + {0} + + }; + + static struct argp_child argp_children[] = { + {&taketwo_argp, 0, NULL, -2}, + {&felix_argp, 0, NULL, -2}, + {&xgandalf_argp, 0, NULL, -2}, + {0} + }; + + static struct argp argp = { options, parse_arg, NULL, doc, + argp_children, NULL, NULL }; + argp_parse(&argp, argc, argv, 0, NULL, &args); /* Check for minimal information */ - if ( filename == NULL ) { + if ( args.filename == NULL ) { ERROR("You need to provide the input filename (use -i)\n"); return 1; } - if ( geom_filename == NULL ) { + if ( args.geom_filename == NULL ) { ERROR("You need to specify the geometry filename (use -g)\n"); return 1; } - if ( outfile == NULL ) { + if ( args.outfile == NULL ) { ERROR("You need to specify the output filename (use -o)\n"); return 1; } - if ( temp_location == NULL ) { - temp_location = strdup("."); - } - /* Open input */ - if ( strcmp(filename, "-") == 0 ) { + if ( strcmp(args.filename, "-") == 0 ) { fh = stdin; } else { - fh = fopen(filename, "r"); + fh = fopen(args.filename, "r"); } if ( fh == NULL ) { - ERROR("Failed to open input file '%s'\n", filename); + ERROR("Failed to open input file '%s'\n", args.filename); return 1; } - free(filename); - - /* Parse peak detection method */ - if ( speaks == NULL ) { - speaks = strdup("zaef"); - STATUS("You didn't specify a peak detection method.\n"); - STATUS("I'm using 'zaef' for you.\n"); - } - if ( strcmp(speaks, "zaef") == 0 ) { - iargs.peaks = PEAK_ZAEF; - } else if ( strcmp(speaks, "peakfinder8") == 0 ) { - iargs.peaks = PEAK_PEAKFINDER8; - } else if ( strcmp(speaks, "hdf5") == 0 ) { - iargs.peaks = PEAK_HDF5; - } else if ( strcmp(speaks, "cxi") == 0 ) { - iargs.peaks = PEAK_CXI; - } else if ( strcmp(speaks, "peakfinder9") == 0 ) { - iargs.peaks = PEAK_PEAKFINDER9; - } else if ( strcmp(speaks, "msgpack") == 0 ) { - iargs.peaks = PEAK_MSGPACK; - } else if ( strcmp(speaks, "none") == 0 ) { - iargs.peaks = PEAK_NONE; - } else { - ERROR("Unrecognised peak detection method '%s'\n", speaks); - return 1; - } - free(speaks); + free(args.filename); /* Check prefix (if given) */ - if ( prefix == NULL ) { - prefix = strdup(""); - } else { - if ( config_checkprefix ) { - prefix = check_prefix(prefix); - } + if ( args.check_prefix ) { + args.prefix = check_prefix(args.prefix); } /* Check number of processes */ - if ( n_proc == 0 ) { + if ( args.n_proc == 0 ) { ERROR("Invalid number of processes.\n"); return 1; } /* Load detector geometry */ - iargs.det = get_detector_geometry_2(geom_filename, iargs.beam, - &iargs.hdf5_peak_path); - if ( iargs.det == NULL ) { + args.iargs.det = get_detector_geometry_2(args.geom_filename, + args.iargs.beam, + &args.iargs.hdf5_peak_path); + if ( args.iargs.det == NULL ) { ERROR("Failed to read detector geometry from '%s'\n", - geom_filename); + args.geom_filename); return 1; } - add_geom_beam_stuff_to_field_list(iargs.copyme, iargs.det, iargs.beam); + add_geom_beam_stuff_to_field_list(args.iargs.copyme, args.iargs.det, + args.iargs.beam); /* If no peak path from geometry file, use these (but see later) */ - if ( iargs.hdf5_peak_path == NULL ) { - if ( iargs.peaks == PEAK_HDF5 ) { - iargs.hdf5_peak_path = strdup("/processing/hitfinder/peakinfo"); - } else if ( iargs.peaks == PEAK_CXI ) { - iargs.hdf5_peak_path = strdup("/entry_1/result_1"); + if ( args.iargs.hdf5_peak_path == NULL ) { + if ( args.iargs.peaks == PEAK_HDF5 ) { + args.iargs.hdf5_peak_path = strdup("/processing/hitfinder/peakinfo"); + } else if ( args.iargs.peaks == PEAK_CXI ) { + args.iargs.hdf5_peak_path = strdup("/entry_1/result_1"); } } /* If an HDF5 peak path was given on the command line, use it */ - if ( command_line_peak_path != NULL ) { - free(iargs.hdf5_peak_path); - iargs.hdf5_peak_path = command_line_peak_path; + if ( args.command_line_peak_path != NULL ) { + free(args.iargs.hdf5_peak_path); + args.iargs.hdf5_peak_path = args.command_line_peak_path; } - /* Parse integration method */ - if ( int_str != NULL ) { - - int err; - - iargs.int_meth = integration_method(int_str, &err); - if ( err ) { - ERROR("Invalid integration method '%s'\n", int_str); - return 1; - } - free(int_str); - } - if ( integrate_saturated ) { - /* Option provided for backwards compatibility */ - iargs.int_meth |= INTEGRATION_SATURATED; - } - if ( have_push_res && !(iargs.int_meth & INTEGRATION_RESCUT) ) { - ERROR("WARNING: You used --push-res, but not -rescut, " - "therefore --push-res will have no effect.\n"); - ERROR("WARNING: Add --integration=rings-rescut or " - "--integration=prof2d-rescut.\n"); - } - - /* Parse unit cell tolerance */ - if ( toler != NULL ) { - int ttt; - ttt = sscanf(toler, "%f,%f,%f,%f,%f,%f", - &iargs.tols[0], &iargs.tols[1], &iargs.tols[2], - &iargs.tols[3], &iargs.tols[4], &iargs.tols[5]); - if ( ttt != 6 ) { - ttt = sscanf(toler, "%f,%f,%f,%f", - &iargs.tols[0], &iargs.tols[1], - &iargs.tols[2], &iargs.tols[3]); - if ( ttt != 4 ) { - ERROR("Invalid parameters for '--tolerance'\n"); - return 1; - } - iargs.tols[4] = iargs.tols[3]; - iargs.tols[5] = iargs.tols[3]; + /* Check for push-res without rescut */ + if ( args.iargs.push_res > 0.0 ) { + if ( !(args.iargs.int_meth & INTEGRATION_RESCUT) ) { + ERROR("WARNING: You used --push-res, but not -rescut, " + "therefore --push-res will have no effect.\n"); + ERROR("WARNING: Add --integration=rings-rescut or " + "--integration=prof2d-rescut.\n"); } - free(toler); - - /* Percent to fraction */ - iargs.tols[0] /= 100.0; - iargs.tols[1] /= 100.0; - iargs.tols[2] /= 100.0; - iargs.tols[3] = deg2rad(iargs.tols[3]); - iargs.tols[4] = deg2rad(iargs.tols[4]); - iargs.tols[5] = deg2rad(iargs.tols[5]); + } else { + /* Set default value */ + args.iargs.push_res = 0.0; } - /* Parse integration radii */ - if ( intrad != NULL ) { - int r; - r = sscanf(intrad, "%f,%f,%f", - &iargs.ir_inn, &iargs.ir_mid, &iargs.ir_out); - if ( r != 3 ) { - ERROR("Invalid parameters for '--int-radius'\n"); - return 1; - } - free(intrad); - } else { + /* If no integration radii were given, apply the defaults */ + if ( args.iargs.ir_inn < 0 ) { STATUS("WARNING: You did not specify --int-radius.\n"); STATUS("WARNING: I will use the default values, which are" " probably not appropriate for your patterns.\n"); + args.iargs.ir_inn = 4.0; + args.iargs.ir_mid = 5.0; + args.iargs.ir_out = 7.0; } - /* Parse peak radii (used for peak detection) */ - if ( pkrad != NULL ) { - int r; - r = sscanf(pkrad, "%f,%f,%f", - &iargs.pk_inn, &iargs.pk_mid, &iargs.pk_out); - if ( r != 3 ) { - ERROR("Invalid parameters for '--peak-radius'\n"); - return 1; - } - free(pkrad); - } - if ( iargs.pk_inn < 0.0 ) { - iargs.pk_inn = iargs.ir_inn; - iargs.pk_mid = iargs.ir_mid; - iargs.pk_out = iargs.ir_out; + /* If no peak radii were given, copy the integration radii */ + if ( args.iargs.pk_inn < 0.0 ) { + args.iargs.pk_inn = args.iargs.ir_inn; + args.iargs.pk_mid = args.iargs.ir_mid; + args.iargs.pk_out = args.iargs.ir_out; } /* Load unit cell (if given) */ - if ( cellfile != NULL ) { - iargs.cell = load_cell_from_file(cellfile); - if ( iargs.cell == NULL ) { - ERROR("Couldn't read unit cell (from %s)\n", cellfile); + if ( args.cellfile != NULL ) { + args.iargs.cell = load_cell_from_file(args.cellfile); + if ( args.iargs.cell == NULL ) { + ERROR("Couldn't read unit cell (from %s)\n", args.cellfile); return 1; } - free(cellfile); + free(args.cellfile); } else { - iargs.cell = NULL; + args.iargs.cell = NULL; } /* Load spectrum from file if given */ - if ( spectrum_fn != NULL ) { - iargs.spectrum = spectrum_load(spectrum_fn); - if ( iargs.spectrum == NULL ) { - ERROR("Couldn't read spectrum (from %s)\n", spectrum_fn); + if ( args.spectrum_fn != NULL ) { + args.iargs.spectrum = spectrum_load(args.spectrum_fn); + if ( args.iargs.spectrum == NULL ) { + ERROR("Couldn't read spectrum (from %s)\n", args.spectrum_fn); return 1; } - free(spectrum_fn); + free(args.spectrum_fn); } else { - iargs.spectrum = NULL; + args.iargs.spectrum = NULL; } - /* Parse integration diagnostic */ - if ( int_diag != NULL ) { - - int r; - signed int h, k, l; - - if ( strcmp(int_diag, "random") == 0 ) { - iargs.int_diag = INTDIAG_RANDOM; - } - - if ( strcmp(int_diag, "all") == 0 ) { - iargs.int_diag = INTDIAG_ALL; - } - - if ( strcmp(int_diag, "negative") == 0 ) { - iargs.int_diag = INTDIAG_NEGATIVE; - } - - if ( strcmp(int_diag, "implausible") == 0 ) { - iargs.int_diag = INTDIAG_IMPLAUSIBLE; - } - - if ( strcmp(int_diag, "strong") == 0 ) { - iargs.int_diag = INTDIAG_STRONG; - } - - r = sscanf(int_diag, "%i,%i,%i", &h, &k, &l); - if ( r == 3 ) { - iargs.int_diag = INTDIAG_INDICES; - iargs.int_diag_h = h; - iargs.int_diag_k = k; - iargs.int_diag_l = l; - } - - if ( (iargs.int_diag == INTDIAG_NONE) - && (strcmp(int_diag, "none") != 0) ) { - ERROR("Invalid value for --int-diag.\n"); - return 1; - } - - free(int_diag); - - } - - tmpdir = create_tempdir(temp_location); + tmpdir = create_tempdir(args.temp_location); if ( tmpdir == NULL ) return 1; /* Change into temporary folder, temporarily, to control the crap @@ -1202,7 +944,8 @@ int main(int argc, char *argv[]) return 1; } - if ( indm_str == NULL ) { + /* Auto-detect indexing methods if 'requested' */ + if ( args.indm_str == NULL ) { STATUS("No indexing methods specified. I will try to "); STATUS("automatically detect the available methods.\n"); @@ -1210,12 +953,12 @@ int main(int argc, char *argv[]) STATUS("which methods to use with --indexing=<methods>.\n"); STATUS("Use --indexing=none to disable indexing and integration.\n"); - indm_str = detect_indexing_methods(iargs.cell); + args.indm_str = detect_indexing_methods(args.iargs.cell); } /* Prepare the indexing system */ - if ( indm_str == NULL ) { + if ( args.indm_str == NULL ) { ERROR("No indexing method specified, and no usable indexing "); ERROR("methods auto-detected.\n"); @@ -1223,48 +966,48 @@ int main(int argc, char *argv[]) ERROR("try again with --indexing=none.\n"); return 1; - } else if ( strcmp(indm_str, "none") == 0 ) { + } else if ( strcmp(args.indm_str, "none") == 0 ) { STATUS("Indexing/integration disabled.\n"); - if ( iargs.cell != NULL ) { + if ( args.iargs.cell != NULL ) { STATUS("Ignoring your unit cell.\n"); } - iargs.ipriv = NULL; + args.iargs.ipriv = NULL; } else { IndexingFlags flags = 0; - if ( iargs.cell != NULL ) { + if ( args.iargs.cell != NULL ) { STATUS("This is what I understood your unit cell to be:\n"); - cell_print(iargs.cell); + cell_print(args.iargs.cell); } else { STATUS("No reference unit cell provided.\n"); } - if ( !if_nocheck ) { + if ( args.if_checkcell ) { flags |= INDEXING_CHECK_CELL; } - - if ( if_refine ) { + if ( args.if_refine ) { flags |= INDEXING_REFINE; } - if ( if_peaks ) { + if ( args.if_peaks ) { flags |= INDEXING_CHECK_PEAKS; } - if ( if_multi ) { + if ( args.if_multi ) { flags |= INDEXING_MULTI; } - if ( if_retry ) { + if ( args.if_retry ) { flags |= INDEXING_RETRY; } - iargs.ipriv = setup_indexing(indm_str, iargs.cell, iargs.det, - iargs.tols, flags, - &iargs.taketwo_opts, - &iargs.xgandalf_opts, - &iargs.felix_opts); - if ( iargs.ipriv == NULL ) { + args.iargs.ipriv = setup_indexing(args.indm_str, args.iargs.cell, + args.iargs.det, + args.iargs.tols, flags, + taketwo_opts, + xgandalf_opts, + felix_opts); + if ( args.iargs.ipriv == NULL ) { ERROR("Failed to set up indexing system\n"); return 1; } @@ -1282,18 +1025,19 @@ int main(int argc, char *argv[]) free(rn); /* Open output stream */ - st = open_stream_for_write_4(outfile, geom_filename, iargs.cell, - argc, argv, indm_str); + st = open_stream_for_write_4(args.outfile, args.geom_filename, + args.iargs.cell, argc, argv, + args.indm_str); if ( st == NULL ) { - ERROR("Failed to open stream '%s'\n", outfile); + ERROR("Failed to open stream '%s'\n", args.outfile); return 1; } - free(outfile); - free(indm_str); + free(args.outfile); + free(args.indm_str); gsl_set_error_handler_off(); - if ( zmq ) { + if ( args.zmq ) { char line[1024]; char *rval; rval = fgets(line, 1024, fh); @@ -1307,19 +1051,19 @@ int main(int argc, char *argv[]) * evenly to workers */ } - r = create_sandbox(&iargs, n_proc, prefix, config_basename, fh, - st, tmpdir, serial_start, zmq_address); + r = create_sandbox(&args.iargs, args.n_proc, args.prefix, args.basename, + fh, st, tmpdir, args.serial_start, zmq_address); - free_imagefile_field_list(iargs.copyme); - cell_free(iargs.cell); - free(iargs.beam->photon_energy_from); - free(prefix); - free(temp_location); + free_imagefile_field_list(args.iargs.copyme); + cell_free(args.iargs.cell); + free(args.iargs.beam->photon_energy_from); + free(args.prefix); + free(args.temp_location); free(tmpdir); - free_detector_geometry(iargs.det); - free(iargs.hdf5_peak_path); + free_detector_geometry(args.iargs.det); + free(args.iargs.hdf5_peak_path); close_stream(st); - cleanup_indexing(iargs.ipriv); + cleanup_indexing(args.iargs.ipriv); if ( r ) { return 0; diff --git a/src/process_image.h b/src/process_image.h index 9a58a64f..c32df634 100644 --- a/src/process_image.h +++ b/src/process_image.h @@ -44,9 +44,6 @@ struct index_args; #include "integration.h" #include "im-sandbox.h" #include "time-accounts.h" -#include "taketwo.h" -#include "xgandalf.h" -#include "felix.h" enum { @@ -67,7 +64,6 @@ struct index_args int cmfilter; int noisefilter; int median_filter; - int satcorr; float threshold; float min_sq_gradient; float min_snr; @@ -115,9 +111,6 @@ struct index_args float fix_divergence; int overpredict; int profile; /* Whether or not to do wall clock profiling */ - struct taketwo_options taketwo_opts; - struct xgandalf_options xgandalf_opts; - struct felix_options felix_opts; Spectrum *spectrum; signed int wait_for_file; /* -1 means wait forever */ int no_image_data; |