~ubuntu-branches/ubuntu/vivid/relion/vivid

« back to all changes in this revision

Viewing changes to src/gui_jobwindow.cpp

  • Committer: Package Import Robot
  • Author(s): Roland Fehrenbacher
  • Date: 2014-10-23 11:52:48 UTC
  • Revision ID: package-import@ubuntu.com-20141023115248-m3y48dxwl8sqxv9d
Tags: upstream-1.3+dfsg
ImportĀ upstreamĀ versionĀ 1.3+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
 *
 
3
 * Author: "Sjors H.W. Scheres"
 
4
 * MRC Laboratory of Molecular Biology
 
5
 *
 
6
 * This program is free software; you can redistribute it and/or modify
 
7
 * it under the terms of the GNU General Public License as published by
 
8
 * the Free Software Foundation; either version 2 of the License, or
 
9
 * (at your option) any later version.
 
10
 *
 
11
 * This program is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 * GNU General Public License for more details.
 
15
 *
 
16
 * This complete copyright notice must be included in any revised version of the
 
17
 * source code. Additional authorship citations may be added, but existing
 
18
 * author citations must be preserved.
 
19
 ***************************************************************************/
 
20
#include "src/gui_jobwindow.h"
 
21
 
 
22
RelionJobWindow::RelionJobWindow(int nr_tabs, bool _has_mpi, bool _has_thread, bool _has_run,
 
23
                int x, int y, int w, int h, const char* title) : Fl_Box(x,y,w,h,title)
 
24
{
 
25
 
 
26
        current_y = y;
 
27
        has_mpi = _has_mpi;
 
28
        has_thread = _has_thread;
 
29
 
 
30
    // Set up tabs
 
31
    if (nr_tabs >= 1) // there is always the running tab, which is not counted on the input nr_tabs!
 
32
    {
 
33
        tabs = new Fl_Tabs(x, current_y, w, h - MENUHEIGHT);
 
34
        current_y += TABHEIGHT;
 
35
        tabs->begin();
 
36
                tab1 = new Fl_Group(x, current_y , w, h - MENUHEIGHT, "");
 
37
                tab1->end();
 
38
                tab1->color(GUI_BACKGROUND_COLOR);
 
39
                tab1->selection_color(GUI_BACKGROUND_COLOR2);
 
40
                if (nr_tabs >= 2)
 
41
                {
 
42
 
 
43
                        tab2 = new Fl_Group(x, current_y , w, h - MENUHEIGHT, "");
 
44
                        tab2->end();
 
45
                        tab2->color(GUI_BACKGROUND_COLOR);
 
46
                        tab2->selection_color(GUI_BACKGROUND_COLOR2);
 
47
                }
 
48
                if (nr_tabs >= 3)
 
49
                {
 
50
                        tab3 = new Fl_Group(x, current_y, w, h - MENUHEIGHT, "");
 
51
                        tab3->end();
 
52
                        tab3->color(GUI_BACKGROUND_COLOR);
 
53
                        tab3->selection_color(GUI_BACKGROUND_COLOR2);
 
54
                }
 
55
                if (nr_tabs >= 4)
 
56
                {
 
57
                        tab4 = new Fl_Group(x, current_y, w, h - MENUHEIGHT, "");
 
58
                        tab4->end();
 
59
                        tab4->color(GUI_BACKGROUND_COLOR);
 
60
                        tab4->selection_color(GUI_BACKGROUND_COLOR2);
 
61
                }
 
62
                if (nr_tabs >= 5)
 
63
                {
 
64
                        tab5 = new Fl_Group(x, current_y, w, h - MENUHEIGHT, "");
 
65
                        tab5->end();
 
66
                        tab5->color(GUI_BACKGROUND_COLOR);
 
67
                        tab5->selection_color(GUI_BACKGROUND_COLOR2);
 
68
                }
 
69
                if (nr_tabs >= 6)
 
70
                {
 
71
                        tab6 = new Fl_Group(x, current_y, w, h - MENUHEIGHT, "");
 
72
                        tab6->end();
 
73
                        tab6->color(GUI_BACKGROUND_COLOR);
 
74
                        tab6->selection_color(GUI_BACKGROUND_COLOR2);
 
75
                }
 
76
                if (nr_tabs >= 7)
 
77
                {
 
78
                        std::cerr << "ERROR: only 6 job-specific tabs implemented..." << std::endl;
 
79
                        exit(1);
 
80
                }
 
81
                current_y += 15;
 
82
            start_y = current_y;
 
83
 
 
84
            if (_has_run)
 
85
            {
 
86
                        runtab = new Fl_Group(x, current_y, w, h - MENUHEIGHT, "");
 
87
                        runtab->label("Running");
 
88
                        setupRunTab();
 
89
                        runtab->end();
 
90
                        runtab->color(GUI_BACKGROUND_COLOR);
 
91
                        runtab->selection_color(GUI_BACKGROUND_COLOR2);
 
92
            }
 
93
 
 
94
            tabs->end();
 
95
 
 
96
    }
 
97
 
 
98
}
 
99
 
 
100
void RelionJobWindow::resetHeight()
 
101
{
 
102
        current_y = start_y;
 
103
}
 
104
 
 
105
void RelionJobWindow::setupRunTab()
 
