aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas White <taw@physics.org>2024-01-12 15:59:29 +0100
committerThomas White <taw@physics.org>2024-01-12 15:59:29 +0100
commit1efc31cb6b6902a10330147dc16a1aa3efe834fe (patch)
treee8edf46cebd3091a91eb47fc93a1064eb96a8e42
parentcc2717022fca0fd6b24b1dba3aaa5173672a3223 (diff)
parenta863e7fc05feb892ffbb7957b4fe74a886992800 (diff)
Merge branch 'millepede-gui'
-rw-r--r--data/crystfel-geometry.pngbin0 -> 1008 bytes
-rw-r--r--data/crystfel-geometry.svg132
-rw-r--r--data/crystfel.gresource.xml1
-rw-r--r--doc/man/align_detector.1.md4
-rw-r--r--doc/man/indexamajig.1.md7
-rw-r--r--libcrystfel/src/crystfel-mille.c26
-rw-r--r--libcrystfel/src/crystfel-mille.h2
-rw-r--r--libcrystfel/src/index.c14
-rw-r--r--libcrystfel/src/index.h3
-rw-r--r--libcrystfel/src/predict-refine.c6
-rw-r--r--libcrystfel/src/predict-refine.h3
-rw-r--r--libcrystfel/src/utils.c14
-rw-r--r--libcrystfel/src/utils.h1
-rw-r--r--meson.build1
-rw-r--r--src/align_detector.c25
-rw-r--r--src/crystfel_gui.c34
-rw-r--r--src/crystfelindexingopts.c35
-rw-r--r--src/crystfelindexingopts.h8
-rw-r--r--src/gui_align.c235
-rw-r--r--src/gui_align.h38
-rw-r--r--src/gui_backend_local.c17
-rw-r--r--src/gui_backend_slurm.c4
-rw-r--r--src/gui_index.c13
-rw-r--r--src/gui_index.h1
-rw-r--r--src/gui_project.c12
-rw-r--r--src/gui_project.h2
-rw-r--r--src/indexamajig.c17
-rw-r--r--src/process_image.c2
-rw-r--r--src/process_image.h1
29 files changed, 608 insertions, 50 deletions
diff --git a/data/crystfel-geometry.png b/data/crystfel-geometry.png
new file mode 100644
index 00000000..df5ee8b2
--- /dev/null
+++ b/data/crystfel-geometry.png
Binary files differ
diff --git a/data/crystfel-geometry.svg b/data/crystfel-geometry.svg
new file mode 100644
index 00000000..7cac81a1
--- /dev/null
+++ b/data/crystfel-geometry.svg
@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ width="48"
+ height="48"
+ viewBox="0 0 48 48"
+ version="1.1"
+ id="svg5"
+ inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)"
+ sodipodi:docname="crystfel-geometry.svg"
+ inkscape:export-filename="crystfel-geometry.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <sodipodi:namedview
+ id="namedview7"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ inkscape:pagecheckerboard="0"
+ inkscape:document-units="px"
+ showgrid="false"
+ inkscape:zoom="18.1875"
+ inkscape:cx="21.415808"
+ inkscape:cy="22.762887"
+ inkscape:window-width="1965"
+ inkscape:window-height="1278"
+ inkscape:window-x="316"
+ inkscape:window-y="144"
+ inkscape:window-maximized="0"
+ inkscape:current-layer="layer1"
+ showguides="false"
+ inkscape:showpageshadow="2"
+ inkscape:deskcolor="#d1d1d1">
+ <inkscape:grid
+ type="xygrid"
+ id="grid7330"
+ originx="0"
+ originy="0"
+ spacingy="1"
+ spacingx="1"
+ units="px"
+ visible="false" />
+ </sodipodi:namedview>
+ <defs
+ id="defs2">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="9.0721649 : 28.728522 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="48 : 24 : 1"
+ inkscape:persp3d-origin="24 : 16 : 1"
+ id="perspective852" />
+ </defs>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <rect
+ style="fill:#001aff;fill-opacity:1;stroke:none;stroke-width:0.467433;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
+ id="rect9322-28"
+ width="7.6862044"
+ height="13.835168"
+ x="11.046838"
+ y="26.27951" />
+ <rect
+ style="fill:#001aff;fill-opacity:1;stroke:none;stroke-width:0.467433;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
+ id="rect9322-2-9"
+ width="7.6862044"
+ height="13.835168"
+ x="1.823392"
+ y="26.27951" />
+ <rect
+ style="fill:#001aff;fill-opacity:1;stroke:none;stroke-width:0.467433;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
+ id="rect9322-0-7"
+ width="7.6862044"
+ height="13.835168"
+ x="27.816751"
+ y="-34.10545"
+ transform="rotate(90)" />
+ <rect
+ style="fill:#001aff;fill-opacity:1;stroke:none;stroke-width:0.467433;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
+ id="rect9322-0-6-3"
+ width="7.6862044"
+ height="13.835168"
+ x="37.040195"
+ y="-34.10545"
+ transform="rotate(90)" />
+ <rect
+ style="fill:none;fill-opacity:1;stroke:#121212;stroke-width:0.467433;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
+ id="rect9322-9-6"
+ width="7.6862044"
+ height="13.835168"
+ x="29.962494"
+ y="-5.9090691"
+ transform="rotate(14.022074)" />
+ <rect
+ style="fill:none;fill-opacity:1;stroke:#121212;stroke-width:0.467433;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
+ id="rect9322-9-0-1"
+ width="7.6862044"
+ height="13.835168"
+ x="39.185944"
+ y="-5.9090691"
+ transform="rotate(14.022074)" />
+ <rect
+ style="fill:#001aff;fill-opacity:1;stroke:none;stroke-width:0.467433;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
+ id="rect9322-3-2"
+ width="7.6862044"
+ height="13.835168"
+ x="-24.742268"
+ y="7.9723563"
+ transform="rotate(-90)" />
+ <rect
+ style="fill:#001aff;fill-opacity:1;stroke:none;stroke-width:0.467433;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
+ id="rect9322-3-6-9"
+ width="7.6862044"
+ height="13.835168"
+ x="-15.518825"
+ y="7.9723563"
+ transform="rotate(-90)" />
+ <path
+ style="fill:#001aff;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-dasharray:none;stroke-opacity:1"
+ d="M 31.780069,17.319588 Z"
+ id="path2" />
+ </g>
+</svg>
diff --git a/data/crystfel.gresource.xml b/data/crystfel.gresource.xml
index c000973a..fa7a1752 100644
--- a/data/crystfel.gresource.xml
+++ b/data/crystfel.gresource.xml
@@ -21,5 +21,6 @@
<file>crystfel-merge.png</file>
<file>crystfel-peak-detection.png</file>
<file>crystfel-unitcell.png</file>
+ <file>crystfel-geometry.png</file>
</gresource>
</gresources>
diff --git a/doc/man/align_detector.1.md b/doc/man/align_detector.1.md
index aa5f5061..f5991641 100644
--- a/doc/man/align_detector.1.md
+++ b/doc/man/align_detector.1.md
@@ -45,6 +45,10 @@ panel "dominoes", and level **3** would refine the individual (roughly square)
ASICs. Higher refinement levels will generally require more and
higher-resolution diffraction data.
+You can use **indexamajig** option **--max-mille-level** to reduce the size of
+the calibration data files, at the cost of limiting the maximum refinement
+level.
+
The default behaviour is to refine only the position components in the x-y
plane, perpendicular to the beam. In favourable circumstances, you can add
option **--out-of-plane** to refine the panel tilts and shifts out of this
diff --git a/doc/man/indexamajig.1.md b/doc/man/indexamajig.1.md
index 85566240..1955ef76 100644
--- a/doc/man/indexamajig.1.md
+++ b/doc/man/indexamajig.1.md
@@ -594,6 +594,13 @@ INDEXING OPTIONS
**--mille-dir=dirname**
: Write the Millepede-II data into _dirname_.
+**--max-mille-level=n**
+: Write the Millepede-II data up to a maximum hierarchy depth _n_. If _n_ is
+: 0, only the overall detector position can be refined. Larger numbers allow
+: finer-grained refinement. Set this to a large number (9 is high enough!)
+: to disable the limit, although this can make the Millepede-II files quite
+: large.
+
**--wavelength-estimate=m** **--camera-length-estimate=m**
: Some indexing algorithms need to know the camera length or the wavelength of
: the incident radiation in advance, e.g. to prepare an internal look-up table.
diff --git a/libcrystfel/src/crystfel-mille.c b/libcrystfel/src/crystfel-mille.c
index 0fca6f30..8eacaa60 100644
--- a/libcrystfel/src/crystfel-mille.c
+++ b/libcrystfel/src/crystfel-mille.c
@@ -145,11 +145,28 @@ static void mille_add_measurement(Mille *m,
}
+/* group must not be NULL
+ * count_depth() = 0 means this is the top group */
+static int count_depth(const struct detgeom_panel_group *group)
+{
+ int depth = 0;
+ assert(group != NULL);
+ do {
+ depth++;
+ group = group->parent;
+ } while ( group != NULL );
+ return depth-1;
+}
+
+
void write_mille(Mille *mille, int n, UnitCell *cell,
struct reflpeak *rps, struct image *image,
- gsl_matrix **Minvs)
+ int max_level, gsl_matrix **Minvs)
{
int i;
+ int depth;
+
+ assert(max_level >= 0);
/* No groups -> no refinement */
if ( image->detgeom->top_group == NULL ) {
@@ -212,8 +229,13 @@ void write_mille(Mille *mille, int n, UnitCell *cell,
/* Global gradients for each hierarchy level, starting at the
* individual panel and working up to the top level */
j = 0;
- levels = 0;
group = image->detgeom->panels[rps[i].peak->pn].group;
+ depth = count_depth(group);
+ while ( depth > max_level ) {
+ depth--;
+ group = group->parent;
+ }
+ levels = 0;
while ( group != NULL ) {
double cx, cy, cz;
diff --git a/libcrystfel/src/crystfel-mille.h b/libcrystfel/src/crystfel-mille.h
index a4b83815..d6602ef0 100644
--- a/libcrystfel/src/crystfel-mille.h
+++ b/libcrystfel/src/crystfel-mille.h
@@ -51,7 +51,7 @@ extern enum gparam mille_unlabel(int n);
extern void write_mille(Mille *mille, int n, UnitCell *cell,
struct reflpeak *rps, struct image *image,
- gsl_matrix **Minvs);
+ int max_level, gsl_matrix **Minvs);
extern void crystfel_mille_delete_last_record(Mille *m);
diff --git a/libcrystfel/src/index.c b/libcrystfel/src/index.c
index f519c3b9..d93664b1 100644
--- a/libcrystfel/src/index.c
+++ b/libcrystfel/src/index.c
@@ -592,7 +592,7 @@ static float real_time()
/* Return non-zero for "success" */
static int try_indexer(struct image *image, IndexingMethod indm,
IndexingPrivate *ipriv, void *mpriv, char *last_task,
- Mille *mille)
+ Mille *mille, int max_mille_level)
{
int i, r;
int n_bad = 0;
@@ -720,7 +720,7 @@ static int try_indexer(struct image *image, IndexingMethod indm,
{
int r;
profile_start("refine");
- r = refine_prediction(image, cr, mille);
+ r = refine_prediction(image, cr, mille, max_mille_level);
profile_end("refine");
if ( r ) {
crystal_set_user_flag(cr, 1);
@@ -921,25 +921,25 @@ static int finished_retry(IndexingMethod indm, IndexingFlags flags,
void index_pattern(struct image *image, IndexingPrivate *ipriv)
{
- index_pattern_4(image, ipriv, NULL, NULL, NULL);
+ index_pattern_4(image, ipriv, NULL, NULL, NULL, 0);
}
void index_pattern_2(struct image *image, IndexingPrivate *ipriv, int *ping)
{
- index_pattern_4(image, ipriv, ping, NULL, NULL);
+ index_pattern_4(image, ipriv, ping, NULL, NULL, 0);
}
void index_pattern_3(struct image *image, IndexingPrivate *ipriv, int *ping,
char *last_task)
{
- index_pattern_4(image, ipriv, ping, last_task, NULL);
+ index_pattern_4(image, ipriv, ping, last_task, NULL, 0);
}
void index_pattern_4(struct image *image, IndexingPrivate *ipriv, int *ping,
- char *last_task, Mille *mille)
+ char *last_task, Mille *mille, int max_mille_level)
{
int n = 0;
ImageFeatureList *orig;
@@ -994,7 +994,7 @@ void index_pattern_4(struct image *image, IndexingPrivate *ipriv, int *ping,
r = try_indexer(image, ipriv->methods[n],
ipriv, ipriv->engine_private[n],
- last_task, mille);
+ last_task, mille, max_mille_level);
success += r;
ntry++;
done = finished_retry(ipriv->methods[n], ipriv->flags,
diff --git a/libcrystfel/src/index.h b/libcrystfel/src/index.h
index fa371276..10d07f08 100644
--- a/libcrystfel/src/index.h
+++ b/libcrystfel/src/index.h
@@ -253,7 +253,8 @@ extern void index_pattern_3(struct image *image, IndexingPrivate *ipriv,
int *ping, char *last_task);
extern void index_pattern_4(struct image *image, IndexingPrivate *ipriv,
- int *ping, char *last_task, Mille *mille);
+ int *ping, char *last_task, Mille *mille,
+ int max_mille_level);
extern void cleanup_indexing(IndexingPrivate *ipriv);
diff --git a/libcrystfel/src/predict-refine.c b/libcrystfel/src/predict-refine.c
index 32d0f77b..d5a3b403 100644
--- a/libcrystfel/src/predict-refine.c
+++ b/libcrystfel/src/predict-refine.c
@@ -796,7 +796,8 @@ static void free_rps_noreflist(struct reflpeak *rps, int n)
}
-int refine_prediction(struct image *image, Crystal *cr, Mille *mille)
+int refine_prediction(struct image *image, Crystal *cr,
+ Mille *mille, int max_mille_level)
{
int n;
int i;
@@ -879,7 +880,8 @@ int refine_prediction(struct image *image, Crystal *cr, Mille *mille)
if ( mille != NULL ) {
profile_start("mille-calc");
- write_mille(mille, n, crystal_get_cell(cr), rps, image, Minvs);
+ write_mille(mille, n, crystal_get_cell(cr), rps, image,
+ max_mille_level, Minvs);
profile_end("mille-calc");
}
diff --git a/libcrystfel/src/predict-refine.h b/libcrystfel/src/predict-refine.h
index 604799c0..080e5923 100644
--- a/libcrystfel/src/predict-refine.h
+++ b/libcrystfel/src/predict-refine.h
@@ -67,7 +67,8 @@ struct reflpeak {
* Prediction refinement: refinement of indexing solutions before integration.
*/
-extern int refine_prediction(struct image *image, Crystal *cr, Mille *mille);
+extern int refine_prediction(struct image *image, Crystal *cr,
+ Mille *mille, int max_mille_level);
extern int refine_radius(Crystal *cr, struct image *image);
diff --git a/libcrystfel/src/utils.c b/libcrystfel/src/utils.c
index 10e4c38e..44faa7ee 100644
--- a/libcrystfel/src/utils.c
+++ b/libcrystfel/src/utils.c
@@ -933,6 +933,20 @@ int file_exists(const char *filename)
}
+int is_dir(const char *filename)
+{
+ struct stat statbuf;
+ int r;
+
+ r = stat(filename, &statbuf);
+ if ( r != 0 ) {
+ return 0;
+ }
+
+ return S_ISDIR(statbuf.st_mode);
+}
+
+
int compare_double(const void *av, const void *bv)
{
double a = *(double *)av;
diff --git a/libcrystfel/src/utils.h b/libcrystfel/src/utils.h
index 3a228b22..cb68069e 100644
--- a/libcrystfel/src/utils.h
+++ b/libcrystfel/src/utils.h
@@ -247,6 +247,7 @@ extern char *safe_strdup(const char *in);
extern void strip_extension(char *bfn);
extern char *load_entire_file(const char *filename);
extern int file_exists(const char *filename);
+extern int is_dir(const char *filename);
extern const char *filename_extension(const char *fn, const char **ext2);
diff --git a/meson.build b/meson.build
index 248a75fa..d0cb0081 100644
--- a/meson.build
+++ b/meson.build
@@ -218,6 +218,7 @@ if gtkdep.found()
'src/gui_fom.c',
'src/gui_export.c',
'src/gui_ambi.c',
+ 'src/gui_align.c',
'src/gui_backend_local.c',
'src/gui_backend_slurm.c',
'src/gui_project.c',
diff --git a/src/align_detector.c b/src/align_detector.c
index bdad7039..bb2eb029 100644
--- a/src/align_detector.c
+++ b/src/align_detector.c
@@ -34,6 +34,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
+#include <dirent.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -255,6 +256,22 @@ static int run_pede()
}
+static void write_children(FILE *fh, const char *dir)
+{
+ DIR *d = opendir(dir);
+ struct dirent *dent = readdir(d);
+
+ while ( dent != NULL ) {
+ if ( dent->d_name[0] == 'm' ) {
+ fprintf(fh, "%s/%s\n", dir, dent->d_name);
+ }
+ dent = readdir(d);
+ }
+
+ closedir(d);
+}
+
+
int main(int argc, char *argv[])
{
int c;
@@ -352,7 +369,7 @@ int main(int argc, char *argv[])
r = stat(argv[i], &statbuf);
if ( r != 0 ) {
- ERROR("File '%s' not found\n", argv[i]);
+ ERROR("File/directory '%s' not found\n", argv[i]);
return 1;
}
@@ -364,7 +381,11 @@ int main(int argc, char *argv[])
}
}
- fprintf(fh, "%s\n", argv[i]);
+ if ( is_dir(argv[i]) ) {
+ write_children(fh, argv[i]);
+ } else {
+ fprintf(fh, "%s\n", argv[i]);
+ }
}
if ( warn_times ) print_time_warning();
diff --git a/src/crystfel_gui.c b/src/crystfel_gui.c
index d0fab3b1..b3d3bc3f 100644
--- a/src/crystfel_gui.c
+++ b/src/crystfel_gui.c
@@ -56,6 +56,7 @@
#include "gui_merge.h"
#include "gui_fom.h"
#include "gui_export.h"
+#include "gui_align.h"
#include "gui_ambi.h"
#include "gui_project.h"
#include "version.h"
@@ -467,34 +468,6 @@ static gint rescan_sig(GtkWidget *widget, struct crystfelproject *proj)
}
-static gint detector_shift_sig(GtkWidget *widget, struct crystfelproject *proj)
-{
- struct gui_indexing_result *res = current_result(proj);
- if ( res != NULL ) {
- GError *error = NULL;
- const gchar *args[64];
- GSubprocess *sp;
- int i;
- args[0] = "detector-shift";
- args[1] = "--";
- for ( i=0; i<MIN(res->n_streams, 60); i++ ) {
- args[2+i] = res->streams[i];
- }
- args[2+res->n_streams] = NULL;
-
- sp = g_subprocess_newv(args, G_SUBPROCESS_FLAGS_NONE, &error);
- if ( sp == NULL ) {
- ERROR("Failed to invoke detector-shift: %s\n",
- error->message);
- g_error_free(error);
- }
- } else {
- ERROR("Select indexing result first!\n");
- }
- return FALSE;
-}
-
-
static gint peakogram_sig(GtkWidget *widget, struct crystfelproject *proj)
{
struct gui_indexing_result *res = current_result(proj);
@@ -825,7 +798,6 @@ static void add_menu_bar(struct crystfelproject *proj, GtkWidget *vbox)
" <menuitem name=\"rescan\" action=\"RescanAction\" />"
" <menuitem name=\"jumpframe\" action=\"JumpFrameAction\" />"
" <separator />"
- " <menuitem name=\"detectorshift\" action=\"DetectorShiftAction\" />"
" <menuitem name=\"peakogram\" action=\"PeakogramAction\" />"
"</menu>"
"<menu name=\"help\" action=\"HelpAction\">"
@@ -852,8 +824,6 @@ static void add_menu_bar(struct crystfelproject *proj, GtkWidget *vbox)
G_CALLBACK(rescan_sig) },
{ "JumpFrameAction", NULL, "Jump to frame", NULL, NULL,
G_CALLBACK(goto_frame_sig) },
- { "DetectorShiftAction", NULL, "Check detector shift", NULL, NULL,
- G_CALLBACK(detector_shift_sig) },
{ "PeakogramAction", NULL, "Check detector saturation (peakogram)", NULL, NULL,
G_CALLBACK(peakogram_sig) },
@@ -933,6 +903,8 @@ static void add_task_buttons(GtkWidget *vbox, struct crystfelproject *proj)
G_CALLBACK(index_all_sig), proj);
add_button(vbox, "Determine unit cell", "crystfel-unitcell",
G_CALLBACK(cell_explorer_sig), proj);
+ add_button(vbox, "Refine detector geometry", "crystfel-geometry",
+ G_CALLBACK(align_sig), proj);
add_button(vbox, "Indexing ambiguity", "crystfel-ambiguity",
G_CALLBACK(ambi_sig), proj);
add_button(vbox, "Merge", "crystfel-merge",
diff --git a/src/crystfelindexingopts.c b/src/crystfelindexingopts.c
index d1cf515f..50a36748 100644
--- a/src/crystfelindexingopts.c
+++ b/src/crystfelindexingopts.c
@@ -734,6 +734,7 @@ static GtkWidget *stream_parameters(CrystFELIndexingOpts *io)
GtkCellRenderer *renderer;
GtkWidget *button;
GtkWidget *hbox;
+ GtkWidget *label;
box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8);
gtk_container_set_border_width(GTK_CONTAINER(box), 8);
@@ -759,6 +760,24 @@ static GtkWidget *stream_parameters(CrystFELIndexingOpts *io)
gtk_widget_set_tooltip_text(io->no_refls_in_stream,
"--no-refls-in-stream");
+ io->millepede = gtk_check_button_new_with_label("Write calibration data for detector alignment");
+ gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(io->millepede),
+ FALSE, FALSE, 4.0);
+ gtk_widget_set_tooltip_text(io->millepede, "--mille");
+
+ hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8);
+ gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(hbox),
+ FALSE, FALSE, 0.0);
+ label = gtk_label_new("Maximum refinement level:");
+ gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(label),
+ FALSE, FALSE, 16.0);
+ io->max_mille = gtk_spin_button_new_with_range(0.0, 9.0, 1.0);
+ gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(io->max_mille),
+ FALSE, FALSE, 4.0);
+ gtk_widget_set_tooltip_text(io->max_mille, "--max-mille-level");
+ i_disable_if_not(io->millepede, io->max_mille);
+ i_disable_if_not(io->millepede, label);
+
io->copy_metadata_store = gtk_list_store_new(1, G_TYPE_STRING);
treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(io->copy_metadata_store));
@@ -1055,6 +1074,14 @@ int crystfel_indexing_opts_get_exclude_reflections(CrystFELIndexingOpts *opts)
}
+int crystfel_indexing_opts_get_millepede(CrystFELIndexingOpts *opts,
+ int *pmax_level)
+{
+ *pmax_level = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(opts->max_mille));
+ return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(opts->millepede));
+}
+
+
char **crystfel_indexing_opts_get_metadata_to_copy(CrystFELIndexingOpts *opts,
int *pn)
{
@@ -1381,6 +1408,14 @@ void crystfel_indexing_opts_set_integration_radii(CrystFELIndexingOpts *opts,
}
+void crystfel_indexing_opts_set_millepede(CrystFELIndexingOpts *opts,
+ int enable, int max_level)
+{
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(opts->max_mille), max_level);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(opts->millepede), enable);
+}
+
+
void crystfel_indexing_opts_set_metadata_to_copy(CrystFELIndexingOpts *opts,
char *const *headers,
int n)
diff --git a/src/crystfelindexingopts.h b/src/crystfelindexingopts.h
index 567bdb8e..e87d2dac 100644
--- a/src/crystfelindexingopts.h
+++ b/src/crystfelindexingopts.h
@@ -96,6 +96,8 @@ struct _crystfelindexingopts
GtkWidget *exclude_nonhits;
GtkWidget *no_peaks_in_stream;
GtkWidget *no_refls_in_stream;
+ GtkWidget *millepede;
+ GtkWidget *max_mille;
GtkListStore *copy_metadata_store;
};
@@ -133,6 +135,8 @@ extern int crystfel_indexing_opts_get_exclude_peaks(CrystFELIndexingOpts *opts);
extern int crystfel_indexing_opts_get_exclude_reflections(CrystFELIndexingOpts *opts);
extern char **crystfel_indexing_opts_get_metadata_to_copy(CrystFELIndexingOpts *opts,
int *n);
+extern int crystfel_indexing_opts_get_millepede(CrystFELIndexingOpts *opts,
+ int *pmax_level);
extern double crystfel_indexing_opts_get_fixed_profile_radius(CrystFELIndexingOpts *opts,
int *active);
extern double crystfel_indexing_opts_get_fixed_divergence(CrystFELIndexingOpts *opts);
@@ -191,6 +195,10 @@ extern void crystfel_indexing_opts_set_exclude_peaks(CrystFELIndexingOpts *opts,
int flag);
extern void crystfel_indexing_opts_set_exclude_reflections(CrystFELIndexingOpts *opts,
int flag);
+
+extern void crystfel_indexing_opts_set_millepede(CrystFELIndexingOpts *opts,
+ int enable, int max_level);
+
extern void crystfel_indexing_opts_set_fixed_profile_radius(CrystFELIndexingOpts *opts,
int active,
double val);
diff --git a/src/gui_align.c b/src/gui_align.c
new file mode 100644
index 00000000..b712681b
--- /dev/null
+++ b/src/gui_align.c
@@ -0,0 +1,235 @@
+/*
+ * gui_align.c
+ *
+ * Align detector via CrystFEL GUI
+ *
+ * Copyright © 2024 Deutsches Elektronen-Synchrotron DESY,
+ * a research centre of the Helmholtz Association.
+ *
+ * Authors:
+ * 2024 Thomas White <taw@physics.org>
+ *
+ * This file is part of CrystFEL.
+ *
+ * CrystFEL is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * CrystFEL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with CrystFEL. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <gtk/gtk.h>
+#include <assert.h>
+
+#include "version.h"
+#include "gui_project.h"
+#include "crystfel_gui.h"
+#include "gtk-util-routines.h"
+
+
+struct align_window
+{
+ struct crystfelproject *proj;
+ GtkWidget *window;
+ GtkWidget *input_combo;
+ GtkWidget *out_of_plane;
+ GtkWidget *level;
+};
+
+
+
+static int run_align(const char *input_name, int level, int out_of_plane,
+ const char *out_geom, struct crystfelproject *proj)
+{
+ GSubprocess *sp;
+ struct gui_indexing_result *res;
+ GError *error;
+ const char *cmdline[16];
+ char level_str[64];
+ GFile *gstream;
+ GFile *gworkdir;
+ GFile *ggeom;
+ GFile *gmilledir;
+ char *input_geom;
+ int i;
+ char *mille_dir;
+
+ res = find_indexing_result_by_name(proj, input_name);
+ if ( res == NULL ) {
+ ERROR("Results for '%s' not found!\n", input_name);
+ return 1;
+ }
+
+ /* Figure out working directory for indexing job */
+ if ( res->n_streams < 1 ) {
+ ERROR("No streams?\n");
+ return 1;
+ }
+ gstream = g_file_new_for_path(res->streams[0]);
+ gworkdir = g_file_get_parent(gstream);
+ g_object_unref(gstream);
+
+ /* Look for Millepede files */
+ gmilledir = g_file_get_child(gworkdir, "mille-data");
+ if ( !g_file_query_exists(gmilledir, NULL) ) {
+ ERROR("No detector alignment data found for indexing run '%s'\n", input_name);
+ return 1;
+ }
+ mille_dir = g_file_get_path(gmilledir);
+ g_object_unref(gmilledir);
+
+ /* Input geometry file */
+ ggeom = g_file_get_child(gworkdir, "detector.geom");
+ input_geom = g_file_get_path(ggeom);
+ g_object_unref(ggeom);
+
+ /* Build command line */
+ snprintf(level_str, 63, "%i", level);
+ cmdline[0] = "align_detector";
+ cmdline[1] = "-g";
+ cmdline[2] = input_geom;
+ cmdline[3] = "--level";
+ cmdline[4] = level_str;
+ cmdline[5] = "-o";
+ cmdline[6] = out_geom;
+ if ( out_of_plane ) {
+ cmdline[7] = "--out-of-plane";
+ cmdline[8] = mille_dir;
+ cmdline[9] = NULL;
+ } else {
+ cmdline[7] = mille_dir;
+ cmdline[8] = NULL;
+ }
+
+ STATUS("Running program: ");
+ i = 0;
+ while ( cmdline[i] != NULL ) {
+ STATUS("%s ", cmdline[i++]);
+ }
+ STATUS("\n");
+
+ error = NULL;
+ sp = g_subprocess_newv(cmdline, G_SUBPROCESS_FLAGS_NONE, &error);
+ if ( sp == NULL ) {
+ ERROR("Failed to run align_detector: %s\n", error->message);
+ g_error_free(error);
+ return 1;
+ }
+
+ g_object_unref(gworkdir);
+ g_free(mille_dir);
+ g_free(input_geom);
+
+ return 0;
+}
+
+
+static void align_response_sig(GtkWidget *dialog, gint resp,
+ struct align_window *win)
+{
+ int r = 0;
+
+ if ( resp == GTK_RESPONSE_ACCEPT ) {
+
+ int level;
+ const char *input_name;
+ int out_of_plane;
+ gchar *filename;
+
+ level = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(win->level));
+
+ input_name = get_combo_id(win->input_combo);
+ if ( input_name == NULL ) {
+ ERROR("Please select the input\n");
+ r = 1;
+ }
+
+ out_of_plane = get_bool(win->out_of_plane);
+ filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
+
+ r = run_align(input_name, level, out_of_plane, filename, win->proj);
+
+ g_free(filename);
+ }
+
+ if ( !r ) gtk_widget_destroy(dialog);
+}
+
+
+gint align_sig(GtkWidget *widget, struct crystfelproject *proj)
+{
+ GtkWidget *hbox;
+ GtkWidget *label;
+ struct align_window *win;
+ int i;
+
+ win = malloc(sizeof(struct align_window));
+ if ( win == NULL ) return 0;
+
+ win->proj = proj;
+
+ win->window = gtk_file_chooser_dialog_new("Align detector",
+ GTK_WINDOW(proj->window),
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
+ NULL);
+ gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(win->window),
+ TRUE);
+
+ hbox = gtk_hbox_new(FALSE, 0.0);
+ gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(win->window),
+ GTK_WIDGET(hbox));
+ gtk_container_set_border_width(GTK_CONTAINER(hbox), 4);
+
+ label = gtk_label_new("Refine using indexing result:");
+ gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(label),
+ FALSE, FALSE, 4.0);
+ win->input_combo = gtk_combo_box_text_new();
+ gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(win->input_combo),
+ FALSE, FALSE, 4.0);
+ for ( i=0; i<proj->n_results; i++ ) {
+ gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(win->input_combo),
+ proj->results[i].name,
+ proj->results[i].name);
+ }
+ gtk_combo_box_set_active_id(GTK_COMBO_BOX(win->input_combo),
+ selected_result(proj));
+
+ label = gtk_label_new("Hierarchy level:");
+ gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(label),
+ FALSE, FALSE, 16.0);
+ win->level = gtk_spin_button_new_with_range(0.0, 9.0, 1.0);
+ gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(win->level),
+ FALSE, FALSE, 4.0);
+ gtk_widget_set_tooltip_text(win->level, "--level");
+
+ win->out_of_plane = gtk_check_button_new_with_label("Include out-of-plane positions and tilts");
+ gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(win->out_of_plane),
+ FALSE, FALSE, 4.0);
+ gtk_widget_set_tooltip_text(win->out_of_plane, "--out-of-plane");
+
+ g_signal_connect(G_OBJECT(win->window), "response",
+ G_CALLBACK(align_response_sig), win);
+
+ gtk_dialog_set_default_response(GTK_DIALOG(win->window),
+ GTK_RESPONSE_CLOSE);
+ gtk_widget_show_all(win->window);
+
+ return FALSE;
+}
diff --git a/src/gui_align.h b/src/gui_align.h
new file mode 100644
index 00000000..50250e6a
--- /dev/null
+++ b/src/gui_align.h
@@ -0,0 +1,38 @@
+/*
+ * gui_align.h
+ *
+ * Align detector via CrystFEL GUI
+ *
+ * Copyright © 2024 Deutsches Elektronen-Synchrotron DESY,
+ * a research centre of the Helmholtz Association.
+ *
+ * Authors:
+ * 2024 Thomas White <taw@physics.org>
+ *
+ * This file is part of CrystFEL.
+ *
+ * CrystFEL is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * CrystFEL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with CrystFEL. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef GUI_ALIGN_H
+#define GUI_ALIGN_H
+
+#include <gtk/gtk.h>
+
+#include "gui_project.h"
+
+extern gint align_sig(GtkWidget *widget, struct crystfelproject *proj);
+
+#endif
diff --git a/src/gui_backend_local.c b/src/gui_backend_local.c
index 03761474..71c94871 100644
--- a/src/gui_backend_local.c
+++ b/src/gui_backend_local.c
@@ -534,6 +534,10 @@ static void *run_indexing(const char *job_title,
gchar *files_rel_filename;
gchar *stream_rel_filename;
gchar *harvest_rel_filename;
+ gchar *mille_rel_filename;
+ GFile *ggeom;
+ GFile *ggeomcopy;
+ GError *error;
workdir = make_job_folder(job_title, job_notes);
if ( workdir == NULL ) return NULL;
@@ -555,6 +559,17 @@ static void *run_indexing(const char *job_title,
files_rel_filename = relative_to_cwd(workdir, "files.lst");
stream_rel_filename = relative_to_cwd(workdir, "crystfel.stream");
harvest_rel_filename = relative_to_cwd(workdir, "parameters.json");
+ mille_rel_filename = relative_to_cwd(workdir, "mille-data");
+
+ /* Copy geometry file into working directory
+ * Used for geometry refinement, not indexing! */
+ ggeom = g_file_new_for_path(proj->geom_filename);
+ ggeomcopy = g_file_get_child(workdir, "detector.geom");
+ error = NULL;
+ g_file_copy(ggeom, ggeomcopy, G_FILE_COPY_BACKUP | G_FILE_COPY_ALL_METADATA,
+ NULL, NULL, NULL, &error);
+ g_object_unref(ggeom);
+ g_object_unref(ggeomcopy);
if ( !write_indexamajig_script(sc_rel_filename,
proj->geom_filename,
@@ -564,6 +579,7 @@ static void *run_indexing(const char *job_title,
stdout_rel_filename,
stderr_rel_filename,
harvest_rel_filename,
+ mille_rel_filename,
NULL,
&proj->peak_search_params,
&proj->indexing_params,
@@ -598,6 +614,7 @@ static void *run_indexing(const char *job_title,
free(stdout_rel_filename);
free(stderr_rel_filename);
free(harvest_rel_filename);
+ free(mille_rel_filename);
return job;
}
diff --git a/src/gui_backend_slurm.c b/src/gui_backend_slurm.c
index 3961a92d..f5ad31c5 100644
--- a/src/gui_backend_slurm.c
+++ b/src/gui_backend_slurm.c
@@ -797,6 +797,7 @@ static void *run_indexing(const char *job_title,
gchar *files_rel_filename;
gchar *stream_rel_filename;
gchar *harvest_rel_filename;
+ gchar *mille_rel_filename;
char *slurm_prologue;
workdir = make_job_folder(job_title, job_notes);
@@ -842,6 +843,7 @@ static void *run_indexing(const char *job_title,
stdout_rel_filename = relative_to_cwd(workdir, "stdout-%a.log");
stderr_rel_filename = relative_to_cwd(workdir, "stderr-%a.log");
harvest_rel_filename = relative_to_cwd(workdir, "parameters.json");
+ mille_rel_filename = relative_to_cwd(workdir, "mille-data");
slurm_prologue = sbatch_bits(&opts->common, job_title, array_inx,
stdout_rel_filename, stderr_rel_filename);
@@ -853,6 +855,7 @@ static void *run_indexing(const char *job_title,
stream_rel_filename,
NULL, NULL,
harvest_rel_filename,
+ mille_rel_filename,
serial_offs,
&proj->peak_search_params,
&proj->indexing_params,
@@ -888,6 +891,7 @@ static void *run_indexing(const char *job_title,
free(stdout_rel_filename);
free(stderr_rel_filename);
free(harvest_rel_filename);
+ free(mille_rel_filename);
g_object_unref(workdir);
return job;
diff --git a/src/gui_index.c b/src/gui_index.c
index aa2301ef..2cc8e8db 100644
--- a/src/gui_index.c
+++ b/src/gui_index.c
@@ -140,6 +140,8 @@ static void get_indexing_opts(struct crystfelproject *proj,
proj->indexing_params.exclude_nonhits = crystfel_indexing_opts_get_exclude_blanks(opts);
proj->indexing_params.exclude_peaks = crystfel_indexing_opts_get_exclude_peaks(opts);
proj->indexing_params.exclude_refls = crystfel_indexing_opts_get_exclude_reflections(opts);
+ proj->indexing_params.millepede = crystfel_indexing_opts_get_millepede(opts,
+ &proj->indexing_params.max_mille_level);
proj->indexing_params.metadata_to_copy = crystfel_indexing_opts_get_metadata_to_copy(opts,
&proj->indexing_params.n_metadata);
}
@@ -383,6 +385,9 @@ static void set_indexing_opts(struct crystfelproject *proj,
proj->indexing_params.exclude_peaks);
crystfel_indexing_opts_set_exclude_reflections(opts,
proj->indexing_params.exclude_refls);
+ crystfel_indexing_opts_set_millepede(opts,
+ proj->indexing_params.millepede,
+ proj->indexing_params.max_mille_level);
crystfel_indexing_opts_set_metadata_to_copy(opts,
proj->indexing_params.metadata_to_copy,
proj->indexing_params.n_metadata);
@@ -846,6 +851,7 @@ static char **indexamajig_command_line(const char *geom_filename,
const char *files_list,
const char *stream_filename,
const char *harvest_filename,
+ const char *mille_filename,
const char *serial_start,
struct peak_params *peak_search_params,
struct index_params *indexing_params,
@@ -997,6 +1003,11 @@ static char **indexamajig_command_line(const char *geom_filename,
if ( indexing_params->exclude_nonhits ) add_arg(args, n_args++, "--no-non-hits-in-stream");
if ( indexing_params->exclude_peaks ) add_arg(args, n_args++, "--no-peaks-in-stream");
if ( indexing_params->exclude_refls ) add_arg(args, n_args++, "--no-refls-in-stream");
+ if ( indexing_params->millepede ) {
+ add_arg(args, n_args++, "--mille");
+ add_arg_string(args, n_args++, "mille-dir", mille_filename);
+ add_arg_int(args, n_args++, "max-mille-level", indexing_params->max_mille_level);
+ }
for ( i=0; i<indexing_params->n_metadata; i++ ) {
add_arg_string(args, n_args++, "copy-header",
indexing_params->metadata_to_copy[i]);
@@ -1079,6 +1090,7 @@ int write_indexamajig_script(const char *script_filename,
const char *stdout_filename,
const char *stderr_filename,
const char *harvest_filename,
+ const char *mille_filename,
const char *serial_start,
struct peak_params *peak_search_params,
struct index_params *indexing_params,
@@ -1095,6 +1107,7 @@ int write_indexamajig_script(const char *script_filename,
files_list,
stream_filename,
harvest_filename,
+ mille_filename,
serial_start,
peak_search_params,
indexing_params,
diff --git a/src/gui_index.h b/src/gui_index.h
index 2f5c1a56..33594e8e 100644
--- a/src/gui_index.h
+++ b/src/gui_index.h
@@ -51,6 +51,7 @@ extern int write_indexamajig_script(const char *script_filename,
const char *stdout_filename,
const char *stderr_filename,
const char *harvest_filename,
+ const char *mille_filename,
const char *serial_start,
struct peak_params *peak_search_params,
struct index_params *indexing_params,
diff --git a/src/gui_project.c b/src/gui_project.c
index 32d6473c..c77e2704 100644
--- a/src/gui_project.c
+++ b/src/gui_project.c
@@ -429,6 +429,12 @@ static void parse_stream_opt(const char *key, const char *val,
if ( strcmp(key, "stream.exclude_refls") == 0 ) {
ip->exclude_refls = parse_int(val);
}
+ if ( strcmp(key, "stream.millepede") == 0 ) {
+ ip->millepede = parse_int(val);
+ }
+ if ( strcmp(key, "stream.max_mille_level") == 0 ) {
+ ip->max_mille_level = parse_int(val);
+ }
if ( strcmp(key, "stream.metadata") == 0 ) {
add_metadata_to_copy(ip, val);
}
@@ -1048,6 +1054,10 @@ int save_project(struct crystfelproject *proj)
proj->indexing_params.exclude_peaks);
fprintf(fh, "stream.exclude_refls %i\n",
proj->indexing_params.exclude_refls);
+ fprintf(fh, "stream.millepede %i\n",
+ proj->indexing_params.millepede);
+ fprintf(fh, "stream.max_mille_level %i\n",
+ proj->indexing_params.max_mille_level);
if ( proj->indexing_params.metadata_to_copy != NULL ) {
int i;
for ( i=0; i<proj->indexing_params.n_metadata; i++ ) {
@@ -1287,6 +1297,8 @@ int default_project(struct crystfelproject *proj)
proj->indexing_params.exclude_nonhits = 0;
proj->indexing_params.exclude_peaks = 0;
proj->indexing_params.exclude_refls = 0;
+ proj->indexing_params.millepede = 1;
+ proj->indexing_params.max_mille_level = 1;
proj->indexing_params.metadata_to_copy = NULL;
proj->indexing_params.n_metadata = 0;
proj->indexing_params.fix_profile_radius = 0.01e9;
diff --git a/src/gui_project.h b/src/gui_project.h
index 318f9453..6d704b81 100644
--- a/src/gui_project.h
+++ b/src/gui_project.h
@@ -87,6 +87,8 @@ struct index_params {
int exclude_refls;
char **metadata_to_copy;
int n_metadata;
+ int millepede;
+ int max_mille_level;
};
struct merging_params {
diff --git a/src/indexamajig.c b/src/indexamajig.c
index cca7dbba..ce8b2cbf 100644
--- a/src/indexamajig.c
+++ b/src/indexamajig.c
@@ -748,6 +748,18 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state)
args->iargs.milledir = strdup(arg);
break;
+ case 418 :
+ if (sscanf(arg, "%d", &args->iargs.max_mille_level) != 1)
+ {
+ ERROR("Invalid value for --max-mille-level\n");
+ return EINVAL;
+ }
+ if ( args->iargs.max_mille_level < 0 ) {
+ ERROR("Invalid value for --max-mille-level\n");
+ return EINVAL;
+ }
+ break;
+
/* ---------- Integration ---------- */
case 501 :
@@ -996,6 +1008,7 @@ int main(int argc, char *argv[])
args.iargs.data_format = DATA_SOURCE_TYPE_UNKNOWN;
args.iargs.mille = 0;
args.iargs.milledir = strdup(".");
+ args.iargs.max_mille_level = 99;
argp_program_version_hook = show_version;
@@ -1122,8 +1135,8 @@ int main(int argc, char *argv[])
"Estimate of the camera length, in metres."},
{"mille", 416, NULL, 0,
"Generate data for detector geometry refinement using Millepede"},
- {"mille-dir", 417, "dirname", 0,
- "Save Millepede data in folder"},
+ {"mille-dir", 417, "dirname", 0, "Save Millepede data in folder"},
+ {"max-mille-level", 418, "n", 0, "Maximum geometry refinement level"},
{NULL, 0, 0, OPTION_DOC, "Integration options:", 5},
{"integration", 501, "method", OPTION_NO_USAGE, "Integration method"},
diff --git a/src/process_image.c b/src/process_image.c
index 57a994ac..2f856594 100644
--- a/src/process_image.c
+++ b/src/process_image.c
@@ -420,7 +420,7 @@ void process_image(const struct index_args *iargs, struct pattern_args *pargs,
set_last_task(last_task, "indexing");
profile_start("index");
index_pattern_4(image, iargs->ipriv, &sb_shared->pings[cookie],
- last_task, mille);
+ last_task, mille, iargs->max_mille_level);
profile_end("index");
r = chdir(rn);
diff --git a/src/process_image.h b/src/process_image.h
index f5e27631..10c9ec31 100644
--- a/src/process_image.h
+++ b/src/process_image.h
@@ -76,6 +76,7 @@ struct index_args
int n_threads;
int mille;
char *milledir;
+ int max_mille_level;
/* Integration */
IntegrationMethod int_meth;