106
{
 
107
    resetHeight();
 
108
 
 
109
        if (has_mpi)
 
110
                nr_mpi.place(current_y, "Number of MPI procs:", 1, 1, 64, 1, "Number of MPI nodes to use in parallel. When set to 1, MPI will not be used.");
 
111
 
 
112
        if (has_thread)
 
113
        {
 
114
                nr_threads.place(current_y, "Number of threads:", 1, 1, 16, 1, "Number of shared-memory (POSIX) threads to use in parallel. \
 
115
When set to 1, no multi-threading will be used. Multi-threading is often useful in 3D refinements to have more memory. 2D class averaging often proceeds more efficiently without threads.");
 
116
 
 
117
                ram_per_thread.place(current_y, "Available RAM (in Gb) per thread:", 4, 1, 16, 1, "Computer memory in Gigabytes that is avaliable for each thread. This will only affect some of the warnings about required computer memory.");
 
118
 
 
119
        }
 
120
 
 
121
        // Add a little spacer
 
122
        if (has_mpi || has_thread)
 
123
                current_y += STEPY/2;
 
124
 
 
125
    // Set up queue groups for running tab
 
126
    queue_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
 
127
    queue_group->end();
 
128
 
 
129
    do_queue.place(current_y, "Submit to queue?", false, "Is set to Yes, the job will be submit to a queue, otherwise \
 
130
the job will be executed locally. Note that only MPI jobs may be sent to a queue.", queue_group);
 
131
 
 
132
        queue_group->begin();
 
133
 
 
134
        queuename.place(current_y, "Queue name: ", "openmpi", "Name of the queue to which to submit the job.");
 
135
 
 
136
        qsub.place(current_y, "Queue submit command:", "qsub", "Name of the command used to submit scripts to the queue, e.g. qsub or bsub.\n\n\
 
137
Note that the person who installed RELION should have made a custom script for your cluster/queue setup. Check this is the case \
 
138
(or create your own script following the RELION WIKI) if you have trouble submitting jobs.");
 
139
 
 
140
        // Two additional options that may be set through environment variables RELION_QSUB_EXTRA1 and RELION_QSUB_EXTRA2 (for more flexibility)
 
141
        char * extra1_text = getenv ("RELION_QSUB_EXTRA1");
 
142
        if (extra1_text != NULL)
 
143
        {
 
144
                have_extra1 = true;
 
145
                char * extra1_default = getenv ("RELION_QSUB_EXTRA1_DEFAULT");
 
146
                char emptychar[] = "";
 
147
                if (extra1_default == NULL)
 
148
                        extra1_default=emptychar;
 
149
                qsub_extra1.place(current_y, extra1_text, extra1_default, "Extra option to pass to the qsub template script. \
 
150
Any occurrences of XXXextra1XXX will be changed by this value.");
 
151
        }
 
152
        else
 
153
                have_extra1 = false;
 
154
 
 
155
        char * extra2_text = getenv ("RELION_QSUB_EXTRA2");
 
156
        if (extra2_text != NULL)
 
157
        {
 
158
                have_extra2 = true;
 
159
                char * extra2_default = getenv ("RELION_QSUB_EXTRA2_DEFAULT");
 
160
                char emptychar[] = "";
 
161
                if (extra2_default == NULL)
 
162
                        extra2_default=emptychar;
 
163
                qsub_extra2.place(current_y, extra2_text, extra2_default, "Extra option to pass to the qsub template script. \
 
164
Any occurrences of XXXextra2XXX will be changed by this value.");
 
165
        }
 
166
        else
 
167
                have_extra2 = false;
 
168
 
 
169
 
 
170
        // Check for environment variable RELION_QSUB_TEMPLATE
 
171
        char * default_location = getenv ("RELION_QSUB_TEMPLATE");
 
172
        if (default_location==NULL)
 
173
        {
 
174
                char mydefault[]=DEFAULTQSUBLOCATION;
 
175
                default_location=mydefault;
 
176
        }
 
177
 
 
178
        qsubscript.place(current_y, "Standard submission script:", default_location, "Script Files (*.{csh,sh,bash,script})",
 
179
"The template for your standard queue job submission script. \
 
180
Its default location may be changed by setting the environment variable RELION_QSUB_TEMPLATE. \
 
181
In the template script a number of variables will be replaced: \n \
 
182
XXXcommandXXX = relion command + arguments; \n \
 
183
XXXqueueXXX = The queue name; \n \
 
184
XXXmpinodesXXX = The number of MPI nodes; \n \
 
185
XXXthreadsXXX = The number of threads; \n \
 
186
XXXcoresXXX = The number of MPI nodes * nr_threads; \n \
 
187
If these options are not enough for your standard jobs, you may define two extra variables: XXXextra1XXX and XXXextra2XXX \
 
188
Their help text is set by the environment variables RELION_QSUB_EXTRA1 and RELION_QSUB_EXTRA2 \
 
189
For example, setenv RELION_QSUB_EXTRA1 \"Max number of hours in queue\" will result in an additional (text) ein the GUI \
 
190
Any variables XXXextra1XXX in the template script will be replaced by the corresponding value.\
 
191
Likewise, default values for the extra entries can be set through environment variables RELION_QSUB_EXTRA1_DEFAULT and  RELION_QSUB_EXTRA2_DEFAULT. \
 
192
But note that (unlike all other entries in the GUI) the extra values are not remembered from one run to the other.");
 
193
 
 
194
 
 
195
        queue_group->end();
 
196
        do_queue.cb_menu_i(); // This is to make the default effective
 
197
 
 
198
    // Add a little spacer
 
199
    current_y += STEPY/2;
 
200
 
 
201
    other_args.place(current_y, "Additional arguments:", "", "In this box command-line arguments may be provided that are not generated by the GUI. \
 
202
This may be useful for testing developmental options and/or expert use of the program. \
 
203
The command 'relion_refine' will print a list of possible options.");
 
204
 
 
205
}
 
206
 
 
207
void RelionJobWindow::toggle_new_continue(bool is_continue)
 
208
{
 
209
        std::cerr << "toggle default is_continue=" << is_continue << std::endl;
 
210
        return;
 
211
}
 
212
 
 
213
void RelionJobWindow::openWriteFile(std::string fn, std::ofstream &fh)
 
214
{
 
215
        fh.open((fn).c_str(), std::ios::out);
 
216
    if (!fh)
 
217
    {
 
218
        std::cerr << "Cannot write to file: "<<fn<<std::endl;
 
219
        exit(1);
 
220
    }
 
221
 
 
222
    // is_continue flag
 
223
    if (is_continue)
 
224
        fh << "is_continue == true" << std::endl;
 
225
    else
 
226
        fh << "is_continue == false" << std::endl;
 
227
}
 
228
 
 
229
bool RelionJobWindow::openReadFile(std::string fn, std::ifstream &fh)
 
230
{
 
231
        fh.open(fn.c_str(), std::ios_base::in);
 
232
    if (fh.fail())
 
233
        return false;
 
234
    else
 
235
    {
 
236
                fh.seekg(0, std::ios::beg);
 
237
                std::string line;
 
238
                getline(fh, line, '\n');
 
239
                if (line.rfind("is_continue == true") == 0)
 
240
                        is_continue = true;
 
241
                else
 
242
                        is_continue = false;
 
243
 
 
244
                return true;
 
245
    }
 
246
}
 
247
 
 
248
void RelionJobWindow::closeWriteFile(std::ofstream& fh)
 
249
{
 
250
        if (has_mpi)
 
251
                nr_mpi.writeValue(fh);
 
252
        if (has_thread)
 
253
        {
 
254
                nr_threads.writeValue(fh);
 
255
                ram_per_thread.writeValue(fh);
 
256
        }
 
257
        do_queue.writeValue(fh);
 
258
        queuename.writeValue(fh);
 
259
        qsub.writeValue(fh);
 
260
        if (have_extra1)
 
261
                qsub_extra1.writeValue(fh);
 
262
        if (have_extra2)
 
263
                qsub_extra2.writeValue(fh);
 
264
        qsubscript.writeValue(fh);
 
265
        other_args.writeValue(fh);
 
266
 
 
267
        fh.close();
 
268
}
 
269
 
 
270
void RelionJobWindow::closeReadFile(std::ifstream& fh)
 
271
{
 
272
        if (has_mpi)
 
273
                nr_mpi.readValue(fh);
 
274
        if (has_thread)
 
275
        {
 
276
                nr_threads.readValue(fh);
 
277
                ram_per_thread.readValue(fh);
 
278
        }
 
279
        do_queue.readValue(fh);
 
280
        queuename.readValue(fh);
 
281
        qsub.readValue(fh);
 
282
        if (have_extra1)
 
283
                qsub_extra1.readValue(fh);
 
284
        if (have_extra2)
 
285
                qsub_extra2.readValue(fh);
 
286
        qsubscript.readValue(fh);
 
287
        other_args.readValue(fh);
 
288
 
 
289
}
 
290
 
 
291
void RelionJobWindow::saveJobSubmissionScript(std::string newfilename, std::string outputname, std::vector<std::string> commands)
 
292
{
 
293
        Fl_Text_Buffer *textbuf = new Fl_Text_Buffer;
 
294
 
 
295
        // Open the standard job submission file
 
296
        int errno;
 
297
        if (errno = textbuf->loadfile(qsubscript.getValue().c_str()))
 
298
            fl_alert("Error reading from file \'%s\':\n%s.", qsubscript.getValue().c_str(), strerror(errno));
 
299
 
 
300
        // default to a single thread
 
301
        int nthr = (has_thread) ? nr_threads.getValue() : 1;
 
302
 
 
303
        replaceStringAll(textbuf, "XXXmpinodesXXX", floatToString(nr_mpi.getValue()) );
 
304
        replaceStringAll(textbuf, "XXXthreadsXXX", floatToString(nthr) );
 
305
        replaceStringAll(textbuf, "XXXcoresXXX", floatToString(nr_mpi.getValue() * nthr) );
 
306
        replaceStringAll(textbuf, "XXXnameXXX", outputname);
 
307
        replaceStringAll(textbuf, "XXXerrfileXXX", outputname + ".err");
 
308
        replaceStringAll(textbuf, "XXXoutfileXXX", outputname + ".out");
 
309
        replaceStringAll(textbuf, "XXXqueueXXX", queuename.getValue() );
 
310
        if (have_extra1)
 
311
                replaceStringAll(textbuf, "XXXextra1XXX", qsub_extra1.getValue() );
 
312
        if (have_extra2)
 
313
                replaceStringAll(textbuf, "XXXextra2XXX", qsub_extra2.getValue() );
 
314
 
 
315
        // Get commands.size() entries with the actual command
 
316
        if (commands.size() > 1)
 
317
                appendLineString(textbuf, "XXXcommandXXX", commands.size() - 1);
 
318
 
 
319
        for (int icom = 0; icom < commands.size(); icom++)
 
320
                replaceStringOnce(textbuf, "XXXcommandXXX", commands[icom] );
 
321
 
 
322
        // Make sure the file ends with an empty line
 
323
        textbuf->append("\n");
 
324
 
 
325
        // Save the modified job submission script using a local name
 
326
        if (errno = textbuf->savefile(newfilename.c_str()))
 
327
            fl_alert("Error writing to file \'%s\':\n%s.", newfilename.c_str(), strerror(errno));
 
328
 
 
329
}
 
330
 
 
331
 
 
332
void RelionJobWindow::prepareFinalCommand(std::string &outputname, std::vector<std::string> &commands, std::string &final_command)
 
333
{
 
334
 
 
335
        // Create output directory if the outname contains a "/"
 
336
        int last_slash = outputname.rfind("/");
 
337
        if (last_slash < outputname.size())
 
338
        {
 
339
                std::string dirs = outputname.substr(0, last_slash);
 
340
                std::string makedirs = "mkdir -p " + dirs;
 
341
                system(makedirs.c_str());
 
342
        }
 
343
 
 
344
        // Prepare full mpi commands or save jobsubmission script to disc
 
345
        if (do_queue.getValue())
 
346
        {
 
347
                // Make the submission script and write it to disc
 
348
                std::string output_script = outputname + "_submit.script";
 
349
                saveJobSubmissionScript(output_script, outputname, commands);
 
350
                final_command = qsub.getValue() + " " + output_script + " &";
 
351
        }
 
352
        else
 
353
        {
 
354
                // If there are multiple commands, then join them all on a single line (final_command)
 
355
                // Also add mpirun in front of all commands if no submission via the queue is done
 
356
                std::string one_command;
 
357
                final_command = "";
 
358
                for (int icom = 0; icom < commands.size(); icom++)
 
359
                {
 
360
                        if (has_mpi && nr_mpi.getValue() > 1)
 
361
                                one_command = "mpirun -n " + floatToString(nr_mpi.getValue()) + " " + commands[icom] ;
 
362
                        else
 
363
                                one_command = commands[icom];
 
364
                        final_command += one_command;
 
365
                        if (icom == commands.size() - 1)
 
366
                                final_command += " & "; // end by putting composite job in the background
 
367
                        else
 
368
                                final_command += " && "; // execute one command after the other...
 
369
                }
 
370
        }
 
371
 
 
372
}
 
373
 
 
374
/*
 
375
XXXXJobWindow::XXXXJobWindow() : RelionJobWindow(4, HAS_MPI, HAS_THREAD)
 
376
{
 
377
        tab1->begin();
 
378
        tab1->label("I/O");
 
379
        resetHeight();
 
380
        //ctf_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
 
381
        //ctf_group->end();
 
382
 
 
383
        tab1->end();
 
384
 
 
385
        // read settings if hidden file exists
 
386
        read(".gui_general.settings", is_continue);
 
387
}
 
388
void XXXXJobWindow::write(std::string fn)
 
389
{
 
390
        std::ofstream fh;
 
391
        openWriteFile(fn + ".gui_general.settings", fh);
 
392
        closeWriteFile(fh);
 
393
}
 
394
void XXXXJobWindow::read(std::string fn, bool &_is_continue)
 
395
{
 
396
        std::ifstream fh;
 
397
        // Only read things if the file exists
 
398
        if (openReadFile(fn, fh))
 
399
        {
 
400
                closeReadFile(fh);
 
401
                _is_continue = is_continue;
 
402
        }
 
403
}
 
404
void XXXXJobWindow::toggle_new_continue(bool _is_continue)
 
405
{
 
406
        is_continue = _is_continue;
 
407
}
 
408
void XXXXJobWindow::getCommands(std::string &outputname, std::vector<std::string> &commands, std::string &final_command)
 
409
{
 
410
        commands.clear();
 
411
        std::string command;
 
412
        if (nr_mpi.getValue() > 1)
 
413
                command="`which relion_XXX_mpi`";
 
414
        else
 
415
                command="`which relion_XXX`";
 
416
 
 
417
 
 
418
        // Other arguments for extraction
 
419
        command += " " + other_args.getValue();
 
420
 
 
421
        commands.push_back(command);
 
422
        outputname = "run_ctffind";
 
423
        prepareFinalCommand(outputname, commands, final_command);
 
424
}
 
425
*/
 
426
 
 
427
GeneralJobWindow::GeneralJobWindow() : RelionJobWindow(1, HAS_MPI, HAS_NOT_THREAD, HAS_NOT_RUN)
 
428
{
 
429
 
 
430
        tab1->begin();
 
431
        tab1->label("I/O");
 
432
        resetHeight();
 
433
 
 
434
        angpix.place(current_y, "Magnified pixel size (Angstrom):", 1.0, 0.1, 5.0, 0.1, "Magnified pixel size in Angstroms (preferably calculated using a calibrated magnification). \
 
435
However, when an exact calibrated pixel size is not available, one may use a preliminary one throughout the entire RELION processing workflow. This will all be internally consistent. \
 
436
Then, at the postprocessing step (when one has a better idea of the actual pixel size, e.g. through the fitting of an atomic model) one may change to a more accurate pixel size at that stage.");
 
437
 
 
438
        particle_diameter.place(current_y, "Particle mask diameter (A):", 200, 0, 1000, 10, "The experimental images will be masked with a soft \
 
439
circular mask with this diameter. Make sure this radius is not set too small because that may mask away part of the signal! \
 
440
If set to a value larger than the image size no masking will be performed.\n\n\
 
441
The same diameter will also be used for a spherical mask of the reference structures if no user-provided mask is specified.");
 
442
 
 
443
        tab1->end();
 
444
 
 
445
        // read settings if hidden file exists
 
446
        read(".gui_general.settings", is_continue);
 
447
}
 
448
 
 
449
void GeneralJobWindow::write(std::string fn)
 
450
{
 
451
        std::ofstream fh;
 
452
        openWriteFile(fn + ".gui_general.settings", fh);
 
453
 
 
454
        angpix.writeValue(fh);
 
455
        particle_diameter.writeValue(fh);
 
456
 
 
457
        closeWriteFile(fh);
 
458
 
 
459
}
 
460
 
 
461
void GeneralJobWindow::read(std::string fn, bool &_is_continue)
 
462
{
 
463
 
 
464
        std::ifstream fh;
 
465
        // Only read things if the file exists
 
466
        if (openReadFile(fn, fh))
 
467
        {
 
468
                angpix.readValue(fh);
 
469
                particle_diameter.readValue(fh);
 
470
 
 
471
                closeReadFile(fh);
 
472
                _is_continue = is_continue;
 
473
        }
 
474
}
 
475
void GeneralJobWindow::toggle_new_continue(bool _is_continue)
 
476
{
 
477
        is_continue = _is_continue;
 
478
 
 
479
}
 
480
 
 
481
void GeneralJobWindow::getCommands(std::string &outputname, std::vector<std::string> &commands, std::string &final_command)
 
482
{
 
483
        commands.clear();
 
484
        outputname = "run_general";
 
485
        final_command="";
 
486
 
 
487
}
 
488
 
 
489
CtffindJobWindow::CtffindJobWindow() : RelionJobWindow(3, HAS_MPI, HAS_NOT_THREAD)
 
490
{
 
491
 
 
492
        tab1->begin();
 
493
        tab1->label("I/O");
 
494
        resetHeight();
 
495
 
 
496
        mic_names.place(current_y, "Input micrographs for CTF:", "micrographs_selected.star", "Input micrographs (*.{star,mrc})", "STAR file with the filenames of all micrographs on which to run CTFFIND3, OR a unix-type wildcard to the filenames of the micrograph(s) (e.g. Micrographs/*.mrc).\
 
497
Note that the micrographs should be in a subdirectory (e.g. called Micrographs/) of the project directory, i.e. the directory from where you are launching the GUI. \
 
498
If this is not the case, then make a symbolic link inside the project directory to the directory where your micrographs are stored.");
 
499
 
 
500
        output_star_ctf_mics.place(current_y, "Output STAR file:", "micrographs_ctf.star", "Name of the output STAR file with all CTF information for each micrograph");
 
501
 
 
502
        // Add a little spacer
 
503
        current_y += STEPY/2;
 
504
 
 
505
        // Check for environment variable RELION_QSUB_TEMPLATE
 
506
        char * default_location = getenv ("RELION_CTFFIND3_EXECUTABLE");
 
507
        if (default_location == NULL)
 
508
        {
 
509
                char mydefault[]=DEFAULTCTFFINDLOCATION;
 
510
                default_location=mydefault;
 
511
        }
 
512
 
 
513
        fn_ctffind3_exe.place(current_y, "CTFFIND3 executable:", default_location, "*.exe", "Location of the CTFFIND3 executable. You can control the default of this field by setting environment variable RELION_CTFFIND3_EXECUTABLE, or by editing the first few lines in src/gui_jobwindow.h and recompile the code.");
 
514
 
 
515
        ctf_win.place(current_y, "Estimate CTF on window size (pix) ", -1, -16, 4096, 16, "If a positive value is given, a squared window of this size at the center of the micrograph will be used to estimate the CTF. This may be useful to exclude parts of the micrograph that are unsuitable for CTF estimation, e.g. the labels at the edge of phtographic film. \n \n The original micrograph will be used (i.e. this option will be ignored) if a negative value is given.");
 
516
 
 
517
        tab1->end();
 
518
 
 
519
 
 
520
        tab2->begin();
 
521
        tab2->label("Microscopy");
 
522
        resetHeight();
 
523
 
 
524
        cs.place(current_y, "Spherical aberration (mm):", 2, 0, 8, 0.1, "Spherical aberration of the microscope used to collect these images (in mm)");
 
525
 
 
526
        kv.place(current_y, "Voltage (kV):", 300, 50, 500, 10, "Voltage the microscope was operated on (in kV)");
 
527
 
 
528
        q0.place(current_y, "Amplitude contrast:", 0.1, 0, 0.3, 0.01, "Fraction of amplitude contrast. Often values around 10% work better than theoretically more accurate lower values...");
 
529
 
 
530
        dstep.place(current_y, "Physical pixel size on detector (um):", 14, 1, 32, 1, "Physical pixel size of the detector (in micrometer), e.g. Falcon is 14 um, K2 is 5 um");
 
531
 
 
532
        tab2->end();
 
533
 
 
534
        tab3->begin();
 
535
        tab3->label("CTFFIND3");
 
536
        resetHeight();
 
537
 
 
538
        box.place(current_y, "FFT box size (pix):", 512, 64, 1024, 8, "CTFFIND3's Box parameter");
 
539
 
 
540
        resmin.place(current_y, "Minimum resolution (A):", 100, 10, 200, 10, "CTFFIND3's ResMin parameter");
 
541
 
 
542
        resmax.place(current_y, "Maximum resolution (A):", 7, 1, 20, 1, "CTFFIND3's ResMax parameter");
 
543
 
 
544
        dfmin.place(current_y, "Minimum defocus value (A):", 5000, 0, 25000, 1000, "CTFFIND3's dFMin parameter");
 
545
 
 
546
        dfmax.place(current_y, "Maximum defocus value (A):", 50000, 20000, 100000, 1000, "CTFFIND3's dFMax parameter");
 
547
 
 
548
        dfstep.place(current_y, "Defocus step size (A):", 500, 200, 2000, 100,"CTFFIND3's FStep parameter");
 
549
 
 
550
        dast.place(current_y, "Amount of astigmatism (A):", 0, 0, 2000, 100,"CTFFIND3's dAst parameter");
 
551
 
 
552
        tab3->end();
 
553
 
 
554
        // read settings if hidden file exists
 
555
        read(".gui_ctffind.settings", is_continue);
 
556
}
 
557
 
 
558
void CtffindJobWindow::write(std::string fn)
 
559
{
 
560
        std::ofstream fh;
 
561
        openWriteFile(fn + ".gui_ctffind.settings", fh);
 
562
 
 
563
        mic_names.writeValue(fh);
 
564
        output_star_ctf_mics.writeValue(fh);
 
565
        cs.writeValue(fh);
 
566
        kv.writeValue(fh);
 
567
        q0.writeValue(fh);
 
568
        dstep.writeValue(fh);
 
569
        box.writeValue(fh);
 
570
        resmin.writeValue(fh);
 
571
        resmax.writeValue(fh);
 
572
        dfmin.writeValue(fh);
 
573
        dfmax.writeValue(fh);
 
574
        dfstep.writeValue(fh);
 
575
        dast.writeValue(fh);
 
576
        fn_ctffind3_exe.writeValue(fh);
 
577
        ctf_win.writeValue(fh);
 
578
 
 
579
        closeWriteFile(fh);
 
580
}
 
581
 
 
582
void CtffindJobWindow::read(std::string fn, bool &_is_continue)
 
583
{
 
584
 
 
585
        std::ifstream fh;
 
586
        // Only read things if the file exists
 
587
        if (openReadFile(fn, fh))
 
588
        {
 
589
                mic_names.readValue(fh);
 
590
                output_star_ctf_mics.readValue(fh);
 
591
                cs.readValue(fh);
 
592
                kv.readValue(fh);
 
593
                q0.readValue(fh);
 
594
                dstep.readValue(fh);
 
595
                box.readValue(fh);
 
596
                resmin.readValue(fh);
 
597
                resmax.readValue(fh);
 
598
                dfmin.readValue(fh);
 
599
                dfmax.readValue(fh);
 
600
                dfstep.readValue(fh);
 
601
                dast.readValue(fh);
 
602
                fn_ctffind3_exe.readValue(fh);
 
603
                ctf_win.readValue(fh);
 
604
 
 
605
                closeReadFile(fh);
 
606
                _is_continue = is_continue;
 
607
        }
 
608
}
 
609
 
 
610
void CtffindJobWindow::toggle_new_continue(bool _is_continue)
 
611
{
 
612
        is_continue = _is_continue;
 
613
 
 
614
        mic_names.deactivate(is_continue);
 
615
        output_star_ctf_mics.deactivate(is_continue);
 
616
        cs.deactivate(is_continue);
 
617
        kv.deactivate(is_continue);
 
618
        q0.deactivate(is_continue);
 
619
        dstep.deactivate(is_continue);
 
620
        fn_ctffind3_exe.deactivate(is_continue);
 
621
 
 
622
        // TODO: check which log files do not have Final values and re-run on those
 
623
        // for that: modify run_ctffind wrapper program
 
624
}
 
625
 
 
626
void CtffindJobWindow::getCommands(std::string &outputname, std::vector<std::string> &commands,
 
627
                std::string &final_command, double angpix)
 
628
{
 
629
        commands.clear();
 
630
        std::string command;
 
631
        if (nr_mpi.getValue() > 1)
 
632
                command="`which relion_run_ctffind_mpi`";
 
633
        else
 
634
                command="`which relion_run_ctffind`";
 
635
 
 
636
 
 
637
        // Calculate magnification from user-specified pixel size in Angstroms
 
638
        double magn = ROUND((dstep.getValue() * 1e-6) / (angpix * 1e-10));
 
639
 
 
640
        command += " --i \"" + mic_names.getValue()+"\"";
 
641
        command += " --o \"" + output_star_ctf_mics.getValue()+"\"";
 
642
        command += " --ctfWin " + floatToString(ctf_win.getValue());
 
643
        command += " --CS " + floatToString(cs.getValue());
 
644
        command += " --HT " + floatToString(kv.getValue());
 
645
        command += " --AmpCnst " + floatToString(q0.getValue());
 
646
        command += " --XMAG " + floatToString(magn);
 
647
        command += " --DStep " + floatToString(dstep.getValue());
 
648
        command += " --Box " + floatToString(box.getValue());
 
649
        command += " --ResMin " + floatToString(resmin.getValue());
 
650
        command += " --ResMax " + floatToString(resmax.getValue());
 
651
        command += " --dFMin " + floatToString(dfmin.getValue());
 
652
        command += " --dFMax " + floatToString(dfmax.getValue());
 
653
        command += " --FStep " + floatToString(dfstep.getValue());
 
654
        command += " --dAst " + floatToString(dast.getValue());
 
655
        command += " --ctffind3_exe " + fn_ctffind3_exe.getValue();
 
656
 
 
657
        if (is_continue)
 
658
                command += " --only_do_unfinished ";
 
659
 
 
660
        // Other arguments
 
661
        command += " " + other_args.getValue();
 
662
 
 
663
        commands.push_back(command);
 
664
 
 
665
        int last_slash_out = mic_names.getValue().rfind("/");
 
666
        if (last_slash_out < mic_names.getValue().size())
 
667
        {
 
668
                // The output name contains a directory: use that one for output
 
669
                outputname = mic_names.getValue().substr(0, last_slash_out + 1) + "run_ctffind";
 
670
        }
 
671
        else
 
672
        {
 
673
                outputname = "run_ctffind";
 
674
        }
 
675
 
 
676
        prepareFinalCommand(outputname, commands, final_command);
 
677
 
 
678
}
 
679
 
 
680
 
 
681
ManualpickJobWindow::ManualpickJobWindow() : RelionJobWindow(3, HAS_NOT_MPI, HAS_NOT_THREAD)
 
682
{
 
683
        tab1->begin();
 
684
        tab1->label("I/O");
 
685
        resetHeight();
 
686
 
 
687
        fn_in.place(current_y, "Input micrographs:", "micrographs_ctf.star", "Input micrographs (*.{star,mrc})", "Input STAR file (with or without CTF information), OR a unix-type wildcard with all micrographs in MRC format (in this case no CTFs can be used).");
 
688
 
 
689
        fn_out.place(current_y, "Output STAR file: ", "selected_micrographs_ctf.star", "Output STAR file (*.star)", "The selected micrographs will all be joined in a new STAR file (which has fewer lines than the original input one if micrographs are deselected on the GUI.");
 
690
 
 
691
        manualpick_rootname.place(current_y, "Picking rootname: ", "manualpick", "Rootname for the coordinate files of all manually picked particles.");
 
692
 
 
693
        tab1->end();
 
694
        tab2->begin();
 
695
        tab2->label("Display");
 
696
        resetHeight();
 
697
 
 
698
        micscale.place(current_y, "Scale for micrographs:", 0.2, 0.1, 1, 0.05, "The micrographs will be displayed at this relative scale, i.e. a value of 0.5 means that only every second pixel will be displayed." );
 
699
        sigma_contrast.place(current_y, "Sigma contrast:", 3, 0, 10, 0.5, "The micrographs will be displayed with the black value set to the average of all values MINUS this values times the standard deviation of all values in the micrograph, and the white value will be set \
 
700
to the average PLUS this value times the standard deviation. Use zero to set the minimum value in the micrograph to black, and the maximum value to white ");
 
701
        white_val.place(current_y, "White value:", 0, 0, 512, 16, "Use non-zero values to set the value of the whitest pixel in the micrograph.");
 
702
        black_val.place(current_y, "Black value:", 0, 0, 512, 16, "Use non-zero values to set the value of the blackest pixel in the micrograph.");
 
703
 
 
704
        current_y += STEPY/2;
 
705
        lowpass.place(current_y, "Lowpass filter (A)", 0, 0, 100, 5, "Lowpass filter that will be applied to the micrograph before displaying (zero for no filter).");
 
706
 
 
707
        current_y += STEPY/2;
 
708
        ctfscale.place(current_y, "Scale for CTF image:", 1, 0.1, 2, 0.1, "CTFFINDs CTF image (with the Thonrings) will be displayed at this relative scale, i.e. a value of 0.5 means that only every second pixel will be displayed." );
 
709
 
 
710
        tab2->end();
 
711
        tab3->begin();
 
712
        tab3->label("Colors");
 
713
        color_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
 
714
        color_group->end();
 
715
 
 
716
        resetHeight();
 
717
        do_color.place(current_y, "Blue<>red color particles?", false, "If set to true, then the circles for each particles are coloured from red to blue (or the other way around) for a given metadatalabel. If this metadatalabel is not in the picked coordinates STAR file \
 
718
(basically only the rlnAutopickFigureOfMerit or rlnClassNumber) would be useful values there, then you may provide an additional STAR file (e.g. after classification/refinement below. Particles with values -999, or that are not in the additional STAR file will be coloured the default color: green", color_group);
 
719
 
 
720
        color_group->begin();
 
721
        color_label.place(current_y, "MetaDataLabel for color:", "rlnParticleSelectZScore", "The Metadata label of the value to plot from red<>blue. Useful examples might be: \n \
 
722
rlnParticleSelectZScore \n rlnClassNumber \n rlnAutopickFigureOfMerit \n rlnAngleTilt \n rlnLogLikeliContribution \n rlnMaxValueProbDistribution \n rlnNrOfSignificantSamples\n");
 
723
 
 
724
        fn_color.place(current_y, "STAR file with color label: ", "", "STAR file (*.star)", "The program will figure out which particles in this STAR file are on the current micrograph and color their circles according to the value in the corresponding column. \
 
725
Particles that are not in this STAR file, but present in the picked coordinates file will be colored green. If this field is left empty, then the color label (e.g. rlnAutopickFigureOfMerit) should be present in the coordinates STAR file.");
 
726
 
 
727
        blue_value.place(current_y, "Blue value: ", 0., 0., 4., 0.1, "The value of this entry will be blue. There will be a linear scale from blue to red, according to this value and the one given below.");
 
728
        red_value.place(current_y, "Red value: ", 2., 0., 4., 0.1, "The value of this entry will be red. There will be a linear scale from blue to red, according to this value and the one given above.");
 
729
        color_group->end();
 
730
        do_color.cb_menu_i(); // make default active
 
731
 
 
732
        tab3->end();
 
733
 
 
734
        // read settings if hidden file exists
 
735
        read(".gui_manualpick.settings", is_continue);
 
736
}
 
737
 
 
738
void ManualpickJobWindow::write(std::string fn)
 
739
{
 
740
        std::ofstream fh;
 
741
        openWriteFile(fn + ".gui_manualpick.settings", fh);
 
742
        fn_in.writeValue(fh);
 
743
        fn_out.writeValue(fh);
 
744
        manualpick_rootname.writeValue(fh);
 
745
        lowpass.writeValue(fh);
 
746
        micscale.writeValue(fh);
 
747
        ctfscale.writeValue(fh);
 
748
        sigma_contrast.writeValue(fh);
 
749
        white_val.writeValue(fh);
 
750
        black_val.writeValue(fh);
 
751
        do_color.writeValue(fh);
 
752
        color_label.writeValue(fh);
 
753
        fn_color.writeValue(fh);
 
754
        blue_value.writeValue(fh);
 
755
        red_value.writeValue(fh);
 
756
 
 
757
 
 
758
        closeWriteFile(fh);
 
759
}
 
760
 
 
761
void ManualpickJobWindow::read(std::string fn, bool &_is_continue)
 
762
{
 
763
        std::ifstream fh;
 
764
        // Only read things if the file exists
 
765
        if (openReadFile(fn, fh))
 
766
        {
 
767
                fn_in.readValue(fh);
 
768
                fn_out.readValue(fh);
 
769
                manualpick_rootname.readValue(fh);
 
770
                lowpass.readValue(fh);
 
771
                micscale.readValue(fh);
 
772
                ctfscale.readValue(fh);
 
773
                sigma_contrast.readValue(fh);
 
774
                white_val.readValue(fh);
 
775
                black_val.readValue(fh);
 
776
                do_color.readValue(fh);
 
777
                color_label.readValue(fh);
 
778
                fn_color.readValue(fh);
 
779
                blue_value.readValue(fh);
 
780
                red_value.readValue(fh);
 
781
                closeReadFile(fh);
 
782
                _is_continue = is_continue;
 
783
        }
 
784
}
 
785
 
 
786
void ManualpickJobWindow::toggle_new_continue(bool _is_continue)
 
787
{
 
788
        is_continue = _is_continue;
 
789
        do_queue.deactivate(true);
 
790
}
 
791
 
 
792
void ManualpickJobWindow::getCommands(std::string &outputname, std::vector<std::string> &commands, std::string &final_command,
 
793
                double angpix, double particle_diameter)
 
794
{
 
795
        commands.clear();
 
796
        std::string command;
 
797
        command="`which relion_manualpick`";
 
798
 
 
799
        command += " --i \"" + fn_in.getValue() + "\"";
 
800
        command += " --o " + fn_out.getValue();
 
801
        command += " --pickname " + manualpick_rootname.getValue();
 
802
 
 
803
        command += " --scale " + floatToString(micscale.getValue());
 
804
        command += " --sigma_contrast " + floatToString(sigma_contrast.getValue());
 
805
        command += " --black " + floatToString(black_val.getValue());
 
806
        command += " --white " + floatToString(white_val.getValue());
 
807
 
 
808
        command += " --lowpass " + floatToString(lowpass.getValue());
 
809
        command += " --angpix " + floatToString(angpix);
 
810
 
 
811
        command += " --ctf_scale " + floatToString(ctfscale.getValue());
 
812
 
 
813
        command += " --particle_diameter " + floatToString(particle_diameter);
 
814
 
 
815
        if (do_color.getValue())
 
816
        {
 
817
                command += " --color_label " + color_label.getValue();
 
818
                command += " --blue " + floatToString(blue_value.getValue());
 
819
                command += " --red " + floatToString(red_value.getValue());
 
820
                if (fn_color.getValue().length() > 0)
 
821
                        command += " --color_star " + fn_color.getValue();
 
822
        }
 
823
 
 
824
        // Other arguments for extraction
 
825
        command += " " + other_args.getValue();
 
826
 
 
827
        commands.push_back(command);
 
828
 
 
829
        outputname = "run_manualpick";
 
830
        prepareFinalCommand(outputname, commands, final_command);
 
831
}
 
832
 
 
833
AutopickJobWindow::AutopickJobWindow() : RelionJobWindow(3, HAS_MPI, HAS_NOT_THREAD)
 
834
{
 
835
 
 
836
        tab1->begin();
 
837
        tab1->label("I/O");
 
838
        resetHeight();
 
839
 
 
840
        fn_input_autopick.place(current_y, "Input micrographs for autopick:", "micrographs_ctf.star", "Input micrographs (*.{star,mrc})", "Input STAR file (with CTF information), or a unix-type wildcard with all micrographs in MRC format (in this case no CTFs can be used).");
 
841
        autopick_rootname.place(current_y, "Autopick rootname:", "autopick", "Output coordinate files will end in rootname.star");
 
842
 
 
843
        tab1->end();
 
844
        tab2->begin();
 
845
        tab2->label("References");
 
846
        resetHeight();
 
847
 
 
848
        //set up group
 
849
        autopick_ctf_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
 
850
        autopick_ctf_group->end();
 
851
 
 
852
        fn_refs_autopick.place(current_y, "References:", "", "Input references (*.{star,mrc,mrcs})", "Input STAR file or MRC (stack of) image(s) with the references to be used for picking. Note that the absolute greyscale needs to be correct, so only use images created by RELION itself, e.g. by 2D class averaging or projecting a RELION reconstruction.");
 
853
 
 
854
        lowpass_autopick.place(current_y, "Lowpass filter references (A)", 20, 10, 100, 5, "Lowpass filter that will be applied to the references before template matching. Do NOT use very high-resolution templates to search your micrographs. The signal will be too weak at high resolution anyway, and you may find Einstein from noise....");
 
855
 
 
856
        psi_sampling_autopick.place(current_y, "Angular sampling (deg)", 5, 1, 30, 1, "Angular sampling in degrees for exhaustive searches of the in-plane rotations for all references.");
 
857
 
 
858
        // Add a little spacer
 
859
        current_y += STEPY/2;
 
860
 
 
861
        do_invert_refs.place(current_y, "References have inverted contrast?", true, "Set to Yes to indicate that the reference have inverted contrast with respect to the particles in the micrographs.");
 
862
 
 
863
        do_ctf_autopick.place(current_y, "Are References CTF corrected?", true, "Set to Yes if the references were created with CTF-correction inside RELION. \n \n If set to Yes, the input micrographs can only be given as a STAR file, which should contain the CTF information for each micrograph.", autopick_ctf_group);
 
864
 
 
865
        autopick_ctf_group->begin();
 
866
 
 
867
        do_ignore_first_ctfpeak_autopick.place(current_y, "Ignore CTFs until first peak?", false,"Set this to Yes, only if this option was also used to generate the references.");
 
868
 
 
869
        autopick_ctf_group->end();
 
870
        do_ctf_autopick.cb_menu_i();
 
871
 
 
872
        tab2->end();
 
873
        tab3->begin();
 
874
        tab3->label("autopicking");
 
875
        resetHeight();
 
876
 
 
877
        threshold_autopick.place(current_y, "Picking threshold:", 0.05, 0, 1., 0.01, "Use lower thresholds to pick more particles (and more junk probably)");
 
878
 
 
879
        mindist_autopick.place(current_y, "Minimum inter-particle distance (A):", 100, 0, 1000, 20, "Particles closer together than this distance will be consider to be a single cluster. From each cluster, only one particle will be picked.");
 
880
 
 
881
        current_y += STEPY/2;
 
882
 
 
883
        do_write_fom_maps.place(current_y, "Write FOM maps?", false, "If set to Yes, intermediate probability maps will be written out, which (upon reading them back in) will speed up tremendously the optimization of the threshold and inter-particle distance parameters. However, with this option, one cannot run in parallel, as disc I/O is very heavy with this option set.");
 
884
 
 
885
        do_read_fom_maps.place(current_y, "Read FOM maps?", false, "If written out previously, read the FOM maps back in and re-run the picking to quickly find the optimal threshold and inter-particle distance parameters");
 
886
 
 
887
        tab3->end();
 
888
 
 
889
        // read settings if hidden file exists
 
890
        read(".gui_autopick.settings", is_continue);
 
891
}
 
892
 
 
893
void AutopickJobWindow::write(std::string fn)
 
894
{
 
895
        std::ofstream fh;
 
896
        openWriteFile(fn + ".gui_autopick.settings", fh);
 
897
 
 
898
        fn_input_autopick.writeValue(fh);
 
899
        fn_refs_autopick.writeValue(fh);
 
900
        autopick_rootname.writeValue(fh);
 
901
        do_invert_refs.writeValue(fh);
 
902
        do_ctf_autopick.writeValue(fh);
 
903
        do_ignore_first_ctfpeak_autopick.writeValue(fh);
 
904
        lowpass_autopick.writeValue(fh);
 
905
        psi_sampling_autopick.writeValue(fh);
 
906
        do_write_fom_maps.writeValue(fh);
 
907
        do_read_fom_maps.writeValue(fh);
 
908
        threshold_autopick.writeValue(fh);
 
909
        mindist_autopick.writeValue(fh);
 
910
 
 
911
        closeWriteFile(fh);
 
912
}
 
913
 
 
914
void AutopickJobWindow::read(std::string fn, bool &_is_continue)
 
915
{
 
916
 
 
917
        std::ifstream fh;
 
918
        if (openReadFile(fn, fh))
 
919
        {
 
920
 
 
921
                fn_input_autopick.readValue(fh);
 
922
                fn_refs_autopick.readValue(fh);
 
923
                autopick_rootname.readValue(fh);
 
924
                do_invert_refs.readValue(fh);
 
925
                do_ctf_autopick.readValue(fh);
 
926
                do_ignore_first_ctfpeak_autopick.readValue(fh);
 
927
                lowpass_autopick.readValue(fh);
 
928
                psi_sampling_autopick.readValue(fh);
 
929
                do_write_fom_maps.readValue(fh);
 
930
                do_read_fom_maps.readValue(fh);
 
931
                threshold_autopick.readValue(fh);
 
932
                mindist_autopick.readValue(fh);
 
933
 
 
934
                closeReadFile(fh);
 
935
                _is_continue = is_continue;
 
936
        }
 
937
}
 
938
 
 
939
void AutopickJobWindow::toggle_new_continue(bool _is_continue)
 
940
{
 
941
        is_continue = _is_continue;
 
942
        return;
 
943
}
 
944
 
 
945
void AutopickJobWindow::getCommands(std::string &outputname, std::vector<std::string> &commands,
 
946
                std::string &final_command, double angpix, double particle_diameter)
 
947
{
 
948
        commands.clear();
 
949
        std::string command;
 
950
        if (nr_mpi.getValue() > 1)
 
951
                command="`which relion_autopick_mpi`";
 
952
        else
 
953
                command="`which relion_autopick`";
 
954
 
 
955
        command += " --i " + fn_input_autopick.getValue();
 
956
        command += " --o " + autopick_rootname.getValue();
 
957
        command += " --particle_diameter " + floatToString(particle_diameter);
 
958
        command += " --angpix " + floatToString(angpix);
 
959
        command += " --ref " + fn_refs_autopick.getValue();
 
960
 
 
961
        if (do_invert_refs.getValue())
 
962
                command += " --invert ";
 
963
 
 
964
        if (do_ctf_autopick.getValue())
 
965
        {
 
966
                command += " --ctf ";
 
967
                if (do_ignore_first_ctfpeak_autopick.getValue())
 
968
                        command += " --ctf_intact_first_peak ";
 
969
        }
 
970
        command += " --ang " + floatToString(psi_sampling_autopick.getValue());
 
971
        command += " --lowpass " + floatToString(lowpass_autopick.getValue());
 
972
 
 
973
        if (do_write_fom_maps.getValue())
 
974
                command += " --write_fom_maps ";
 
975
 
 
976
        if (do_read_fom_maps.getValue())
 
977
                command += " --read_fom_maps ";
 
978
 
 
979
        command += " --threshold " + floatToString(threshold_autopick.getValue());
 
980
        command += " --min_distance " + floatToString(mindist_autopick.getValue());
 
981
 
 
982
 
 
983
        // Other arguments
 
984
        command += " " + other_args.getValue();
 
985
 
 
986
        commands.push_back(command);
 
987
 
 
988
        outputname = autopick_rootname.getValue();
 
989
 
 
990
        prepareFinalCommand(outputname, commands, final_command);
 
991
 
 
992
}
 
993
 
 
994
 
 
995
ExtractJobWindow::ExtractJobWindow() : RelionJobWindow(3, HAS_MPI, HAS_NOT_THREAD)
 
996
{
 
997
        tab1->begin();
 
998
        tab1->label("I/O");
 
999
        resetHeight();
 
1000
 
 
1001
        star_mics.place(current_y,"micrograph STAR file: ", "selected_micrographs_ctf.star", "Input STAR file (*.{star})", "Filename of the STAR file that contains all micrographs from which to extract particles.");
 
1002
        pick_suffix.place(current_y,"Coordinate-file suffix: ", "_autopick.star", "Suffix for all the particle coordinate files. The micrograph rootnames will be extracted from each line in the input micrograph STAR file by removing the (.mrc) extension. \
 
1003
Then the coordinate filenames are formed by the micrograph rootname + this suffix. For example, a suffix of _autopick.star yields a coordinate filename of mic001_autopick.star for micrograph mic001.mrc. Likewise, a .box suffix would yield mic001.box. \n \n \
 
1004
Possible formats for coordinate files are RELION-generated STAR files (.star), EMAN boxer (.box) or ASCII files (with any other extension), where each line has the X and Y coordinates of a particle, possibly preceded by a single-line non-numeric header.");
 
1005
        extract_rootname.place(current_y, "Extract rootname:", "particles", "Output rootname. All particle stacks will contain this rootname, and the final particles STAR file will be called this rootname plus a .star extension. This rootname should NOT contain a directory structure. \n \n Also, when extracting movie-particles, this rootname should be THE SAME ONE as the one you used to extract the average particles. \
 
1006
On disc, movie particles will be distinguished from the average particles by the movie rootname on the movie tab. If you change the extract rootname upon extration of the movies, then movie processing will NOT work! ");
 
1007
 
 
1008
        tab1->end();
 
1009
        tab2->begin();
 
1010
        tab2->label("extract");
 
1011
        resetHeight();
 
1012
        extract_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
 
1013
        extract_group->end();
 
1014
 
 
1015
        do_extract.place(current_y, "Extract particles from micrographs?", true, "If set to Yes, particles will be extracted from the micrographs using all selected coordinate files. \
 
1016
Niko Grigorieff's program CTFFIND3 will be used for this.", extract_group);
 
1017
 
 
1018
        extract_group->begin();
 
1019
 
 
1020
        extract_size.place(current_y,"Particle box size :", 128, 64, 512, 8, "Size of the extracted particles (in pixels). This should be an even number!");
 
1021
        do_invert.place(current_y, "Invert contrast?", false, "If set to Yes, the contrast in the particles will be inverted.");
 
1022
 
 
1023
        // Add a little spacer
 
1024
        current_y += STEPY/2;
 
1025
 
 
1026
        rescale_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
 
1027
        rescale_group->end();
 
1028
        do_rescale.place(current_y, "Rescale particles?", false, "If set to Yes, particles will be re-scaled. Note that the particle diameter below will be in the down-scaled images.", rescale_group);
 
1029
        rescale_group->begin();
 
1030
        rescale.place(current_y, "Re-scaled size (pixels): ", 128, 64, 512, 8, "The re-scaled value needs to be an even number");
 
1031
        rescale_group->end();
 
1032
        do_rescale.cb_menu_i();
 
1033
 
 
1034
        // Add a little spacer
 
1035
        current_y += STEPY/2;
 
1036
 
 
1037
        norm_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
 
1038
        norm_group->end();
 
1039
        do_norm.place(current_y, "Normalize particles?", true, "If set to Yes, particles will be normalized in the way RELION prefers it.", norm_group);
 
1040
 
 
1041
        norm_group->begin();
 
1042
        white_dust.place(current_y, "Stddev for white dust removal: ", -1, -1, 10, 0.1, "Remove very white pixels from the extracted particles. \
 
1043
Pixels values higher than this many times the image stddev will be replaced with values from a Gaussian distribution. \n \n Use negative value to switch off dust removal.");
 
1044
 
 
1045
        black_dust.place(current_y, "Stddev for black dust removal: ", -1, -1, 10, 0.1, "Remove very black pixels from the extracted particles. \
 
1046
Pixels values higher than this many times the image stddev will be replaced with values from a Gaussian distribution. \n \n Use negative value to switch off dust removal.");
 
1047
        norm_group->end();
 
1048
        do_norm.cb_menu_i();
 
1049
 
 
1050
        extract_group->end();
 
1051
        do_extract.cb_menu_i();
 
1052
 
 
1053
        tab2->end();
 
1054
        tab3->begin();
 
1055
        tab3->label("movies");
 
1056
        resetHeight();
 
1057
        movie_extract_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
 
1058
        movie_extract_group->end();
 
1059
 
 
1060
        do_movie_extract.place(current_y, "Extract from movies?", false, "If set to yes, then particles will be extracted from all frames of the MRC stacks that hold the movies.\n \
 
1061
The name of the MCR stacks should be the rootname of the micrographs + '_movierootname.mrcs', where the movierootname is given below.", movie_extract_group);
 
1062
 
 
1063
        movie_extract_group->begin();
 
1064
 
 
1065
        movie_rootname.place(current_y, "Rootname of movies files:", "movie", "rootname to relate each movie to the single-frame averaged micropgraph. With a rootname of 'movie', the movie for mic001.mrc should be called mic001_movie.mrcs");
 
1066
 
 
1067
        first_movie_frame.place(current_y, "First movie frame to extract: ", 1, 1, 20, 1, "Extract from this movie frame onwards. The first frame is number 1.");
 
1068
 
 
1069
        last_movie_frame.place(current_y, "Last movie frame to extract: ", 0, 0, 64, 1, "Extract until this movie frame. Zero means: extract all frames in the movie");
 
1070
 
 
1071
        movie_extract_group->end();
 
1072
        do_movie_extract.cb_menu_i();
 
1073
 
 
1074
        tab3->end();
 
1075
 
 
1076
        // read settings if hidden file exists
 
1077
        read(".gui_extract.settings", is_continue);
 
1078
}
 
1079
 
 
1080
 
 
1081
void ExtractJobWindow::write(std::string fn)
 
1082
{
 
1083
        std::ofstream fh;
 
1084
        openWriteFile(fn + ".gui_extract.settings", fh);
 
1085
 
 
1086
        // I/O
 
1087
        star_mics.writeValue(fh);
 
1088
        pick_suffix.writeValue(fh);
 
1089
        extract_rootname.writeValue(fh);
 
1090
 
 
1091
        // extract
 
1092
        do_extract.writeValue(fh);
 
1093
        extract_size.writeValue(fh);
 
1094
        do_rescale.writeValue(fh);
 
1095
        rescale.writeValue(fh);
 
1096
        do_norm.writeValue(fh);
 
1097
        white_dust.writeValue(fh);
 
1098
        black_dust.writeValue(fh);
 
1099
        do_invert.writeValue(fh);
 
1100
 
 
1101
        // movies
 
1102
        do_movie_extract.writeValue(fh);
 
1103
        movie_rootname.writeValue(fh);
 
1104
        first_movie_frame.writeValue(fh);
 
1105
        last_movie_frame.writeValue(fh);
 
1106
 
 
1107
        closeWriteFile(fh);
 
1108
}
 
1109
void ExtractJobWindow::read(std::string fn, bool &_is_continue)
 
1110
{
 
1111
        std::ifstream fh;
 
1112
        // Only read things if the file exists
 
1113
        if (openReadFile(fn, fh))
 
1114
        {
 
1115
 
 
1116
                // I/O
 
1117
                star_mics.readValue(fh);
 
1118
                pick_suffix.readValue(fh);
 
1119
                extract_rootname.readValue(fh);
 
1120
 
 
1121
                // extract
 
1122
                do_extract.readValue(fh);
 
1123
                extract_size.readValue(fh);
 
1124
                do_rescale.readValue(fh);
 
1125
                rescale.readValue(fh);
 
1126
                do_norm.readValue(fh);
 
1127
                white_dust.readValue(fh);
 
1128
                black_dust.readValue(fh);
 
1129
                do_invert.readValue(fh);
 
1130
 
 
1131
                // movies
 
1132
                do_movie_extract.readValue(fh);
 
1133
                movie_rootname.readValue(fh);
 
1134
                first_movie_frame.readValue(fh);
 
1135
                last_movie_frame.readValue(fh);
 
1136
 
 
1137
 
 
1138
                closeReadFile(fh);
 
1139
                _is_continue = is_continue;
 
1140
        }
 
1141
}
 
1142
void ExtractJobWindow::toggle_new_continue(bool _is_continue)
 
1143
{
 
1144
        is_continue = _is_continue;
 
1145
}
 
1146
 
 
1147
void ExtractJobWindow::getCommands(std::string &outputname, std::vector<std::string> &commands, std::string &final_command,
 
1148
                double angpix, double particle_diameter)
 
1149
{
 
1150
        commands.clear();
 
1151
        std::string command;
 
1152
        if (nr_mpi.getValue() > 1)
 
1153
                command="`which relion_preprocess_mpi`";
 
1154
        else
 
1155
                command="`which relion_preprocess`";
 
1156
 
 
1157
        command += " --o " + extract_rootname.getValue();
 
1158
        command += " --mic_star " + star_mics.getValue();
 
1159
        command += " --coord_suffix " + pick_suffix.getValue();
 
1160
 
 
1161
        if (do_extract.getValue())
 
1162
        {
 
1163
                command += " --extract";
 
1164
                command += " --extract_size " + floatToString(extract_size.getValue());
 
1165
                if (do_movie_extract.getValue())
 
1166
                {
 
1167
                        command += " --extract_movies";
 
1168
                        command += " --movie_rootname " + movie_rootname.getValue();
 
1169
                        command += " --first_movie_frame " + floatToString(first_movie_frame.getValue());
 
1170
                        command += " --last_movie_frame " + floatToString(last_movie_frame.getValue());
 
1171
                }
 
1172
 
 
1173
                // Operate stuff
 
1174
                double bg_radius;
 
1175
                bg_radius = (particle_diameter / (2. * angpix));
 
1176
                if (do_rescale.getValue())
 
1177
                {
 
1178
                        command += " --scale " + floatToString(rescale.getValue());
 
1179
                        bg_radius *= rescale.getValue() / extract_size.getValue();
 
1180
                }
 
1181
                // Get an integer number for the bg_radius
 
1182
                bg_radius = (int)(bg_radius);
 
1183
                if (do_norm.getValue())
 
1184
                {
 
1185
                        command += " --norm --bg_radius " + floatToString(bg_radius);
 
1186
                        command += " --white_dust " + floatToString(white_dust.getValue());
 
1187
                        command += " --black_dust " + floatToString(black_dust.getValue());
 
1188
                }
 
1189
                if (do_invert.getValue())
 
1190
                        command += " --invert_contrast ";
 
1191
 
 
1192
        }
 
1193
 
 
1194
        // Other arguments for extraction
 
1195
        command += " " + other_args.getValue();
 
1196
 
 
1197
        commands.push_back(command);
 
1198
        outputname = extract_rootname.getValue();
 
1199
        prepareFinalCommand(outputname, commands, final_command);
 
1200
}
 
1201
 
 
1202
SortJobWindow::SortJobWindow() : RelionJobWindow(1, HAS_MPI, HAS_NOT_THREAD)
 
1203
{
 
1204
        tab1->begin();
 
1205
        tab1->label("I/O");
 
1206
        resetHeight();
 
1207
        ctf_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
 
1208
        ctf_group->end();
 
1209
 
 
1210
        input_star.place(current_y, "Input particles to be sorted:", "", "Input particles(*.{star})", "This STAR file should contain in-plane rotations, in-plane translations and a class number that were obtained by alignment (class2D/class3D or auto3D) OR auto-picking. A column called rlnParticleSelectZScore will be added to this same STAR file with the sorting result. This column can then be used in the display programs to sort the particles on.");
 
1211
 
 
1212
        // Add a little spacer
 
1213
        current_y += STEPY/2;
 
1214
 
 
1215
        fn_refs.place(current_y, "References:", "", "Input references (*.{star,mrc,mrcs})", "Input STAR file or MRC (stack of) image(s) with the references to be used for sorting. These should be the same references as used to determine the class number and in-plane orientations as given in the STAR file with the input particles");
 
1216
        do_ctf.place(current_y, "Are References CTF corrected?", true, "Set to Yes if the references were created with CTF-correction inside RELION. \n ", ctf_group);
 
1217
 
 
1218
        ctf_group->begin();
 
1219
        do_ignore_first_ctfpeak.place(current_y, "Ignore CTFs until first peak?", false,"Set this to Yes, only if this option was also used to generate the references.");
 
1220
        ctf_group->end();
 
1221
        do_ctf.cb_menu_i();
 
1222
 
 
1223
 
 
1224
        tab1->end();
 
1225
 
 
1226
        // read settings if hidden file exists
 
1227
        read(".gui_sort.settings", is_continue);
 
1228
}
 
1229
 
 
1230
void SortJobWindow::write(std::string fn)
 
1231
{
 
1232
        std::ofstream fh;
 
1233
        openWriteFile(fn + ".gui_sort.settings", fh);
 
1234
 
 
1235
        input_star.writeValue(fh);
 
1236
        fn_refs.writeValue(fh);
 
1237
        do_ctf.writeValue(fh);
 
1238
        do_ignore_first_ctfpeak.writeValue(fh);
 
1239
 
 
1240
        closeWriteFile(fh);
 
1241
}
 
1242
void SortJobWindow::read(std::string fn, bool &_is_continue)
 
1243
{
 
1244
        std::ifstream fh;
 
1245
        // Only read things if the file exists
 
1246
        if (openReadFile(fn, fh))
 
1247
        {
 
1248
                input_star.readValue(fh);
 
1249
                fn_refs.readValue(fh);
 
1250
                do_ctf.readValue(fh);
 
1251
                do_ignore_first_ctfpeak.readValue(fh);
 
1252
 
 
1253
                closeReadFile(fh);
 
1254
                _is_continue = is_continue;
 
1255
        }
 
1256
}
 
1257
void SortJobWindow::toggle_new_continue(bool _is_continue)
 
1258
{
 
1259
        is_continue = _is_continue;
 
1260
}
 
1261
 
 
1262
void SortJobWindow::getCommands(std::string &outputname, std::vector<std::string> &commands,
 
1263
                std::string &final_command, double angpix, double particle_diameter)
 
1264
{
 
1265
        commands.clear();
 
1266
        std::string command;
 
1267
        if (nr_mpi.getValue() > 1)
 
1268
                command="`which relion_particle_sort_mpi`";
 
1269
        else
 
1270
                command="`which relion_particle_sort`";
 
1271
 
 
1272
        command += " --i " + input_star.getValue();
 
1273
        command += " --ref " + fn_refs.getValue();
 
1274
        command += " --angpix " + floatToString(angpix);
 
1275
        command += " --particle_diameter " + floatToString(particle_diameter);
 
1276
 
 
1277
        if (do_ctf.getValue())
 
1278
        {
 
1279
                command += " --ctf ";
 
1280
                if (do_ignore_first_ctfpeak.getValue())
 
1281
                        command += " --ctf_intact_first_peak ";
 
1282
        }
 
1283
 
 
1284
        // Other arguments for extraction
 
1285
        command += " " + other_args.getValue();
 
1286
 
 
1287
        commands.push_back(command);
 
1288
 
 
1289
 
 
1290
        int last_slash = input_star.getValue().rfind("/");
 
1291
        if (last_slash < input_star.getValue().size())
 
1292
        {
 
1293
                // The output name contains a directory: use that one for output
 
1294
                outputname = input_star.getValue().substr(0, last_slash + 1) + "run_sort";
 
1295
        }
 
1296
        else
 
1297
        {
 
1298
                outputname = "run_sort";
 
1299
        }
 
1300
 
 
1301
        prepareFinalCommand(outputname, commands, final_command);
 
1302
}
 
1303
 
 
1304
 
 
1305
 
 
1306
 
 
1307
Class2DJobWindow::Class2DJobWindow() : RelionJobWindow(4, HAS_MPI, HAS_THREAD)
 
1308
{
 
1309
 
 
1310
        tab1->begin();
 
1311
        tab1->label("I/O");
 
1312
        resetHeight();
 
1313
 
 
1314
        fn_img.place(current_y, "Input images STAR file:", "", "STAR files (*.star) \t Image stacks (not recommended, read help!) (*.{spi,mrcs})", "A STAR file with all images (and their metadata). \n \n Alternatively, you may give a Spider/MRC stack of 2D images, but in that case NO metadata can be included and thus NO CTF correction can be performed, \
 
1315
nor will it be possible to perform noise spectra estimation or intensity scale corrections in image groups. Therefore, running RELION with an input stack will in general provide sub-optimal results and is therefore not recommended!! Use the Preprocessing procedure to get the input STAR file in a semi-automated manner. Read the RELION wiki for more information.");
 
1316
 
 
1317
        fn_out.place(current_y, "Output rootname:", "Class2D/run1", "Output rootname for all files of this run. \
 
1318
If this rootname contains a directory structure (e.g. 20110724/run1), the directory (20110724) will be created if it does not exist.");
 
1319
 
 
1320
        fn_cont.place(current_y, "Continue from here: ", "", "STAR Files (*_optimiser.star)", "Select the *_optimiser.star file for the iteration \
 
1321
from which you want to continue a previous run. \
 
1322
Note that the Output rootname of the continued run and the rootname of the previous run cannot be the same. \
 
1323
If they are the same, the program will automatically add a '_ctX' to the output rootname, \
 
1324
with X being the iteration from which one continues the previous run.");
 
1325
 
 
1326
        // Add a little spacer
 
1327
        current_y += STEPY/2;
 
1328
 
 
1329
        nr_classes.place(current_y, "Number of classes:", 1, 1, 50, 1, "The number of classes (K) for a multi-reference refinement. \
 
1330
These classes will be made in an unsupervised manner from a single reference by division of the data into random subsets during the first iteration.");
 
1331
 
 
1332
        // Add a little spacer
 
1333
        current_y += STEPY/2;
 
1334
 
 
1335
 
 
1336
 
 
1337
 
 
1338
        tab1->end();
 
1339
 
 
1340
        tab2->begin();
 
1341
        tab2->label("CTF");
 
1342
 
 
1343
        ctf_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
 
1344
        ctf_group->end();
 
1345
 
 
1346
        resetHeight();
 
1347
        do_ctf_correction.place(current_y, "Do CTF-correction?", true, "If set to Yes, CTFs will be corrected inside the MAP refinement. \
 
1348
The resulting algorithm intrinsically implements the optimal linear, or Wiener filter. \
 
1349
Note that CTF parameters for all images need to be given in the input STAR file. \
 
1350
The command 'relion_refine --print_metadata_labels' will print a list of all possible metadata labels for that STAR file. \
 
1351
See the RELION Wiki for more details.\n\n Also make sure that the correct pixel size (in Angstrom) is given above!)", ctf_group);
 
1352
 
 
1353
        ctf_group->begin();
 
1354
 
 
1355
        ctf_phase_flipped.place(current_y, "Have data been phase-flipped?", false, "Set this to Yes if the images have been \
 
1356
ctf-phase corrected during the pre-processing steps. \
 
1357
Note that CTF-phase flipping is NOT a necessary pre-processing step for MAP-refinement in RELION, \
 
1358
as this can be done inside the internal CTF-correction. \
 
1359
However, if the phases have been flipped, you should tell the program about it by setting this option to Yes.");
 
1360
 
 
1361
        ctf_intact_first_peak.place(current_y, "Ignore CTFs until first peak?", false, "If set to Yes, then CTF-amplitude correction will \
 
1362
only be performed from the first peak of each CTF onward. This can be useful if the CTF model is inadequate at the lowest resolution. \
 
1363
Still, in general using higher amplitude contrast on the CTFs (e.g. 10-20%) often yields better results. \
 
1364
Therefore, this option is not generally recommended: try increasing amplitude contrast (in your input STAR file) first!");
 
1365
 
 
1366
        ctf_group->end();
 
1367
 
 
1368
        do_ctf_correction.cb_menu_i(); // To make default effective
 
1369
 
 
1370
        tab2->end();
 
1371
 
 
1372
        tab3->begin();
 
1373
        tab3->label("Optimisation");
 
1374
        resetHeight();
 
1375
 
 
1376
        nr_iter.place(current_y, "Number of iterations:", 25, 1, 50, 1, "Number of iterations to be performed. \
 
1377
Note that the current implementation of 2D class averaging and 3D classification does NOT comprise a convergence criterium. \
 
1378
Therefore, the calculations will need to be stopped by the user if further iterations do not yield improvements in resolution or classes. \n\n \
 
1379
Also note that upon restarting, the iteration number continues to be increased, starting from the final iteration in the previous run. \
 
1380
The number given here is the TOTAL number of iterations. For example, if 10 iterations have been performed previously and one restarts to perform \
 
1381
an additional 5 iterations (for example with a finer angular sampling), then the number given here should be 10+5=15.");
 
1382
 
 
1383
        tau_fudge.place(current_y, "Regularisation parameter T:", 2 , 0.1, 10, 0.1, "Bayes law strictly determines the relative weight between \
 
1384
the contribution of the experimental data and the prior. However, in practice one may need to adjust this weight to put slightly more weight on \
 
1385
the experimental data to allow optimal results. Values greater than 1 for this regularisation parameter (T in the JMB2011 paper) put more \
 
1386
weight on the experimental data. Values around 2-4 have been observed to be useful for 3D refinements, values of 1-2 for 2D refinements. \
 
1387
Too small values yield too-low resolution structures; too high values result in over-estimated resolutions, mostly notable by the apparition of high-frequency noise in the references.");
 
1388
 
 
1389
        // Add a little spacer
 
1390
        current_y += STEPY/2;
 
1391
 
 
1392
        do_zero_mask.place(current_y, "Mask individual particles with zeros?", true, "If set to Yes, then in the individual particles, \
 
1393
the area outside a circle with the radius of the particle will be set to zeros prior to taking the Fourier transform. \
 
1394
This will remove noise and therefore increase sensitivity in the alignment and classification. However, it will also introduce correlations \
 
1395
between the Fourier components that are not modelled. When set to No, then the solvent area is filled with random noise, which prevents introducing correlations.\
 
1396
High-resolution refinements (e.g. ribosomes or other large complexes in 3D auto-refine) tend to work better when filling the solvent area with random noise (i.e. setting this option to No), refinements of smaller complexes and most classifications go better when using zeros (i.e. setting this option to Yes).");
 
1397
 
 
1398
        // Add a little spacer
 
1399
        current_y += STEPY/2;
 
1400
 
 
1401
        highres_limit.place(current_y, "Limit resolution E-step to (A): ", -1, -1, 20, 1, "If set to a positive number, then the expectation step (i.e. the alignment) will be done only including the Fourier components up to this resolution (in Angstroms). \
 
1402
This is useful to prevent overfitting, as the classification runs in RELION are not to be guaranteed to be 100% overfitting-free (unlike the 3D auto-refine with its gold-standard FSC). In particular for very difficult data sets, e.g. of very small or featureless particles, this has been shown to give much better class averages. \
 
1403
In such cases, values in the range of 7-12 Angstroms have proven useful.");
 
1404
 
 
1405
        tab3->end();
 
1406
 
 
1407
        tab4->begin();
 
1408
        tab4->label("Sampling");
 
1409
 
 
1410
        //set up groups
 
1411
        dont_skip_align_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
 
1412
        dont_skip_align_group->end();
 
1413
 
 
1414
        resetHeight();
 
1415
 
 
1416
        dont_skip_align.place(current_y, "Perform image alignment?", true, "If set to No, then rather than \
 
1417
performing both alignment and classification, only classification will be performed. This allows the use of very focused masks.\
 
1418
This requires that the optimal orientations of all particles are already stored in the input STAR file. ", dont_skip_align_group);
 
1419
        dont_skip_align_group->begin();
 
1420
 
 
1421
        psi_sampling.place(current_y, "In-plane angular sampling:", 5., 0.5, 20, 0.5, "The sampling rate for the in-plane rotation angle (psi) in degrees. \
 
1422
Using fine values will slow down the program. Recommended value for most 2D refinements: 5 degrees.\n\n \
 
1423
If auto-sampling is used, this will be the value for the first iteration(s) only, and the sampling rate will be increased automatically after that.");
 
1424
 
 
1425
 
 
1426
        offset_range.place(current_y, "Offset search range (pix):", 5, 0, 30, 1, "Probabilities will be calculated only for translations \
 
1427
in a circle with this radius (in pixels). The center of this circle changes at every iteration and is placed at the optimal translation \
 
1428
for each image in the previous iteration.\n\n \
 
1429
If auto-sampling is used, this will be the value for the first iteration(s) only, and the sampling rate will be increased automatically after that.");
 
1430
 
 
1431
        offset_step.place(current_y, "Offset search step (pix):", 1, 0.1, 5, 0.1, "Translations will be sampled with this step-size (in pixels).\
 
1432
Translational sampling is also done using the adaptive approach. \
 
1433
Therefore, if adaptive=1, the translations will first be evaluated on a 2x coarser grid.\n\n \
 
1434
If auto-sampling is used, this will be the value for the first iteration(s) only, and the sampling rate will be increased automatically after that.");
 
1435
 
 
1436
        dont_skip_align_group->end();
 
1437
        dont_skip_align.cb_menu_i(); // to make default effective
 
1438
 
 
1439
        tab4->end();
 
1440
 
 
1441
        // read settings if hidden file exists
 
1442
        read(".gui_class2d.settings", is_continue);
 
1443
 
 
1444
}
 
1445
 
 
1446
void Class2DJobWindow::write(std::string fn)
 
1447
{
 
1448
        std::ofstream fh;
 
1449
        openWriteFile(fn + ".gui_class2d.settings", fh);
 
1450
 
 
1451
        // I/O
 
1452
        fn_out.writeValue(fh);
 
1453
        fn_cont.writeValue(fh);
 
1454
        fn_img.writeValue(fh);
 
1455
        nr_classes.writeValue(fh);
 
1456
 
 
1457
        // CTF
 
1458
        do_ctf_correction.writeValue(fh);
 
1459
        ctf_phase_flipped.writeValue(fh);
 
1460
        ctf_intact_first_peak.writeValue(fh);
 
1461
 
 
1462
        // Optimisation
 
1463
        nr_iter.writeValue(fh);
 
1464
        tau_fudge.writeValue(fh);
 
1465
        do_zero_mask.writeValue(fh);
 
1466
        highres_limit.writeValue(fh);
 
1467
 
 
1468
        // Sampling
 
1469
        dont_skip_align.writeValue(fh);
 
1470
        psi_sampling.writeValue(fh);
 
1471
        offset_range.writeValue(fh);
 
1472
        offset_step.writeValue(fh);
 
1473
 
 
1474
        closeWriteFile(fh);
 
1475
}
 
1476
 
 
1477
void Class2DJobWindow::read(std::string fn, bool &_is_continue)
 
1478
{
 
1479
 
 
1480
        std::ifstream fh;
 
1481
        if (openReadFile(fn, fh))
 
1482
        {
 
1483
 
 
1484
                // I/O
 
1485
                fn_out.readValue(fh);
 
1486
                fn_cont.readValue(fh);
 
1487
                fn_img.readValue(fh);
 
1488
                nr_classes.readValue(fh);
 
1489
 
 
1490
                // CTF
 
1491
                do_ctf_correction.readValue(fh);
 
1492
                ctf_phase_flipped.readValue(fh);
 
1493
                ctf_intact_first_peak.readValue(fh);
 
1494
 
 
1495
                // Optimisation
 
1496
                nr_iter.readValue(fh);
 
1497
                tau_fudge.readValue(fh);
 
1498
                do_zero_mask.readValue(fh);
 
1499
                highres_limit.readValue(fh);
 
1500
 
 
1501
                // Sampling
 
1502
                dont_skip_align.readValue(fh);
 
1503
                psi_sampling.readValue(fh);
 
1504
                offset_range.readValue(fh);
 
1505
                offset_step.readValue(fh);
 
1506
 
 
1507
                closeReadFile(fh);
 
1508
                _is_continue = is_continue;
 
1509
        }
 
1510
}
 
1511
 
 
1512
void Class2DJobWindow::toggle_new_continue(bool _is_continue)
 
1513
{
 
1514
        is_continue = _is_continue;
 
1515
 
 
1516
        fn_cont.deactivate(!is_continue);
 
1517
        fn_img.deactivate(is_continue);
 
1518
        nr_classes.deactivate(is_continue);
 
1519
        do_zero_mask.deactivate(is_continue);
 
1520
        do_ctf_correction.deactivate(is_continue);
 
1521
        ctf_phase_flipped.deactivate(is_continue);
 
1522
        ctf_intact_first_peak.deactivate(is_continue);
 
1523
 
 
1524
}
 
1525
 
 
1526
void Class2DJobWindow::getCommands(std::string &outputname, std::vector<std::string> &commands,
 
1527
                std::string &final_command, double angpix, double particle_diameter)
 
1528
{
 
1529
        commands.clear();
 
1530
        std::string command;
 
1531
 
 
1532
        if (nr_mpi.getValue() > 1)
 
1533
                command="`which relion_refine_mpi`";
 
1534
        else
 
1535
                command="`which relion_refine`";
 
1536
 
 
1537
        // I/O
 
1538
        // Save the real output name (could be with _ctX for continuation)
 
1539
        // This name will also be used for the stderr and stdout outputs and the submit script and gui settings filenames
 
1540
        outputname = fn_out.getValue();
 
1541
        if (is_continue)
 
1542
        {
 
1543
                int pos_it = fn_cont.getValue().rfind("_it");
 
1544
                int pos_op = fn_cont.getValue().rfind("_optimiser");
 
1545
                if (pos_it < 0 || pos_op < 0)
 
1546
                        std::cerr << "Warning: invalid optimiser.star filename provided for continuation run: " << fn_cont.getValue() << std::endl;
 
1547
                int it = (int)textToFloat((fn_cont.getValue().substr(pos_it+3, 6)).c_str());
 
1548
                outputname += "_ct" + floatToString(it);
 
1549
        }
 
1550
        command += " --o " + outputname;
 
1551
        if (is_continue)
 
1552
        {
 
1553
                command += " --continue " + fn_cont.getValue();
 
1554
        }
 
1555
        else
 
1556
        {
 
1557
                command += " --i " + fn_img.getValue();
 
1558
                command += " --particle_diameter " + floatToString(particle_diameter);
 
1559
                command += " --angpix " + floatToString(angpix);
 
1560
        }
 
1561
 
 
1562
        // CTF stuff
 
1563
        if (!is_continue)
 
1564
        {
 
1565
 
 
1566
                if (do_ctf_correction.getValue())
 
1567
                {
 
1568
                        command += " --ctf ";
 
1569
                        if (ctf_phase_flipped.getValue())
 
1570
                                command += " --ctf_phase_flipped ";
 
1571
                        if (ctf_intact_first_peak.getValue())
 
1572
                                command += " --ctf_intact_first_peak ";
 
1573
                }
 
1574
        }
 
1575
 
 
1576
        // Optimisation
 
1577
        command += " --iter " + floatToString(nr_iter.getValue());
 
1578
        command += " --tau2_fudge " + floatToString(tau_fudge.getValue());
 
1579
        if (!is_continue)
 
1580
        {
 
1581
                command += " --K " + floatToString(nr_classes.getValue());
 
1582
                // Always flatten the solvent
 
1583
                command += " --flatten_solvent ";
 
1584
                if (do_zero_mask.getValue())
 
1585
                        command += " --zero_mask ";
 
1586
                if (highres_limit.getValue() > 0)
 
1587
                        command += " --strict_highres_exp " + floatToString(highres_limit.getValue());
 
1588
        }
 
1589
 
 
1590
        // Sampling
 
1591
        int iover = 1;
 
1592
        command += " --oversampling " + floatToString((float)iover);
 
1593
 
 
1594
        if (!dont_skip_align.getValue())
 
1595
        {
 
1596
                command += " --skip_align ";
 
1597
        }
 
1598
        else
 
1599
        {
 
1600
                // The sampling given in the GUI will be the oversampled one!
 
1601
                command += " --psi_step " + floatToString(psi_sampling.getValue() * pow(2., iover));
 
1602
                // Offset range
 
1603
                command += " --offset_range " + floatToString(offset_range.getValue());
 
1604
                // The sampling given in the GUI will be the oversampled one!
 
1605
                command += " --offset_step " + floatToString(offset_step.getValue() * pow(2., iover));
 
1606
        }
 
1607
 
 
1608
        // Always do norm and scale correction
 
1609
        if (!is_continue)
 
1610
                command += " --norm --scale ";
 
1611
 
 
1612
        // Running stuff
 
1613
        command += " --j " + floatToString(nr_threads.getValue());
 
1614
        if (!is_continue)
 
1615
                command += " --memory_per_thread " + floatToString(ram_per_thread.getValue());
 
1616
 
 
1617
        // Other arguments
 
1618
        command += " " + other_args.getValue();
 
1619
 
 
1620
        commands.push_back(command);
 
1621
 
 
1622
        prepareFinalCommand(outputname, commands, final_command);
 
1623
 
 
1624
}
 
1625
 
 
1626
 
 
1627
 
 
1628
Class3DJobWindow::Class3DJobWindow() : RelionJobWindow(5, HAS_MPI, HAS_THREAD)
 
1629
{
 
1630
 
 
1631
        tab1->begin();
 
1632
        tab1->label("I/O");
 
1633
        resetHeight();
 
1634
 
 
1635
        fn_img.place(current_y, "Input images STAR file:", "", "STAR files (*.star) \t Image stacks (not recommended, read help!) (*.{spi,mrcs})", "A STAR file with all images (and their metadata). \n \n Alternatively, you may give a Spider/MRC stack of 2D images, but in that case NO metadata can be included and thus NO CTF correction can be performed, \
 
1636
nor will it be possible to perform noise spectra estimation or intensity scale corrections in image groups. Therefore, running RELION with an input stack will in general provide sub-optimal results and is therefore not recommended!! Use the Preprocessing procedure to get the input STAR file in a semi-automated manner. Read the RELION wiki for more information.");
 
1637
 
 
1638
        fn_out.place(current_y, "Output rootname:", "Class3D/run1", "Output rootname for all files of this run. \
 
1639
If this rootname contains a directory structure (e.g. 20110724/run1), the directory (20110724) will be created if it does not exist.");
 
1640
 
 
1641
        fn_cont.place(current_y, "Continue from here: ", "", "STAR Files (*_optimiser.star)", "Select the *_optimiser.star file for the iteration \
 
1642
from which you want to continue a previous run. \
 
1643
Note that the Output rootname of the continued run and the rootname of the previous run cannot be the same. \
 
1644
If they are the same, the program will automatically add a '_ctX' to the output rootname, \
 
1645
with X being the iteration from which one continues the previous run.");
 
1646
 
 
1647
        // Add a little spacer
 
1648
        current_y += STEPY/2;
 
1649
 
 
1650
        nr_classes.place(current_y, "Number of classes:", 1, 1, 50, 1, "The number of classes (K) for a multi-reference refinement. \
 
1651
These classes will be made in an unsupervised manner from a single reference by division of the data into random subsets during the first iteration.");
 
1652
 
 
1653
        tab1->end();
 
1654
        tab2->begin();
 
1655
        tab2->label("Reference");
 
1656
        resetHeight();
 
1657
 
 
1658
        fn_ref.place(current_y, "Reference map:", "", "Image Files (*.{spi,vol,mrc})", "A 3D map in MRC/Spider format. \
 
1659
        Make sure this map has the same dimensions and the same pixel size as your input images.");
 
1660
 
 
1661
        ref_correct_greyscale.place(current_y, "Ref. map is on absolute greyscale?", false, "Probabilities are calculated based on a Gaussian noise model, \
 
1662
which contains a squared difference term between the reference and the experimental image. This has a consequence that the \
 
1663
reference needs to be on the same absolute intensity grey-scale as the experimental images. \
 
1664
RELION and XMIPP reconstruct maps at their absolute intensity grey-scale. \
 
1665
Other packages may perform internal normalisations of the reference density, which will result in incorrect grey-scales. \
 
1666
Therefore: if the map was reconstructed in RELION or in XMIPP, set this option to Yes, otherwise set it to No. \
 
1667
If set to No, RELION will use a (grey-scale invariant) cross-correlation criterion in the first iteration, \
 
1668
and prior to the second iteration the map will be filtered again using the initial low-pass filter. \
 
1669
This procedure is relatively quick and typically does not negatively affect the outcome of the subsequent MAP refinement. \
 
1670
Therefore, if in doubt it is recommended to set this option to No.");
 
1671
 
 
1672
        ini_high.place(current_y, "Initial low-pass filter (A):", 60, 0, 200, 5, "It is recommended to strongly low-pass filter your initial reference map. \
 
1673
If it has not yet been low-pass filtered, it may be done internally using this option. \
 
1674
If set to 0, no low-pass filter will be applied to the initial reference(s).");
 
1675
 
 
1676
        // Add a little spacer
 
1677
        current_y += STEPY/2;
 
1678
 
 
1679
        sym_name.place(current_y, "Symmetry:", "C1", "If the molecule is asymmetric, \
 
1680
set Symmetry group to C1. Note their are multiple possibilities for icosahedral symmetry: \n \
 
1681
* I1: No-Crowther 222 (standard in Heymann, Chagoyen & Belnap, JSB, 151 (2005) 196ā€“207) \n \
 
1682
* I2: Crowther 222 \n \
 
1683
* I3: 52-setting (as used in SPIDER?)\n \
 
1684
* I4: A different 52 setting \n \
 
1685
The command 'relion_refine --sym D2 --print_symmetry_ops' prints a list of all symmetry operators for symmetry group D2. \
 
1686
RELION uses XMIPP's libraries for symmetry operations. \
 
1687
Therefore, look at the XMIPP Wiki for more details:  http://xmipp.cnb.csic.es/twiki/bin/view/Xmipp/WebHome?topic=Symmetry");
 
1688
 
 
1689
        tab2->end();
 
1690
        tab3->begin();
 
1691
        tab3->label("CTF");
 
1692
 
 
1693
        ctf_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
 
1694
        ctf_group->end();
 
1695
 
 
1696
        resetHeight();
 
1697
        do_ctf_correction.place(current_y, "Do CTF-correction?", true, "If set to Yes, CTFs will be corrected inside the MAP refinement. \
 
1698
The resulting algorithm intrinsically implements the optimal linear, or Wiener filter. \
 
1699
Note that CTF parameters for all images need to be given in the input STAR file. \
 
1700
The command 'relion_refine --print_metadata_labels' will print a list of all possible metadata labels for that STAR file. \
 
1701
See the RELION Wiki for more details.\n\n Also make sure that the correct pixel size (in Angstrom) is given above!)", ctf_group);
 
1702
 
 
1703
        ctf_group->begin();
 
1704
 
 
1705
        ctf_corrected_ref.place(current_y, "Has reference been CTF-corrected?", false, "Set this option to Yes if the reference map \
 
1706
represents density that is unaffected by CTF phases and amplitudes, e.g. it was created using CTF correction (Wiener filtering) inside RELION or from a PDB. \n\n\
 
1707
If set to No, then in the first iteration, the Fourier transforms of the reference projections are not multiplied by the CTFs.");
 
1708
 
 
1709
        ctf_phase_flipped.place(current_y, "Have data been phase-flipped?", false, "Set this to Yes if the images have been \
 
1710
ctf-phase corrected during the pre-processing steps. \
 
1711
Note that CTF-phase flipping is NOT a necessary pre-processing step for MAP-refinement in RELION, \
 
1712
as this can be done inside the internal CTF-correction. \
 
1713
However, if the phases have been flipped, you should tell the program about it by setting this option to Yes.");
 
1714
 
 
1715
        ctf_intact_first_peak.place(current_y, "Ignore CTFs until first peak?", false, "If set to Yes, then CTF-amplitude correction will \
 
1716
only be performed from the first peak of each CTF onward. This can be useful if the CTF model is inadequate at the lowest resolution. \
 
1717
Still, in general using higher amplitude contrast on the CTFs (e.g. 10-20%) often yields better results. \
 
1718
Therefore, this option is not generally recommended: try increasing amplitude contrast (in your input STAR file) first!");
 
1719
 
 
1720
        ctf_group->end();
 
1721
 
 
1722
        do_ctf_correction.cb_menu_i(); // To make default effective
 
1723
 
 
1724
        tab3->end();
 
1725
        tab4->begin();
 
1726
        tab4->label("Optimisation");
 
1727
        resetHeight();
 
1728
 
 
1729
        nr_iter.place(current_y, "Number of iterations:", 25, 1, 50, 1, "Number of iterations to be performed. \
 
1730
Note that the current implementation of 2D class averaging and 3D classification does NOT comprise a convergence criterium. \
 
1731
Therefore, the calculations will need to be stopped by the user if further iterations do not yield improvements in resolution or classes. \n\n \
 
1732
Also note that upon restarting, the iteration number continues to be increased, starting from the final iteration in the previous run. \
 
1733
The number given here is the TOTAL number of iterations. For example, if 10 iterations have been performed previously and one restarts to perform \
 
1734
an additional 5 iterations (for example with a finer angular sampling), then the number given here should be 10+5=15.");
 
1735
 
 
1736
        tau_fudge.place(current_y, "Regularisation parameter T:", 2 , 0.1, 10, 0.1, "Bayes law strictly determines the relative weight between \
 
1737
the contribution of the experimental data and the prior. However, in practice one may need to adjust this weight to put slightly more weight on \
 
1738
the experimental data to allow optimal results. Values greater than 1 for this regularisation parameter (T in the JMB2011 paper) put more \
 
1739
weight on the experimental data. Values around 2-4 have been observed to be useful for 3D refinements, values of 1-2 for 2D refinements. \
 
1740
Too small values yield too-low resolution structures; too high values result in over-estimated resolutions, mostly notable by the apparition of high-frequency noise in the references.");
 
1741
        // Add a little spacer
 
1742
        current_y += STEPY/2;
 
1743
 
 
1744
        do_zero_mask.place(current_y, "Mask individual particles with zeros?", true, "If set to Yes, then in the individual particles, \
 
1745
the area outside a circle with the radius of the particle will be set to zeros prior to taking the Fourier transform. \
 
1746
This will remove noise and therefore increase sensitivity in the alignment and classification. However, it will also introduce correlations \
 
1747
between the Fourier components that are not modelled. When set to No, then the solvent area is filled with random noise, which prevents introducing correlations.\
 
1748
High-resolution refinements (e.g. ribosomes or other large complexes in 3D auto-refine) tend to work better when filling the solvent area with random noise (i.e. setting this option to No), refinements of smaller complexes and most classifications go better when using zeros (i.e. setting this option to Yes).");
 
1749
 
 
1750
        fn_mask.place(current_y, "Reference mask (optional):", "", "Image Files (*.{spi,vol,msk,mrc})", "\
 
1751
If no mask is provided, a soft spherical mask based on the particle diameter will be used.\n\
 
1752
\n\
 
1753
Otherwise, provide a Spider/mrc map containing a (soft) mask with the same \
 
1754
dimensions as the reference(s), and values between 0 and 1, with 1 being 100% protein and 0 being 100% solvent. \
 
1755
The reconstructed reference map will be multiplied by this mask.\n\
 
1756
\n\
 
1757
In some cases, for example for non-empty icosahedral viruses, it is also useful to use a second mask. For all white (value 1) pixels in this second mask \
 
1758
the corresponding pixels in the reconstructed map are set to the average value of these pixels. \
 
1759
Thereby, for example, the higher density inside the virion may be set to a constant. \
 
1760
Note that this second mask should have one-values inside the virion and zero-values in the capsid and the solvent areas. \
 
1761
To use a second mask, use the additional option --solvent_mask2, which may given in the Additional arguments line (in the Running tab).");
 
1762
 
 
1763
        // Add a little spacer
 
1764
        current_y += STEPY/2;
 
1765
 
 
1766
        highres_limit.place(current_y, "Limit resolution E-step to (A): ", -1, -1, 20, 1, "If set to a positive number, then the expectation step (i.e. the alignment) will be done only including the Fourier components up to this resolution (in Angstroms). \
 
1767
This is useful to prevent overfitting, as the classification runs in RELION are not to be guaranteed to be 100% overfitting-free (unlike the 3D auto-refine with its gold-standard FSC). In particular for very difficult data sets, e.g. of very small or featureless particles, this has been shown to give much better class averages. \
 
1768
In such cases, values in the range of 7-12 Angstroms have proven useful.");
 
1769
 
 
1770
        tab4->end();
 
1771
 
 
1772
        tab5->begin();
 
1773
        tab5->label("Sampling");
 
1774
 
 
1775
        //set up groups
 
1776
        dont_skip_align_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
 
1777
        dont_skip_align_group->end();
 
1778
 
 
1779
        resetHeight();
 
1780
 
 
1781
        dont_skip_align.place(current_y, "Perform image alignment?", true, "If set to No, then rather than \
 
1782
performing both alignment and classification, only classification will be performed. This allows the use of very focused masks.\
 
1783
This requires that the optimal orientations of all particles are already stored in the input STAR file. ", dont_skip_align_group);
 
1784
        dont_skip_align_group->begin();
 
1785
 
 
1786
        sampling.place(current_y, "Angular sampling interval:", sampling_options, &sampling_options[2], "There are only a few discrete \
 
1787
angular samplings possible because we use the HealPix library to generate the sampling of the first two Euler angles on the sphere. \
 
1788
The samplings are approximate numbers and vary slightly over the sphere.\n\n \
 
1789
If auto-sampling is used, this will be the value for the first iteration(s) only, and the sampling rate will be increased automatically after that.");
 
1790
 
 
1791
        offset_range.place(current_y, "Offset search range (pix):", 5, 0, 30, 1, "Probabilities will be calculated only for translations \
 
1792
in a circle with this radius (in pixels). The center of this circle changes at every iteration and is placed at the optimal translation \
 
1793
for each image in the previous iteration.\n\n \
 
1794
If auto-sampling is used, this will be the value for the first iteration(s) only, and the sampling rate will be increased automatically after that.");
 
1795
 
 
1796
        offset_step.place(current_y, "Offset search step (pix):", 1, 0.1, 5, 0.1, "Translations will be sampled with this step-size (in pixels).\
 
1797
Translational sampling is also done using the adaptive approach. \
 
1798
Therefore, if adaptive=1, the translations will first be evaluated on a 2x coarser grid.\n\n \
 
1799
If auto-sampling is used, this will be the value for the first iteration(s) only, and the sampling rate will be increased automatically after that.");
 
1800
 
 
1801
        localsearch_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
 
1802
        localsearch_group->end();
 
1803
 
 
1804
        do_local_ang_searches.place(current_y, "Perform local angular searches?", false, "If set to Yes, then rather than \
 
1805
performing exhaustive angular searches, local searches within the range given below will be performed. \
 
1806
A prior Gaussian distribution centered at the optimal orientation in the previous iteration and \
 
1807
with a stddev of 1/3 of the range given below will be enforced.", localsearch_group);
 
1808
        localsearch_group->begin();
 
1809
 
 
1810
        sigma_angles.place(current_y, "Local angular search range:", 5., 0, 15, 0.1, "Local angular searches will be performed \
 
1811
within +/- the given amount (in degrees) from the optimal orientation in the previous iteration. \
 
1812
A Gaussian prior (also see previous option) will be applied, so that orientations closer to the optimal orientation \
 
1813
in the previous iteration will get higher weights than those further away.");
 
1814
 
 
1815
        localsearch_group->end();
 
1816
        do_local_ang_searches.cb_menu_i(); // to make default effective
 
1817
 
 
1818
        dont_skip_align_group->end();
 
1819
        dont_skip_align.cb_menu_i(); // to make default effective
 
1820
 
 
1821
        tab5->end();
 
1822
 
 
1823
        // read settings if hidden file exists
 
1824
        read(".gui_class3d.settings", is_continue);
 
1825
 
 
1826
}
 
1827
 
 
1828
void Class3DJobWindow::write(std::string fn)
 
1829
{
 
1830
        std::ofstream fh;
 
1831
        openWriteFile(fn + ".gui_class3d.settings", fh);
 
1832
 
 
1833
        // I/O
 
1834
        fn_out.writeValue(fh);
 
1835
        fn_cont.writeValue(fh);
 
1836
        fn_img.writeValue(fh);
 
1837
        nr_classes.writeValue(fh);
 
1838
 
 
1839
        // Reference
 
1840
        fn_ref.writeValue(fh);
 
1841
        ref_correct_greyscale.writeValue(fh);
 
1842
        ini_high.writeValue(fh);
 
1843
        sym_name.writeValue(fh);
 
1844
 
 
1845
        // CTF
 
1846
        do_ctf_correction.writeValue(fh);
 
1847
        ctf_corrected_ref.writeValue(fh);
 
1848
        ctf_phase_flipped.writeValue(fh);
 
1849
        ctf_intact_first_peak.writeValue(fh);
 
1850
 
 
1851
        // Optimisation
 
1852
        nr_iter.writeValue(fh);
 
1853
        tau_fudge.writeValue(fh);
 
1854
        do_zero_mask.writeValue(fh);
 
1855
        fn_mask.writeValue(fh);
 
1856
        highres_limit.writeValue(fh);
 
1857
 
 
1858
        // Sampling
 
1859
        dont_skip_align.writeValue(fh);
 
1860
        sampling.writeValue(fh);
 
1861
        offset_range.writeValue(fh);
 
1862
        offset_step.writeValue(fh);
 
1863
        do_local_ang_searches.writeValue(fh);
 
1864
        sigma_angles.writeValue(fh);
 
1865
 
 
1866
        closeWriteFile(fh);
 
1867
}
 
1868
 
 
1869
void Class3DJobWindow::read(std::string fn, bool &_is_continue)
 
1870
{
 
1871
 
 
1872
        std::ifstream fh;
 
1873
        if (openReadFile(fn, fh))
 
1874
        {
 
1875
 
 
1876
                // I/O
 
1877
                fn_out.readValue(fh);
 
1878
                fn_cont.readValue(fh);
 
1879
                fn_img.readValue(fh);
 
1880
                nr_classes.readValue(fh);
 
1881
 
 
1882
                // Reference
 
1883
                fn_ref.readValue(fh);
 
1884
                ref_correct_greyscale.readValue(fh);
 
1885
                ini_high.readValue(fh);
 
1886
                sym_name.readValue(fh);
 
1887
 
 
1888
                // CTF
 
1889
                do_ctf_correction.readValue(fh);
 
1890
                ctf_corrected_ref.readValue(fh);
 
1891
                ctf_phase_flipped.readValue(fh);
 
1892
                ctf_intact_first_peak.readValue(fh);
 
1893
 
 
1894
                // Optimisation
 
1895
                nr_iter.readValue(fh);
 
1896
                tau_fudge.readValue(fh);
 
1897
                do_zero_mask.readValue(fh);
 
1898
                fn_mask.readValue(fh);
 
1899
                highres_limit.readValue(fh);
 
1900
 
 
1901
                // Sampling
 
1902
                dont_skip_align.readValue(fh);
 
1903
                sampling.readValue(fh);
 
1904
                offset_range.readValue(fh);
 
1905
                offset_step.readValue(fh);
 
1906
                do_local_ang_searches.readValue(fh);
 
1907
                sigma_angles.readValue(fh);
 
1908
 
 
1909
                closeReadFile(fh);
 
1910
                _is_continue = is_continue;
 
1911
        }
 
1912
}
 
1913
 
 
1914
void Class3DJobWindow::toggle_new_continue(bool _is_continue)
 
1915
{
 
1916
        is_continue = _is_continue;
 
1917
 
 
1918
        fn_cont.deactivate(!is_continue);
 
1919
        fn_img.deactivate(is_continue);
 
1920
        nr_classes.deactivate(is_continue);
 
1921
 
 
1922
        // Reference
 
1923
        fn_ref.deactivate(is_continue);
 
1924
        ref_correct_greyscale.deactivate(is_continue);
 
1925
        ini_high.deactivate(is_continue);
 
1926
        sym_name.deactivate(is_continue);
 
1927
 
 
1928
        //CTF
 
1929
        do_ctf_correction.deactivate(is_continue);
 
1930
        ctf_corrected_ref.deactivate(is_continue);
 
1931
        ctf_phase_flipped.deactivate(is_continue);
 
1932
        ctf_intact_first_peak.deactivate(is_continue);
 
1933
 
 
1934
        //Optimisation
 
1935
        do_zero_mask.deactivate(is_continue);
 
1936
 
 
1937
        // Sampling
 
1938
 
 
1939
 
 
1940
}
 
1941
 
 
1942
void Class3DJobWindow::getCommands(std::string &outputname, std::vector<std::string> &commands,
 
1943
                std::string &final_command, double angpix, double particle_diameter)
 
1944
{
 
1945
        commands.clear();
 
1946
        std::string command;
 
1947
 
 
1948
        if (nr_mpi.getValue() > 1)
 
1949
                command="`which relion_refine_mpi`";
 
1950
        else
 
1951
                command="`which relion_refine`";
 
1952
 
 
1953
        // I/O
 
1954
        // Save the real output name (could be with _ctX for continuation)
 
1955
        // This name will also be used for the stderr and stdout outputs and the submit script and gui settings filenames
 
1956
        outputname = fn_out.getValue();
 
1957
        if (is_continue)
 
1958
        {
 
1959
                int pos_it = fn_cont.getValue().rfind("_it");
 
1960
                int pos_op = fn_cont.getValue().rfind("_optimiser");
 
1961
                if (pos_it < 0 || pos_op < 0)
 
1962
                        std::cerr << "Warning: invalid optimiser.star filename provided for continuation run: " << fn_cont.getValue() << std::endl;
 
1963
                int it = (int)textToFloat((fn_cont.getValue().substr(pos_it+3, 6)).c_str());
 
1964
                outputname += "_ct" + floatToString(it);
 
1965
        }
 
1966
        command += " --o " + outputname;
 
1967
        if (is_continue)
 
1968
        {
 
1969
                command += " --continue " + fn_cont.getValue();
 
1970
        }
 
1971
        else
 
1972
        {
 
1973
                command += " --i " + fn_img.getValue();
 
1974
                command += " --particle_diameter " + floatToString(particle_diameter);
 
1975
                command += " --angpix " + floatToString(angpix);
 
1976
                if (fn_ref.getValue() != "None")
 
1977
                        command += " --ref " + fn_ref.getValue();
 
1978
                if (!ref_correct_greyscale.getValue() && fn_ref.getValue() != "None") // dont do firstiter_cc when giving None
 
1979
                        command += " --firstiter_cc";
 
1980
                if (ini_high.getValue() > 0.)
 
1981
                        command += " --ini_high " + floatToString(ini_high.getValue());
 
1982
 
 
1983
        }
 
1984
 
 
1985
        // CTF stuff
 
1986
        if (!is_continue)
 
1987
        {
 
1988
 
 
1989
                if (do_ctf_correction.getValue())
 
1990
                {
 
1991
                        command += " --ctf";
 
1992
                        if (ctf_corrected_ref.getValue())
 
1993
                                command += " --ctf_corrected_ref";
 
1994
                        if (ctf_phase_flipped.getValue())
 
1995
                                command += " --ctf_phase_flipped";
 
1996
                        if (ctf_intact_first_peak.getValue())
 
1997
                                command += " --ctf_intact_first_peak";
 
1998
                }
 
1999
        }
 
2000
 
 
2001
        // Optimisation
 
2002
        command += " --iter " + floatToString(nr_iter.getValue());
 
2003
        command += " --tau2_fudge " + floatToString(tau_fudge.getValue());
 
2004
        if (!is_continue)
 
2005
        {
 
2006
                command += " --K " + floatToString(nr_classes.getValue());
 
2007
                // Always flatten the solvent
 
2008
                command += " --flatten_solvent";
 
2009
                if (do_zero_mask.getValue())
 
2010
                        command += " --zero_mask";
 
2011
                if (highres_limit.getValue() > 0)
 
2012
                        command += " --strict_highres_exp " + floatToString(highres_limit.getValue());
 
2013
        }
 
2014
        if (fn_mask.getValue().length() > 0)
 
2015
                command += " --solvent_mask " + fn_mask.getValue();
 
2016
 
 
2017
        // Sampling
 
2018
        int iover = 1;
 
2019
        command += " --oversampling " + floatToString((float)iover);
 
2020
 
 
2021
        if (!dont_skip_align.getValue())
 
2022
        {
 
2023
                command += " --skip_align ";
 
2024
        }
 
2025
        else
 
2026
        {
 
2027
                for (int i = 0; i < 10; i++)
 
2028
                {
 
2029
                        if (strcmp((sampling.getValue()).c_str(), sampling_options[i].label()) == 0)
 
2030
                        {
 
2031
                                // The sampling given in the GUI will be the oversampled one!
 
2032
                                command += " --healpix_order " + floatToString((float)i + 1 - iover);
 
2033
                                break;
 
2034
                        }
 
2035
                }
 
2036
                // Manually input local angular searches
 
2037
                if (do_local_ang_searches.getValue())
 
2038
                        command += " --sigma_ang " + floatToString(sigma_angles.getValue() / 3.);
 
2039
 
 
2040
                // Offset range
 
2041
                command += " --offset_range " + floatToString(offset_range.getValue());
 
2042
                // The sampling given in the GUI will be the oversampled one!
 
2043
                command += " --offset_step " + floatToString(offset_step.getValue() * pow(2., iover));
 
2044
        }
 
2045
 
 
2046
        // Provide symmetry, and always do norm and scale correction
 
2047
        if (!is_continue)
 
2048
        {
 
2049
                command += " --sym " + sym_name.getValue();
 
2050
                command += " --norm --scale ";
 
2051
        }
 
2052
 
 
2053
        // Running stuff
 
2054
        command += " --j " + floatToString(nr_threads.getValue());
 
2055
        if (!is_continue)
 
2056
                command += " --memory_per_thread " + floatToString(ram_per_thread.getValue());
 
2057
 
 
2058
        // Other arguments
 
2059
        command += " " + other_args.getValue();
 
2060
 
 
2061
        commands.push_back(command);
 
2062
 
 
2063
        prepareFinalCommand(outputname, commands, final_command);
 
2064
 
 
2065
}
 
2066
 
 
2067
 
 
2068
Auto3DJobWindow::Auto3DJobWindow() : RelionJobWindow(6, HAS_MPI, HAS_THREAD)
 
2069
{
 
2070
 
 
2071
        tab1->begin();
 
2072
        tab1->label("I/O");
 
2073
        resetHeight();
 
2074
 
 
2075
        fn_img.place(current_y, "Input images STAR file:", "", "STAR files (*.star) \t Image stacks (not recommended, read help!) (*.{spi,mrcs})", "A STAR file with all images (and their metadata). \n \n Alternatively, you may give a Spider/MRC stack of 2D images, but in that case NO metadata can be included and thus NO CTF correction can be performed, \
 
2076
nor will it be possible to perform noise spectra estimation or intensity scale corrections in image groups. Therefore, running RELION with an input stack will in general provide sub-optimal results and is therefore not recommended!! Use the Preprocessing procedure to get the input STAR file in a semi-automated manner. Read the RELION wiki for more information.");
 
2077
 
 
2078
        fn_out.place(current_y, "Output rootname:", "Refine3D/run1", "Output rootname for all files of this run. \
 
2079
If this rootname contains a directory structure (e.g. 20110724/run1), the directory (20110724) will be created if it does not exist.");
 
2080
 
 
2081
        fn_cont.place(current_y, "Continue from here: ", "", "STAR Files (*_optimiser.star)", "Select the *_optimiser.star file for the iteration \
 
2082
from which you want to continue a previous run. \
 
2083
Note that the Output rootname of the continued run and the rootname of the previous run cannot be the same. \
 
2084
If they are the same, the program will automatically add a '_ctX' to the output rootname, \
 
2085
with X being the iteration from which one continues the previous run. \n \
 
2086
Besides restarting jobs that were somehow stopped before convergence, also use the continue-option after the last iteration to do movie processing.");
 
2087
 
 
2088
        tab1->end();
 
2089
        tab2->begin();
 
2090
        tab2->label("Reference");
 
2091
        resetHeight();
 
2092
 
 
2093
        fn_ref.place(current_y, "Reference map:", "", "Image Files (*.{spi,vol,mrc})", "A 3D map in MRC/Spider format. \
 
2094
        Make sure this map has the same dimensions and the same pixel size as your input images.");
 
2095
 
 
2096
        ref_correct_greyscale.place(current_y, "Ref. map is on absolute greyscale?", false, "Probabilities are calculated based on a Gaussian noise model, \
 
2097
which contains a squared difference term between the reference and the experimental image. This has a consequence that the \
 
2098
reference needs to be on the same absolute intensity grey-scale as the experimental images. \
 
2099
RELION and XMIPP reconstruct maps at their absolute intensity grey-scale. \
 
2100
Other packages may perform internal normalisations of the reference density, which will result in incorrect grey-scales. \
 
2101
Therefore: if the map was reconstructed in RELION or in XMIPP, set this option to Yes, otherwise set it to No. \
 
2102
If set to No, RELION will use a (grey-scale invariant) cross-correlation criterion in the first iteration, \
 
2103
and prior to the second iteration the map will be filtered again using the initial low-pass filter. \
 
2104
This procedure is relatively quick and typically does not negatively affect the outcome of the subsequent MAP refinement. \
 
2105
Therefore, if in doubt it is recommended to set this option to No.");
 
2106
 
 
2107
        ini_high.place(current_y, "Initial low-pass filter (A):", 60, 0, 200, 5, "It is recommended to strongly low-pass filter your initial reference map. \
 
2108
If it has not yet been low-pass filtered, it may be done internally using this option. \
 
2109
If set to 0, no low-pass filter will be applied to the initial reference(s).");
 
2110
 
 
2111
        // Add a little spacer
 
2112
        current_y += STEPY/2;
 
2113
 
 
2114
 
 
2115
        sym_name.place(current_y, "Symmetry:", "C1", "If the molecule is asymmetric, \
 
2116
set Symmetry group to C1. Note their are multiple possibilities for icosahedral symmetry: \n \
 
2117
* I1: No-Crowther 222 (standard in Heymann, Chagoyen & Belnap, JSB, 151 (2005) 196ā€“207) \n \
 
2118
* I2: Crowther 222 \n \
 
2119
* I3: 52-setting (as used in SPIDER?)\n \
 
2120
* I4: A different 52 setting \n \
 
2121
The command 'relion_refine --sym D2 --print_symmetry_ops' prints a list of all symmetry operators for symmetry group D2. \
 
2122
RELION uses XMIPP's libraries for symmetry operations. \
 
2123
Therefore, look at the XMIPP Wiki for more details:  http://xmipp.cnb.csic.es/twiki/bin/view/Xmipp/WebHome?topic=Symmetry");
 
2124
 
 
2125
        tab2->end();
 
2126
        tab3->begin();
 
2127
        tab3->label("CTF");
 
2128
 
 
2129
        ctf_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
 
2130
        ctf_group->end();
 
2131
 
 
2132
        resetHeight();
 
2133
        do_ctf_correction.place(current_y, "Do CTF-correction?", true, "If set to Yes, CTFs will be corrected inside the MAP refinement. \
 
2134
The resulting algorithm intrinsically implements the optimal linear, or Wiener filter. \
 
2135
Note that CTF parameters for all images need to be given in the input STAR file. \
 
2136
The command 'relion_refine --print_metadata_labels' will print a list of all possible metadata labels for that STAR file. \
 
2137
See the RELION Wiki for more details.\n\n Also make sure that the correct pixel size (in Angstrom) is given above!)", ctf_group);
 
2138
 
 
2139
        ctf_group->begin();
 
2140
 
 
2141
        ctf_corrected_ref.place(current_y, "Has reference been CTF-corrected?", false, "Set this option to Yes if the reference map \
 
2142
represents density that is unaffected by CTF phases and amplitudes, e.g. it was created using CTF correction (Wiener filtering) inside RELION or from a PDB. \n\n\
 
2143
If set to No, then in the first iteration, the Fourier transforms of the reference projections are not multiplied by the CTFs.");
 
2144
 
 
2145
        ctf_phase_flipped.place(current_y, "Have data been phase-flipped?", false, "Set this to Yes if the images have been \
 
2146
ctf-phase corrected during the pre-processing steps. \
 
2147
Note that CTF-phase flipping is NOT a necessary pre-processing step for MAP-refinement in RELION, \
 
2148
as this can be done inside the internal CTF-correction. \
 
2149
However, if the phases have been flipped, you should tell the program about it by setting this option to Yes.");
 
2150
 
 
2151
        ctf_intact_first_peak.place(current_y, "Ignore CTFs until first peak?", false, "If set to Yes, then CTF-amplitude correction will \
 
2152
only be performed from the first peak of each CTF onward. This can be useful if the CTF model is inadequate at the lowest resolution. \
 
2153
Still, in general using higher amplitude contrast on the CTFs (e.g. 10-20%) often yields better results. \
 
2154
Therefore, this option is not generally recommended: try increasing amplitude contrast (in your input STAR file) first!");
 
2155
 
 
2156
        ctf_group->end();
 
2157
 
 
2158
        do_ctf_correction.cb_menu_i(); // To make default effective
 
2159
 
 
2160
        tab3->end();
 
2161
        tab4->begin();
 
2162
        tab4->label("Optimisation");
 
2163
        resetHeight();
 
2164
 
 
2165
        do_zero_mask.place(current_y, "Mask individual particles with zeros?", true, "If set to Yes, then in the individual particles, \
 
2166
the area outside a circle with the radius of the particle will be set to zeros prior to taking the Fourier transform. \
 
2167
This will remove noise and therefore increase sensitivity in the alignment and classification. However, it will also introduce correlations \
 
2168
between the Fourier components that are not modelled. When set to No, then the solvent area is filled with random noise, which prevents introducing correlations.\
 
2169
High-resolution refinements (e.g. ribosomes or other large complexes in 3D auto-refine) tend to work better when filling the solvent area with random noise (i.e. setting this option to No), refinements of smaller complexes and most classifications go better when using zeros (i.e. setting this option to Yes).");
 
2170
 
 
2171
        fn_mask.place(current_y, "Reference mask (optional):", "", "Image Files (*.{spi,vol,msk,mrc})", "\
 
2172
If no mask is provided, a soft spherical mask based on the particle diameter will be used.\n\
 
2173
\n\
 
2174
Otherwise, provide a Spider/mrc map containing a (soft) mask with the same \
 
2175
dimensions as the reference(s), and values between 0 and 1, with 1 being 100% protein and 0 being 100% solvent. \
 
2176
The reconstructed reference map will be multiplied by this mask.\n\
 
2177
\n\
 
2178
In some cases, for example for non-empty icosahedral viruses, it is also useful to use a second mask. For all white (value 1) pixels in this second mask \
 
2179
the corresponding pixels in the reconstructed map are set to the average value of these pixels. \
 
2180
Thereby, for example, the higher density inside the virion may be set to a constant. \
 
2181
Note that this second mask should have one-values inside the virion and zero-values in the capsid and the solvent areas. \
 
2182
To use a second mask, use the additional option --solvent_mask2, which may given in the Additional arguments line (in the Running tab).");
 
2183
 
 
2184
 
 
2185
        tab4->end();
 
2186
        tab5->begin();
 
2187
        tab5->label("Auto-sampling");
 
2188
        resetHeight();
 
2189
 
 
2190
        autosample_text.place(current_y, "Note that initial sampling rates will be auto-incremented!");
 
2191
 
 
2192
        sampling.place(current_y, "Initial angular sampling:", sampling_options, &sampling_options[2], "There are only a few discrete \
 
2193
angular samplings possible because we use the HealPix library to generate the sampling of the first two Euler angles on the sphere. \
 
2194
The samplings are approximate numbers and vary slightly over the sphere.\n\n \
 
2195
Note that this will only be the value for the first few iteration(s): the sampling rate will be increased automatically after that.");
 
2196
 
 
2197
        offset_range.place(current_y, "Initial offset range (pix):", 5, 0, 30, 1, "Probabilities will be calculated only for translations \
 
2198
in a circle with this radius (in pixels). The center of this circle changes at every iteration and is placed at the optimal translation \
 
2199
for each image in the previous iteration.\n\n \
 
2200
Note that this will only be the value for the first few iteration(s): the sampling rate will be increased automatically after that.");
 
2201
 
 
2202
        offset_step.place(current_y, "Initial offset step (pix):", 1, 0.1, 5, 0.1, "Translations will be sampled with this step-size (in pixels).\
 
2203
Translational sampling is also done using the adaptive approach. \
 
2204
Therefore, if adaptive=1, the translations will first be evaluated on a 2x coarser grid.\n\n \
 
2205
Note that this will only be the value for the first few iteration(s): the sampling rate will be increased automatically after that.");
 
2206
 
 
2207
        // Add a little spacer
 
2208
        current_y += STEPY/2;
 
2209
 
 
2210
        auto_local_sampling.place(current_y, "Local searches from auto-sampling:", sampling_options, &sampling_options[4], "In the automated procedure to \
 
2211
increase the angular samplings, local angular searches of -6/+6 times the sampling rate will be used from this angular sampling rate onwards. For most \
 
2212
lower-symmetric particles a value of 1.8 degrees will be sufficient. Perhaps icosahedral symmetries may benefit from a smaller value such as 0.9 degrees.");
 
2213
 
 
2214
        tab5->end();
 
2215
        tab4->end();
 
2216
        tab6->begin();
 
2217
        tab6->label("Movies");
 
2218
        resetHeight();
 
2219
        movie_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
 
2220
        movie_group->end();
 
2221
 
 
2222
        do_movies.place(current_y, "Realign movie frames?", false, "If set to Yes, then running averages of the individual frames of recorded movies will be aligned as independent particles.", movie_group);
 
2223
 
 
2224
        movie_group->begin();
 
2225
 
 
2226
        fn_movie_star.place(current_y, "Input movie frames STAR file:", "", "STAR Files (*.{star})", "Select the output STAR file from the preprocessing \
 
2227
procedure of the movie frames.");
 
2228
 
 
2229
        movie_runavg_window.place(current_y, "Running average window:", 5, 1, 15, 1, "The individual movie frames will be averaged using a running \
 
2230
average window with the specified width. Use an odd number. The optimal value will depend on the SNR in the individual movie frames. For ribosomes, we used a value of 5, where \
 
2231
each movie frame integrated approximately 1 electron per squared Angstrom.");
 
2232
 
 
2233
        movie_sigma_offset.place(current_y, "Stddev on the translations (pix):", 1., 0.5, 10, 0.5, "A Gaussian prior with the specified standard deviation \
 
2234
will be centered at the rotations determined for the corresponding particle where all movie-frames were averaged. For ribosomes, we used a value of 2 pixels");
 
2235
 
 
2236
        alsorot_movie_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
 
2237
        alsorot_movie_group->end();
 
2238
 
 
2239
        do_alsorot_movies.place(current_y, "Also include rotational searches?", false, "If set to Yes, then running averages of the individual frames of recorded movies will also be aligned rotationally. \n \
 
2240
If one wants to perform particle polishing, then rotational alignments of the movie frames is NOT necessary and will only take more computing time.", alsorot_movie_group);
 
2241
 
 
2242
        alsorot_movie_group->begin();
 
2243
 
 
2244
        movie_sigma_angles.place(current_y, "Stddev on the rotations (deg):", 1., 0.5, 10, 0.5, "A Gaussian prior with the specified standard deviation \
 
2245
will be centered at the rotations determined for the corresponding particle where all movie-frames were averaged. For ribosomes, we used a value of 1 degree");
 
2246
 
 
2247
        alsorot_movie_group->end();
 
2248
        do_alsorot_movies.cb_menu_i(); // to make default effective
 
2249
 
 
2250
        movie_group->end();
 
2251
        do_movies.cb_menu_i(); // to make default effective
 
2252
 
 
2253
        tab6->end();
 
2254
        // read settings if hidden file exists
 
2255
        read(".gui_auto3d.settings", is_continue);
 
2256
 
 
2257
}
 
2258
 
 
2259
void Auto3DJobWindow::write(std::string fn)
 
2260
{
 
2261
        std::ofstream fh;
 
2262
        openWriteFile(fn + ".gui_auto3d.settings", fh);
 
2263
 
 
2264
        // I/O
 
2265
        fn_out.writeValue(fh);
 
2266
        fn_cont.writeValue(fh);
 
2267
        fn_img.writeValue(fh);
 
2268
 
 
2269
        // Reference
 
2270
        fn_ref.writeValue(fh);
 
2271
        ref_correct_greyscale.writeValue(fh);
 
2272
        ini_high.writeValue(fh);
 
2273
        sym_name.writeValue(fh);
 
2274
 
 
2275
        // CTF
 
2276
        do_ctf_correction.writeValue(fh);
 
2277
        ctf_corrected_ref.writeValue(fh);
 
2278
        ctf_phase_flipped.writeValue(fh);
 
2279
        ctf_intact_first_peak.writeValue(fh);
 
2280
 
 
2281
        // Optimisation
 
2282
        do_zero_mask.writeValue(fh);
 
2283
        fn_mask.writeValue(fh);
 
2284
 
 
2285
        // Sampling
 
2286
        sampling.writeValue(fh);
 
2287
        offset_range.writeValue(fh);
 
2288
        offset_step.writeValue(fh);
 
2289
        auto_local_sampling.writeValue(fh);
 
2290
 
 
2291
        // Movies
 
2292
        do_movies.writeValue(fh);
 
2293
        fn_movie_star.writeValue(fh);
 
2294
        movie_runavg_window.writeValue(fh);
 
2295
        movie_sigma_offset.writeValue(fh);
 
2296
        do_alsorot_movies.writeValue(fh);
 
2297
        movie_sigma_angles.writeValue(fh);
 
2298
 
 
2299
        closeWriteFile(fh);
 
2300
}
 
2301
 
 
2302
void Auto3DJobWindow::read(std::string fn, bool &_is_continue)
 
2303
{
 
2304
 
 
2305
        std::ifstream fh;
 
2306
        if (openReadFile(fn, fh))
 
2307
        {
 
2308
 
 
2309
                // I/O
 
2310
                fn_out.readValue(fh);
 
2311
                fn_cont.readValue(fh);
 
2312
                fn_img.readValue(fh);
 
2313
 
 
2314
                // Reference
 
2315
                fn_ref.readValue(fh);
 
2316
                ref_correct_greyscale.readValue(fh);
 
2317
                ini_high.readValue(fh);
 
2318
                sym_name.readValue(fh);
 
2319
 
 
2320
                // CTF
 
2321
                do_ctf_correction.readValue(fh);
 
2322
                ctf_corrected_ref.readValue(fh);
 
2323
                ctf_phase_flipped.readValue(fh);
 
2324
                ctf_intact_first_peak.readValue(fh);
 
2325
 
 
2326
                // Optimisation
 
2327
                do_zero_mask.readValue(fh);
 
2328
                fn_mask.readValue(fh);
 
2329
 
 
2330
                // Sampling
 
2331
                sampling.readValue(fh);
 
2332
                offset_range.readValue(fh);
 
2333
                offset_step.readValue(fh);
 
2334
                auto_local_sampling.readValue(fh);
 
2335
 
 
2336
                // Movies
 
2337
                do_movies.readValue(fh);
 
2338
                fn_movie_star.readValue(fh);
 
2339
                movie_runavg_window.readValue(fh);
 
2340
                movie_sigma_offset.readValue(fh);
 
2341
                do_alsorot_movies.readValue(fh);
 
2342
                movie_sigma_angles.readValue(fh);
 
2343
 
 
2344
                closeReadFile(fh);
 
2345
                _is_continue = is_continue;
 
2346
        }
 
2347
}
 
2348
 
 
2349
void Auto3DJobWindow::toggle_new_continue(bool _is_continue)
 
2350
{
 
2351
        is_continue = _is_continue;
 
2352
 
 
2353
        fn_cont.deactivate(!is_continue);
 
2354
        fn_img.deactivate(is_continue);
 
2355
 
 
2356
        // Reference
 
2357
        fn_ref.deactivate(is_continue);
 
2358
        ref_correct_greyscale.deactivate(is_continue);
 
2359
        ini_high.deactivate(is_continue);
 
2360
        sym_name.deactivate(is_continue);
 
2361
 
 
2362
        //CTF
 
2363
        do_ctf_correction.deactivate(is_continue);
 
2364
        ctf_corrected_ref.deactivate(is_continue);
 
2365
        ctf_phase_flipped.deactivate(is_continue);
 
2366
        ctf_intact_first_peak.deactivate(is_continue);
 
2367
 
 
2368
        //Optimisation
 
2369
        do_zero_mask.deactivate(is_continue);
 
2370
 
 
2371
        // Sampling
 
2372
        sampling.deactivate(is_continue);
 
2373
        offset_range.deactivate(is_continue);
 
2374
        offset_step.deactivate(is_continue);
 
2375
        auto_local_sampling.deactivate(is_continue);
 
2376
 
 
2377
        // Movies
 
2378
        do_movies.deactivate(!is_continue);
 
2379
        fn_movie_star.deactivate(!is_continue);
 
2380
        movie_runavg_window.deactivate(!is_continue);
 
2381
        movie_sigma_offset.deactivate(!is_continue);
 
2382
        do_alsorot_movies.deactivate(!is_continue);
 
2383
        movie_sigma_angles.deactivate(!is_continue);
 
2384
 
 
2385
 
 
2386
}
 
2387
 
 
2388
void Auto3DJobWindow::getCommands(std::string &outputname, std::vector<std::string> &commands,
 
2389
                std::string &final_command, double angpix, double particle_diameter)
 
2390
{
 
2391
        commands.clear();
 
2392
        std::string command;
 
2393
 
 
2394
        if (nr_mpi.getValue() > 1)
 
2395
                command="`which relion_refine_mpi`";
 
2396
        else
 
2397
                command="`which relion_refine`";
 
2398
 
 
2399
        // I/O
 
2400
        // Save the real output name (could be with _ctX for continuation)
 
2401
        // This name will also be used for the stderr and stdout outputs and the submit script and gui settings filenames
 
2402
        outputname = fn_out.getValue();
 
2403
        if (is_continue)
 
2404
        {
 
2405
                int pos_it = fn_cont.getValue().rfind("_it");
 
2406
                int pos_op = fn_cont.getValue().rfind("_optimiser");
 
2407
                if (pos_it < 0 || pos_op < 0)
 
2408
                        std::cerr << "Warning: invalid optimiser.star filename provided for continuation run: " << fn_cont.getValue() << std::endl;
 
2409
                int it = (int)textToFloat((fn_cont.getValue().substr(pos_it+3, 6)).c_str());
 
2410
                outputname += "_ct" + floatToString(it);
 
2411
        }
 
2412
        command += " --o " + outputname;
 
2413
        if (is_continue)
 
2414
        {
 
2415
                command += " --continue " + fn_cont.getValue();
 
2416
        }
 
2417
        else
 
2418
        {
 
2419
                command += " --auto_refine --split_random_halves --i " + fn_img.getValue();
 
2420
                command += " --particle_diameter " + floatToString(particle_diameter);
 
2421
                command += " --angpix " + floatToString(angpix);
 
2422
                if (fn_ref.getValue() != "None")
 
2423
                        command += " --ref " + fn_ref.getValue();
 
2424
                if (!ref_correct_greyscale.getValue() && fn_ref.getValue() != "None") // dont do firstiter_cc when giving None
 
2425
                        command += " --firstiter_cc";
 
2426
                if (ini_high.getValue() > 0.)
 
2427
                        command += " --ini_high " + floatToString(ini_high.getValue());
 
2428
 
 
2429
        }
 
2430
 
 
2431
        // CTF stuff
 
2432
        if (!is_continue)
 
2433
        {
 
2434
 
 
2435
                if (do_ctf_correction.getValue())
 
2436
                {
 
2437
                        command += " --ctf";
 
2438
                        if (ctf_corrected_ref.getValue())
 
2439
                                command += " --ctf_corrected_ref";
 
2440
                        if (ctf_phase_flipped.getValue())
 
2441
                                command += " --ctf_phase_flipped";
 
2442
                        if (ctf_intact_first_peak.getValue())
 
2443
                                command += " --ctf_intact_first_peak";
 
2444
                }
 
2445
        }
 
2446
 
 
2447
        // Optimisation
 
2448
        if (!is_continue)
 
2449
        {
 
2450
                // Always flatten the solvent
 
2451
                command += " --flatten_solvent";
 
2452
                if (do_zero_mask.getValue())
 
2453
                        command += " --zero_mask";
 
2454
        }
 
2455
        if (fn_mask.getValue().length() > 0)
 
2456
                command += " --solvent_mask " + fn_mask.getValue();
 
2457
 
 
2458
        // Sampling
 
2459
        int iover = 1;
 
2460
        command += " --oversampling " + floatToString((float)iover);
 
2461
 
 
2462
        for (int i = 0; i < 10; i++)
 
2463
        {
 
2464
                if (strcmp((sampling.getValue()).c_str(), sampling_options[i].label()) == 0)
 
2465
                {
 
2466
                        // The sampling given in the GUI will be the oversampled one!
 
2467
                        command += " --healpix_order " + floatToString((float)i + 1 - iover);
 
2468
                        break;
 
2469
                }
 
2470
 
 
2471
        }
 
2472
        // Minimum sampling rate to perform local searches (may be changed upon continuation
 
2473
        for (int i = 0; i < 10; i++)
 
2474
        {
 
2475
                if (strcmp((auto_local_sampling.getValue()).c_str(), sampling_options[i].label()) == 0)
 
2476
                {
 
2477
                        command += " --auto_local_healpix_order " + floatToString((float)i + 1 - iover);
 
2478
                        break;
 
2479
                }
 
2480
        }
 
2481
 
 
2482
        // Offset range
 
2483
        command += " --offset_range " + floatToString(offset_range.getValue());
 
2484
        // The sampling given in the GUI will be the oversampled one!
 
2485
        command += " --offset_step " + floatToString(offset_step.getValue() * pow(2., iover));
 
2486
 
 
2487
        // Provide symmetry, and always do norm and scale correction
 
2488
        if (!is_continue)
 
2489
        {
 
2490
 
 
2491
                command += " --sym " + sym_name.getValue();
 
2492
                // Always join low-res data, as some D&I point group refinements may fall into different hands!
 
2493
                command += " --low_resol_join_halves 40";
 
2494
                command += " --norm --scale ";
 
2495
        }
 
2496
 
 
2497
        // Movies
 
2498
        if (is_continue && do_movies.getValue())
 
2499
        {
 
2500
                command += " --realign_movie_frames " + fn_movie_star.getValue();
 
2501
                command += " --movie_frames_running_avg " + floatToString(movie_runavg_window.getValue());
 
2502
                command += " --sigma_off " + floatToString(movie_sigma_offset.getValue());
 
2503
 
 
2504
                if (do_alsorot_movies.getValue())
 
2505
                {
 
2506
                        command += " --sigma_ang " + floatToString(movie_sigma_angles.getValue());
 
2507
                }
 
2508
                else
 
2509
                {
 
2510
                        command += " --skip_rotate --skip_maximize ";
 
2511
                }
 
2512
        }
 
2513
 
 
2514
        // Running stuff
 
2515
        command += " --j " + floatToString(nr_threads.getValue());
 
2516
        if (!is_continue)
 
2517
                command += " --memory_per_thread " + floatToString(ram_per_thread.getValue());
 
2518
 
 
2519
        // Other arguments
 
2520
        command += " " + other_args.getValue();
 
2521
 
 
2522
        commands.push_back(command);
 
2523
 
 
2524
        prepareFinalCommand(outputname, commands, final_command);
 
2525
 
 
2526
}
 
2527
 
 
2528
PostJobWindow::PostJobWindow() : RelionJobWindow(4, HAS_NOT_MPI, HAS_NOT_THREAD)
 
2529
{
 
2530
        tab1->begin();
 
2531
        tab1->label("I/O");
 
2532
        resetHeight();
 
2533
        fn_in.place(current_y, "One of the 2 unfiltered half-maps:", "", "MRC map files (*_unfil.mrc)",  "Provide one of the two unfiltered half-reconstructions that were output upon convergence of a 3D auto-refine run.");
 
2534
 
 
2535
        fn_out.place(current_y, "Output rootname", "postprocess", "Output rootname. All output files will be saved in the same directory as the unfiltered maps, unless the output name contains a forward slash. In that case, the corresponding directory will be created .");
 
2536
 
 
2537
        //ctf_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
 
2538
        //ctf_group->end();
 
2539
 
 
2540
        tab1->end();
 
2541
        tab2->begin();
 
2542
        tab2->label("Mask");
 
2543
        resetHeight();
 
2544
        automask_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
 
2545
        automask_group->end();
 
2546
 
 
2547
        do_automask.place(current_y, "Perform auto-masking?", true, "If set to Yes, the program will automatically calculate a mask around the reconstructed particle. \
 
2548
 A nicely fitting mask will result in an optimal resolution-estimation, as a maximal amount of noise will be removed from the resolution-estimation process. \
 
2549
The effect of the masking on the FSC-curve will be measured using the randomised phase-approach as in Shaoxia Chen et al, (2013) Ultramicroscopy", automask_group);
 
2550
 
 
2551
        automask_group->begin();
 
2552
 
 
2553
        inimask_threshold.place(current_y, "Initial binarisation threshold:", 0.02, 0., 0.5, 0.01, "This threshold is used to make an initial binary mask from the average of the two unfiltered half-reconstructions. \
 
2554
If you don't know what value to use, display one of the unfiltered half-maps in a 3D surface rendering viewer and find the lowest threshold that gives no noise peaks outside the reconstruction.");
 
2555
        extend_inimask.place(current_y, "Extend binary map this many pixels:", 3, 0, 20, 1, "The initial binary mask is extended this number of pixels in all directions." );
 
2556
        width_mask_edge.place(current_y, "Add a soft-edge of this many pixels:", 3, 0, 20, 1, "The extended binary mask is further extended with a raised-cosine soft edge of the specified width." );
 
2557
        automask_group->end();
 
2558
        do_automask.cb_menu_i();
 
2559
 
 
2560
        usermask_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
 
2561
        usermask_group->end();
 
2562
 
 
2563
        do_usermask.place(current_y, "Provide your own mask?", false, "If set to Yes, the program will mask the unfiltered half-reconstructions using a user-provided mask below. This also allows you to save execution time, by providing a previously determined automask for the same particle.", usermask_group);
 
2564
        usermask_group->begin();
 
2565
        fn_mask.place(current_y, "User-provided mask:", "", "Image Files (*.{spi,vol,msk,mrc})", "Use this to skip auto-masking by providing your own mask. You may also save execution time by providing a previously determined automask for the same particle.");
 
2566
        usermask_group->end();
 
2567
        do_usermask.cb_menu_i();
 
2568
 
 
2569
        tab2->end();
 
2570
        tab3->begin();
 
2571
        tab3->label("Sharpen");
 
2572
        resetHeight();
 
2573
        //ctf_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
 
2574
        //ctf_group->end();
 
2575
 
 
2576
        fn_mtf.place(current_y, "MTF of the detector (STAR file)", "", "STAR Files (*.star)", "The MTF of the detector is used in the (later) post-processing and particle polishing stages of refinement.  \
 
2577
If you know the MTF of your detector, provide it here. Curves for some well-known detectors may be downloaded from the RELION Wiki. Also see there for the exact format \
 
2578
\n If you do not know the MTF of your detector and do not want to measure it, then by leaving this entry empty, you include the MTF of your detector in your overall estimated B-factor upon sharpening the map.\
 
2579
Although that is probably slightly less accurate, the overall quality of your map will probably not suffer very much.");
 
2580
 
 
2581
        current_y += STEPY/2;
 
2582
 
 
2583
        autobfac_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
 
2584
        autobfac_group->end();
 
2585
        do_auto_bfac.place(current_y,"Estimate B-factor automatically?", true, "If set to Yes, then the program will use the automated procedure described by Rosenthal and Henderson (2003, JMB) to estimate an overall B-factor for your map, and sharpen it accordingly. \
 
2586
Note that your map must extend well beyond the lowest resolution included in the procedure below, which should not be set to resolutions much lower than 10 Angstroms. ", autobfac_group);
 
2587
 
 
2588
        autobfac_group->begin();
 
2589
        autob_lowres.place(current_y,"Lowest resolution for auto-B fit (A):", 10, 8, 15, 0.5, "This is the lowest frequency (in Angstroms) that will be included in the linear fit of the Guinier plot as described in Rosenthal and Henderson (2003, JMB). Dont use values much lower or higher than 10 Angstroms. If your map does not extend beyond 10 Angstroms, then instead of the automated procedure use your own B-factor.");
 
2590
        autobfac_group->end();
 
2591
        do_auto_bfac.cb_menu_i();
 
2592
 
 
2593
        adhocbfac_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
 
2594
        adhocbfac_group->end();
 
2595
        do_adhoc_bfac.place(current_y,"Use your own B-factor?", false, "Instead of using the automated B-factor estimation, provide your own value. Use negative values for sharpening the map. \
 
2596
This option is useful if your map does not extend beyond the 10A needed for the automated procedure, or when the automated procedure does not give a suitable value (e.g. in more disordered parts of the map).",adhocbfac_group);
 
2597
 
 
2598
        adhocbfac_group->begin();
 
2599
        adhoc_bfac.place(current_y,"User-provided B-factor:", -1000, -2000, 0, -50, "Use negative values for sharpening. Be careful: if you over-sharpen your map, you may end up interpreting noise for signal!");
 
2600
        adhocbfac_group->end();
 
2601
        do_adhoc_bfac.cb_menu_i();
 
2602
 
 
2603
        tab3->end();
 
2604
        tab4->begin();
 
2605
        tab4->label("Filter");
 
2606
        resetHeight();
 
2607
        skipweight_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
 
2608
        skipweight_group->end();
 
2609
 
 
2610
        do_skip_fsc_weighting.place(current_y, "Skip FSC-weighting?", false, "If set to No (the default), then the output map will be low-pass filtered according to the mask-corrected, gold-standard FSC-curve. \
 
2611
Sometimes, it is also useful to provide an ad-hoc low-pass filter (option below), as due to local resolution variations some parts of the map may be better and other parts may be worse than the overall resolution as measured by the FSC. \
 
2612
In such cases, set this option to Yes and provide an ad-hoc filter as described below.", skipweight_group);
 
2613
 
 
2614
        skipweight_group->begin();
 
2615
        low_pass.place(current_y, "Ad-hoc low-pass filter (A):",5,1,40,1,"This option allows one to low-pass filter the map at a user-provided frequency (in Angstroms). When using a resolution that is higher than the gold-standard FSC-reported resolution, take care not to interpret noise in the map for signal...");
 
2616
        skipweight_group->end();
 
2617
        do_skip_fsc_weighting.cb_menu_i();
 
2618
 
 
2619
        tab4->end();
 
2620
 
 
2621
 
 
2622
        // read settings if hidden file exists
 
2623
        read(".gui_post.settings", is_continue);
 
2624
}
 
2625
void PostJobWindow::write(std::string fn)
 
2626
{
 
2627
        std::ofstream fh;
 
2628
        openWriteFile(fn + ".gui_post.settings", fh);
 
2629
        fn_in.writeValue(fh);
 
2630
        fn_out.writeValue(fh);
 
2631
        do_automask.writeValue(fh);
 
2632
        inimask_threshold.writeValue(fh);
 
2633
        extend_inimask.writeValue(fh);
 
2634
        width_mask_edge.writeValue(fh);
 
2635
        do_usermask.writeValue(fh);
 
2636
        fn_mask.writeValue(fh);
 
2637
        do_auto_bfac.writeValue(fh);
 
2638
        autob_lowres.writeValue(fh);
 
2639
        do_adhoc_bfac.writeValue(fh);
 
2640
        adhoc_bfac.writeValue(fh);
 
2641
        fn_mtf.writeValue(fh);
 
2642
        do_skip_fsc_weighting.writeValue(fh);
 
2643
        low_pass.writeValue(fh);
 
2644
        closeWriteFile(fh);
 
2645
}
 
2646
void PostJobWindow::read(std::string fn, bool &_is_continue)
 
2647
{
 
2648
        std::ifstream fh;
 
2649
        // Only read things if the file exists
 
2650
        if (openReadFile(fn, fh))
 
2651
        {
 
2652
                fn_in.readValue(fh);
 
2653
                fn_out.readValue(fh);
 
2654
                do_automask.readValue(fh);
 
2655
                inimask_threshold.readValue(fh);
 
2656
                extend_inimask.readValue(fh);
 
2657
                width_mask_edge.readValue(fh);
 
2658
                do_usermask.readValue(fh);
 
2659
                fn_mask.readValue(fh);
 
2660
                do_auto_bfac.readValue(fh);
 
2661
                autob_lowres.readValue(fh);
 
2662
                do_adhoc_bfac.readValue(fh);
 
2663
                adhoc_bfac.readValue(fh);
 
2664
                fn_mtf.readValue(fh);
 
2665
                do_skip_fsc_weighting.readValue(fh);
 
2666
                low_pass.readValue(fh);
 
2667
                closeReadFile(fh);
 
2668
                _is_continue = is_continue;
 
2669
        }
 
2670
}
 
2671
void PostJobWindow::toggle_new_continue(bool _is_continue)
 
2672
{
 
2673
        is_continue = _is_continue;
 
2674
}
 
2675
void PostJobWindow::getCommands(std::string &outputname, std::vector<std::string> &commands, std::string &final_command,
 
2676
                double angpix)
 
2677
{
 
2678
        commands.clear();
 
2679
        std::string command;
 
2680
        command="`which relion_postprocess`";
 
2681
 
 
2682
        // Get the input rootname from the half-map name
 
2683
        // run1_half1_class001_unfil.mrc -> run1
 
2684
        int pos_half = fn_in.getValue().rfind("_half");
 
2685
        if (pos_half < fn_in.getValue().size())
 
2686
                command += " --i " + fn_in.getValue().substr(0, pos_half);
 
2687
        else
 
2688
        {
 
2689
                std::cerr << "PostJobWindow::getCommands ERROR: cannot find _half substring in input filename: " << fn_in.getValue() << std::endl;
 
2690
                exit(1);
 
2691
        }
 
2692
 
 
2693
        // Get the output name. If the specified fn_out contains a directory, then make this directory and use it for output
 
2694
        // If it doesn't contain a directory, then use the directory as in fn_in.
 
2695
        int last_slash_out = fn_out.getValue().rfind("/");
 
2696
        int last_slash_in = fn_in.getValue().rfind("/");
 
2697
        if (last_slash_out < fn_out.getValue().size())
 
2698
        {
 
2699
                // The output name contains a directory: use that one for output
 
2700
                outputname = fn_out.getValue();
 
2701
        }
 
2702
        else if  (last_slash_in < fn_in.getValue().size())
 
2703
        {
 
2704
                // Otherwise: the input name contains a directory: use that one for output
 
2705
                std::string dirs = fn_in.getValue().substr(0, last_slash_in + 1);
 
2706
                outputname = dirs + fn_out.getValue();
 
2707
        }
 
2708
        // The output name contains a directory: use it for output
 
2709
        command += " --o " + outputname;
 
2710
        command += "  --angpix " + floatToString(angpix);
 
2711
 
 
2712
        // Masking
 
2713
        if (do_automask.getValue())
 
2714
        {
 
2715
                command += " --auto_mask ";
 
2716
                command += " --inimask_threshold " + floatToString(inimask_threshold.getValue());
 
2717
                command += " --extend_inimask " + floatToString(extend_inimask.getValue());
 
2718
                command += " --width_mask_edge " + floatToString(width_mask_edge.getValue());
 
2719
        }
 
2720
        if (do_usermask.getValue())
 
2721
                command += " --mask " + fn_mask.getValue();
 
2722
 
 
2723
        // Sharpening
 
2724
        if (fn_mtf.getValue().length() > 0)
 
2725
        {
 
2726
                command += " --mtf " + fn_mtf.getValue();
 
2727
        }
 
2728
        if (do_auto_bfac.getValue())
 
2729
        {
 
2730
                command += " --auto_bfac ";
 
2731
                command += " --autob_lowres "  + floatToString(autob_lowres.getValue());
 
2732
        }
 
2733
        if (do_adhoc_bfac.getValue())
 
2734
        {
 
2735
                command += " --adhoc_bfac " + floatToString(adhoc_bfac.getValue());
 
2736
        }
 
2737
 
 
2738
        // Filtering
 
2739
        if (do_skip_fsc_weighting.getValue())
 
2740
        {
 
2741
                command += " --skip_fsc_weighting ";
 
2742
                command += " --low_pass "  + floatToString(low_pass.getValue());
 
2743
        }
 
2744
 
 
2745
        // Other arguments for extraction
 
2746
        command += " " + other_args.getValue();
 
2747
 
 
2748
        commands.push_back(command);
 
2749
        prepareFinalCommand(outputname, commands, final_command);
 
2750
}
 
2751
 
 
2752
 
 
2753
 
 
2754
PolishJobWindow::PolishJobWindow() : RelionJobWindow(3, HAS_MPI, HAS_THREAD)
 
2755
{
 
2756
        tab1->begin();
 
2757
        tab1->label("I/O");
 
2758
        resetHeight();
 
2759
 
 
2760
        fn_in.place(current_y, "Input STAR file with aligned movies:", "", "STAR files (*_data.star)",  "Provide the data.star file that was output by the movie-processing option in the auto-refine job.");
 
2761
 
 
2762
        fn_out.place(current_y, "Output rootname", "shiny", "Output rootname. Note that the program will write out ");
 
2763
 
 
2764
        tab1->end();
 
2765
        tab2->begin();
 
2766
        tab2->label("Movement");
 
2767
        resetHeight();
 
2768
 
 
2769
        fit_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
 
2770
        fit_group->end();
 
2771
 
 
2772
 
 
2773
        do_fit_movement.place(current_y, "Linear fit particle movements?", true, "If set to Yes, then the program will fit linear tracks (in X-Y and in time) through \
 
2774
the estimated movie tracks in the input STAR file. For small particles (e.g. < 1MDa) this will lead to more robust beam-induced movement modelling. Because particles that are close to each other on a \
 
2775
micrograph often move in similar directions, the estimated tracks from neighbouring particles may also be included in the fitting of each particle. Again, in particular for smaller particles \
 
2776
this may improve the robustness of the fits.", fit_group);
 
2777
 
 
2778
        fit_group->begin();
 
2779
 
 
2780
        movie_runavg_window.place(current_y, "Running average window:", 5, 1, 15, 1, "Provide the same value as the one that was used to estimate the movement tracks in the movie-processing tab of the auto-refine job.");
 
2781
 
 
2782
        sigma_nb.place(current_y, "Stddev on particle distance (pix)", 100, 0, 1000, 50, "This value determines how much neighbouring particles contribute to the fit of the movements of each particle. \
 
2783
This value is the standard deviation of a Gaussian on the inter-particle distance. Larger values mean that particles that are further away still contribute more. Particles beyond 3 standard deviations are excluded \
 
2784
from the fit. Very large values will lead to all fitted tracks pointing in the same direction. A value of zero means that each particle is fitted independently.");
 
2785
        fit_group->end();
 
2786
        do_fit_movement.cb_menu_i();
 
2787
 
 
2788
        tab2->end();
 
2789
        tab3->begin();
 
2790
        tab3->label("Damage");
 
2791
        resetHeight();
 
2792
 
 
2793
        weight_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
 
2794
        weight_group->end();
 
2795
 
 
2796
        do_bfactor_weighting.place(current_y, "Perform B-factor weighting?", true, "If set to Yes, then the program will estimate a resolution-dependent weight for each movie frames by calculating independent half-reconstructions for each movie frame separately. \
 
2797
Gold-standard FSCs between these are then converted into relative Guinier plots, through which straight lines are fitted. Linear fits are often suitable beyond 20A resolution. Small particles may not yield such high resolutions for the individual-frame reconstructions. \
 
2798
Therefore, in some cases it may be better to skip this step. It is however recommended to always try and perform B-factor weighting, and to inspect the output bfactors.star and guinier.star files, as adequate weighting may significantly improve resolution in the final map.", weight_group);
 
2799
 
 
2800
        weight_group->begin();
 
2801
        perframe_highres.place(current_y, "Highres-limit per-frame maps (A)", 6, 1, 25, 1, "To estimate the resolution and dose dependency of the radiation damage, the program \
 
2802
will calculate reconstructions from all first movie frames, second movie frames, etc. These per-frame reconstructions will have lower resolution than the reconstruction from all-frames. \
 
2803
To speed up the calculations (and reduce memory requirements), the per-frame reconstructions may be limited in resolution using this parameter. One can inspect the output STAR files of the per-frame reconstructions \
 
2804
to check afterwards that this value was not chosen lower than the actual resolution of these reconstructions");
 
2805
 
 
2806
        perframe_bfac_lowres.place(current_y, "Lowres-limit B-factor estimation (A)", 20 , 1, 40, 1, "This value describes the lowest resolution that is included in the B-factor estimation of the per-frame reconstructions. \
 
2807
Because the power spectrum of per-frame reconstructions is compared to the power spectrum of the reconstruction from all frames, a much lower value than the 10A described in the Rosenthal and Henderson (2003) paper in JMB can be used. Probably a value around 20A is still OK.");
 
2808
 
 
2809
        weight_group->end();
 
2810
        do_bfactor_weighting.cb_menu_i();
 
2811
 
 
2812
        current_y += STEPY/2;
 
2813
 
 
2814
        fn_mask.place(current_y, "Mask for the reconstructions", "", "Image Files (*.{spi,vol,msk,mrc})", "A continuous mask with values between 0 (solvent) and 1 (protein). You may provide the same map that was obtained in the post-processing of the corresponding auto-refine jobs before the movie processing.");
 
2815
 
 
2816
        sym_name.place(current_y, "Symmetry:", "C1", "If the molecule is asymmetric, \
 
2817
set Symmetry group to C1. Note their are multiple possibilities for icosahedral symmetry: \n \
 
2818
* I1: No-Crowther 222 (standard in Heymann, Chagoyen & Belnap, JSB, 151 (2005) 196ā€“207) \n \
 
2819
* I2: Crowther 222 \n \
 
2820
* I3: 52-setting (as used in SPIDER?)\n \
 
2821
* I4: A different 52 setting \n \
 
2822
The command 'relion_refine --sym D2 --print_symmetry_ops' prints a list of all symmetry operators for symmetry group D2. \
 
2823
RELION uses XMIPP's libraries for symmetry operations. \
 
2824
Therefore, look at the XMIPP Wiki for more details:  http://xmipp.cnb.csic.es/twiki/bin/view/Xmipp/WebHome?topic=Symmetry");
 
2825
 
 
2826
        tab3->end();
 
2827
        // read settings if hidden file exists
 
2828
        read(".gui_polish.settings", is_continue);
 
2829
}
 
2830
 
 
2831
void PolishJobWindow::write(std::string fn)
 
2832
{
 
2833
        std::ofstream fh;
 
2834
        openWriteFile(fn + ".gui_polish.settings", fh);
 
2835
        fn_in.writeValue(fh);
 
2836
        fn_out.writeValue(fh);
 
2837
        movie_runavg_window.writeValue(fh);
 
2838
        do_fit_movement.writeValue(fh);
 
2839
        sigma_nb.writeValue(fh);
 
2840
        do_bfactor_weighting.writeValue(fh);
 
2841
        perframe_highres.writeValue(fh);
 
2842
        perframe_bfac_lowres.writeValue(fh);
 
2843
        fn_mask.writeValue(fh);
 
2844
        sym_name.writeValue(fh);
 
2845
 
 
2846
        closeWriteFile(fh);
 
2847
}
 
2848
void PolishJobWindow::read(std::string fn, bool &_is_continue)
 
2849
{
 
2850
        std::ifstream fh;
 
2851
        // Only read things if the file exists
 
2852
        if (openReadFile(fn, fh))
 
2853
        {
 
2854
                fn_in.readValue(fh);
 
2855
                fn_out.readValue(fh);
 
2856
                movie_runavg_window.readValue(fh);
 
2857
                do_fit_movement.readValue(fh);
 
2858
                sigma_nb.readValue(fh);
 
2859
                do_bfactor_weighting.readValue(fh);
 
2860
                perframe_highres.readValue(fh);
 
2861
                perframe_bfac_lowres.readValue(fh);
 
2862
                fn_mask.readValue(fh);
 
2863
                sym_name.readValue(fh);
 
2864
 
 
2865
                closeReadFile(fh);
 
2866
                _is_continue = is_continue;
 
2867
        }
 
2868
}
 
2869
void PolishJobWindow::toggle_new_continue(bool _is_continue)
 
2870
{
 
2871
        is_continue = _is_continue;
 
2872
}
 
2873
 
 
2874
void PolishJobWindow::getCommands(std::string &outputname, std::vector<std::string> &commands, std::string &final_command,
 
2875
                double angpix, double particle_diameter, double black_dust, double white_dust)
 
2876
{
 
2877
        commands.clear();
 
2878
        std::string command;
 
2879
        if (nr_mpi.getValue() > 1)
 
2880
                command="`which relion_particle_polish_mpi`";
 
2881
        else
 
2882
                command="`which relion_particle_polish`";
 
2883
 
 
2884
        // General
 
2885
        command += " --i " + fn_in.getValue();
 
2886
        command += " --o " + fn_out.getValue();
 
2887
        command += "  --angpix " + floatToString(angpix);
 
2888
        command += " --movie_frames_running_avg " + floatToString(movie_runavg_window.getValue());
 
2889
        // If this is not a continue job, then re-start from scratch....
 
2890
        if (!is_continue)
 
2891
                command += " --dont_read_old_files ";
 
2892
 
 
2893
        // Beam-induced movement fitting options
 
2894
        if (do_fit_movement.getValue())
 
2895
                command += " --sigma_nb " + floatToString(sigma_nb.getValue());
 
2896
        else
 
2897
                command += " --no_fit ";
 
2898
 
 
2899
        // Damage
 
2900
        if (do_bfactor_weighting.getValue())
 
2901
        {
 
2902
                command += " --perframe_highres " + floatToString(perframe_highres.getValue());
 
2903
                command += " --autob_lowres " + floatToString(perframe_bfac_lowres.getValue());
 
2904
        }
 
2905
        else
 
2906
        {
 
2907
                command += " --skip_bfactor_weighting ";
 
2908
        }
 
2909
 
 
2910
        if (fn_mask.getValue().length() > 0)
 
2911
                command += " --mask " + fn_mask.getValue();
 
2912
 
 
2913
        // Symmetry group
 
2914
        command += " --sym " + sym_name.getValue();
 
2915
 
 
2916
        // Normalisation
 
2917
        double bg_rad = ROUND(particle_diameter / (2. * angpix));
 
2918
        command += " --bg_radius " + floatToString(bg_rad);
 
2919
        command += " --white_dust " + floatToString(white_dust);
 
2920
        command += " --black_dust " + floatToString(black_dust);
 
2921
 
 
2922
        // Other arguments for extraction
 
2923
        command += " " + other_args.getValue();
 
2924
 
 
2925
        commands.push_back(command);
 
2926
 
 
2927
        // Place the job submission script and the stdout and stderr files in the same directory as the input data.star
 
2928
 
 
2929
        int last_slash = fn_in.getValue().rfind("/");
 
2930
        if (last_slash < fn_in.getValue().size())
 
2931
        {
 
2932
                std::string dirs = fn_in.getValue().substr(0, last_slash + 1); // +1 includes the slash
 
2933
                outputname = dirs + fn_out.getValue();
 
2934
        }
 
2935
        else
 
2936
        {
 
2937
                outputname = fn_out.getValue();
 
2938
        }
 
2939
        prepareFinalCommand(outputname, commands, final_command);
 
2940
}
 
2941
 
 
2942
ResmapJobWindow::ResmapJobWindow() : RelionJobWindow(1, HAS_NOT_MPI, HAS_NOT_THREAD)
 
2943
{
 
2944
        tab1->begin();
 
2945
        tab1->label("I/O");
 
2946
        resetHeight();
 
2947
 
 
2948
        fn_in.place(current_y, "One of the 2 unfiltered half-maps:", "", "MRC map files (*_unfil.mrc)",  "Provide one of the two unfiltered half-reconstructions that were output upon convergence of a 3D auto-refine run.");
 
2949
 
 
2950
        current_y += STEPY /2 ;
 
2951
 
 
2952
        pval.place(current_y, "P-value:", 0.05, 0., 1., 0.01, "This value is typically left at 0.05. If you change it, report the modified value in your paper!");
 
2953
        minres.place(current_y, "Highest resolution (A): ", 0., 0., 10., 0.1, "ResMaps minRes parameter. By default (0), the program will start at just above 2x the pixel size");
 
2954
        maxres.place(current_y, "Lowest resolution (A): ", 0., 0., 10., 0.1, "ResMaps maxRes parameter. By default (0), the program will stop at 4x the pixel size");
 
2955
        stepres.place(current_y, "Resolution step size (A)", 1., 0.1, 3, 0.1, "ResMaps stepSize parameter." );
 
2956
 
 
2957
        current_y += STEPY /2 ;
 
2958
        fn_mask.place(current_y, "User-provided mask (optional):", "", "Image Files (*.{spi,vol,msk,mrc})", "A binary (!) mask with values 0 for solvent and 1 for protein. \
 
2959
Note that values larger than zero will be changed to 1 by ResMap, therefore the continuous masks from the postprocessing may be too wide. If left empty (default), then ResMap will determine its own mask");
 
2960
 
 
2961
        current_y += STEPY /2 ;
 
2962
 
 
2963
        // Check for environment variable RELION_RESMAP_TEMPLATE
 
2964
        char * default_location = getenv ("RELION_RESMAP_EXECUTABLE");
 
2965
        if (default_location == NULL)
 
2966
        {
 
2967
                char mydefault[] = DEFAULTRESMAPLOCATION;
 
2968
                default_location = mydefault;
 
2969
        }
 
2970
 
 
2971
        fn_resmap.place(current_y, "ResMap executable:", default_location, "ResMap*", "Location of the ResMap executable. You can control the default of this field by setting environment variable RELION_RESMAP_EXECUTABLE, or by editing the first few lines in src/gui_jobwindow.h and recompile the code.");
 
2972
 
 
2973
        tab1->end();
 
2974
 
 
2975
        // read settings if hidden file exists
 
2976
        read(".gui_resmap.settings", is_continue);
 
2977
}
 
2978
 
 
2979
void ResmapJobWindow::write(std::string fn)
 
2980
{
 
2981
        std::ofstream fh;
 
2982
        openWriteFile(fn + ".gui_resmap.settings", fh);
 
2983
        fn_resmap.writeValue(fh);
 
2984
        fn_in.writeValue(fh);
 
2985
        pval.writeValue(fh);
 
2986
        minres.writeValue(fh);
 
2987
        maxres.writeValue(fh);
 
2988
        stepres.writeValue(fh);
 
2989
        fn_mask.writeValue(fh);
 
2990
        closeWriteFile(fh);
 
2991
}
 
2992
 
 
2993
void ResmapJobWindow::read(std::string fn, bool &_is_continue)
 
2994
{
 
2995
        std::ifstream fh;
 
2996
        // Only read things if the file exists
 
2997
        if (openReadFile(fn, fh))
 
2998
        {
 
2999
                fn_resmap.readValue(fh);
 
3000
                fn_in.readValue(fh);
 
3001
                pval.readValue(fh);
 
3002
                minres.readValue(fh);
 
3003
                maxres.readValue(fh);
 
3004
                stepres.readValue(fh);
 
3005
                fn_mask.readValue(fh);
 
3006
                closeReadFile(fh);
 
3007
                _is_continue = is_continue;
 
3008
        }
 
3009
}
 
3010
 
 
3011
void ResmapJobWindow::toggle_new_continue(bool _is_continue)
 
3012
{
 
3013
        is_continue = _is_continue;
 
3014
        // never submit this to queue, as ResMap needs user interaction
 
3015
        do_queue.deactivate(true);
 
3016
}
 
3017
 
 
3018
void ResmapJobWindow::getCommands(std::string &outputname, std::vector<std::string> &commands, std::string &final_command,
 
3019
                double angpix)
 
3020
{
 
3021
        commands.clear();
 
3022
        std::string command;
 
3023
 
 
3024
        if (fn_resmap.getValue().length() == 0)
 
3025
        {
 
3026
                std::cerr << "ResmapJobWindow::getCommands ERROR: please provide an executable for the ResMap program." << std::endl;
 
3027
                exit(1);
 
3028
        }
 
3029
 
 
3030
        command = fn_resmap.getValue();
 
3031
 
 
3032
        // Get the two half-reconstruction names from the single one
 
3033
        std::string fn_half1, fn_half2;
 
3034
        int pos_half = fn_in.getValue().rfind("_half");
 
3035
        if (pos_half < fn_in.getValue().size())
 
3036
        {
 
3037
                fn_half1 = fn_in.getValue().substr(0, pos_half) + "_half1_class001_unfil.mrc";
 
3038
                fn_half2 = fn_in.getValue().substr(0, pos_half) + "_half2_class001_unfil.mrc";
 
3039
        }
 
3040
        else
 
3041
        {
 
3042
                std::cerr << "ResMapJobWindow::getCommands ERROR: cannot find _half substring in input filename: " << fn_in.getValue() << std::endl;
 
3043
                exit(1);
 
3044
        }
 
3045
 
 
3046
        command += " --vis2D --noguiSplit " + fn_half1 + " " + fn_half2;
 
3047
        command += " --vxSize=" + floatToString(angpix);
 
3048
        command += " --pVal=" + floatToString(pval.getValue());
 
3049
        command += " --minRes=" + floatToString(minres.getValue());
 
3050
        command += " --maxRes=" + floatToString(maxres.getValue());
 
3051
        command += " --stepRes=" + floatToString(stepres.getValue());
 
3052
        if (fn_mask.getValue().length() > 0)
 
3053
                command += " --maskVol=" + fn_mask.getValue();
 
3054
 
 
3055
        // Other arguments for extraction
 
3056
        command += " " + other_args.getValue();
 
3057
 
 
3058
        commands.push_back(command);
 
3059
 
 
3060
        int last_slash = fn_in.getValue().rfind("/");
 
3061
        if (last_slash < fn_in.getValue().size())
 
3062
        {
 
3063
                // The output name contains a directory: use that one for output
 
3064
                outputname = fn_in.getValue().substr(0, last_slash + 1) + "run_resmap";
 
3065
        }
 
3066
        else
 
3067
        {
 
3068
                outputname = "run_resmap";
 
3069
        }
 
3070
 
 
3071
        prepareFinalCommand(outputname, commands, final_command);
 
3072
}
 
3073
 
 
3074
 
 
3075
PublishJobWindow::PublishJobWindow() : RelionJobWindow(2, HAS_NOT_MPI, HAS_NOT_THREAD)
 
3076
{
 
3077
        tab1->begin();
 
3078
        tab1->label("cite RELION");
 
3079
        resetHeight();
 
3080
 
 
3081
        cite_text.place(current_y, "\
 
3082
If RELION is useful in your work, please cite us. Relevant papers are:\n \n \
 
3083
 * The general Bayesian approach (and the first mention of RELION): \n \
 
3084
     Scheres (2012) J. Mol. Biol. (PMID: 22100448)       \n \n\
 
3085
 * RELION implementation details and the 3D auto-refine procedure: \n \
 
3086
     Scheres (2012) J. Struct. Biol. (PMID: 23000701)    \n \n\
 
3087
 * The gold-standard FSC and the relevance of the 0.143 criterion: \n \
 
3088
     Scheres & Chen (2012) Nat. Meth. (PMID: 22842542)   \n \n\
 
3089
 * The movie-processing procedure: \n \
 
3090
     Bai et al. (2013) eLife (PMID: 23427024 )   \n \n\
 
3091
 * The correction of mask effects on the FSC curve by randomised phases: \n \
 
3092
     Chen et al. (2013) Ultramicroscopy (PMID: 23872039)         \n \n\
 
3093
 * The auto-picking, sorting and particle-polishing: \n \
 
3094
     Scheres (2014) in preparation"
 
3095
, GUIWIDTH - WCOL0 - 50, GUIHEIGHT - 150);
 
3096
 
 
3097
        //cite_text.mydisp->textsize(12);
 
3098
 
 
3099
        tab1->end();
 
3100
        tab2->begin();
 
3101
        tab2->label("cite others");
 
3102
        resetHeight();
 
3103
 
 
3104
        cite_external_text.place(current_y, "\
 
3105
Please also cite the following EXTERNAL programs: \n \n \
 
3106
* CTFFIND3 for CTF-estimation: \n \
 
3107
    Mindell & Grigorieff (2003) J. Mol. Biol. (PMID: 12781660) \n \n\
 
3108
* ResMap for local-resolution estimation:  \n\
 
3109
    Kucukelbir et al. (2014) Nat. Meth. (PMID: 24213166)"
 
3110
, GUIWIDTH - WCOL0 - 50, GUIHEIGHT - 150);
 
3111
 
 
3112
        tab2->end();
 
3113
 
 
3114
}
 
3115
 
 
3116
void PublishJobWindow::toggle_new_continue(bool _is_continue)
 
3117
{
 
3118
        is_continue = _is_continue;
 
3119
        // never submit this to queue, as ResMap needs user interaction
 
3120
        do_queue.deactivate(true);
 
3121
}
 
3122
 
 
3123
void PublishJobWindow::getCommands(std::string &outputname, std::vector<std::string> &commands, std::string &final_command)
 
3124
{
 
3125
        commands.clear();
 
3126
        std::string command = " Sorry, you still need to write your own paper... ;-) ";
 
3127
 
 
3128
        commands.push_back(command);
 
3129
        outputname = "run_publish";
 
3130
        prepareFinalCommand(outputname, commands, final_command);
 
3131
}
 
3132