Xmipp  v3.23.11-Nereus
ml_tomo.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  *
3  * Authors: Sjors Scheres scheres@cnb.csic.es (2007)
4  *
5  * Unidad de Bioinformatica del Centro Nacional de Biotecnologia , CSIC
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20  * 02111-1307 USA
21  *
22  * All comments concerning this program package may be sent to the
23  * e-mail address 'xmipp@cnb.csic.es'
24  ***************************************************************************/
25 #include "ml_tomo.h"
27 #include "core/metadata_sql.h"
28 
29 //#define JM_DEBUG
30 
31 // For blocking of threads
32 pthread_mutex_t mltomo_weightedsum_update_mutex = PTHREAD_MUTEX_INITIALIZER;
33 pthread_mutex_t mltomo_selfile_access_mutex = PTHREAD_MUTEX_INITIALIZER;
34 
35 // Usage ===================================================================
36 void
38 {
40  "Align and classify 3D images with missing data regions in Fourier space,");
42  "e.g. subtomograms or RCT reconstructions, by a 3D multi-reference refinement");
43  addUsageLine("based on a maximum-likelihood (ML) target function.");
45  "+++For several cases, this method has been shown to be able to both align and "
46  "classify in a completely *reference-free* manner, by starting from random assignments of "
47  "the orientations and classes. The mathematical details behind this approach are explained "
48  "in detail in");
49  addUsageLine("+++Scheres et al. (2009) Structure, 17, 1563-1572", true);
51  "+++*Please cite this paper if this program is of use to you!* %BR% "
52  "There also exists a standardized python script [[http://newxmipp.svn.sourceforge.net/viewvc/"
53  "newxmipp/trunk/xmipp/applications/scripts/protocols/protocol__mltomo.py]"
54  "[xmipp_protocol__mltomo.py]] for this program. "
55  "Thereby, rather than executing the command line options explained below, the user"
56  " can submit his jobs through a convenient GUI in the [[GettingStartedWithProtocols][Xmipp_protocols]], "
57  "although we still recommend reading this page carefully in order "
58  "to fully understand the options given in the protocol. Note that this protocol is available "
59  "from the main xmipp_protocols setup window by pressing the _Additional protocols_ button.)");
60  addUsageLine(" ");
61  addUsageLine("See http://xmipp.cnb.csic.es/twiki/bin/view/Xmipp/Ml_tomo_v3 for further documentation");
63  " -i <metadata> : Metadata file with input images (and angles) ");
65  " --nref <int=0> : Number of references to generate automatically (recommended)");
67  " OR --ref <file=\"\"> : or metadata file with initial references/single reference image ");
68  addParamsLine(" [ --oroot <rootname=mltomo> ] : Output rootname ");
69  addParamsLine(" alias -o;");
70  //docfile not implemented, it can go in the -i option
71  //addParamsLine(" [ --doc <metadata=\"\"> ] : MetaData with orientations for all particles ");
72  addParamsLine(" [ --sym <symgroup=c1> ] : Symmetry group ");
74  " [ --missing <metadata=\"\"> ] : Metadata file with missing data region definitions");
75 
76  addParamsLine("== Angular sampling ==");
78  " [ --ang <float=10.> ] : Angular sampling rate (in degrees)");
80  " [ --ang_search <float=-1.> ] : Angular search range around orientations from Metadata ");
82  " : (by default, exhaustive searches are performed)");
84  " [ --dont_limit_psirange ] : Exhaustive psi searches when using -ang_search (only for c1 symmetry)");
86  " [ --limit_trans <float=-1.> ] : Maximum allowed shifts (negative value means no restriction)");
88  " [ --tilt0+ <float=0> ] : Limit tilt angle search from tilt0 to tiltF (in degrees) ");
90  " [ --tiltF+ <float=180> ] : Limit tilt angle search from tilt0 to tiltF (in degrees) ");
92  " [ --psi_sampling+ <float=-1.> ] : Angular sampling rate for the in-plane rotations(in degrees)");
93 
94  addParamsLine("== Regularization ==");
96  " [ --reg0 <float=0.> ] : Initial regularization parameters (in N/K^2) ");
98  " [ --regF <float=0.> ] : Final regularization parameters (in N/K^2) ");
100  " [ --reg_steps <int=5> ] : Number of iterations in which the regularization is changed from reg0 to regF");
101 
102  addParamsLine("== Others ==");
104  " [ --dont_rotate ] : Keep orientations from Metadata fixed, only translate and classify ");
106  " [ --dont_align ] : Keep orientations and tran Metadata (otherwise start from random)");
108  " [ --only_average ] : Keep orientations and classes from docfile, only output weighted averages ");
110  " [ --perturb ] : Apply random perturbations to angular sampling in each iteration");
112  " [ --dim <int=-1> ] : Use downscaled (in fourier space) images of this size ");
114  " [ --maxres <float=0.5> ] : Maximum resolution (in pixel^-1) to use ");
116  " [ --thr <int=1> ] : Number of shared-memory threads to use in parallel ");
117 
118  addParamsLine("==+ Additional options: ==");
120  " [ --impute_iter <int=1> ] : Number of iterations for inner imputation loop ");
122  " [ --iter <int=25> ] : Maximum number of iterations to perform ");
124  " [ --istart <int=1> ] : number of initial iteration ");
126  " [ --noise <float=1.> ] : Expected standard deviation for pixel noise ");
128  " [ --offset <float=3.> ] : Expected standard deviation for origin offset [pix]");
130  " [ --frac <metadata=\"\"> ] : Metadata with expected model fractions (default: even distr.)");
132  " [ --restart <logfile> ] : restart a run with all parameters as in the logfile ");
134  " [ --fix_sigma_noise] : Do not re-estimate the standard deviation in the pixel noise ");
136  " [ --fix_sigma_offset] : Do not re-estimate the standard deviation in the origin offsets ");
138  " [ --fix_fractions] : Do not re-estimate the model fractions ");
139  addParamsLine(" [ --eps <float=5e-5> ] : Stopping criterium ");
141  " [ --pixel_size <float=1> ] : Pixel size (in Anstrom) for resolution in FSC plots ");
142 
144  " [ --mask <maskfile=\"\"> ] : Mask particles; only valid in combination with -dont_align ");
146  " [ --maxCC ] : Use constrained cross-correlation and weighted averaging instead of ML ");
148  " [ --dont_impute ] : Use weighted averaging, rather than imputation ");
150  " [ --noimp_threshold <float=1.>] : Threshold to avoid division by zero for weighted averaging ");
151 
152  addParamsLine("==+++++ Hidden arguments ==");
153  addParamsLine(" [--trymindiff_factor <float=0.9>]");
154  addParamsLine(" [ --no_SMALLANGLE <float=5e-5> ]: ");
155  addParamsLine(" [ --keep_angles]: ");
156  addParamsLine(" [ --filter]: ");
157  addParamsLine(" [ --ini_filter]: ");
158 
159  addExampleLine("+++---+++Input images file", false);
161  "+++ The input metadata should contain the =image= column = and =missingRegionNumber=, "
162  "indicating the subtomogran filename and the missing region number, respectively. It can"
163  "also contains columns with angles and shift information. The output will be a metadata"
164  "with the same format. Follow is an example:", false);
165  addExampleLine("+++ # XMIPP_STAR_1 *", true);
166  addExampleLine("+++ # ", true);
167  addExampleLine("+++ data_ ", true);
168  addExampleLine("+++ loop_ ", true);
169  addExampleLine("+++ _image ", true);
170  addExampleLine("+++ _missingRegionNumber ", true);
171  addExampleLine("+++ _angleRot ", true);
172  addExampleLine("+++ _angleTilt ", true);
173  addExampleLine("+++ _anglePsi ", true);
174  addExampleLine("+++ _shiftX ", true);
175  addExampleLine("+++ _shiftY ", true);
176  addExampleLine("+++ _shiftZ ", true);
177  addExampleLine("+++ _ref ", true);
178  addExampleLine("+++ _logLikelihood ", true);
180  "+++ 32_000001.scl 0.00 0.000000 0.000 0.000 0.000000 0.000000 0 0.000000 1",
181  true);
183  "+++ 32_000002.scl 0.00 0.000000 0.000 0.000 0.000000 0.000000 0 0.000000 1",
184  true);
185  // where:
186  // =ref= is the number of the corresponding reference (from 1 to NUMBER_OF_REFERENCES)
187  // =missingRegionNumber= is the number of the corresponding missing region number (starting at 1) from the missing regionn Metadata.
188  // =Pmax= is the height of the maximum of the (normalized) probability distribution. (Pmax=1 means delta functions, small Pmax values mean broad distributions)
189  // =dLL= is the contribution to the log-likelihood function for this image. The larger this value the better the image fits to the model.
190  //
191  //
192  // addExampleLine("+++ ---+++MissingDocFileFormat",false);
193  // The format of the docfile to define missing data regions is as follows:
194  addExampleLine("+++---+++Input missing regions file", false);
195  addExampleLine("+++ # XMIPP_STAR_1 *", true);
196  addExampleLine("+++ # Wedgeinfo", true);
197  addExampleLine("+++ data_", true);
198  addExampleLine("+++ loop_ ", true);
199  addExampleLine("+++ _missingRegionNumber ", true);
200  addExampleLine("+++ _missingRegionType ", true);
201  addExampleLine("+++ _missingRegionThetaY0", true);
202  addExampleLine("+++ _missingRegionThetaYF", true);
203  addExampleLine("+++ 1 wedge_y -64 64", true);
204 
206  "+++ The first column =missingRegionNumber= (starting at 1) is required for each type "
207  "of missing region, this number should appears in the input images metadata %BR% ",
208  false);
210  "+++ Here =missingRegionType= can be one of the following: %BR% ", false);
212  "+++ * =wedge_y= for a missing wedge where the tilt axis is along Y,",
213  false);
215  "+++ colums =missingRegionThetaY0= and =missingRegionThetaYF= are used",
216  false);
218  "+++ * =wedge_x= for a missing wedge where the tilt axis is along X,",
219  false);
221  "+++ colums =missingRegionThetaX0= and =missingRegionThetaXF= are used",
222  false);
224  "+++ * =pyramid= for a missing pyramid where the tilt axes are along Y and X,",
225  false);
226  addExampleLine("+++ same columns as =wedge_y= and =wedge_x= are used",
227  false);
229  "+++ * =cone= for a missing cone (pointing along Z) ",
230  false);
231  addExampleLine("+++ column =missingRegionThetaY0= is used", false);
232 
233 }
234 
235 // Read arguments ==========================================================
236 void
238 {
239  // Generate new command line for restart procedure
240  cline = "";
241  int argc2 = 0;
242  char ** argv2 = nullptr;
243 
244  if (checkParameter(argc, argv, "-restart"))
245  {
247  "restart procedure temporarily de-activated.... sorry!");
248  /*
249  std::string comment;
250  FileName fn_sel;
251  MetaData DFi;
252  DFi.read(getParameter(argc, argv, "-restart"));
253  DFi.go_beginning();
254  comment = (DFi.get_current_line()).get_text();
255  if (strstr(comment.c_str(), "ml_tomo-logfile") == NULL)
256  {
257  std::cerr << "Error!! MetaData is not of ml_tomo-logfile type. " << std::endl;
258  exit(1);
259  }
260  else
261  {
262  char *copy;
263  int n = 0;
264  int nmax = DFi.dataLineNo();
265  SFr.reserve(nmax);
266  copy = NULL;
267  DFi.next();
268  comment = " -frac " + DFi.name();
269  fn_sel = DFi.name();
270  fn_sel = fn_sel.without_extension() + "_restart.sel";
271  comment += " -ref " + fn_sel;
272  comment += (DFi.get_current_line()).get_text();
273  DFi.next();
274  cline = (DFi.get_current_line()).get_text();
275  // Also read additional options upon restart
276  for (int i=1; i <argc; i+=2)
277  {
278  std::cerr<<"i= "<<i<<" argc= "<<argc<<" argv[i]"<<argv[i]<<std::endl;
279  if ((strcmp("-restart", argv[i]) != 0))
280  {
281  comment += " ";
282  comment += argv[i];
283  comment += " ";
284  comment += argv[i+1];
285  comment += " ";
286  }
287  }
288  comment = comment + cline;
289  // regenerate command line
290  generateCommandLine(comment, argc2, argv2, copy);
291  // Read images names from restart file
292  DFi.next();
293  while (n < nmax)
294  {
295  n++;
296  DFi.next();
297  if (DFi.get_current_line().Is_comment()) fn_sel = ((DFi.get_current_line()).get_text()).erase(0, 3);
298  SFr.insert(fn_sel, SelLine::ACTIVE);
299  DFi.adjust_to_data_line();
300  }
301  fn_sel = DFi.name();
302  fn_sel = fn_sel.without_extension() + "_restart.sel";
303  SFr.write(fn_sel);
304  SFr.clear();
305  }
306  */
307  }
308  else
309  {
310  // no restart, just copy argc to argc2 and argv to argv2
311  argc2 = argc;
312  argv2 = (char **)argv;
313  for (int i = 1; i < argc2; i++)
314  {
315  cline = cline + (std::string) argv2[i] + " ";
316  }
317  }
318 
319  fn_sel = getParam("-i");
320  nr_ref = getIntParam("--nref");
321  fn_ref = getParam("--ref");
322  if (!fn_ref.empty() && (!compareImageSize(fn_sel, fn_ref)))
323  REPORT_ERROR(ERR_GRID_SIZE, "Reference and images aren't of same size");
324  //fn_doc = getParam("--doc");
325 
326  fn_root = getParam("--oroot");
327  fn_sym = getParam("--sym");
328  Niter = getIntParam("--iter");
329  Niter2 = getIntParam("--impute_iter");
330  istart = getIntParam("--istart");
331  sigma_noise = getDoubleParam("--noise");
332  sigma_offset = getDoubleParam("--offset");
333  fn_frac = getParam("--frac");
334  fix_fractions = checkParam("--fix_fractions");
335  fix_sigma_offset = checkParam("--fix_sigma_offset");
336  fix_sigma_noise = checkParam("--fix_sigma_noise");
337  eps = getDoubleParam("--eps");
338  no_SMALLANGLE = checkParam("--no_SMALLANGLE");
339  do_keep_angles = checkParam("--keep_angles");
340  do_perturb = checkParam("--perturb");
341  pixel_size = getDoubleParam("--pixel_size");
342 
343  // Low-pass filter
344  do_filter = checkParam("--filter");
345  do_ini_filter = checkParam("--ini_filter");
346 
347  // regularization
348  reg0 = getDoubleParam("--reg0");
349  regF = getDoubleParam("--regF");
350  reg_steps = getIntParam("--reg_steps");
351 
352  // ML (with/without) imputation, or maxCC
353  do_ml = !checkParam("--maxCC");
354  do_impute = !checkParam("--dont_impute");
355  noimp_threshold = getDoubleParam("--noimp_threshold");
356 
357  // Angular sampling
358  angular_sampling = getDoubleParam("--ang");
359  psi_sampling = getDoubleParam("--psi_sampling");
360  tilt_range0 = getDoubleParam("--tilt0");
361  tilt_rangeF = getDoubleParam("--tiltF");
362  ang_search = getDoubleParam("--ang_search");
363  do_limit_psirange = !checkParam("--dont_limit_psirange");
364  limit_trans = getDoubleParam("--limit_trans");
365 
366  // Skip rotation, only translate and classify
367  dont_rotate = checkParam("--dont_rotate");
368  // Skip rotation and translation, only classify
369  dont_align = checkParam("--dont_align");
370  // Skip rotation and translation and classification
371  do_only_average = checkParam("--only_average");
372 
373  // For focussed classification (only in combination with dont_align)
374  fn_mask = getParam("--mask");
375 
376  // Missing data structures
377  fn_missing = getParam("--missing");
378  dim = getIntParam("--dim");
379  maxres = getDoubleParam("--maxres");
380 
381  // Hidden arguments
382  trymindiff_factor = getDoubleParam("--trymindiff_factor");
383 
384  // Number of threads
385  threads = getIntParam("--thr");
386 
387 }
388 
389 void
391 {
392  double LL, sumw_allrefs, sumcorr;
393  bool converged;
394  std::vector<double> conv;
395  double wsum_sigma_noise, wsum_sigma_offset;
396  std::vector<MultidimArray<double> > wsumimgs; //3D
397  std::vector<MultidimArray<double> > wsumweds; //3D
398  std::vector<MultidimArray<double> > fsc;
399  MultidimArray<double> sumw; //1D
400  MultidimArray<double> P_phi, Mr2, Maux; //3D
401  FileName fn_img, fn_tmp;
402  MultidimArray<double> oneline(0); //1D
403 
404  produceSideInfo();
405  show();
407  Maux.resize(dim, dim, dim);
408  Maux.setXmippOrigin();
409 
410  // Loop over all iterations
411  for (int iter = istart; iter <= Niter; iter++)
412  {
413 
414  if (verbose)
415  std::cout << " Multi-reference refinement: iteration " << iter << " of "
416  << Niter << std::endl;
417  // Save old reference images
418  for (int refno = 0; refno < nr_ref; refno++)
419  Iold[refno]() = Iref[refno]();
420  //#define DEBUG5
421 #ifdef DEBUG5
422 
423  try
424  {
425  //wrong
426  MDimg.write("0.xmd");
427  }
428  catch (XmippError XE)
429  {
430  std::cout << XE;
431  exit(0);
432  }
433 #endif
434  // Integrate over all images
435  expectation(MDimg, Iref, iter, LL, sumcorr, wsumimgs, wsumweds,
436  wsum_sigma_noise, wsum_sigma_offset, sumw);
437 #ifdef DEBUG5
438 
439  try
440  {
441  //wrong
442  MDimg.write("1.xmd");
443  }
444  catch (XmippError XE)
445  {
446  std::cout << XE;
447  exit(0);
448  }
449 #endif
450  // Update model parameters
451  maximization(wsumimgs, wsumweds, wsum_sigma_noise, wsum_sigma_offset, sumw,
452  sumcorr, sumw_allrefs, fsc, iter);
453 #ifdef DEBUG5
454 
455  try
456  {
457  //wrong
458  MDimg.write("2.xmd");
459  }
460  catch (XmippError XE)
461  {
462  std::cout << XE;
463  exit(0);
464  }
465 #endif
466  // Check convergence
467  converged = checkConvergence(conv);
468 #ifdef DEBUG5
469 
470  try
471  {
472  //wrong
473  MDimg.write("3.xmd");
474  }
475  catch (XmippError XE)
476  {
477  std::cout << XE;
478  exit(0);
479  }
480 #endif
482 
483 #ifdef DEBUG5
484 
485  try
486  {
487  //wrong
488  MDimg.write("4.xmd");
489  }
490  catch (XmippError XE)
491  {
492  std::cout << XE;
493  exit(0);
494  }
495 #endif
496  writeOutputFiles(iter, wsumweds, sumw_allrefs, LL, sumcorr, conv, fsc);
497  if (converged)
498  {
499  if (verbose)
500  std::cout << " Optimization converged!" << std::endl;
501  break;
502  }
503 
504  } // end loop iterations
505 
506  writeOutputFiles(-1, wsumweds, sumw_allrefs, LL, sumcorr, conv, fsc);
507 
508 }
509 
510 // Show ====================================================================
511 void
513 {
514 
515  if (verbose)
516  {
517  // To screen
518  std::cout
519  << " -----------------------------------------------------------------"
520  << std::endl;
521  std::cout
522  << " | Read more about this program in the following publication: |"
523  << std::endl;
524  std::cout
525  << " | Scheres et al. (2009) Structure, 17, 1563-1572 |"
526  << std::endl;
527  std::cout
528  << " | |"
529  << std::endl;
530  std::cout
531  << " | *** Please cite it if this program is of use to you! *** |"
532  << std::endl;
533  std::cout
534  << " -----------------------------------------------------------------"
535  << std::endl;
536  std::cout << "--> Maximum-likelihood multi-reference refinement "
537  << std::endl;
538  std::cout << " Input images : " << fn_sel << " ("
539  << nr_images_global << ")" << std::endl;
540  if (!fn_ref.empty())
541  std::cout << " Reference image(s) : " << fn_ref << std::endl;
542  else
543  std::cout << " Number of references: : " << nr_ref << std::endl;
544  std::cout << " Output rootname : " << fn_root << std::endl;
546  {
547  std::cout << " Angular sampling rate : " << angular_sampling
548  << " degrees" << std::endl;
549  if (ang_search > 0.)
550  {
551  std::cout << " Local angular searches : " << ang_search << " degrees"
552  << std::endl;
553  if (!do_limit_psirange)
554  std::cout
555  << " : but with complete psi searches"
556  << std::endl;
557  }
558  }
559  if (limit_trans >= 0.)
560  std::cout << " Maximum allowed shifts : " << limit_trans << " pixels"
561  << std::endl;
562  std::cout << " Symmetry group : " << fn_sym << std::endl;
563  std::cout << " Stopping criterium : " << eps << std::endl;
564  std::cout << " initial sigma noise : " << sigma_noise << std::endl;
565  std::cout << " initial sigma offset : " << sigma_offset << std::endl;
566  std::cout << " Maximum resolution : " << maxres << " pix^-1"
567  << std::endl;
568  std::cout << " Use images of size : " << dim << std::endl;
569  if (reg0 > 0.)
570  {
571  std::cout << " Regularization from : " << reg0 << " to " << regF
572  << " in " << reg_steps << " steps" << std::endl;
573  }
574  if (!fn_missing.empty())
575  {
576  std::cout << " Missing data info : " << fn_missing << std::endl;
577  if (do_impute && do_ml)
578  std::cout << " Missing data treatment : imputation " << std::endl;
579  else
580  std::cout << " Missing data treatment : conventional division "
581  << std::endl;
582  }
583  if (!fn_frac.empty())
584  std::cout << " Initial model fractions : " << fn_frac << std::endl;
585 
586  if (dont_rotate)
587  {
588  std::cout << " -> Skip rotational searches, only translate and classify "
589  << std::endl;
590  }
591  if (dont_align)
592  {
593  std::cout << " -> Skip alignment, only classify " << std::endl;
594  if (do_mask)
595  std::cout << " -> Classify within mask " << fn_mask << std::endl;
596  }
597  if (do_only_average)
598  {
599  std::cout
600  << " -> Skip alignment and classification, only calculate weighted average "
601  << std::endl;
602  }
603  if (!do_ml)
604  {
605  std::cout
606  << " -> Use constrained correlation coefficient instead of ML-imputation approach."
607  << std::endl;
608  }
609  if (do_perturb)
610  {
611  std::cout << " -> Perturb angular sampling." << std::endl;
612  }
613  if (fix_fractions)
614  {
615  std::cout << " -> Do not update estimates of model fractions."
616  << std::endl;
617  }
618  if (fix_sigma_offset)
619  {
620  std::cout << " -> Do not update sigma-estimate of origin offsets."
621  << std::endl;
622  }
623  if (fix_sigma_noise)
624  {
625  std::cout << " -> Do not update sigma-estimate of noise." << std::endl;
626  }
627  if (threads > 1)
628  {
629  std::cout << " -> Using " << threads << " parallel threads" << std::endl;
630  }
631 
632  std::cout
633  << " -----------------------------------------------------------------"
634  << std::endl;
635 
636  }
637 
638 }
639 
640 // Set up a lot of general stuff
641 // This side info is general, i.e. in parallel mode it is the same for
642 // all processors! (in contrast to produce_Side_info2)
643 void
645 {
646 
647  FileName fn_img, fn_tmp, fn_base, fn_tmp2;
648  Image<double> vol;
649  Matrix1D<double> offsets(3), dum;
650  MultidimArray<double> Maux, Maux2;
652  Matrix1D<int> center(3);
653  MultidimArray<int> radial_count;
654  size_t xdim, ydim, zdim;
655  size_t ndim;
656 
657 #ifdef DEBUG
658 
659  std::cerr<<"Start produceSideInfo"<<std::endl;
660 #endif
661 
662  // For several random operations
664 
665  // Read metadatafile with experimental images
666  MDimg.read(fn_sel);
669  //Get all images id for threads work on it
671 
672  // Check whether MDimg contains orientations
673  // mdimg_contains_angles = (MDimg.containsLabel(MDL_ANGLE_ROT)
674  // && MDimg.containsLabel(MDL_ANGLE_TILT) && MDimg.containsLabel(MDL_ANGLE_PSI)
675  // && MDimg.containsLabel(MDL_SHIFT_X) && MDimg.containsLabel(MDL_SHIFT_Y)
676  // && MDimg.containsLabel(MDL_SHIFT_Z));
677  // Check angles and shifts are not present on input metadata, fill it with 0 value
679  String labelStr = "WARNING: Labels ";
680  mdimg_contains_angles = true;
681  for (int i = 0; i < 6; ++i)
682  {
683  if (!MDimg.containsLabel(labels[i]))
684  {
685  mdimg_contains_angles = false;
686  MDimg.fillConstant(labels[i], "0.0");
687  labelStr += MDL::label2Str(labels[i]) + " ";
688  std::cerr << "missing label: " << labels[i] << " " << labelStr<<std::endl;
689  }
690  }
692  std::cerr << labelStr + "are missing in input metadata and are filled with value 0.0" <<std::endl;
693 
695  {
696  if (MDmissing.size() > 1)
697  REPORT_ERROR(ERR_MD_OBJECTNUMBER, "missingRegionNumber is missing from input images metadata"
698  "and your missing region metadata contains more than one missing region");
699  int missno=0;
702  std::cerr << "WARNING: missingRegionNumber is missing from input images metadata,"
703  "column filled with unique missing region provided" <<std::endl;
704  }
705 
706  //WHY ROB <<<<<<<<<<<<<<<<<<<<<<<<<<<<
707  //MDimg.fillConstant(MDL_ANGLE_PSI, "0");
708 
709  // Get original dimension
710  getImageSize(MDimg, xdim, ydim, zdim, ndim);
711  if (xdim != ydim || xdim != zdim)
712  REPORT_ERROR(ERR_MULTIDIM_SIZE, "Only cubic volumes are allowed");
713  oridim = (int) xdim;
714 
715  // Downscaled dimension
716  if (dim < 0)
717  dim = oridim;
718  if (dim > oridim)
720  "dim should be smaller than the size of the images");
721  // Keep both dim and oridim even or uneven
722  if (oridim % 2 != dim % 2)
723  dim++;
724  hdim = dim / 2;
725  dim3 = dim * dim * dim;
726  ddim3 = (double) dim3;
727  scale_factor = (double) dim / (double) oridim;
729 
730  if (regF > reg0)
731  REPORT_ERROR(ERR_VALUE_INCORRECT, "regF should be smaller than reg0!");
732  reg_current = reg0;
733 
734  // Make real-space masks
735  MultidimArray<int> int_mask(dim, dim, dim);
736  int_mask.setXmippOrigin();
737  real_mask.resize(dim, dim, dim);
739  BinaryCircularMask(int_mask, hdim, INNER_MASK);
741  {
743  (double) DIRECT_MULTIDIM_ELEM(int_mask,n);
744  }
746  real_omask = 1. - real_mask;
747 
748  if (fn_mask.empty())
749  {
750  do_mask = false;
751  }
752  else
753  {
754  if (!dont_align)
756  "option -mask is only valid in combination with -dont_align");
757  Imask.read(fn_mask);
758  if (Imask().computeMin() < 0. || Imask().computeMax() > 1.)
760  "mask should have values within the range [0,1]");
761  Imask().setXmippOrigin();
762  reScaleVolume(Imask(), true);
763  // Remove any borders from the mask (to prevent problems rotating it later on)
765  {
767  (double) DIRECT_MULTIDIM_ELEM(int_mask,n);
768  }
769  nr_mask_pixels = Imask().sum();
770  }
771 
772  // Set-up fourier-space mask
773  MultidimArray<double> cosine_mask(dim, dim, dim);
774  cosine_mask.setXmippOrigin();
775  fourier_mask.resize(dim, dim, hdim + 1);
776  fourier_imask.resize(dim, dim, hdim + 1);
777  int r_maxres = XMIPP_MIN(hdim, FLOOR(maxres * dim));
778  RaisedCosineMask(cosine_mask, r_maxres - 2, r_maxres, INNER_MASK);
779  int yy, zz;
780  int dimb = (dim - 1) / 2;
781  for (int z = 0, ii = 0; z < dim; z++)
782  {
783  if (z > dimb)
784  zz = z - dim;
785  else
786  zz = z;
787  for (int y = 0; y < dim; y++)
788  {
789  if (y > dimb)
790  yy = y - dim;
791  else
792  yy = y;
793  for (int xx = 0; xx < hdim + 1; xx++, ii++)
794  {
795  if (xx <= FINISHINGX(cosine_mask))
796  {
797  DIRECT_MULTIDIM_ELEM(fourier_mask,ii) = A3D_ELEM(cosine_mask,xx,yy,zz);
798  if (A3D_ELEM(cosine_mask,xx,yy,zz) > 0.)
800  else
802  }
803  }
804  }
805  }
806  // exclude origin voxel from fourier masks
809 
810  // Precalculate sampling
811  do_sym = false;
813  {
815  REPORT_ERROR(
817  "Options --dont_align, --dont_rotate and --only_average require that angle information is present in input images metadata");
818  ang_search = -1.;
819  }
820  else
821  {
825  (std::string)"Invalid symmetry " + fn_sym);
827  // Check whether we are using symmetry
828  if (mysampling.SL.symsNo() > 0)
829  {
830  do_sym = true;
831  if (verbose)
832  {
833  std::cout << " --> Using symmetry version of the code: " << std::endl;
834  std::cout
835  << " [-psi, -tilt, -rot] is applied to the references, thereby "
836  << std::endl;
837  std::cout << " tilt and psi are sampled on an hexagonal lattice, "
838  << std::endl;
839  std::cout << " and rot is sampled linearly " << std::endl;
840  std::cout
841  << " Note that --dont_limit_psirange option is not allowed.... "
842  << std::endl;
843  }
844  if (!do_limit_psirange && ang_search > 0.)
846  "exhaustive psi-angle search only allowed for C1 symmetry");
847  }
849  // by default max_tilt= 180, min_tilt= 0
850  mysampling.computeSamplingPoints(false, // half sphere?
853  0.75 * angular_sampling);
854  if (psi_sampling < 0)
856 
857  }
858  readMissingInfo();
859  // Get number of references
860  if (do_only_average)
861  {
862  int refno;
863  nr_ref = 0;
864  for (size_t objId : MDimg.ids())
865  {
866  if (MDimg.getValue(MDL_REF, refno, objId))
867  {
868  nr_ref = XMIPP_MAX(refno, nr_ref);
869  }
870  else
871  {
872  nr_ref = 1;
873  break;
874  }
875  }
876  fn_ref = "tt";
877  Niter = 1;
878  do_impute = false;
879  do_ml = false;
880  }
881  else
882  {
883  do_generate_refs = fn_ref.empty();
884  if (do_generate_refs) //assign bool value and asking at same time
886  }
887 
888 
889 
890 } //end of function produceSideInfo
891 
892 // Generate initial references =============================================
893 void
895 {
896 
897  //MetaData SFtmp;
898  Image<double> Iave1, Iave2, Itmp, Iout;
899  MultidimArray<double> Msumwedge1, Msumwedge2;
902  std::vector<MultidimArray<double> > fsc; //1D
903  Matrix2D<double> my_A; //2D
904  Matrix1D<double> my_offsets(3); //1D
905  FileName fn_tmp;
906  //SelLine line;
907  MetaDataVec MDrand;
908  std::vector<MetaDataVec> MDtmp(nr_ref);
909  int Nsub = ROUND((double)nr_images_global / nr_ref);
910  double my_rot, my_tilt, my_psi, resolution;
911  //DocLine DL;
912  int missno, c = 0, cc = XMIPP_MAX(1, nr_images_global / 60);
913 
914 #ifdef DEBUG
915 
916  std::cerr<<"Start generateInitialReferences"<<std::endl;
917 #endif
918 #ifdef DEBUG_JM
919 
920  std::cerr << "DEBUG_JM: entering ProgMLTomo::generateInitialReferences" <<std::endl;
921 #endif
922 
923  if (verbose)
924  {
925  std::cout
926  << " Generating initial references by averaging over random subsets"
927  << std::endl;
929  }
930 
931  fsc.clear();
932  fsc.resize(nr_ref + 1);
933  Iave1().resize(dim, dim, dim);
934  Iave1().setXmippOrigin();
935  Iave2().resize(dim, dim, dim);
936  Iave2().setXmippOrigin();
937  Msumwedge1.resize(dim, dim, hdim + 1);
938  Msumwedge2.resize(dim, dim, hdim + 1);
939  // Make random subsets and calculate average images in random orientations
940  // and correct using conventional division by the sum of the wedges
941  MDrand.randomize(MDimg);
942  MDrand.split(nr_ref, MDtmp);
943  MDref.clear(); //Just to be sure
944 
945  for (int refno = 0; refno < nr_ref; ++refno)
946  {
947  Iave1().initZeros();
948  Iave2().initZeros();
949  Msumwedge1.initZeros();
950  Msumwedge2.initZeros();
951 
952  MetaDataVec &md = MDtmp[refno];
953  for (size_t objId : md.ids())
954  {
955  md.getValue(MDL_IMAGE, fn_tmp, objId);
956  Itmp.read(fn_tmp);
957  Itmp().setXmippOrigin();
958  reScaleVolume(Itmp(), true);
960  {
961  // angles from MetaData
962  md.getValue(MDL_ANGLE_ROT, my_rot, objId);
963  md.getValue(MDL_ANGLE_TILT, my_tilt, objId);
964  md.getValue(MDL_ANGLE_PSI, my_psi, objId);
965 
966  md.getValue(MDL_SHIFT_X, my_offsets(0), objId);
967  md.getValue(MDL_SHIFT_Y, my_offsets(1), objId);
968  md.getValue(MDL_SHIFT_Z, my_offsets(2), objId);
969  my_offsets *= scale_factor;
970 
971  selfTranslate(xmipp_transformation::LINEAR, Itmp(), my_offsets, xmipp_transformation::DONT_WRAP);
972  }
973  else
974  {
975  // reset to random angles
976  my_rot = 360. * rnd_unif(0., 1.);
977  my_tilt = ACOSD((2.*rnd_unif(0., 1.) - 1));
978  my_psi = 360. * rnd_unif(0., 1.);
979  }
980 
981  Euler_angles2matrix(my_rot, my_tilt, my_psi, my_A, true);
982  selfApplyGeometry(xmipp_transformation::LINEAR, Itmp(), my_A, xmipp_transformation::IS_NOT_INV, xmipp_transformation::DONT_WRAP, 0.);
983 
984  int iran_fsc = ROUND(rnd_unif());
985  if (iran_fsc == 0)
986  Iave1() += Itmp();
987  else
988  Iave2() += Itmp();
989  if (do_missing)
990  {
991  md.getValue(MDL_MISSINGREGION_NR, missno, objId);
992  --missno;
993  getMissingRegion(Mmissing, my_A, missno);
994  if (iran_fsc == 0)
996  DIRECT_MULTIDIM_ELEM(Msumwedge1,n)+=DIRECT_MULTIDIM_ELEM(Mmissing,n);
997  else
999  DIRECT_MULTIDIM_ELEM(Msumwedge2,n)+=DIRECT_MULTIDIM_ELEM(Mmissing,n);
1000  }
1001  c++;
1002  if (verbose && c % cc == 0)
1003  progress_bar(c);
1004  }
1005 
1006  // Calculate resolution
1007  calculateFsc(Iave1(), Iave2(), Msumwedge1, Msumwedge2, fsc[0],
1008  fsc[refno + 1], resolution);
1009  Iave1() += Iave2();
1010  Msumwedge1 += Msumwedge2;
1011 
1012  if (do_missing)
1013  {
1014  // 1. Correct for missing wedge by division of sumwedge
1015  transformer.FourierTransform(Iave1(), Fave, true);
1017  {
1018  if (DIRECT_MULTIDIM_ELEM(Msumwedge1,n) > noimp_threshold)
1019  {
1020  DIRECT_MULTIDIM_ELEM(Fave,n) /= DIRECT_MULTIDIM_ELEM(Msumwedge1,n);
1021  }
1022  else
1023  {
1024  DIRECT_MULTIDIM_ELEM(Fave,n) = 0.;
1025  }
1026  }
1027  transformer.inverseFourierTransform(Fave, Iave1());
1028  }
1029  else
1030  {
1031  Iave1() /= (double) Nsub;
1032  }
1033 
1034  // Enforce fourier_mask, symmetry and omask
1035  if (do_ini_filter)
1036  postProcessVolume(Iave1, resolution);
1037  else
1038  postProcessVolume(Iave1);
1039 
1040  fn_tmp = FN_ITER_VOL(0, "ref", refno);
1041  Iout = Iave1;
1042  reScaleVolume(Iout(), false);
1043  Iout.write(fn_tmp);
1044  MDref.setValue(MDL_IMAGE, fn_tmp, MDref.addObject());
1045  // Also write out average wedge of this reference
1046  fn_tmp = FN_ITER_VOL(0, "wedge", refno);
1047  Iout() = Msumwedge1;
1048  reScaleVolume(Iout(), false);
1049  Iout.write(fn_tmp);
1050  }
1051  if (verbose)
1053  fn_ref = FN_ITER_MD(0);
1054  MDref.write(fn_ref);
1055 
1056 #ifdef DEBUG
1057 
1058  std::cerr<<"Finished generateInitialReferences"<<std::endl;
1059 #endif
1060 }
1061 
1063 void
1065 {
1067  // By default set myFirst and myLast equal to 0 and N - 1
1068  // respectively, this should be changed when using MPI
1069  // by calling setWorkingImages before produceSideInfo2
1070  myFirstImg = 0;
1072 }
1073 // Read reference images to memory and initialize offset vectors
1074 // This side info is NOT general, i.e. in parallel mode it is NOT the
1075 // same for all processors! (in contrast to produce_Side_info)
1076 void
1078 {
1079 
1080 #ifdef JM_DEBUG
1081 
1082  std::cerr<<"Start produceSideInfo2"<<std::endl;
1083 #endif
1084 
1085  MetaDataVec DF, DFsub;
1086  FileName fn_tmp;
1087  Image<double> img, Vaux;
1088  std::vector<Matrix1D<double> > Vdm;
1089 
1091  // Store tomogram angles, offset vectors and missing wedge parameters
1092  imgs_optrefno.assign(nr_images_local, 0.);
1093  imgs_optangno.assign(nr_images_local, 0.);
1094  imgs_optpsi.assign(nr_images_local, 0.);
1095  imgs_trymindiff.assign(nr_images_local, -1.);
1096  Matrix1D<double> dum(3);
1097  if (do_missing)
1098  {
1100  REPORT_ERROR(
1102  "Expecting missing region label 'missingRegionNumber' on input metadata");
1103  imgs_missno.assign(nr_images_local, -1);
1104  }
1106  imgs_optoffsets.assign(nr_images_local, dum);
1107  //--------Setup for Docfile -----------
1109  // Read in MetaData with wedge info, optimal angles, etc.
1110  size_t count = 0, imgno;
1111  int refno;
1112  MetaDataVec MDsub;
1113 
1114  double rot, tilt, psi;
1115 
1116  for (size_t img = myFirstImg; img <= myLastImg; ++img)
1117  {
1118  MDRowVec row;
1119  imgno = img - myFirstImg;
1120  MDimg.getRow(row, imgs_id[imgno]);
1121  // Get missing wedge type
1122  if (do_missing)
1123  {
1125  //The label MDL_MISSINGREGION_NR should be the index of missing regions, starting at 1
1126  --imgs_missno[imgno];
1127  }
1128  // Generate a MetaData from the (possible subset of) images in SF
1130  {
1131  row.getValue(MDL_ANGLE_ROT, rot);
1132  row.getValue(MDL_ANGLE_PSI, psi);
1133  row.getValue(MDL_ANGLE_TILT, tilt);
1134 
1135  if (do_sym)
1136  {
1137  imgs_optpsi[imgno] = rot; // for limited psi (now rot) searches
1138  // Reverse rotation applied to the references!!
1139  row.setValue(MDL_ANGLE_ROT, -psi);
1140  row.setValue(MDL_ANGLE_TILT, -tilt);
1141  row.setValue(MDL_ANGLE_PSI, -rot);
1142  }
1143  else
1144  imgs_optpsi[imgno] = psi; // for limited psi searches
1145  #ifdef DEBUG
1146  std::cerr << "r t p " << rot << " " << tilt << " " << psi <<std::endl;
1147  #endif
1148  MDsub.addRow(row);
1149  imgs_optangno[imgno] = count++;
1150 
1151  row.getValue(MDL_REF, refno);
1152  --refno;
1153  imgs_optrefno[imgno] = (refno < 0 || refno >= nr_ref) ? 0 : refno;
1154 
1156  {
1157  row.getValue(MDL_SHIFT_X, imgs_optoffsets[imgno](0));
1158  row.getValue(MDL_SHIFT_Y, imgs_optoffsets[imgno](1));
1159  row.getValue(MDL_SHIFT_Z, imgs_optoffsets[imgno](2));
1160  }
1161  }
1162  }
1163  // Set up local searches
1164  if (ang_search > 0.)
1165  {
1166  std::cerr << "myLastImg" << myLastImg <<std::endl;
1167  std::cerr << "ang_search " << ang_search << std::endl;
1169  std::cerr << "MDsub.size " << MDsub.size() << std::endl;
1170 
1172  std::cerr << "exp_data_projection_direction_by_L_R "
1174  <<std::endl;
1176  std::cerr << "no_redundant_sampling_points_vector"
1177  << mysampling.no_redundant_sampling_points_vector.size() <<std::endl;
1179  //mysampling.saveSamplingFile("NEW");
1180  //MDsub.write("NEWexp.xmd");
1182  for (size_t i = 0; i < mysampling.no_redundant_sampling_points_index.size(); i++)
1185 
1186  //exit(1);
1187  }
1188 
1189 
1190  // Calculate angular sampling
1191  // A. from MetaData entries (MDsub) only
1193  {
1194 
1195  AnglesInfo myinfo;
1196  all_angle_info.clear();
1197  nr_ang = 0;
1198  /*DFsub.go_first_data_line();
1199  while (!DFsub.eof())*/
1200  for (const auto& row : MDsub)
1201  {
1202  row.getValue(MDL_ANGLE_ROT, myinfo.rot);
1203  row.getValue(MDL_ANGLE_TILT, myinfo.tilt);
1204  row.getValue(MDL_ANGLE_PSI, myinfo.psi);
1205  if (do_sym)
1206  {
1207  rot = myinfo.rot;
1208  myinfo.rot = -myinfo.psi;
1209  myinfo.tilt *= -1;
1210  myinfo.psi = -rot;
1211  }
1212  Euler_angles2matrix(myinfo.rot, myinfo.tilt, myinfo.psi, myinfo.A, true);
1213  myinfo.direction = nr_ang++;
1214  all_angle_info.push_back(myinfo);
1215  }
1216  }
1217  // B. from mysampling
1218  else
1219  {
1220 
1221  int nr_psi = CEIL(360. / psi_sampling);
1222  AnglesInfo myinfo;
1223  all_angle_info.clear();
1224  nr_ang = 0;
1225  for (size_t i = 0; i < mysampling.no_redundant_sampling_points_angles.size(); i++)
1226  {
1229  for (int ipsi = 0; ipsi < nr_psi; ipsi++)
1230  {
1231  psi = (double) (ipsi * 360. / nr_psi);
1232  if (!no_SMALLANGLE)
1233  psi += SMALLANGLE;
1234  if (do_sym)
1235  {
1236  // Inverse rotation because A_rot is being applied to the reference
1237  // and rot, tilt and psi apply to the experimental subtomogram!
1238  myinfo.rot = -psi;
1239  myinfo.tilt = -tilt;
1240  myinfo.psi = -rot;
1241  }
1242  else
1243  {
1244  // Only in C1 we get away with reverse order rotations...
1245  // This is ugly, but allows -dont_limit_psirange....
1246  myinfo.rot = rot;
1247  myinfo.tilt = tilt;
1248  myinfo.psi = psi;
1249  }
1250  Euler_angles2matrix(myinfo.rot, myinfo.tilt, myinfo.psi, myinfo.A,
1251  true);
1252  if (ang_search > 0.)
1254  else
1255  myinfo.direction = i;
1256  all_angle_info.push_back(myinfo);
1257  nr_ang++;
1258  }
1259  }
1260  }
1261 
1262  // Copy all rot, tilr, psi and A into _ori equivalents
1263  for (int angno = 0; angno < nr_ang; angno++)
1264  {
1265  all_angle_info[angno].rot_ori = all_angle_info[angno].rot;
1266  all_angle_info[angno].tilt_ori = all_angle_info[angno].tilt;
1267  all_angle_info[angno].psi_ori = all_angle_info[angno].psi;
1268  all_angle_info[angno].A_ori = all_angle_info[angno].A;
1269  }
1270 
1271 #ifdef JM_DEBUG
1272 
1273  MetaDataVec DFt;
1274  size_t _id;
1275  for (int angno = 0; angno < nr_ang; angno++)
1276  {
1277  _id = DFt.addObject();
1278 
1279  double rot=all_angle_info[angno].rot;
1280  double tilt=all_angle_info[angno].tilt;
1281  double psi=all_angle_info[angno].psi;
1282  DFt.setValue(MDL_ANGLE_ROT,rot,_id);
1283  DFt.setValue(MDL_ANGLE_TILT,tilt,_id);
1284  DFt.setValue(MDL_ANGLE_PSI,psi,_id);
1285  DFt.setValue(MDL_ANGLE_PSI,psi,_id);
1286  // DFt.append_angles(rot,tilt,psi,"rot","tilt","psi");
1287  }
1288  FileName fnt;
1289  fnt = fn_root + "_angles1.doc";
1290  DFt.write(fnt);
1291  mysampling.saveSamplingFile(fn_root + "_sampling.doc");
1292 #endif
1293 
1294  // Prepare reference images
1295  if (do_only_average)
1296  {
1297  img().initZeros(dim, dim, dim);
1298  img().setXmippOrigin();
1299  for (int refno = 0; refno < nr_ref; refno++)
1300  {
1301  Iref.push_back(img);
1302  Iold.push_back(img);
1303  }
1304  }
1305  else
1306  {
1307  // Read in all reference images in memory
1308  MDref.read(fn_ref);
1309  nr_ref = MDref.size();
1310  FileName fn_img;
1311  for (size_t objId : MDref.ids())
1312  {
1313  MDref.getValue(MDL_IMAGE, fn_img, objId);
1314  img.read(fn_img);
1315  img().setXmippOrigin();
1316 
1317  if (do_mask)
1318  {
1319  img() *= Imask();
1320  }
1321  reScaleVolume(img(), true);
1322  // From now on we will assume that all references are omasked, so enforce this here
1324  // Rotate some arbitrary (off-axis) angle and rotate back again to remove high frequencies
1325  // that will be affected by the interpolation due to rotation
1326  // This makes that the A2 values of the rotated references are much less sensitive to rotation
1327  Matrix2D<double> E_rot;
1328  Euler_angles2matrix(32., 61., 53., E_rot, true);
1329  selfApplyGeometry(xmipp_transformation::LINEAR, img(), E_rot, xmipp_transformation::IS_NOT_INV, xmipp_transformation::DONT_WRAP,
1330  DIRECT_MULTIDIM_ELEM(img(), 0));
1331  selfApplyGeometry(xmipp_transformation::LINEAR, img(), E_rot, xmipp_transformation::IS_INV, xmipp_transformation::DONT_WRAP,
1332  DIRECT_MULTIDIM_ELEM(img(), 0));
1333  Iref.push_back(img);
1334  Iold.push_back(img);
1335 
1336  }
1337  }
1338 
1339  // Prepare prior alpha_k
1342  //if (fn_frac != "")
1343  {
1344  // read in model fractions if given on command line
1345  double sumfrac = 0.;
1346  //MetaData DF;
1347  //DocLine DL;
1348  //DF.read(fn_frac);
1349  //DF.go_first_data_line();
1350  //for (int refno = 0; refno < nr_ref; refno++)
1351  int refno = 0;
1352  for (size_t objId : MDref.ids())
1353  {
1354  MDref.getValue(MDL_WEIGHT, alpha_k(refno), objId);
1355  //DL = DF.get_current_line();
1356  //alpha_k(refno) = DL[0];
1357  sumfrac += alpha_k(refno);
1358  ++refno;
1359  //DF.next_data_line();
1360  }
1361  if (ABS(sumfrac - 1.) > 1e-3)
1362  if (verbose)
1363  std::cerr << " ->WARNING: Sum of all expected model fractions ("
1364  << sumfrac << ") is not one!" << std::endl;
1365  for (int refno = 0; refno < nr_ref; refno++)
1366  {
1367  alpha_k(refno) /= sumfrac;
1368  }
1369  }
1370  else
1371  {
1372  // Even distribution
1373  alpha_k.initConstant(1. / (double) nr_ref);
1374  }
1375 
1376  //exit(1);
1377 
1378  // Regularization (do not regularize during restarts!)
1379  if (istart == 1)
1380  regularize(istart - 1);
1381 
1382  //#define DEBUG_GENERAL
1383 #ifdef JM_DEBUG
1384 
1385  // std::cerr<<"nr images= "<<SF.ImgNo()<<std::endl;
1386  std::cerr<<"do_generate_refs ="<<do_generate_refs<<std::endl;
1387  std::cerr<<"nr_ref= "<<nr_ref<<std::endl;
1388  std::cerr<<"nr_miss= "<<nr_miss<<std::endl;
1389  std::cerr<<"dim= "<<dim<<std::endl;
1390  std::cerr<<"Finished produceSideInfo"<<std::endl;
1391  std::cerr<<"nr_ang= "<<nr_ang<<std::endl;
1392  // std::cerr<<"nr_psi= "<<nr_psi<<std::endl;
1393 #endif
1394 
1395 #ifdef JM_DEBUG
1396 
1397  std::cerr<<"Finished produceSideInfo2"<<std::endl;
1398 #endif
1399 
1400 }
1401 
1402 void
1404 {
1405 
1406  Matrix2D<double> R, I(3, 3);
1407  double ran1, ran2, ran3;
1408  I.initIdentity();
1409 
1410  // Note that each mpi process will have a different random perturbation!!
1411  ran1 = rnd_gaus(0., angular_sampling / 3.);
1412  ran2 = rnd_gaus(0., angular_sampling / 3.);
1413  ran3 = rnd_gaus(0., angular_sampling / 3.);
1414  Euler_angles2matrix(ran1, ran2, ran3, R, true);
1415  R.resize(3, 3);
1416 
1417  //#define DEBUG_PERTURB
1418 #ifdef DEBUG_PERTURB
1419 
1420  std::cerr<<" random perturbation= "<<ran1<<" "<<ran2<<" "<<ran3<<std::endl;
1421 #endif
1422 
1423  for (int angno = 0; angno < nr_ang; angno++)
1424  {
1425  Euler_apply_transf(I, R, all_angle_info[angno].rot_ori,
1426  all_angle_info[angno].tilt_ori, all_angle_info[angno].psi_ori,
1427  all_angle_info[angno].rot, all_angle_info[angno].tilt,
1428  all_angle_info[angno].psi);
1429  Euler_angles2matrix(all_angle_info[angno].rot, all_angle_info[angno].tilt,
1430  all_angle_info[angno].psi, all_angle_info[angno].A, true);
1431  }
1432 
1433 }
1434 
1435 void
1437 {
1438  // Read in MetaData with information about the missing wedges
1439  nr_miss = 0;
1440  do_missing = !fn_missing.empty();
1441  if (do_missing) //if provided missing wedges metadata
1442  {
1444  nr_miss = MDmissing.size();
1445  if (nr_miss <= 0)
1446  REPORT_ERROR(ERR_ARG_INCORRECT, "Empty metadata with missing wedges info");
1447 
1448  MultidimArray<double> Mcomplete(dim, dim, dim);
1449  MultidimArray<unsigned char> Mmissing(dim, dim, hdim + 1);
1450  Matrix2D<double> I(4, 4);
1451  I.initIdentity();
1452  //Create a clean missing info
1453  MissingInfo emptyMissingInfo;
1454  emptyMissingInfo.do_limit_x = emptyMissingInfo.do_limit_y =
1455  emptyMissingInfo.do_cone = false;
1456  emptyMissingInfo.thx0 = emptyMissingInfo.thxF = emptyMissingInfo.thy0 =
1457  emptyMissingInfo.thyF = 0.;
1458  emptyMissingInfo.tg0_x = emptyMissingInfo.tgF_x = emptyMissingInfo.tg0_y =
1459  emptyMissingInfo.tgF_y = 0.;
1460  emptyMissingInfo.nr_pixels = 0.;
1461  all_missing_info.assign(nr_miss, emptyMissingInfo);
1462 
1463  int missno = 0;
1464  String missingType;
1465 
1466  for (const auto& row : MDmissing)
1467  {
1468  //Note: Now we are assuming that all missing regions will be numerate
1469  //from 0 to n - 1 (missno), and images belonging to missno 0 will
1470  //have the value 1 in MDL_MISSINGREGION_NR and so on...
1471  MissingInfo &myinfo = all_missing_info[missno];
1472  row.getValue(MDL_MISSINGREGION_TYPE, missingType);
1473  if (missingType == "wedge_y")
1474  myinfo.type = MISSING_WEDGE_Y;
1475  else if (missingType == "wedge_x")
1476  myinfo.type = MISSING_WEDGE_X;
1477  else if (missingType == "pyramid")
1478  myinfo.type = MISSING_PYRAMID;
1479  else if (missingType == "cone")
1480  myinfo.type = MISSING_CONE;
1481  else
1482  REPORT_ERROR(
1484  formatString("Unrecognized type of missing region: '%s'", missingType.c_str()));
1485 
1486  if (myinfo.type == MISSING_WEDGE_Y || myinfo.type == MISSING_PYRAMID)
1487  {
1488  myinfo.do_limit_x = true;
1489  row.getValue(MDL_MISSINGREGION_THY0, myinfo.thy0);
1490  row.getValue(MDL_MISSINGREGION_THYF, myinfo.thyF);
1491  myinfo.tg0_y = -tan(PI * (-90. - myinfo.thyF) / 180.);
1492  myinfo.tgF_y = -tan(PI * (90. - myinfo.thy0) / 180.);
1493  }
1494  if (myinfo.type == MISSING_WEDGE_X || myinfo.type == MISSING_PYRAMID)
1495  {
1496  myinfo.do_limit_y = true;
1497  row.getValue(MDL_MISSINGREGION_THX0, myinfo.thx0);
1498  row.getValue(MDL_MISSINGREGION_THXF, myinfo.thxF);
1499  myinfo.tg0_x = -tan(PI * (-90. - myinfo.thxF) / 180.);
1500  myinfo.tgF_x = -tan(PI * (90. - myinfo.thx0) / 180.);
1501  }
1502  if (myinfo.type == MISSING_CONE)
1503  {
1504  myinfo.do_cone = true;
1505  row.getValue(MDL_MISSINGREGION_THY0, myinfo.thy0);
1506  myinfo.tg0_y = -tan(PI * (-90. - myinfo.thy0) / 180.);
1507  }
1508 
1509  getMissingRegion(Mmissing, I, missno);
1510 
1512  {
1513  if (j < XSIZE(Mmissing)
1514  )
1515  myinfo.nr_pixels += DIRECT_A3D_ELEM(Mmissing,k,i,j);
1516  else
1517  myinfo.nr_pixels +=
1518  DIRECT_A3D_ELEM( Mmissing,(dim-k)%dim,(dim-i)%dim,dim-j);
1519  }
1520 
1521  ++missno;
1522  }
1523  }
1524 }
1525 
1526 void
1528  const Matrix2D<double> &A, const int missno)
1529 {
1530 #ifdef DEBUG_JM
1531  std::cerr << " DEBUG_JM: entering ProgMLTomo::getMissingRegion" <<std::endl;
1532  std::cerr << " DEBUG_JM: missno: " << missno << std::endl;
1533 #endif
1534 
1535  if (missno < 0 || missno >= nr_miss)
1536  REPORT_ERROR(
1538  "ProgMLTomo::getMissingRegion: missno should be between 0 and nr_miss - 1");
1539 
1540  Matrix2D<double> Ainv = A.inv();
1541  double xp, yp, zp;
1542  double limx0 = 0., limxF = 0., limy0 = 0., limyF = 0., lim = 0.;
1543  bool is_observed;
1544  Mmissing.resizeNoCopy(dim, dim, hdim + 1);
1545 
1546  MissingInfo &myinfo = all_missing_info[missno];
1547 
1548  //#define DEBUG_WEDGE
1549 #ifdef DEBUG_WEDGE
1550 
1551  std::cerr<<"do_limit_x= "<<do_limit_x<<std::endl;
1552  std::cerr<<"do_limit_y= "<<do_limit_y<<std::endl;
1553  std::cerr<<"do_cone= "<<do_cone<<std::endl;
1554  std::cerr<<"tg0_y= "<<tg0_y<<std::endl;
1555  std::cerr<<"tgF_y= "<<tgF_y<<std::endl;
1556  std::cerr<<"tg0_x= "<<tg0_x<<std::endl;
1557  std::cerr<<"tgF_x= "<<tgF_x<<std::endl;
1558  std::cerr<<"XMIPP_EQUAL_ACCURACY= "<<XMIPP_EQUAL_ACCURACY<<std::endl;
1559  std::cerr<<"Ainv= "<<Ainv<<" A= "<<A<<std::endl;
1560 #endif
1561 
1562  int zz, yy;
1563  int dimb = (dim - 1) / 2;
1564  double Ainv_zz_x, Ainv_zz_y, Ainv_zz_z;
1565  double Ainv_yy_x, Ainv_yy_y, Ainv_yy_z;
1566 
1567  for (int z = 0, ii = 0; z < dim; ++z)
1568  {
1569  zz = (z > dimb ) ? z - dim : z;
1570  Ainv_zz_x = dMij(Ainv, 0, 2) * zz;
1571  Ainv_zz_y = dMij(Ainv, 1, 2) * zz;
1572  Ainv_zz_z = dMij(Ainv, 2, 2) * zz;
1573 
1574  for (int y = 0; y < dim; ++y)
1575  {
1576  yy = (y > dimb ) ? y - dim : y;
1577  Ainv_yy_x = Ainv_zz_x + dMij(Ainv, 0, 1) * yy;
1578  Ainv_yy_y = Ainv_zz_y + dMij(Ainv, 1, 1) * yy;
1579  Ainv_yy_z = Ainv_zz_z + dMij(Ainv, 2, 1) * yy;
1580 
1581  for (int xx = 0; xx < hdim + 1; ++xx, ++ii)
1582  {
1583 
1584  unsigned char maskvalue = DIRECT_MULTIDIM_ELEM(fourier_imask,ii);
1585  if (!maskvalue)
1586  {
1587  DIRECT_MULTIDIM_ELEM(Mmissing,ii) = 0;
1588  }
1589  else
1590  {
1591  // Rotate the wedge
1592  xp = dMij(Ainv, 0, 0) * xx + Ainv_yy_x;
1593  yp = dMij(Ainv, 1, 0) * xx + Ainv_yy_y;
1594  zp = dMij(Ainv, 2, 0) * xx + Ainv_yy_z;
1595 
1596  // Calculate the limits
1597  if (myinfo.do_cone)
1598  {
1599  lim = myinfo.tg0_y * zp;
1600  lim *= lim;
1601  is_observed = (xp * xp + yp * yp >= lim);
1602  }
1603  else
1604  {
1605  is_observed = false; // for pyramid
1606  if (myinfo.do_limit_x)
1607  {
1608  limx0 = myinfo.tg0_y * zp;
1609  limxF = myinfo.tgF_y * zp;
1610  if (zp >= 0)
1611  is_observed = (xp <= limx0 || xp >= limxF);
1612  else
1613  is_observed = (xp <= limxF || xp >= limx0);
1614  }
1615  if (myinfo.do_limit_y && !is_observed)
1616  {
1617  limy0 = myinfo.tg0_x * zp;
1618  limyF = myinfo.tgF_x * zp;
1619  if (zp >= 0)
1620  is_observed = (yp <= limy0 || yp >= limyF);
1621  else
1622  is_observed = (yp <= limyF || yp >= limy0);
1623  }
1624  }
1625 
1626  if (is_observed)
1627  DIRECT_MULTIDIM_ELEM(Mmissing,ii) = maskvalue;
1628  else
1629  DIRECT_MULTIDIM_ELEM(Mmissing,ii) = 0;
1630  }
1631  }
1632  }
1633  }
1634 
1635 #ifdef DEBUG_WEDGE
1636  Image<double> test(dim,dim,dim), ori;
1637  ori()=Mmissing;
1638  ori.write("oriwedge.fft");
1639  test().initZeros();
1641  if (j<hdim+1)
1642  DIRECT_A3D_ELEM(test(),k,i,j)=
1643  DIRECT_A3D_ELEM(ori(),k,i,j);
1644  else
1645  DIRECT_A3D_ELEM(test(),k,i,j)=
1646  DIRECT_A3D_ELEM(ori(),
1647  (dim-k)%dim,
1648  (dim-i)%dim,
1649  dim-j);
1650  test.write("wedge.ftt");
1651  CenterFFT(test(),true);
1652  test.write("Fwedge.vol");
1653  test().setXmippOrigin();
1654  MultidimArray<int> ress(dim,dim,dim);
1655  ress.setXmippOrigin();
1656  //ROB
1657  // BinaryWedgeMask(test(),all_missing_info[missno].thy0, all_missing_info[missno].thyF, A);
1658  BinaryWedgeMask(test(),all_missing_info[missno].thy0, all_missing_info[missno].thyF, A.inv());
1659  test.write("Mwedge.vol");
1660 #endif
1661 #ifdef DEBUG_JM
1662 
1663  std::cerr << " DEBUG_JM: leaving ProgMLTomo::getMissingRegion" <<std::endl;
1664 #endif
1665 }
1666 
1667 // Calculate probability density function of all in-plane transformations phi
1668 void
1670 {
1671 
1672 #ifdef DEBUG
1673  std::cerr<<"start calculatePdfTranslations"<<std::endl;
1674 #endif
1675 
1676  double r2, pdfpix;
1677  P_phi.resize(dim, dim, dim);
1679  Mr2.resize(dim, dim, dim);
1680  Mr2.setXmippOrigin();
1681 
1683  {
1684  r2 = (double) (j * j + i * i + k * k);
1685 
1686  if (limit_trans >= 0. && r2 > limit_trans * limit_trans)
1687  A3D_ELEM(P_phi, k, i, j) = 0.;
1688  else
1689  {
1691  {
1692  pdfpix = exp(-r2 / (2. * sigma_offset * sigma_offset));
1693  pdfpix *= pow(2. * PI * sigma_offset * sigma_offset, -3. / 2.);
1694  }
1695  else
1696  {
1697  if (k == 0 && i == 0 && j == 0)
1698  pdfpix = 1.;
1699  else
1700  pdfpix = 0.;
1701  }
1702  A3D_ELEM(P_phi, k, i, j) = pdfpix;
1703  A3D_ELEM(Mr2, k, i, j) = (float) r2;
1704  }
1705  }
1706 
1707  // Re-normalize for limit_trans
1708  if (limit_trans >= 0.)
1709  {
1710  double sum = P_phi.sum();
1711  P_phi /= sum;
1712  }
1713 
1714  //#define DEBUG_PDF_SHIFT
1715 #ifdef DEBUG_PDF_SHIFT
1716  std::cerr<<" Sum of translation pdfs (should be one) = "<<P_phi.sum()<<std::endl;
1717  Image<double> Vt;
1718  Vt()=P_phi;
1719  Vt.write("pdf.vol");
1720 #endif
1721 
1722 #ifdef DEBUG
1723 
1724  std::cerr<<"finished calculatePdfTranslations"<<std::endl;
1725 #endif
1726 
1727 }
1728 
1729 void
1731 {
1732  double outside_density = 0., sumdd = 0.;
1734  {
1735  outside_density += DIRECT_MULTIDIM_ELEM(Min,n)
1737  sumdd += DIRECT_MULTIDIM_ELEM(real_omask,n);
1738  }
1739  outside_density /= sumdd;
1740 
1742  {
1744  DIRECT_MULTIDIM_ELEM(Min,n) += outside_density
1746  }
1747 }
1748 
1749 void
1751 {
1753  MultidimArray<double> Mout;
1754  FourierTransformer local_transformer_in, local_transformer_out;
1755 
1756  if (oridim == dim)
1757  return;
1758 
1759  int newdim = down_scale ? dim : oridim;
1760 
1761  local_transformer_in.setReal(Min);
1762  local_transformer_in.FourierTransform();
1763  local_transformer_in.getCompleteFourier(Fin);
1764  Mout.resize(newdim, newdim, newdim);
1765  Mout.setXmippOrigin();
1766  local_transformer_out.setReal(Mout);
1767 
1768  CenterFFT(Fin, true);
1769  Fin.setXmippOrigin();
1770  Fin.selfWindow(STARTINGZ(Mout), STARTINGY(Mout), STARTINGX(Mout),
1771  FINISHINGZ(Mout), FINISHINGY(Mout), FINISHINGX(Mout));
1772  CenterFFT(Fin, false);
1773  local_transformer_out.setFromCompleteFourier(Fin);
1774  local_transformer_out.inverseFourierTransform();
1775 
1776  //#define DEBUG_RESCALE_VOLUME
1777 #ifdef DEBUG_RESCALE_VOLUME
1778 
1779  Image<double> Vt;
1780  Vt()=Min;
1781  Vt.write("Min.vol");
1782  Vt()=Mout;
1783  Vt.write("Mout.vol");
1784 #endif
1785 
1786  Min = Mout;
1787 
1788 }
1789 
1790 void
1792 {
1793 
1795 #ifdef DEBUG
1796 
1797  std::cerr<<"start postProcessVolume"<<std::endl;
1798 #endif
1799 
1800  // Fourier transform
1801  transformer.FourierTransform(Vin(), Faux, true);
1802 
1803  // Apply fourier mask
1805  {
1807  }
1808 
1809  // Low-pass filter for given resolution
1810  if (resolution > 0.)
1811  {
1812  Matrix1D<double> w(3);
1813  double raised_w = 0.02;
1814  double w1 = resolution;
1815  double w2 = w1 + raised_w;
1816 
1818  {
1819  FFT_IDX2DIGFREQ(k, ZSIZE(Vin()), ZZ(w));
1820  FFT_IDX2DIGFREQ(i, YSIZE(Vin()), YY(w));
1821  FFT_IDX2DIGFREQ(j, XSIZE(Vin()), XX(w));
1822  double absw = w.module();
1823  if (absw > w2)
1824  DIRECT_A3D_ELEM(Faux,k,i,j) *= 0.;
1825  else if (absw > w1 && absw < w2)
1826  DIRECT_A3D_ELEM(Faux,k,i,j) *= (1 + cos(PI / raised_w * (absw - w1)))
1827  / 2;
1828  }
1829  }
1830 
1831  // Inverse Fourier Transform
1832  transformer.inverseFourierTransform(Faux, Vin());
1833 
1834  // Spherical mask with average outside density
1836 
1837  // Apply symmetry
1838  if (mysampling.SL.symsNo() > 0)
1839  {
1840  // Note that for no-imputation this is not correct!
1841  // One would have to symmetrize the missing wedges and the sum of the images separately
1842  if (do_missing && !do_impute)
1843  std::cerr
1844  << " WARNING: Symmetrization and dont_impute together are not implemented correctly...\n Proceed at your own risk"
1845  << std::endl;
1846 
1847  Image<double> Vaux, Vsym = Vin;
1848  Matrix2D<double> L(4, 4), R(4, 4);
1849  Matrix1D<double> sh(3);
1850  Vaux().initZeros(dim, dim, dim);
1851  Vaux().setXmippOrigin();
1852  for (int isym = 0; isym < mysampling.SL.symsNo(); isym++)
1853  {
1854  mysampling.SL.getMatrices(isym, L, R);
1855  mysampling.SL.getShift(isym, sh);
1856  R(3, 0) = sh(0) * dim;
1857  R(3, 1) = sh(1) * dim;
1858  R(3, 2) = sh(2) * dim;
1859  applyGeometry(xmipp_transformation::LINEAR, Vaux(), Vin(), R.transpose(), xmipp_transformation::IS_NOT_INV, xmipp_transformation::DONT_WRAP,
1860  DIRECT_MULTIDIM_ELEM(Vin(), 0));
1861  Vsym() += Vaux();
1862  }
1863  Vsym() /= mysampling.SL.symsNo() + 1.;
1864  Vin = Vsym;
1865  }
1866 
1867 #ifdef DEBUG
1868  std::cerr<<"finished postProcessVolume"<<std::endl;
1869 #endif
1870 
1871 }
1872 
1873 // Calculate FT of each reference and calculate A2 =============
1874 void
1876 {
1877 
1878 #ifdef DEBUG
1879  std::cerr<<"start precalculateA2"<<std::endl;
1880  TimeStamp t0;
1881  time_config();
1882  annotate_time(&t0);
1883 #endif
1884 #ifdef DEBUG_JM
1885 
1886  std::cerr << "DEBUG_JM: entering ProgMLTomo::precalculateA2" <<std::endl;
1887 #endif
1888 
1889  double AA, stdAA, corr;
1890  Matrix2D<double> A_rot_inv(4, 4), I(4, 4);
1891  MultidimArray<double> Maux(dim, dim, dim);
1893  MultidimArray<std::complex<double> > Faux, Faux2;
1894 
1895  A2.clear();
1896  corrA2.clear();
1897  I.initIdentity();
1898  Maux.setXmippOrigin();
1899  for (int refno = 0; refno < nr_ref; refno++)
1900  {
1901  MultidimArray<double> &Iref_refno=Iref[refno]();
1902  // Calculate A2 for all different orientations
1903  for (int angno = 0; angno < nr_ang; angno++)
1904  {
1905  A_rot_inv = ((all_angle_info[angno]).A).inv();
1906  // use DONT_WRAP and put density of first element outside
1907  // i.e. assume volume has been processed with omask
1908  applyGeometry(xmipp_transformation::LINEAR, Maux, Iref_refno, A_rot_inv, xmipp_transformation::IS_NOT_INV,
1909  xmipp_transformation::DONT_WRAP, DIRECT_MULTIDIM_ELEM(Iref_refno,0));
1910  //#define DEBUG_PRECALC_A2_ROTATE
1911 #ifdef DEBUG_PRECALC_A2_ROTATE
1912 
1913  Image<double> Vt;
1914  Vt()=Maux;
1915  Vt.write("rot.vol");
1916  Vt()=Iref[refno]();
1917  Vt.write("ref.vol");
1918  std::cerr<<" angles= "<<(all_angle_info[angno]).rot<<" "<<(all_angle_info[angno]).tilt<<" "<<(all_angle_info[angno]).psi<<std::endl;
1919  std::cerr<<" Written volume rot.vol and ref.vol, press any key to continue ..."<<std::endl;
1920  char c;
1921  std::cin >> c;
1922 #endif
1923 
1924  AA = Maux.sum2();
1925  if (angno == 0)
1926  stdAA = AA;
1927  if (AA > 0)
1928  {
1929  corr = sqrt(stdAA / AA);
1930  Maux *= corr;
1931  }
1932  else
1933  corr = 1.;
1934  corrA2.push_back(corr);
1935  if (do_missing)
1936  {
1937  transformer.FourierTransform(Maux, Faux, false);
1938  // Save original copy of Faux in Faux2
1939  Faux2=Faux;
1940 
1941  for (int missno = 0; missno < nr_miss; ++missno)
1942  {
1943  getMissingRegion(Mmissing, I, missno);
1944  Faux.initZeros();
1946  if (DIRECT_MULTIDIM_ELEM(Mmissing,n))
1949  A2.push_back(Maux.sum2());
1950  //#define DEBUG_PRECALC_A2
1951 #ifdef DEBUG_PRECALC_A2
1952 
1953  std::cerr<<"rot= "<<all_angle_info[angno].rot<<" tilt= "<<all_angle_info[angno].tilt<<" psi= "<<all_angle_info[angno].psi<<std::endl;
1954  std::cerr<<"refno= "<<refno<<" angno= "<<angno<<" missno= "<<missno<<" A2= "<<Maux.sum2()<<" corrA2= "<<corr<<std::endl;
1955  //#define DEBUG_PRECALC_A2_b
1956 #ifdef DEBUG_PRECALC_A2_b
1957 
1958  Image<double> tt;
1959  tt()=Maux;
1960  tt.write("refrotwedge.vol");
1961  std::cerr<<"press any key"<<std::endl;
1962  char c;
1963  std::cin >> c;
1964 #endif
1965 #endif
1966 
1967  }
1968  }
1969  else
1970  {
1971  A2.push_back(Maux.sum2());
1972 #ifdef DEBUG_PRECALC_A2
1973 
1974  std::cerr<<"refno= "<<refno<<" angno= "<<angno<<" A2= "<<Maux.sum2()<<std::endl;
1975 #endif
1976 
1977  }
1978  }
1979  }
1980 
1981 #ifdef DEBUG
1982  std::cerr<<"finished precalculateA2"<<std::endl;
1983  print_elapsed_time(t0);
1984 #endif
1985 }
1986 
1987 // Maximum Likelihood calculation for one image ============================================
1988 // Integration over all translation, given model and in-plane rotation
1989 void
1991  const int missno, double old_psi, std::vector<Image<double> > &Iref,
1992  std::vector<MultidimArray<double> > &wsumimgs,
1993  std::vector<MultidimArray<double> > &wsumweds, double &wsum_sigma_noise,
1994  double &wsum_sigma_offset, MultidimArray<double> &sumw, double &LL,
1995  double &dLL, double &fracweight, double &sumfracweight, double &trymindiff,
1996  int &opt_refno, int &opt_angno, Matrix1D<double> &opt_offsets)
1997 {
1998 
1999 #ifdef DEBUG
2000  std::cerr<<"start expectationSingleImage"<<std::endl;
2001  TimeStamp t0, t1;
2002  time_config();
2003  annotate_time(&t0);
2004  annotate_time(&t1);
2005 #endif
2006 
2007  //#define DEBUG_JM
2008 #ifdef DEBUG_JM
2009 
2010  std::cerr << "DEBUG_JM: entering ProgMLTomo::expectationSingleImage" <<std::endl;
2011  std::cerr << " DEBUG_JM: imgno: " << imgno << std::endl;
2012  std::cerr << "DEBUG_JM: missno: " << missno << std::endl;
2013 #endif
2014 
2015  MultidimArray<double> Maux, Maux2, Mweight, Mzero(dim, dim,
2016  hdim + 1), Mzero2(dim, dim, dim);
2018  MultidimArray<std::complex<double> > Faux, Faux2(dim, dim, hdim + 1), Fimg,
2019  Fimg0, Fimg_rot;
2020  std::complex<double> complex_zero=0;
2021  std::vector<MultidimArray<double> > mysumimgs;
2022  std::vector<MultidimArray<double> > mysumweds;
2023  MultidimArray<double> refw;
2024  double sigma_noise2, aux, pdf, fracpdf, myA2, mycorrAA, myXi2, A2_plus_Xi2,
2025  myXA;
2026  double diff, mindiff, my_mindiff;
2027  double my_sumweight, weight;
2028  double wsum_sc, wsum_sc2, wsum_offset;
2029  double wsum_corr, sum_refw, maxweight, my_maxweight;
2030  int sigdim;
2031  int ioptx = 0, iopty = 0, ioptz = 0;
2032  bool is_ok_trymindiff = false;
2033  int my_nr_ang, old_optangno = opt_angno, old_optrefno = opt_refno;
2034  std::vector<double> all_Xi2;
2035  Matrix2D<double> A_rot(4, 4), I(4, 4), A_rot_inv(4, 4);
2036  bool is_a_neighbor, is_within_psirange = true;
2037  FourierTransformer local_transformer;
2038 
2039  my_nr_ang = (dont_align || dont_rotate) ? 1 : nr_ang;
2040 
2041  // Only translations smaller than 6 sigma_offset are considered!
2042  // TODO: perhaps 3 sigma??
2043  I.initIdentity();
2044  sigdim = 2 * CEIL(sigma_offset * 6);
2045  sigdim++; // (to get uneven number)
2046  sigdim = XMIPP_MIN(dim, sigdim);
2047  // Setup matrices and constants
2048  Maux.resize(dim, dim, dim);
2049  Maux2.resize(dim, dim, dim);
2050  Maux.setXmippOrigin();
2051  Maux2.setXmippOrigin();
2052  if (dont_align)
2053  Mweight.initZeros(1, 1, 1);
2054  else
2055  Mweight.initZeros(sigdim, sigdim, sigdim);
2056  Mweight.setXmippOrigin();
2057  Mzero.initZeros();
2058  Mzero2.initZeros();
2059  Mzero2.setXmippOrigin();
2060 
2061  sigma_noise2 = sigma_noise * sigma_noise;
2062 
2063  Maux = Mimg;
2064  // Apply inverse rotation to the mask and apply
2065  if (do_mask)
2066  {
2067  if (!dont_align)
2069  "BUG: !dont_align and do_mask cannot coincide at this stage...");
2070  MultidimArray<double> Mmask;
2071  A_rot = (all_angle_info[opt_angno]).A;
2072  A_rot_inv = A_rot.inv();
2073  applyGeometry(xmipp_transformation::LINEAR, Mmask, Imask(), A_rot_inv, xmipp_transformation::IS_NOT_INV, xmipp_transformation::DONT_WRAP, 0.);
2074  Maux *= Mmask;
2075  }
2076  // Calculate the unrotated Fourier transform with enforced wedge of Mimg (store in Fimg0)
2077  // also calculate myXi2;
2078  // Note that from here on local_transformer will act on Maux <-> Faux
2079  local_transformer.FourierTransform(Maux, Faux, false);
2080  if (do_missing)
2081  {
2082  // Enforce missing wedge
2083  getMissingRegion(Mmissing, I, missno);
2085  if (!DIRECT_MULTIDIM_ELEM(Mmissing,n))
2086  DIRECT_MULTIDIM_ELEM(Faux,n) = complex_zero;
2087  }
2088  Fimg0 = Faux;
2089  // BE CAREFUL: inverseFourierTransform messes up Faux!
2090  local_transformer.inverseFourierTransform();
2091  myXi2 = Maux.sum2();
2092 
2093  // To avoid numerical problems, subtract smallest difference from all differences.
2094  // That way: Pmax will be one and all other probabilities will be [0,1>
2095  // But to find mindiff I first have to loop over all hidden variables...
2096  // Fortunately, there is some flexibility as the reliable domain of the exp-functions goes from -700 to 700.
2097  // Therefore, make a first guess for mindiff (trymindiff) and check whether the difference
2098  // with the real mindiff is not larger than 500 (to be on the save side).
2099  // If that is the case: OK; if not: do the entire loop again.
2100  // The efficiency of this will depend on trymindiff.
2101  // First cycle use trymindiff = trymindiff_factor * 0.5 * Xi2
2102  // From then on: use mindiff from the previous iteration
2103  if (trymindiff < 0.)
2104  // 90% of Xi2 may be a good idea (factor half because 0.5*diff is calculated)
2105  trymindiff = trymindiff_factor * 0.5 * myXi2;
2106  int redo_counter = 0;
2107  while (!is_ok_trymindiff)
2108  {
2109  // Initialize mindiff, weighted sums and maxweights
2110  mindiff = 99.e99;
2111  wsum_corr = wsum_offset = wsum_sc = wsum_sc2 = 0.;
2112  maxweight = sum_refw = 0.;
2113  mysumimgs.assign(nr_ref, Mzero2);
2114  if (do_missing)
2115  mysumweds.assign(nr_ref, Mzero);
2116  refw.initZeros(nr_ref);
2117  // The real stuff: now loop over all orientations, references and translations
2118  // Start the loop over all refno at old_optangno (=opt_angno from the previous iteration).
2119  // This will speed-up things because we will find Pmax probably right away,
2120  // and this will make the if-statement that checks SIGNIFICANT_WEIGHT_LOW
2121  // effective right from the start
2122  for (int aa = old_optangno; aa < old_optangno + my_nr_ang; aa++)
2123  {
2124  int angno = aa;
2125  if (angno >= nr_ang)
2126  angno -= nr_ang;
2127 
2128  // See whether this image is in the neighborhood for this imgno
2129  if (ang_search > 0.)
2130  {
2131  is_a_neighbor = false;
2132  if (do_limit_psirange)
2133  {
2134  // Only restrict psi range for directions away from the poles...
2135  // Otherwise the is_a_neighbour construction may give errors:
2136  // (-150, 0, 150) and (-100, 0, 150) would be considered as equal, since
2137  // the distance between (-150,0) and (-100,0) is zero AND
2138  // the distance between 150 and 150 is also zero...
2139  if (ABS(realWRAP(all_angle_info[angno].tilt, -90., 90.))
2140  < 1.1 * ang_search)
2141  is_within_psirange = true;
2142  else if ((do_sym
2143  && ABS(realWRAP(old_psi - (all_angle_info[angno]).rot,-180.,180.))
2144  <= ang_search)
2145  || (!do_sym
2146  && ABS(realWRAP(old_psi - (all_angle_info[angno]).psi,-180.,180.))
2147  <= ang_search))
2148  is_within_psirange = true;
2149  else
2150  is_within_psirange = false;
2151  }
2152 
2153  if (!do_limit_psirange || is_within_psirange)
2154  {
2155  for (size_t i = 0; i < mysampling.my_neighbors[imgno].size(); i++)
2156  {
2157  if (mysampling.my_neighbors[imgno][i]
2158  == (all_angle_info[angno]).direction)
2159  {
2160  is_a_neighbor = true;
2161  break;
2162  }
2163  }
2164  }
2165  }
2166  else
2167  {
2168  is_a_neighbor = true;
2169  }
2170 
2171  // If it is in the neighborhood: proceed
2172  if (is_a_neighbor)
2173  {
2174  A_rot = (all_angle_info[angno]).A;
2175  A_rot_inv = A_rot.inv();
2176 
2177  // Start the loop over all refno at old_optrefno (=opt_refno from the previous iteration).
2178  // This will speed-up things because we will find Pmax probably right away,
2179  // and this will make the if-statement that checks SIGNIFICANT_WEIGHT_LOW
2180  // effective right from the start
2181  for (int rr = old_optrefno; rr < old_optrefno + nr_ref; rr++)
2182  {
2183  int refno = rr;
2184  if (refno >= nr_ref)
2185  refno -= nr_ref;
2186 
2187  fracpdf = alpha_k(refno) * (1. / nr_ang);
2188  // Now (inverse) rotate the reference and calculate its Fourier transform
2189  // Use DONT_WRAP and assume map has been omasked
2190  applyGeometry(xmipp_transformation::LINEAR, Maux2, Iref[refno](), A_rot_inv, xmipp_transformation::IS_NOT_INV,
2191  xmipp_transformation::DONT_WRAP, DIRECT_MULTIDIM_ELEM(Iref[refno](),0));
2192  mycorrAA = corrA2[refno * nr_ang + angno];
2193  Maux = Maux2 * mycorrAA;
2194  local_transformer.FourierTransform();
2195  if (do_missing)
2196  myA2 = A2[refno * nr_ang * nr_miss + angno * nr_miss + missno];
2197  else
2198  myA2 = A2[refno * nr_ang + angno];
2199  A2_plus_Xi2 = 0.5 * (myA2 + myXi2);
2200  // A. Backward FFT to calculate weights in real-space
2202  {
2203  dAkij(Faux,k,i,j) = dAkij(Fimg0,k,i,j) * conj(dAkij(Faux,k,i,j));
2204  }
2205  local_transformer.inverseFourierTransform();
2206  CenterFFT(Maux, true);
2207 
2208  // B. Calculate weights for each pixel within sigdim (Mweight)
2209  my_sumweight = my_maxweight = 0.;
2211  {
2212 
2213  pdf = fracpdf * A3D_ELEM(P_phi, k, i, j);
2214  // Sjors 5 aug 2010
2215  // With -limit_trans pdf can actually be zero, and mindiff is irrelevant for those.
2216  if (pdf > 0.)
2217  {
2218  myXA = A3D_ELEM(Maux, k, i, j) * ddim3;
2219  diff = A2_plus_Xi2 - myXA;
2220  mindiff = XMIPP_MIN(mindiff,diff);
2221  //#define DEBUG_MINDIFF
2222 #ifdef DEBUG_MINDIFF
2223 
2224  if (mindiff < 0)
2225  {
2226  std::cerr<<"k= "<<k<<" j= "<<j<<" i= "<<i<<std::endl;
2227  std::cerr<<"xaux="<<STARTINGX(Maux)<<" xw= "<<STARTINGX(Mweight)<<std::endl;
2228  std::cerr<<"yaux="<<STARTINGY(Maux)<<" yw= "<<STARTINGY(Mweight)<<std::endl;
2229  std::cerr<<"zaux="<<STARTINGZ(Maux)<<" zw= "<<STARTINGZ(Mweight)<<std::endl;
2230  std::cerr<<"diff= "<<diff<<" A2_plus_Xi"<<std::endl;
2231  std::cerr<<" mycorrAA= "<<mycorrAA<<" "<<std::endl;
2232  std::cerr<<"debug mindiff= " <<mindiff<<" trymindiff= "<<trymindiff<< std::endl;
2233  std::cerr<<"A2_plus_Xi2= "<<A2_plus_Xi2<<" myA2= "<<myA2<<" myXi2= "<<myXi2<<std::endl;
2234  std::cerr.flush();
2235  Image<double> tt;
2236  tt()=Maux;
2237  tt.write("Maux.vol");
2238  tt()=Mweight;
2239  tt.write("Mweight.vol");
2240  std::cerr<<"Ainv= "<<A_rot_inv<<std::endl;
2241  std::cerr<<"A= "<<A_rot_inv.inv()<<std::endl;
2242  exit(1);
2243  }
2244 #endif
2245  // Normal distribution
2246  aux = (diff - trymindiff) / sigma_noise2;
2247  // next line because of numerical precision of exp-function
2248  if (aux > 1000.)
2249  weight = 0.;
2250  else
2251  weight = exp(-aux) * pdf;
2252  A3D_ELEM(Mweight, k, i, j) = weight;
2253  // Accumulate sum weights for this (my) matrix
2254  my_sumweight += weight;
2255  // calculate weighted sum of (X-A)^2 for sigma_noise update
2256  wsum_corr += weight * diff;
2257  // calculated weighted sum of offsets as well
2258  wsum_offset += weight * A3D_ELEM(Mr2, k, i, j);
2259  // keep track of optimal parameters
2260  my_maxweight = XMIPP_MAX(my_maxweight, weight);
2261  if (weight > maxweight)
2262  {
2263  maxweight = weight;
2264  ioptz = k;
2265  iopty = i;
2266  ioptx = j;
2267  opt_angno = angno;
2268  opt_refno = refno;
2269  }
2270  } // close if (pdf > 0.)
2271 
2272  } // close for over all elements in Mweight
2273 
2274  // C. only for significant settings, store weighted sums
2275  if (my_maxweight > SIGNIFICANT_WEIGHT_LOW * maxweight)
2276  {
2277  //#define DEBUG_EXP_A2
2278 #ifdef DEBUG_EXP_A2
2279  std::cout<<" imgno= "<<imgno<<" refno= "<<refno<<" angno= "<<angno<<" A2= "<<myA2<<" <<Xi2= "<<myXi2<<" my_maxweight= "<<my_maxweight<<std::endl;
2280 #endif
2281 
2282  sum_refw += my_sumweight;
2283  refw(refno) += my_sumweight;
2284  // Back from smaller Mweight to original size of Maux
2285  Maux.initZeros();
2287  {
2288  A3D_ELEM(Maux, k, i, j) = A3D_ELEM(Mweight, k, i, j);
2289  }
2290  // Use forward FFT in convolution theorem again
2291  CenterFFT(Maux, false);
2292  local_transformer.FourierTransform();
2294  {
2295  dAkij(Faux, k, i, j) = conj(dAkij(Faux,k,i,j))
2296  * dAkij(Fimg0,k,i,j);
2297  }
2298  local_transformer.inverseFourierTransform();
2300  selfApplyGeometry(xmipp_transformation::LINEAR, Maux, A_rot, xmipp_transformation::IS_NOT_INV, xmipp_transformation::DONT_WRAP,
2301  DIRECT_MULTIDIM_ELEM(Maux,0));
2302  if (do_missing)
2303  {
2304  // Store sum of wedges!
2305  getMissingRegion(Mmissing, A_rot, missno);
2306  MultidimArray<double> &mysumweds_refno=mysumweds[refno];
2308  if (DIRECT_MULTIDIM_ELEM(Mmissing,n))
2309  DIRECT_MULTIDIM_ELEM(mysumweds_refno,n) += my_sumweight;
2310 
2311  // Again enforce missing region to avoid filling it with artifacts from the rotation
2312  local_transformer.FourierTransform();
2314  if (!DIRECT_MULTIDIM_ELEM(Mmissing,n))
2315  DIRECT_MULTIDIM_ELEM(Faux,n)=complex_zero;
2316  local_transformer.inverseFourierTransform();
2317  }
2318  // Store sum of rotated images
2319  mysumimgs[refno] += Maux * ddim3;
2320  } // close if SIGNIFICANT_WEIGHT_LOW
2321  } // close for refno
2322  } // close if is_a_neighbor
2323  } // close for angno
2324 
2325  // Now check whether our trymindiff was OK.
2326  // The limit of the exp-function lies around
2327  // exp(700)=1.01423e+304, exp(800)=inf; exp(-700) = 9.85968e-305; exp(-800) = 0
2328  // Use 500 to be on the save side?
2329  if (ABS((mindiff - trymindiff) / sigma_noise2) > 500.)
2330  {
2331 
2332  //#define DEBUG_REDOCOUNTER
2333 #ifdef DEBUG_REDOCOUNTER
2334  std::cerr<<"repeating mindiff "<<redo_counter<<"th time"<<std::endl;
2335  std::cerr<<"trymindiff= "<<trymindiff<<" mindiff= "<<mindiff<<std::endl;
2336  std::cerr<<"diff= "<<ABS((mindiff - trymindiff) / sigma_noise2)<<std::endl;
2337 #endif
2338  // Re-do whole calculation now with the real mindiff
2339  trymindiff = mindiff;
2340  redo_counter++;
2341  // Never re-do more than once!
2342  if (redo_counter > 1)
2343  REPORT_ERROR(ERR_DEBUG_IMPOSIBLE, "ml_tomo BUG, redo_counter > 1");
2344  }
2345  else
2346  {
2347  is_ok_trymindiff = true;
2348  my_mindiff = trymindiff;
2349  trymindiff = mindiff;
2350  }
2351  }
2352 
2353  fracweight = maxweight / sum_refw;
2354  wsum_sc /= sum_refw;
2355  wsum_sc2 /= sum_refw;
2356 
2357  // Calculate remaining optimal parameters
2358 
2359  XX(opt_offsets) = -(double) ioptx;
2360  YY(opt_offsets) = -(double) iopty;
2361  ZZ(opt_offsets) = -(double) ioptz;
2362 
2363  // From here on lock threads
2364  pthread_mutex_lock(&mltomo_weightedsum_update_mutex);
2365 
2366  // Update all global weighted sums after division by sum_refw
2367  wsum_sigma_noise += (2 * wsum_corr / sum_refw);
2368  wsum_sigma_offset += (wsum_offset / sum_refw);
2369  sumfracweight += fracweight;
2370  // Randomly choose 0 or 1 for FSC calculation
2371  int iran_fsc = ROUND(rnd_unif());
2372  for (int refno = 0; refno < nr_ref; refno++)
2373  {
2374  sumw(refno) += refw(refno) / sum_refw;
2375  // Sum mysumimgs to the global weighted sum
2376  wsumimgs[iran_fsc * nr_ref + refno] += (mysumimgs[refno]) / sum_refw;
2377  if (do_missing)
2378  {
2379  wsumweds[iran_fsc * nr_ref + refno] += mysumweds[refno] / sum_refw;
2380  }
2381  }
2382 
2383  // 1st term: log(refw_i)
2384  // 2nd term: for subtracting mindiff
2385  // 3rd term: for (sqrt(2pi)*sigma_noise)^-1 term in formula (12) Sigworth (1998)
2386  // TODO: check this!!
2387  if (do_missing)
2388 
2389  dLL =
2390  log(sum_refw) - my_mindiff / sigma_noise2
2391  - all_missing_info[missno].nr_pixels
2392  * log(sqrt(2. * PI * sigma_noise2));
2393  else
2394  dLL = log(sum_refw) - my_mindiff / sigma_noise2
2395  - ddim3 * log(sqrt(2. * PI * sigma_noise2));
2396  LL += dLL;
2397 
2398  pthread_mutex_unlock(&mltomo_weightedsum_update_mutex);
2399 
2400 #ifdef DEBUG_JM
2401 
2402  std::cerr << " DEBUG_JM: my_mindiff: " << my_mindiff << std::endl;
2403  std::cerr << " DEBUG_JM: sigma_noise2: " << sigma_noise2 << std::endl;
2404  //std::cerr << " DEBUG_JM: miss_nr_pixels[missno]: " << miss_nr_pixels[missno] << std::endl;
2405 
2406  std::cerr << " DEBUG_JM: sum_refw: " << sum_refw << std::endl;
2407  std::cerr << " DEBUG_JM: wsum_sigma_noise: " << wsum_sigma_noise << std::endl;
2408  std::cerr << " DEBUG_JM: wsum_sigma_offset: " << wsum_sigma_offset << std::endl;
2409  std::cerr << " DEBUG_JM: sumfracweight: " << sumfracweight << std::endl;
2410  std::cerr << " DEBUG_JM: dLL: " << dLL << std::endl;
2411  std::cerr << " DEBUG_JM: LL: " << LL << std::endl;
2412  std::cerr << "DEBUG_JM: leaving ProgMLTomo::expectationSingleImage" <<std::endl;
2413 #endif
2414 #undef DEBUG_JM
2415 
2416 #ifdef DEBUG
2417 
2418  std::cerr<<"finished expectationSingleImage"<<std::endl;
2419  print_elapsed_time(t0);
2420 #endif
2421 }
2422 
2423 void
2425  int imgno, int missno, double old_psi, std::vector<Image<double> > &Iref,
2426  std::vector<MultidimArray<double> > &wsumimgs,
2427  std::vector<MultidimArray<double> > &wsumweds, MultidimArray<double> &sumw,
2428  double &maxCC, double &sumCC, int &opt_refno, int &opt_angno,
2429  Matrix1D<double> &opt_offsets)
2430 {
2431  //#define DEBUG
2432 #ifdef DEBUG
2433  std::cerr<<"start maxConstrainedCorrSingleImage"<<std::endl;
2434  TimeStamp t0, t1;
2435  time_config();
2436  annotate_time(&t0);
2437  annotate_time(&t1);
2438 #endif
2439 #ifdef DEBUG_JM
2440 
2441  std::cerr << "DEBUG_JM: entering ProgMLTomo::maxConstrainedCorrSingleImage" <<std::endl;
2442 #endif
2443 
2444  MultidimArray<double> Mimg0, Maux, Mref;
2446  MultidimArray<std::complex<double> > Faux, Fimg0, Fref;
2447  FourierTransformer local_transformer;
2448  Matrix2D<double> A_rot(4, 4), I(4, 4), A_rot_inv(4, 4);
2449  std::complex<double> complex_zero=0;
2450  bool is_a_neighbor;
2451  double img_stddev, ref_stddev, corr, maxcorr = -9999.;
2452  int ioptx=0, iopty=0, ioptz=0;
2453  int my_nr_ang, old_optangno = opt_angno, old_optrefno = opt_refno;
2454  bool is_within_psirange = true;
2455 
2456  my_nr_ang = (dont_align || dont_rotate) ? 1 : nr_ang;
2457  I.initIdentity();
2458  Maux.resize(dim, dim, dim);
2459  Maux.setXmippOrigin();
2460 
2461  Maux = Mimg;
2462  // Apply inverse rotation to the mask and apply
2463  if (do_mask)
2464  {
2465  if (!dont_align)
2467  "BUG: !dont_align and do_mask cannot coincide at this stage...");
2468  MultidimArray<double> Mmask;
2469  A_rot = (all_angle_info[opt_angno]).A;
2470  A_rot_inv = A_rot.inv();
2471  applyGeometry(xmipp_transformation::LINEAR, Mmask, Imask(), A_rot_inv, xmipp_transformation::IS_NOT_INV, xmipp_transformation::DONT_WRAP, 0.);
2472  Maux *= Mmask;
2473  }
2474  // Calculate the unrotated Fourier transform with enforced wedge of Mimg (store in Fimg0)
2475  // Note that from here on local_transformer will act on Maux <-> Faux
2476  local_transformer.FourierTransform(Maux, Faux, false);
2477  if (do_missing)
2478  {
2479  // Enforce missing wedge
2480  getMissingRegion(Mmissing, I, missno);
2482  if (!DIRECT_MULTIDIM_ELEM(Mmissing,n))
2483  DIRECT_MULTIDIM_ELEM(Faux,n)=complex_zero;
2484  // BE CAREFUL: inverseFourierTransform messes up Faux!!
2485  Fimg0 = Faux;
2486  local_transformer.inverseFourierTransform();
2487  }
2488  else
2489  Fimg0 = Faux;
2490  Mimg0 = Maux;
2491 
2492  if (do_only_average)
2493  {
2494  maxcorr = 1.;
2495  ioptz = 0;
2496  iopty = 0;
2497  ioptx = 0;
2498  opt_angno = old_optangno;
2499  opt_refno = old_optrefno;
2500  }
2501  else
2502  {
2503  // Calculate stddev of (wedge-inforced) image
2504  img_stddev = Mimg0.computeStddev();
2505  // Loop over all orientations
2506  for (int aa = old_optangno; aa < old_optangno + my_nr_ang; aa++)
2507  {
2508  int angno = aa;
2509  if (angno >= nr_ang)
2510  angno -= nr_ang;
2511 
2512  // See whether this image is in the neighborhoood for this imgno
2513  if (ang_search > 0.)
2514  {
2515  is_a_neighbor = false;
2516  if (do_limit_psirange)
2517  {
2518  // Only restrict psi range for directions away from the poles...
2519  // Otherwise the is_a_neighbour construction may give errors:
2520  // (-150, 0, 150) and (-100, 0, 150) would be considered as equal, since
2521  // the distance between (-150,0) and (-100,0) is zero AND
2522  // the distance between 150 and 150 is also zero...
2523  if (ABS(realWRAP(all_angle_info[angno].tilt, -90., 90.))
2524  < 1.1 * ang_search)
2525  is_within_psirange = true;
2526  else if ((do_sym
2527  && ABS(realWRAP(old_psi - (all_angle_info[angno]).rot,-180.,180.))
2528  <= ang_search)
2529  || (!do_sym
2530  && ABS(realWRAP(old_psi - (all_angle_info[angno]).psi,-180.,180.))
2531  <= ang_search))
2532  is_within_psirange = true;
2533  else
2534  is_within_psirange = false;
2535  }
2536 
2537  if (!do_limit_psirange || is_within_psirange)
2538  {
2539  for (size_t i = 0; i < mysampling.my_neighbors[imgno].size(); i++)
2540  {
2541  if (mysampling.my_neighbors[imgno][i]
2542  == (all_angle_info[angno]).direction)
2543  {
2544  is_a_neighbor = true;
2545  break;
2546  }
2547  }
2548  }
2549  }
2550  else
2551  {
2552  is_a_neighbor = true;
2553  }
2554  // If it is in the neighborhoood: proceed
2555  if (is_a_neighbor)
2556  {
2557  A_rot = (all_angle_info[angno]).A;
2558  A_rot_inv = A_rot.inv();
2559  // std::cerr << "A_rot" << A_rot << std::endl;
2560  // std::cerr << "all_angle_info[angno].rot" << all_angle_info[angno].rot << std::endl;
2561  // std::cerr << "all_angle_info[angno].tilt" << all_angle_info[angno].tilt << std::endl;
2562  // std::cerr << "all_angle_info[angno].psi" << all_angle_info[angno].psi << std::endl;
2563 
2564  // Loop over all references
2565  for (int rr = old_optrefno; rr < old_optrefno + nr_ref; rr++)
2566  {
2567  int refno = rr;
2568  if (refno >= nr_ref)
2569  refno -= nr_ref;
2570 
2571  // Now (inverse) rotate the reference and calculate its Fourier transform
2572  // Use DONT_WRAP because the reference has been omasked
2573  applyGeometry(xmipp_transformation::LINEAR, Maux, Iref[refno](), A_rot_inv, xmipp_transformation::IS_NOT_INV,
2574  xmipp_transformation::DONT_WRAP, DIRECT_MULTIDIM_ELEM(Iref[refno](),0));
2575  local_transformer.FourierTransform();
2576  if (do_missing)
2577  {
2578  // Enforce wedge on the reference
2580  {
2581  DIRECT_MULTIDIM_ELEM(Faux,n) *= DIRECT_MULTIDIM_ELEM(Mmissing,n);
2582  }
2583  // BE CAREFUL! inverseFourierTransform messes up Faux
2584  Fref = Faux;
2585  local_transformer.inverseFourierTransform();
2586  }
2587  else
2588  Fref = Faux;
2589  // Calculate stddev of (wedge-inforced) reference
2590  Mref = Maux;
2591  ref_stddev = Mref.computeStddev();
2592 
2593  // Calculate correlation matrix via backward FFT
2595  {
2596  dAkij(Faux,k,i,j) = dAkij(Fimg0,k,i,j) * conj(dAkij(Fref,k,i,j));
2597  }
2598  local_transformer.inverseFourierTransform();
2599  CenterFFT(Maux, true);
2600  //#define DEBUG_IMG
2601 #ifdef DEBUG_IMG
2602 
2603  static size_t jjjj=1;
2604  Maux.write("kk.spi");
2605  Image<double> tmpImg;
2606  tmpImg() = Maux;
2607  String s;
2608  formatStringFast(s, "%d@%s.%s", jjjj++,"Maux","spi");
2609  std::cerr << s <<std::endl;
2610  tmpImg.write(s);
2611 
2612 #endif
2613 
2614  if (dont_align)
2615  {
2616  corr = A3D_ELEM(Maux,0,0,0) / (img_stddev * ref_stddev);
2617  if (corr > maxcorr)
2618  {
2619  maxcorr = corr;
2620  ioptz = 0;
2621  iopty = 0;
2622  ioptx = 0;
2623  opt_angno = angno;
2624  opt_refno = refno;
2625  }
2626  }
2627  else
2628  {
2630  {
2631  corr = A3D_ELEM(Maux,k,i,j) / (img_stddev * ref_stddev);
2632  if (corr > maxcorr)
2633  {
2634  maxcorr = corr;
2635  ioptz = k;
2636  iopty = i;
2637  ioptx = j;
2638  opt_angno = angno;
2639  opt_refno = refno;
2640  }
2641  }
2642  }
2643  }
2644  }
2645  }
2646  }
2647 
2648  // Now that we have optimal hidden parameters, update output
2649 
2650  XX(opt_offsets) = -(double) ioptx;
2651  YY(opt_offsets) = -(double) iopty;
2652  ZZ(opt_offsets) = -(double) ioptz;
2653  selfTranslate(xmipp_transformation::LINEAR, Mimg0, opt_offsets, xmipp_transformation::DONT_WRAP);
2654  A_rot = (all_angle_info[opt_angno]).A;
2656  selfApplyGeometry(xmipp_transformation::LINEAR, Mimg0, A_rot, xmipp_transformation::IS_NOT_INV, xmipp_transformation::DONT_WRAP,
2657  DIRECT_MULTIDIM_ELEM(Mimg0,0));
2658  maxCC = maxcorr;
2659 
2660  if (do_missing)
2661  {
2662  // Store sum of wedges
2663  getMissingRegion(Mmissing, A_rot, missno);
2664  Maux = Mimg0;
2665  // Again enforce missing region to avoid filling it with artifacts from the rotation
2666  local_transformer.FourierTransform();
2668  {
2669  DIRECT_MULTIDIM_ELEM(Faux,n) *= DIRECT_MULTIDIM_ELEM(Mmissing,n);
2670  }
2671  local_transformer.inverseFourierTransform();
2672  Mimg0 = Maux;
2673  }
2674 
2675  // Randomly choose 0 or 1 for FSC calculation
2676  int iran_fsc = ROUND(rnd_unif());
2677 
2678  // From here on lock threads to add to sums
2679  pthread_mutex_lock(&mltomo_weightedsum_update_mutex);
2680 
2681  sumCC += maxCC;
2682  sumw(opt_refno) += 1.;
2683  wsumimgs[iran_fsc * nr_ref + opt_refno] += Mimg0;
2684  if (do_missing)
2685  {
2686  MultidimArray<double> &wsumweds_i=wsumweds[iran_fsc * nr_ref + opt_refno];
2688  DIRECT_MULTIDIM_ELEM(wsumweds_i,n)=DIRECT_MULTIDIM_ELEM(Mmissing,n);
2689  }
2690 
2691  pthread_mutex_unlock(&mltomo_weightedsum_update_mutex);
2692 
2693 #ifdef DEBUG
2694 
2695  std::cerr<<"finished maxConstrainedCorrSingleImage"<<std::endl;
2696  print_elapsed_time(t0);
2697 #endif
2698 
2699 }
2700 
2701 void *
2703 {
2704  auto * thread_data =
2706 
2707  // Variables from above
2708  int thread_id = thread_data->thread_id;
2709  ProgMLTomo *prm = thread_data->prm;
2710  MetaDataVec *MDimg = thread_data->MDimg;
2711  double *wsum_sigma_noise = thread_data->wsum_sigma_noise;
2712  double *wsum_sigma_offset = thread_data->wsum_sigma_offset;
2713  double *sumfracweight = thread_data->sumfracweight;
2714  double *LL = thread_data->LL;
2715  std::vector<MultidimArray<double> > *wsumimgs = thread_data->wsumimgs;
2716  std::vector<MultidimArray<double> > *wsumweds = thread_data->wsumweds;
2717  std::vector<Image<double> > *Iref = thread_data->Iref;
2718 
2719  MultidimArray<double> *sumw = thread_data->sumw;
2720  std::vector<size_t> * imgs_id = thread_data->imgs_id;
2721  ThreadTaskDistributor * distributor = thread_data->distributor;
2722 
2723  //#define DEBUG_THREAD
2724 #ifdef DEBUG_THREAD
2725 
2726  std::cerr<<"start threadMLTomoExpectationSingleImage"<<std::endl;
2727 #endif
2728 
2729  // Local variables
2730  Image<double> img;
2731  FileName fn_img, fn_trans;
2732  std::vector<MultidimArray<double> > allref_offsets;
2733  Matrix1D<double> opt_offsets(3);
2734  float old_psi = -999.;
2735  double fracweight, trymindiff, dLL;
2736  int opt_refno, opt_angno, missno;
2737 
2738  //try
2739  {
2740  //Approximate number of images
2741  size_t myNum = MDimg->size() / prm->threads;
2742  //First and last image to process in each block
2743  size_t firstIndex, lastIndex;
2744 
2745  if (prm->verbose && thread_id == 0)
2746  init_progress_bar(myNum);
2747 
2748  // Loop over all images
2749  size_t cc = 0;
2751 
2752  //Work while there are tasks to do
2753  while (distributor->getTasks(firstIndex, lastIndex))
2754  {
2755  for (size_t imgno = firstIndex; imgno <= lastIndex; ++imgno)
2756  {
2757  //TODO: Check if really needed the mutexes
2758  //only for read from MetaData
2759  pthread_mutex_lock(&mltomo_selfile_access_mutex);
2760 
2761  MDimg->getValue(MDL_IMAGE, fn_img, (*imgs_id)[imgno + prm->myFirstImg]);
2762 
2763  pthread_mutex_unlock(&mltomo_selfile_access_mutex);
2764 
2765  img.read(fn_img);
2766  img().setXmippOrigin();
2767 
2768  if (prm->dont_align || prm->do_only_average)
2769  {
2770  selfTranslate(xmipp_transformation::LINEAR, img(), prm->imgs_optoffsets[imgno], xmipp_transformation::DONT_WRAP);
2771  }
2772  prm->reScaleVolume(img(), true);
2773  missno = (prm->do_missing) ? prm->imgs_missno[imgno] : -1;
2774  // These three parameters speed up expectationSingleImage
2775  trymindiff = prm->imgs_trymindiff[imgno];
2776  opt_refno = prm->imgs_optrefno[imgno];
2777  opt_angno = prm->imgs_optangno[imgno];
2778  old_psi = prm->imgs_optpsi[imgno];
2779 
2780  if (prm->do_ml)
2781  {
2782  // A. Use maximum likelihood approach
2783  prm->expectationSingleImage(img(), imgno, missno, old_psi, *Iref,
2784  *wsumimgs, *wsumweds, *wsum_sigma_noise, *wsum_sigma_offset,
2785  *sumw, *LL, dLL, fracweight, *sumfracweight, trymindiff,
2786  opt_refno, opt_angno, opt_offsets);
2787  }
2788  else
2789  {
2790  // B. Use constrained correlation coefficient approach
2791  prm->maxConstrainedCorrSingleImage(img(), imgno, missno, old_psi,
2792  *Iref, *wsumimgs, *wsumweds, *sumw, fracweight, *sumfracweight,
2793  opt_refno, opt_angno, opt_offsets);
2794  }
2795  // Store for next iteration
2796  prm->imgs_trymindiff[imgno] = trymindiff;
2797  prm->imgs_optrefno[imgno] = opt_refno;
2798  prm->imgs_optangno[imgno] = opt_angno;
2799  // Output MetaData
2800  //FIXME: THIS ALSO LIKE JoseMiguel did ML2D
2801  dAij(docfiledata, imgno, 0) = (prm->all_angle_info[opt_angno]).rot; // rot
2802  dAij(docfiledata, imgno, 1) = (prm->all_angle_info[opt_angno]).tilt; // tilt
2803  dAij(docfiledata, imgno, 2) = (prm->all_angle_info[opt_angno]).psi; // psi
2804  if (prm->dont_align || prm->do_only_average)
2805  {
2806  dAij(docfiledata, imgno, 3) = prm->imgs_optoffsets[imgno](0); // Xoff
2807  dAij(docfiledata, imgno, 4) = prm->imgs_optoffsets[imgno](1); // Yoff
2808  dAij(docfiledata, imgno, 5) = prm->imgs_optoffsets[imgno](2); // zoff
2809  }
2810  else
2811  {
2812  dAij(docfiledata, imgno, 3) = opt_offsets(0) / prm->scale_factor; // Xoff
2813  dAij(docfiledata, imgno, 4) = opt_offsets(1) / prm->scale_factor; // Yoff
2814  dAij(docfiledata, imgno, 5) = opt_offsets(2) / prm->scale_factor; // Zoff
2815  }
2816  dAij(docfiledata, imgno, 6) = (double) (opt_refno + 1); // Ref
2817  dAij(docfiledata, imgno, 7) = (double) (missno + 1); // Wedge number
2818 
2819  dAij(docfiledata, imgno, 8) = fracweight; // P_max/P_tot
2820  dAij(docfiledata, imgno, 9) = dLL; // log-likelihood
2821 
2822  if (prm->verbose && thread_id == 0)
2823  progress_bar(cc);
2824  cc++;
2825  }
2826  }
2827  if (prm->verbose && thread_id == 0)
2828  progress_bar(myNum);
2829  }
2830 
2831 #ifdef DEBUG_THREAD
2832 
2833  std::cerr<<"finished threadMLTomoExpectationSingleImage"<<std::endl;
2834 #endif
2835  return nullptr;
2836 }
2837 
2838 void
2840  int iter, double &LL, double &sumfracweight,
2841  std::vector<MultidimArray<double> > &wsumimgs,
2842  std::vector<MultidimArray<double> > &wsumweds, double &wsum_sigma_noise,
2843  double &wsum_sigma_offset, MultidimArray<double> &sumw)
2844 {
2845  //#define DEBUG
2846 #ifdef DEBUG
2847  std::cerr<<"start expectation"<<std::endl;
2848 #endif
2849 
2850  MultidimArray<double> Mzero(dim, dim, hdim + 1), Mzero2(dim, dim, dim);
2851 
2852  // Perturb all angles
2853  // (Note that each mpi process will have a different random perturbation)
2854  if (do_perturb)
2856 
2857  if (do_ml)
2858  {
2859  // Precalculate A2-values for all references
2861 
2862  // Pre-calculate pdf of all in-plane transformations
2864  }
2865 
2866  // Initialize weighted sums
2867  LL = 0.;
2868  wsum_sigma_noise = 0.;
2869  wsum_sigma_offset = 0.;
2870  sumfracweight = 0.;
2871  sumw.initZeros(nr_ref);
2872  //Create a task distributor to distribute images to process
2873  //each thread will process images one by one
2874  auto * distributor = new ThreadTaskDistributor(
2875  nr_images_local, 1);
2876 
2877  Mzero.initZeros();
2878  Mzero2.initZeros();
2879  Mzero2.setXmippOrigin();
2880  wsumimgs.assign(2 * nr_ref, Mzero2);
2881  wsumweds.assign(2 * nr_ref, Mzero);
2882  // Call threads to calculate the expectation of each image in the selfile
2883  auto * th_ids = (pthread_t *) malloc(threads * sizeof(pthread_t));
2884  auto * threads_d =
2887  for (int c = 0; c < threads; c++)
2888  {
2889  threads_d[c].thread_id = c;
2890  threads_d[c].thread_num = threads;
2891  threads_d[c].prm = this;
2892  threads_d[c].MDimg = &MDimg;
2893  threads_d[c].iter = &iter;
2894  threads_d[c].wsum_sigma_noise = &wsum_sigma_noise;
2895  threads_d[c].wsum_sigma_offset = &wsum_sigma_offset;
2896  threads_d[c].sumfracweight = &sumfracweight;
2897  threads_d[c].LL = &LL;
2898  threads_d[c].wsumimgs = &wsumimgs;
2899  threads_d[c].wsumweds = &wsumweds;
2900  threads_d[c].Iref = &Iref;
2901  threads_d[c].sumw = &sumw;
2902  threads_d[c].imgs_id = &imgs_id;
2903  threads_d[c].distributor = distributor;
2904  pthread_create(
2905  (th_ids + c), nullptr, threadMLTomoExpectationSingleImage, (void *)(threads_d+c) );
2906  }
2907  // Wait for threads to finish and get joined MetaData
2908  for (int c = 0; c < threads; c++)
2909  {
2910  pthread_join(*(th_ids + c), nullptr);
2911  }
2912  //Free some memory
2913  delete distributor;
2914  free(threads_d);
2915  free(th_ids);
2916 
2917  //FIXME
2918  // Send back output in the form of a MetaData
2919  //use docfiledata in writingOutput files
2920  /* SF.go_beginning();
2921  for (int imgno = 0; imgno < SF.ImgNo(); imgno++)
2922  {
2923  DFo.append_comment(SF.NextImg());
2924  DFo.append_data_line(docfiledata[imgno]);
2925  }*/
2926 
2927 #ifdef DEBUG
2928 
2929  std::cerr<<"finished expectation"<<std::endl;
2930 #endif
2931 #undef DEBUG
2932 }
2933 
2934 // Update all model parameters
2935 void
2937  std::vector<MultidimArray<double> > &wsumweds, double &wsum_sigma_noise,
2938  double &wsum_sigma_offset, MultidimArray<double> &sumw,
2939  double &sumfracweight, double &sumw_allrefs,
2940  std::vector<MultidimArray<double> > &fsc, int iter)
2941 {
2942 #ifdef DEBUG
2943  std::cerr<<"started maximization"<<std::endl;
2944 #endif
2945 
2946  MultidimArray<double> rmean_sigma2, rmean_signal2;
2947  Matrix1D<int> center(3);
2948  MultidimArray<int> radial_count;
2949  MultidimArray<std::complex<double> > Faux(dim, dim, hdim + 1), Fwsumimgs;
2950  MultidimArray<double> Maux, Msumallwedges(dim, dim, hdim + 1);
2951  std::vector<double> refs_resol(nr_ref);
2952  Image<double> Vaux;
2953  FileName fn_tmp;
2954 
2955  // Calculate resolutions
2956  fsc.clear();
2957  fsc.resize(nr_ref + 1);
2958  for (int refno = 0; refno < nr_ref; refno++)
2959  {
2960  calculateFsc(wsumimgs[refno], wsumimgs[nr_ref + refno], wsumweds[refno],
2961  wsumweds[nr_ref + refno], fsc[0], fsc[refno + 1], refs_resol[refno]);
2962  // Restore original wsumimgs and wsumweds
2963  wsumimgs[refno] += wsumimgs[nr_ref + refno];
2964  wsumweds[refno] += wsumweds[nr_ref + refno];
2965  }
2966 
2967  // Update the reference images
2968  sumw_allrefs = 0.;
2969  Msumallwedges.initZeros();
2970  for (int refno = 0; refno < nr_ref; refno++)
2971  {
2972  sumw_allrefs += sumw(refno);
2973  transformer.FourierTransform(wsumimgs[refno], Fwsumimgs, true);
2974  if (do_missing)
2975  {
2976  Msumallwedges += wsumweds[refno];
2977  // Only impute for ML-approach (maxCC approach uses division by sumwedge)
2978  if (do_ml && do_impute)
2979  {
2980  transformer.FourierTransform(Iref[refno](), Faux, true);
2981  if (sumw(refno) > 0.)
2982  {
2983  // inner iteration: marginalize over missing data only
2984  for (int iter2 = 0; iter2 < Niter2; iter2++)
2985  {
2987  {
2988  // Impute old reference for missing pixels
2989  DIRECT_MULTIDIM_ELEM(Faux,n) *= (1.
2990  - DIRECT_MULTIDIM_ELEM(wsumweds[refno],n) / sumw(refno));
2991  // And sum the weighted sum for observed pixels
2992  DIRECT_MULTIDIM_ELEM(Faux,n) += (DIRECT_MULTIDIM_ELEM(Fwsumimgs,n)
2993  / sumw(refno));
2994  }
2995  }
2996  }
2997  // else do nothing (i.e. impute old reference completely
2998  }
2999  else
3000  {
3001  // no imputation: divide by number of times a pixel has been observed
3003  {
3004  if (DIRECT_MULTIDIM_ELEM(wsumweds[refno],n) > noimp_threshold)
3005  {
3006  DIRECT_MULTIDIM_ELEM(Faux,n) = DIRECT_MULTIDIM_ELEM(Fwsumimgs,n)
3007  / DIRECT_MULTIDIM_ELEM(wsumweds[refno],n);
3008  // TODO: CHECK THE FOLLOWING LINE!!
3009  DIRECT_MULTIDIM_ELEM(Faux,n) *= sumw(refno) / sumw(refno);
3010  }
3011  else
3012  {
3013  DIRECT_MULTIDIM_ELEM(Faux,n) = 0.;
3014  }
3015  }
3016  }
3017  }
3018  else
3019  {
3020  // No missing data
3021  if (sumw(refno) > 0.)
3022  {
3023  // if no missing data: calculate straightforward average,
3025  {
3026  DIRECT_MULTIDIM_ELEM(Faux,n) = DIRECT_MULTIDIM_ELEM(Fwsumimgs,n)
3027  / sumw(refno);
3028  }
3029  }
3030  }
3031  // Back to real space
3032  transformer.inverseFourierTransform(Faux, Iref[refno]());
3033  }
3034 
3035  // Average fracweight
3036  sumfracweight /= sumw_allrefs;
3037 
3038  // Update the model fractions
3039  if (!fix_fractions)
3040  {
3041  for (int refno = 0; refno < nr_ref; refno++)
3042  {
3043  if (sumw(refno) > 0.)
3044  alpha_k(refno) = sumw(refno) / sumw_allrefs;
3045  else
3046  alpha_k(refno) = 0.;
3047  }
3048  }
3049 
3050  // Update sigma of the origin offsets
3051  if (!fix_sigma_offset)
3052  {
3053  sigma_offset = sqrt(wsum_sigma_offset / (2. * sumw_allrefs));
3054  }
3055 
3056  // Update the noise parameters
3057  if (!fix_sigma_noise)
3058  {
3059  if (do_missing)
3060  {
3061  double sum_complete_wedge = 0.;
3062  double sum_complete_fourier = 0.;
3063  MultidimArray<double> Mcomplete(dim, dim, dim);
3065  {
3066  if (j < XSIZE(Msumallwedges))
3067  {
3068  sum_complete_wedge += DIRECT_A3D_ELEM(Msumallwedges,k,i,j);
3069  sum_complete_fourier += DIRECT_A3D_ELEM(fourier_imask,k,i,j);
3070  }
3071  else
3072  {
3073  sum_complete_wedge += DIRECT_A3D_ELEM(Msumallwedges,
3074  (dim-k)%dim,(dim-i)%dim,dim-j);
3075  sum_complete_fourier += DIRECT_A3D_ELEM(fourier_imask,
3076  (dim-k)%dim,(dim-i)%dim,dim-j);
3077  }
3078  }
3079  //#define DEBUG_UPDATE_SIGMA
3080 #ifdef DEBUG_UPDATE_SIGMA
3081  std::cerr<<" sum_complete_wedge= "<<sum_complete_wedge<<" = "<<100*sum_complete_wedge/(sumw_allrefs*sum_complete_fourier)<<"%"<<std::endl;
3082  std::cerr<<" ddim3= "<<ddim3<<std::endl;
3083  std::cerr<<" sum_complete_fourier= "<<sum_complete_fourier<<std::endl;
3084  std::cerr<<" sumw_allrefs= "<<sumw_allrefs<<std::endl;
3085  std::cerr<<" wsum_sigma_noise= "<<wsum_sigma_noise<<std::endl;
3086  std::cerr<<" sigma_noise_old= "<<sigma_noise<<std::endl;
3087  std::cerr<<" sigma_new_impute= "<<sqrt((sigma_noise*sigma_noise*(sumw_allrefs*sum_complete_fourier - sum_complete_wedge ) + wsum_sigma_noise)/(sumw_allrefs * sum_complete_fourier))<<std::endl;
3088  std::cerr<<" sigma_new_noimpute= "<<sqrt(wsum_sigma_noise / (sum_complete_wedge))<<std::endl;
3089  std::cerr<<" sigma_new_nomissing= "<<sqrt(wsum_sigma_noise / (sumw_allrefs * sum_complete_fourier))<<std::endl;
3090 #endif
3091 
3092  if (do_impute)
3093  {
3094  for (int iter2 = 0; iter2 < Niter2; iter2++)
3095  {
3097  sigma_noise *= sumw_allrefs * sum_complete_fourier
3098  - sum_complete_wedge;
3099  sigma_noise += wsum_sigma_noise;
3100  sigma_noise = sqrt(
3101  sigma_noise / (sumw_allrefs * sum_complete_fourier));
3102  }
3103  }
3104  else
3105  {
3106  sigma_noise = sqrt(wsum_sigma_noise / sum_complete_wedge);
3107  }
3108  }
3109  else
3110  {
3111  sigma_noise = sqrt(wsum_sigma_noise / (sumw_allrefs * ddim3));
3112  }
3113  // Correct sigma_noise for number of pixels within the mask
3114  if (do_mask)
3116  }
3117 
3118  // post-process reference volumes
3119  for (int refno = 0; refno < nr_ref; refno++)
3120  {
3121  if (do_filter)
3122  postProcessVolume(Iref[refno], refs_resol[refno]);
3123  else
3124  postProcessVolume(Iref[refno]);
3125  }
3126 
3127  // Regularize
3128  regularize(iter);
3129 
3130 #ifdef DEBUG
3131 
3132  std::cerr<<"finished maximization"<<std::endl;
3133 #endif
3134 }
3135 
3136 void
3139  MultidimArray<double> &freq, MultidimArray<double> &fsc, double &resolution)
3140 {
3141 
3143  FourierTransformer transformer1, transformer2;
3144  transformer1.FourierTransform(M1, FT1, false);
3145  transformer2.FourierTransform(M2, FT2, false);
3146 
3147  int vsize = hdim + 1;
3148  Matrix1D<double> f(3);
3149  MultidimArray<double> num, den1, den2;
3150  double w1, w2, R;
3151  freq.initZeros(vsize);
3152  fsc.initZeros(vsize);
3153  num.initZeros(vsize);
3154  den1.initZeros(vsize);
3155  den2.initZeros(vsize);
3156 
3158  {
3159  FFT_IDX2DIGFREQ(j, XSIZE(M1), XX(f));
3160  FFT_IDX2DIGFREQ(i, YSIZE(M1), YY(f));
3161  FFT_IDX2DIGFREQ(k, ZSIZE(M1), ZZ(f));
3162  R = f.module();
3163  if (R > 0.5)
3164  continue;
3165  int idx = ROUND(R*XSIZE(M1));
3166  if (do_missing)
3167  {
3168  w1 = dAkij(W1, k, i, j);
3169  w2 = dAkij(W2, k, i, j);
3170  }
3171  else
3172  {
3173  w1 = w2 = 1.;
3174  }
3175  std::complex<double> z1 = w2 * dAkij(FT1, k, i, j);
3176  std::complex<double> z2 = w1 * dAkij(FT2, k, i, j);
3177  double absz1 = abs(z1);
3178  double absz2 = abs(z2);
3179  num(idx) += real(conj(z1) * z2);
3180  den1(idx) += absz1 * absz1;
3181  den2(idx) += absz2 * absz2;
3182  }
3183 
3185  {
3186  freq(i) = (double) i / (XSIZE(M1) * pixel_size);
3187  if (num(i) != 0)
3188  fsc(i) = num(i) / sqrt(den1(i) * den2(i));
3189  else
3190  fsc(i) = 0;
3191  }
3192 
3193  // Find resolution limit acc. to FSC=0.5 criterion
3194  int idx;
3195  for (idx = 1; idx < XSIZE(freq); idx++)
3196  if (fsc(idx) < 0.5)
3197  break;
3198  idx = XMIPP_MAX(idx - 1, 1);
3199  resolution = freq(idx);
3200 
3201  //#define DEBUG_FSC
3202 #ifdef DEBUG_FSC
3203 
3205  {
3206  std::cerr<<freq(i)<<" "<<fsc(i)<<std::endl;
3207  }
3208  std::cerr<<"resolution= "<<resolution<<std::endl;
3209 #endif
3210 
3211 }
3212 
3213 // Apply regularization
3214 void
3216 {
3217 
3218  // Update regularization constant in a linear manner
3219  reg_current = reg0 - (double) iter * (reg0 - regF) / (double) reg_steps;
3221 
3222  if (reg_current > 0.)
3223  {
3224 #ifdef DEBUG
3225  std::cerr<<"start regularize"<<std::endl;
3226 #endif
3227  // Write out original volumes (before regularization)
3228  FileName fnt;
3229  for (int refno = 0; refno < nr_ref; refno++)
3230  {
3231  fnt = formatString("%s_it%06d_oriref%06d.mrc", fn_root.c_str(), iter,
3232  refno + 1);
3233  Iref[refno].write(fnt);
3234  }
3235  // Normalized regularization (in N/K)
3236  double reg_norm = reg_current * (double) nr_images_global / (double) nr_ref;
3237  MultidimArray<std::complex<double> > Fref, Favg, Fzero(dim, dim, hdim + 1);
3238  MultidimArray<double> Mavg, Mdiff;
3239  double sum_diff2 = 0.;
3240 
3241  //#define DEBUG_REGULARISE
3242 #ifdef DEBUG_REGULARISE
3243 
3244  std::cerr<<"written out oriref volumes"<<std::endl;
3245 #endif
3246  // Calculate FT of average of all references
3247  // and sum of squared differences between all references
3248  for (int refno = 0; refno < nr_ref; refno++)
3249  {
3250  if (refno == 0)
3251  Mavg = Iref[refno]();
3252  else
3253  Mavg += Iref[refno]();
3254  for (int refno2 = 0; refno2 < nr_ref; refno2++)
3255  {
3256  Mdiff = Iref[refno]() - Iref[refno2]();
3257  sum_diff2 += Mdiff.sum2();
3258  }
3259  }
3260  transformer.FourierTransform(Mavg, Favg, true);
3261  Favg *= std::complex<double>(reg_norm, 0.);
3262 #ifdef DEBUG_REGULARISE
3263 
3264  std::cerr<<"calculated Favg"<<std::endl;
3265 #endif
3266 
3267  // Update the regularized references
3268  for (int refno = 0; refno < nr_ref; refno++)
3269  {
3270  transformer.FourierTransform(Iref[refno](), Fref, true);
3271  double sumw = alpha_k(refno) * (double) nr_images_global;
3272  // Fref = (sumw*Fref + reg_norm*Favg) / (sumw + nr_ref * reg_norm)
3273 #ifdef DEBUG_REGULARISE
3274 
3275  if (verb>0)
3276  std::cerr<<"refno= "<<refno<<" sumw = "<<sumw<<" reg_current= "<<reg_current<<" reg_norm= "<<reg_norm<<" Fref1= "<<DIRECT_MULTIDIM_ELEM(Fref,1) <<" Favg1= "<<DIRECT_MULTIDIM_ELEM(Favg,1)<<" (sumw + nr_ref * reg_norm)= "<<(sumw + nr_ref * reg_norm)<<std::endl;
3277 #endif
3278 
3279  Fref *= std::complex<double>(sumw, 0.);
3280  Fref += Favg;
3281  Fref /= std::complex<double>((sumw + nr_ref * reg_norm), 0.);
3282 #ifdef DEBUG_REGULARISE
3283 
3284  if (verb>0)
3285  std::cerr<<" newFref1= "<<DIRECT_MULTIDIM_ELEM(Fref,1) <<std::endl;
3286 #endif
3287 
3288  transformer.inverseFourierTransform(Fref, Iref[refno]());
3289  }
3290 
3291  // Update the regularized sigma_noise estimate
3292  if (!fix_sigma_noise)
3293  {
3294  double reg_sigma_noise2 = sigma_noise * sigma_noise * ddim3
3295  * (double) nr_images_global;
3296 #ifdef DEBUG_REGULARISE
3297 
3298  if (verb>0)
3299  std::cerr<<"reg_sigma_noise2= "<<reg_sigma_noise2<<" nr_exp_images="<<nr_images_global<<" ddim3= "<<ddim3<<" sigma_noise= "<<sigma_noise<<" sum_diff2= "<<sum_diff2<<" reg_norm= "<<reg_norm<<std::endl;
3300 #endif
3301 
3302  reg_sigma_noise2 += reg_norm * sum_diff2;
3303  sigma_noise = sqrt(
3304  reg_sigma_noise2 / ((double) nr_images_global * ddim3));
3305 #ifdef DEBUG_REGULARISE
3306 
3307  if (verb>0)
3308  std::cerr<<"new sigma_noise= "<<sigma_noise<<std::endl;
3309 #endif
3310 
3311  }
3312 
3313 #ifdef DEBUG
3314  std::cerr<<"finished regularize"<<std::endl;
3315 #endif
3316 
3317  }
3318 }
3319 // Check convergence
3320 bool
3321 ProgMLTomo::checkConvergence(std::vector<double> &conv)
3322 {
3323 #ifdef DEBUG
3324  std::cerr<<"started checkConvergence"<<std::endl;
3325 #endif
3326 
3327  bool converged = true;
3328  double convv;
3329  MultidimArray<double> Maux;
3330 
3331  Maux.resize(dim, dim, dim);
3332  Maux.setXmippOrigin();
3333 
3334  conv.clear();
3335  for (int refno = 0; refno < nr_ref; refno++)
3336  {
3337  if (alpha_k(refno) > 0.)
3338  {
3339  Maux = Iold[refno]() * Iold[refno]();
3340  convv = 1. / (Maux.computeAvg());
3341  Maux = Iold[refno]() - Iref[refno]();
3342  Maux = Maux * Maux;
3343  convv *= Maux.computeAvg();
3344  conv.push_back(convv);
3345  if (convv > eps)
3346  converged = false;
3347  }
3348  else
3349  {
3350  conv.push_back(-1.);
3351  }
3352  }
3353 
3354 #ifdef DEBUG
3355  std::cerr<<"finished checkConvergence"<<std::endl;
3356 #endif
3357 #undef DEBUG
3358 
3359  return converged;
3360 }
3361 
3362 void
3364  size_t first, size_t last)
3365 {
3366  size_t index;
3367  MDRowVec row;
3368 
3369  for (size_t imgno = first; imgno <= last; ++imgno)
3370  {
3371  index = imgno - first ;
3372  size_t objId=imgs_id[imgno];
3373  MDimg.setValue(MDL_ANGLE_ROT, dAij(data, index, 0),objId);
3374  MDimg.setValue(MDL_ANGLE_TILT, dAij(data, index, 1),objId);
3375  MDimg.setValue(MDL_ANGLE_PSI, dAij(data, index, 2),objId);
3376  MDimg.setValue(MDL_SHIFT_X, dAij(data, index, 3),objId);
3377  MDimg.setValue(MDL_SHIFT_Y, dAij(data, index, 4),objId);
3378  MDimg.setValue(MDL_SHIFT_Z, dAij(data, index, 5),objId);
3379  MDimg.setValue(MDL_REF, int(dAij(data, index, 6)),objId);
3380  if (do_missing)
3381  MDimg.setValue(MDL_MISSINGREGION_NR, int(dAij(data, index, 7)),objId);
3382  MDimg.setValue(MDL_LL, dAij(data, index, 9),objId);
3383  }
3384 }
3385 
3386 void
3388  std::vector<MultidimArray<double> > &wsumweds, double &sumw_allrefs,
3389  double &LL, double &avefracweight, std::vector<double> &conv,
3390  std::vector<MultidimArray<double> > &fsc)
3391 {
3392 
3393  FileName fn_tmp, fn_base, fn_tmp2;
3394  MultidimArray<double> fracline(2);
3395  MetaDataVec SFo, SFc;
3396  MetaDataVec DFl;
3397  MetaDataVec MDo, MDo_sorted, MDSel, MDfsc;
3398  std::string comment;
3399  Image<double> Vt;
3400 
3401  DFl.clear();
3402  SFo.clear();
3403  SFc.clear();
3404 
3405  fn_base = fn_root;
3406  if (iter >= 0)
3407  {
3408  fn_base = formatString("%s_it%06d", fn_root.c_str(), iter);
3409  }
3410 
3411  // Write out current reference images and fill sel & log-file
3412  //Re-use the MDref that were read in produceSideInfo2
3413  int refno = 0;
3414  //for (int refno = 0; refno < nr_ref; refno++)
3415  for (size_t objId : MDref.ids())
3416  {
3417  fn_tmp = formatString("%s_ref%06d.mrc", fn_base.c_str(), refno + 1);
3418  Vt = Iref[refno];
3419  reScaleVolume(Vt(), false);
3420  Vt.write(fn_tmp);
3421 
3422  MDref.setValue(MDL_IMAGE, fn_tmp, objId);
3423  MDref.setValue(MDL_ENABLED, 1, objId);
3424  MDref.setValue(MDL_REF, refno + 1, objId);
3425  //SFo.insert(fn_tmp, SelLine::ACTIVE);
3426  //fracline(0) = alpha_k(refno);
3427  //fracline(1) = 1000 * conv[refno]; // Output 1000x the change for precision
3428  MDref.setValue(MDL_WEIGHT, alpha_k(refno), objId);
3429  MDref.setValue(MDL_SIGNALCHANGE, conv[refno] * 1000, objId);
3430  //DFl.insert_comment(fn_tmp);
3431  //DFl.insert_data_line(fracline);
3432 
3433  if (iter >= 1 && do_missing)
3434  {
3435  //double sumw = alpha_k(refno)*sumw_allrefs;
3436  Vt().resize(dim, dim, dim);
3437  Vt().setXmippOrigin();
3438  Vt().initZeros();
3439 
3440  size_t shdim=hdim;
3442  if (j < shdim + 1)
3443  DIRECT_A3D_ELEM(Vt(),k,i,j) = DIRECT_A3D_ELEM(wsumweds[refno],k,i,j)
3444  / sumw_allrefs;
3445  else
3446  DIRECT_A3D_ELEM(Vt(),k,i,j) = DIRECT_A3D_ELEM(wsumweds[refno],
3447  (dim-k)%dim,
3448  (dim-i)%dim,
3449  dim-j) / sumw_allrefs;
3450 
3451  CenterFFT(Vt(), true);
3452  reScaleVolume(Vt(), false);
3453  fn_tmp = formatString("%s_wedge%06d.mrc", fn_base.c_str(), refno + 1);
3454  Vt.write(fn_tmp);
3455  }
3456  refno++;
3457  }
3458  fn_tmp = fn_base + "_ref.xmd";
3459  MDref.write(formatString("classes@%s", fn_tmp.c_str()));
3460  fn_tmp = fn_root + "_ref.xmd";
3461  MDref.write(formatString("classes@%s", fn_tmp.c_str()));
3462 
3463  // Write out FSC curves
3464 /* std::ofstream fh;
3465  fn_tmp = fn_base + ".fsc";
3466  fh.open((fn_tmp).c_str(), std::ios::out);
3467  if (!fh)
3468  REPORT_ERROR(ERR_IO_NOTOPEN, (std::string)"Cannot write file: " + fn_tmp);
3469 
3470  fh << "# freq. FSC refno 1-n... \n";
3471  for (int idx = 1; idx < hdim + 1; idx++)
3472  {
3473  fh << fsc[0](idx) << " ";
3474  for (int refno = 0; refno < nr_ref; refno++)
3475  {
3476  fh << fsc[refno + 1](idx) << " ";
3477  }
3478  fh << "\n";
3479  }
3480  fh.close();
3481 */
3482  MDfsc.clear();
3483  fn_tmp = fn_base + ".fsc";
3484  for (int refno = 0; refno < nr_ref; refno++)
3485  {
3486  for (int idx = 1; idx < hdim + 1; idx++)
3487  {
3488  size_t id=MDfsc.addObject();
3489  MDfsc.setValue(MDL_RESOLUTION_FREQ, fsc[0](idx), id);
3490  MDfsc.setValue(MDL_RESOLUTION_FRC, fsc[refno + 1](idx), id);
3491  }
3492  MDfsc.write(formatString("class_%06d@%s", refno + 1, fn_tmp.c_str()), MD_APPEND);
3493  MDfsc.clear();
3494  }
3495 
3496  // Write out images with new docfile data
3497  fn_tmp = fn_base + "_img.xmd";
3498  MDimg.write(fn_tmp);
3499 
3500  if (iter >= 1)
3501  {
3502  //Write out log-file
3503  MDo.clear();
3504  MDo.setColumnFormat(false);
3505  MDo.setComment(cline);
3506  size_t id = MDo.addObject();
3507  MDo.setValue(MDL_LL, LL, id);
3508  MDo.setValue(MDL_PMAX, avefracweight, id);
3511  MDo.setValue(MDL_ITER, iter, id);
3512  fn_tmp = fn_base + "_img.xmd";
3513  MDo.setValue(MDL_IMGMD, fn_tmp, id);
3514  fn_tmp = fn_base + "_ref.xmd";
3515  MDo.setValue(MDL_REFMD, fn_tmp, id);
3516 
3517  fn_tmp = fn_base + "_log.xmd";
3518  MDo.write(fn_tmp);
3519 /*
3520  DFl.go_beginning();
3521  comment = "ml_tomo-logfile: Number of images= " + floatToString(sumw_allrefs);
3522  comment += " LL= " + floatToString(LL, 15, 10) + " <Pmax/sumP>= " + floatToString(avefracweight, 10, 5);
3523  DFl.insert_comment(comment);
3524  comment = "-noise " + floatToString(sigma_noise, 15, 12) + " -offset " + floatToString(sigma_offset/scale_factor, 15, 12) + " -istart " + integerToString(iter + 1);
3525  DFl.insert_comment(comment);
3526  DFl.insert_comment(cline);
3527  DFl.insert_comment("columns: model fraction (1); 1000x signal change (2); resolution (3)");
3528  fn_tmp = fn_base + ".log";
3529  DFl.write(fn_tmp);*/
3530 
3531  // Write out MetaData with optimal transformation & references
3532  //fn_tmp = fn_base + ".doc";
3533  //DFo.write(fn_tmp);
3534  // Also write out selfiles of all experimental images,
3535  // classified according to optimal reference image
3536  }
3537  fn_tmp = fn_root + "_ref.xmd";
3538  for (int refno = 0; refno < nr_ref; refno++)
3539  {
3540  /*DFo.go_beginning();
3541  SFo.clear();
3542  for (int n = 0; n < DFo.dataLineNo(); n++)
3543  {
3544  DFo.next();
3545  fn_tmp = ((DFo.get_current_line()).get_text()).erase(0, 3);
3546  DFo.adjust_to_data_line();
3547  if ((refno + 1) == (int)DFo(6))
3548  SFo.insert(fn_tmp, SelLine::ACTIVE);
3549  }
3550  fn_tmp.compose(fn_base + "_ref", refno + 1, "sel");
3551  SFo.write(fn_tmp);
3552  */
3553  MDo.clear();
3554  MDo.importObjects(MDimg, MDValueEQ(MDL_REF, refno + 1));
3555  MDo_sorted.sort(MDo, MDL_IMAGE);
3556  MDo_sorted.write(formatString("class%06d_images@%s", refno + 1, fn_tmp.c_str()), MD_APPEND);
3557  }
3558 
3559 }
3560 
Argument missing.
Definition: xmipp_error.h:114
void selfApplyGeometry(int Splinedegree, MultidimArray< std::complex< double > > &V1, const Matrix2D< double > &A, bool inv, bool wrap, std::complex< double > outside)
bool checkParameter(int argc, const char **argv, const char *param)
Definition: args.cpp:97
int nr_ref
Definition: ml_tomo.h:113
void init_progress_bar(long total)
contribution of an image to log-likelihood value
void selfWindow(int n0, int z0, int y0, int x0, int nF, int zF, int yF, int xF, T init_value=0)
Name of Metadata file for all references(string)
double eps
Definition: ml_tomo.h:127
Rotation angle of an image (double,degrees)
#define YSIZE(v)
void setSampling(double sampling)
Definition: sampling.cpp:121
int sym_order
Definition: ml_tomo.h:240
void resize(size_t Ndim, size_t Zdim, size_t Ydim, size_t Xdim, bool copy=true)
#define XMIPP_MAX(x, y)
Definition: xmipp_macros.h:193
double limit_trans
Definition: ml_tomo.h:154
double trymindiff_factor
Definition: ml_tomo.h:148
double module() const
Definition: matrix1d.h:983
FileName fn_sym
Definition: ml_tomo.h:90
double psi_sampling
Definition: ml_tomo.h:220
void sort(const MetaDataVec &MDin, const MDLabel sortLabel, bool asc=true, int limit=-1, int offset=0)
alglib::complex conj(const alglib::complex &z)
Definition: ap.cpp:4988
double getDoubleParam(const char *param, int arg=0)
void regularize(int iter)
Apply regularization.
Definition: ml_tomo.cpp:3215
bool do_missing
Internally store all missing wedges or re-compute on the fly?
Definition: ml_tomo.h:165
void getMatrices(int i, Matrix2D< double > &L, Matrix2D< double > &R, bool homogeneous=true) const
Definition: symmetries.cpp:348
void inverseFourierTransform()
Definition: xmipp_fftw.cpp:329
void read(const FileName &inFile, const std::vector< MDLabel > *desiredLabels=nullptr, bool decomposeStack=true) override
size_t nr_images_global
Definition: ml_tomo.h:117
Just an error for debugging purpose.
Definition: xmipp_error.h:119
Matrix2D< double > A
Definition: ml_tomo.h:213
bool mdimg_contains_angles
Definition: ml_tomo.h:131
std::vector< int > imgs_optrefno
Definition: ml_tomo.h:142
#define FINISHINGX(v)
#define SIGNIFICANT_WEIGHT_LOW
Definition: ml_tomo.h:46
#define REPORT_ERROR(nerr, ErrormMsg)
Definition: xmipp_error.h:211
Error with some arguments dependencies.
Definition: xmipp_error.h:115
void Euler_angles2matrix(T alpha, T beta, T gamma, Matrix2D< T > &A, bool homogeneous)
Definition: geometry.cpp:624
doublereal * c
Initial tilt angle in X for missing region in subtomogram.
bool dont_align
Definition: ml_tomo.h:178
void resizeNoCopy(const MultidimArray< T1 > &v)
#define dAij(M, i, j)
std::vector< double > corrA2
Definition: ml_tomo.h:125
double sigma_offset
Definition: ml_tomo.h:96
void calculatePdfTranslations()
Calculate probability density distribution for in-plane transformations.
Definition: ml_tomo.cpp:1669
void BinaryWedgeMask(MultidimArray< int > &mask, double theta0, double thetaF, const Matrix2D< double > &A, bool centerOrigin)
Definition: mask.cpp:524
bool do_only_average
Definition: ml_tomo.h:189
MultidimArray< double > P_phi
Definition: ml_tomo.h:135
void show()
Show.
Definition: ml_tomo.cpp:512
Just for debugging, situation that can&#39;t happens.
Definition: xmipp_error.h:120
void sqrt(Image< double > &op)
void BinaryCircularMask(MultidimArray< int > &mask, double radius, int mode, double x0, double y0, double z0)
Definition: mask.cpp:193
std::vector< Image< double > > Iold
Definition: ml_tomo.h:133
MultidimArray< double > alpha_k
Definition: ml_tomo.h:98
Signal change for an image.
MultidimArray< double > fourier_mask
Definition: ml_tomo.h:174
double regF
Definition: ml_tomo.h:229
std::string cline
Definition: ml_tomo.h:92
void setNeighborhoodRadius(double neighborhood)
Definition: sampling.cpp:140
Tilting angle of an image (double,degrees)
static double * y
void setValue(const MDObject &object) override
Initial tilt angle in Y for missing region in subtomogram.
double maxres
Definition: ml_tomo.h:173
int readSymmetryFile(FileName fn_sym, double accuracy=SYM_ACCURACY)
Definition: symmetries.cpp:33
int nr_ang
Definition: ml_tomo.h:224
Shift for the image in the X axis (double)
virtual void expectation(MetaDataVec &MDimg, std::vector< Image< double > > &Iref, int iter, double &LL, double &sumfracweight, std::vector< MultidimArray< double > > &wsumimgs, std::vector< MultidimArray< double > > &wsumweds, double &wsum_sigma_noise, double &wsum_sigma_offset, MultidimArray< double > &sumw)
Integrate over all experimental images.
Definition: ml_tomo.cpp:2839
void applyGeometry(int SplineDegree, MultidimArray< std::complex< double > > &V2, const MultidimArray< std::complex< double > > &V1, const Matrix2D< double > &A, bool inv, bool wrap, std::complex< double > outside, MultidimArray< double > *BcoeffsPtr)
void setFromCompleteFourier(T &V)
Definition: xmipp_fftw.h:326
bool getTasks(size_t &first, size_t &last)
void write(const FileName &name="", size_t select_img=ALL_IMAGES, bool isStack=false, int mode=WRITE_OVERWRITE, CastWriteMode castMode=CW_CAST, int _swapWrite=0)
bool isSymmetryGroup(FileName fn_sym, int &pgGroup, int &pgOrder)
Definition: symmetries.cpp:601
void getImageSize(const MetaData &md, size_t &Xdim, size_t &Ydim, size_t &Zdim, size_t &Ndim, MDLabel image_label)
FileName fn_mask
Definition: ml_tomo.h:90
std::vector< Matrix1D< double > > no_redundant_sampling_points_vector
Definition: sampling.h:118
MultidimArray< double > Mr2
Definition: ml_tomo.h:135
void computeNeighbors(bool only_winner=false)
Definition: sampling.cpp:1715
Unexpected label.
Definition: xmipp_error.h:157
int Niter2
Definition: ml_tomo.h:108
int dim3
Definition: ml_tomo.h:110
#define FN_ITER_MD(iter)
Definition: ml_tomo.h:53
void reScaleVolume(MultidimArray< double > &Min, bool down_scale=true)
Definition: ml_tomo.cpp:1750
void inv(Matrix2D< T > &result) const
Definition: matrix2d.cpp:663
Special label to be used when gathering MDs in MpiMetadataPrograms.
doublereal * w
void split(size_t n, std::vector< MetaDataVec > &results, const MDLabel sortLabel=MDL_OBJID) const
void initConstant(T val)
void abs(Image< double > &op)
MultidimArray< double > docfiledata
Definition: ml_tomo.h:123
double reg_current
Definition: ml_tomo.h:229
void write(const FileName &outFile, WriteModeMetaData mode=MD_OVERWRITE) const
bool checkConvergence(std::vector< double > &conv)
check convergence
Definition: ml_tomo.cpp:3321
bool do_ini_filter
Definition: ml_tomo.h:158
Matrix2D< T > transpose() const
Definition: matrix2d.cpp:1314
#define FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY3D(V)
void removeRedundantPointsExhaustive(const int symmetry, int sym_order, bool only_half_sphere, double max_ang)
Definition: sampling.cpp:1253
virtual void generateInitialReferences()
Generate initial references from random subset averages.
Definition: ml_tomo.cpp:894
Incorrect MultidimArray size.
Definition: xmipp_error.h:174
#define FINISHINGZ(v)
int symsNo() const
Definition: symmetries.h:268
glob_prnt iter
void expectationSingleImage(MultidimArray< double > &Mimg, int imgno, const int missno, double old_rot, std::vector< Image< double > > &Iref, std::vector< MultidimArray< double > > &wsumimgs, std::vector< MultidimArray< double > > &wsumweds, double &wsum_sigma_noise, double &wsum_sigma_offset, MultidimArray< double > &sumw, double &LL, double &dLL, double &fracweight, double &sumfracweight, double &trymindiff, int &opt_refno, int &opt_angno, Matrix1D< double > &opt_offsets)
ML-integration over all hidden parameters.
Definition: ml_tomo.cpp:1990
ParallelTaskDistributor * distributor
void getShift(int i, Matrix1D< double > &shift) const
Definition: symmetries.cpp:391
void saveSamplingFile(const FileName &fn_base, bool write_vectors=true, bool write_sampling_sphere=false)
Definition: sampling.cpp:1495
virtual IdIteratorProxy< false > ids()
double reg0
Definition: ml_tomo.h:229
Sampling mysampling
Definition: ml_tomo.h:236
double noimp_threshold
Definition: ml_tomo.h:171
std::unique_ptr< MDRow > getRow(size_t id) override
std::vector< Matrix1D< double > > imgs_optoffsets
Definition: ml_tomo.h:144
void randomize(const MetaData &MDin)
void Euler_apply_transf(const Matrix2D< double > &L, const Matrix2D< double > &R, double rot, double tilt, double psi, double &newrot, double &newtilt, double &newpsi)
Definition: geometry.cpp:1038
MultidimArray< double > real_mask
Definition: ml_tomo.h:174
bool no_SMALLANGLE
Definition: ml_tomo.h:233
bool do_generate_refs
Definition: ml_tomo.h:137
#define STARTINGX(v)
FileName fn_frac
Definition: ml_tomo.h:90
int oridim
Definition: ml_tomo.h:110
std::vector< int > imgs_missno
Definition: ml_tomo.h:146
size_t size() const override
#define i
Is this image enabled? (int [-1 or 1])
void maxConstrainedCorrSingleImage(MultidimArray< double > &Mimg, int imgno, int missno, double old_rot, std::vector< Image< double > > &Iref, std::vector< MultidimArray< double > > &wsumimgs, std::vector< MultidimArray< double > > &wsumweds, MultidimArray< double > &sumw, double &maxCC, double &sumCC, int &opt_refno, int &opt_angno, Matrix1D< double > &opt_offsets)
Maximum constrained correlation search over all hidden parameters.
Definition: ml_tomo.cpp:2424
ql0001_ & k(htemp+1),(cvec+1),(atemp+1),(bj+1),(bl+1),(bu+1),(x+1),(clamda+1), &iout, infoqp, &zero,(w+1), &lenw,(iw+1), &leniw, &glob_grd.epsmac
virtual void setComment(const String &newComment="No comment")
pthread_mutex_t mltomo_selfile_access_mutex
Definition: ml_tomo.cpp:33
Incorrect number of objects in Metadata.
Definition: xmipp_error.h:160
size_t addRow(const MDRow &row) override
MetaDataVec MDmissing
Definition: ml_tomo.h:129
T & getValue(MDLabel label)
double tilt_range0
Definition: ml_tomo.h:238
bool do_sym
Definition: ml_tomo.h:160
void time_config()
#define STARTINGY(v)
double nr_mask_pixels
Definition: ml_tomo.h:187
void CenterFFT(MultidimArray< T > &v, bool forward)
Definition: xmipp_fft.h:291
double rnd_unif()
#define A3D_ELEM(V, k, i, j)
void clear() override
std::vector< Matrix1D< double > > exp_data_projection_direction_by_L_R
Definition: sampling.h:108
MetaDataVec MDref
Definition: ml_tomo.h:129
glob_log first
int argc
Original command line arguments.
Definition: xmipp_program.h:86
virtual void writeOutputFiles(const int iter, std::vector< MultidimArray< double > > &wsumweds, double &sumw_allrefs, double &LL, double &avefracweight, std::vector< double > &conv, std::vector< MultidimArray< double > > &fsc)
Write out reference images, selfile and logfile.
Definition: ml_tomo.cpp:3387
MetaDataVec MDimg
Definition: ml_tomo.h:129
#define FOR_ALL_ELEMENTS_IN_ARRAY3D(V)
#define M2
std::vector< size_t > no_redundant_sampling_points_index
Definition: sampling.h:123
void computeSamplingPoints(bool only_half_sphere=true, double max_tilt=180, double min_tilt=0)
Definition: sampling.cpp:155
#define M1
#define FLOOR(x)
Definition: xmipp_macros.h:240
int istart
Definition: ml_tomo.h:106
void log(Image< double > &op)
const char * getParam(const char *param, int arg=0)
#define XX(v)
Definition: matrix1d.h:85
size_t numberSamplesAsymmetricUnit
Definition: sampling.h:78
void setReal(MultidimArray< double > &img)
Definition: xmipp_fftw.cpp:129
if(fabs(c[*nmax+ *nmax *c_dim1])==0.e0)
std::vector< double > imgs_optpsi
Definition: ml_tomo.h:143
viol index
size_t myLastImg
Definition: ml_tomo.h:121
void selfTranslate(int SplineDegree, MultidimArray< T > &V1, const Matrix1D< double > &v, bool wrap=xmipp_transformation::WRAP, T outside=0)
bool setValue(const MDObject &mdValueIn, size_t id)
#define CEIL(x)
Definition: xmipp_macros.h:225
size_t addObject() override
size_t myFirstImg
Definition: ml_tomo.h:121
void getCompleteFourier(T &V)
Definition: xmipp_fftw.h:234
double * f
bool fix_fractions
Definition: ml_tomo.h:100
Incorrect argument received.
Definition: xmipp_error.h:113
#define dMij(m, i, j)
Definition: matrix2d.h:139
size_t firstRowId() const override
double scale_factor
Definition: ml_tomo.h:173
void importObjects(const MetaData &md, const std::vector< size_t > &objectsToAdd, bool doClear=true) override
int Niter
Definition: ml_tomo.h:108
#define XMIPP_EQUAL_ACCURACY
Definition: xmipp_macros.h:119
#define SMALLANGLE
Definition: ml_tomo.h:48
void findObjects(std::vector< size_t > &objectsOut, const MDQuery &query) const override
virtual void setNumberOfLocalImages()
Set the number of images, this function is useful only for MPI.
Definition: ml_tomo.cpp:1064
#define XSIZE(v)
void calculateFsc(MultidimArray< double > &M1, MultidimArray< double > &M2, MultidimArray< double > &W1, MultidimArray< double > &W2, MultidimArray< double > &freq, MultidimArray< double > &fsc, double &resolution)
Calculate resolution by FSC.
Definition: ml_tomo.cpp:3137
void progress_bar(long rlen)
bool do_filter
Definition: ml_tomo.h:158
#define FN_ITER_VOL(iter, base, refno)
Definition: ml_tomo.h:52
double sigma_noise
Definition: ml_tomo.h:94
void write(const FileName &fn) const
Maximum value of normalized probability function (now called "Pmax/sumP") (double) ...
int threads
Definition: ml_tomo.h:243
int nr_miss
Definition: ml_tomo.h:202
#define FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(v)
const char ** argv
Definition: xmipp_program.h:87
#define dAkij(V, k, i, j)
Standard deviation of the noise in ML model.
#define ABS(x)
Definition: xmipp_macros.h:142
bool do_limit_psirange
Definition: ml_tomo.h:152
virtual void addPartialDocfileData(const MultidimArray< double > &data, size_t first, size_t last)
Add info of some processed images to later write to files.
Definition: ml_tomo.cpp:3363
free((char *) ob)
#define ZSIZE(v)
double z
#define DIRECT_MULTIDIM_ELEM(v, n)
void addExampleLine(const char *example, bool verbatim=true)
bool fix_sigma_noise
Definition: ml_tomo.h:104
#define ROUND(x)
Definition: xmipp_macros.h:210
bool do_perturb
Definition: ml_tomo.h:156
void print_elapsed_time(ProcessorTimeStamp &time, bool _IN_SECS)
FourierTransformer transformer
Definition: ml_tomo.h:246
void perturbAngularSampling()
Calculate Angular sampling.
Definition: ml_tomo.cpp:1403
Number of missing region in subtomogram.
int symmetry
Definition: ml_tomo.h:240
int verbose
Verbosity level.
void fillConstant(MDLabel label, const String &value) override
std::vector< double > A2
Definition: ml_tomo.h:125
bool do_impute
Definition: ml_tomo.h:167
#define ACOSD(x)
Definition: xmipp_macros.h:338
double pixel_size
Definition: ml_tomo.h:226
bool compareImageSize(const FileName &filename1, const FileName &filename2)
compare if same dimensions
bool do_ml
Definition: ml_tomo.h:169
#define DIRECT_A3D_ELEM(v, k, i, j)
void maskSphericalAverageOutside(MultidimArray< double > &Min)
Definition: ml_tomo.cpp:1730
void FourierTransform(T &v, T1 &V, bool getCopy=true)
Definition: xmipp_fftw.h:166
void fillLRRepository(void)
Definition: sampling.cpp:2216
__device__ float FFT_IDX2DIGFREQ(int idx, int size)
FileName fn_sel
Definition: ml_tomo.h:90
#define XMIPP_MIN(x, y)
Definition: xmipp_macros.h:181
Standard deviation of the offsets in ML model.
Type of missing region in subtomogram.
std::vector< std::vector< size_t > > my_neighbors
Definition: sampling.h:87
#define j
Frequency in 1/A (double)
MultidimArray< unsigned char > fourier_imask
Definition: ml_tomo.h:175
virtual void produceSideInfo()
Setup lots of stuff.
Definition: ml_tomo.cpp:644
std::vector< double > imgs_trymindiff
Definition: ml_tomo.h:143
#define YY(v)
Definition: matrix1d.h:93
bool getValue(MDObject &mdValueOut, size_t id) const override
int hdim
Definition: ml_tomo.h:110
virtual void produceSideInfo2(int nr_vols=1)
Definition: ml_tomo.cpp:1077
MultidimArray< double > real_omask
Definition: ml_tomo.h:174
Class to which the image belongs (int)
std::vector< Matrix1D< double > > no_redundant_sampling_points_angles
Definition: sampling.h:121
virtual void setColumnFormat(bool column)
double sum2() const
#define FINISHINGY(v)
#define FOR_ALL_ELEMENTS_IN_ARRAY1D(v)
void readParams()
Read arguments from command line.
Definition: ml_tomo.cpp:237
Name of Metadata file for all images (string)
virtual void removeDisabled()
Incorrect number of GRID volumes or shapes.
Definition: xmipp_error.h:126
bool do_mask
Definition: ml_tomo.h:183
double ran1(int *idum)
double angular_sampling
Missing data information.
Definition: ml_tomo.h:220
void defineParams()
Define the arguments accepted.
Definition: ml_tomo.cpp:37
void precalculateA2(std::vector< Image< double > > &Iref)
Fill vector of matrices with all rotations of reference.
Definition: ml_tomo.cpp:1875
std::string String
Definition: xmipp_strings.h:34
double psi(const double x)
void run()
Main body of the program.
Definition: ml_tomo.cpp:390
void * threadMLTomoExpectationSingleImage(void *data)
Definition: ml_tomo.cpp:2702
MissingType type
Definition: ml_tomo.h:195
double rnd_gaus()
double ddim3
Definition: ml_tomo.h:111
std::vector< size_t > convert_refno_to_stack_position
Definition: ml_tomo.h:139
String formatString(const char *format,...)
Shift for the image in the Z axis (double)
#define realWRAP(x, x0, xF)
Definition: xmipp_macros.h:304
Final tilt angle in Y for missing region in subtomogram.
bool checkParam(const char *param)
int read(const FileName &name, DataMode datamode=DATA, size_t select_img=ALL_IMAGES, bool mapData=false, int mode=WRITE_READONLY)
AnglesInfoVector all_angle_info
Definition: ml_tomo.h:222
Incorrect MultidimArray dimensions.
Definition: xmipp_error.h:173
float r2
std::vector< int > imgs_optangno
Definition: ml_tomo.h:142
static String label2Str(const MDLabel &label)
ProgClassifyCL2D * prm
Final tilt angle in X for missing region in subtomogram.
void getMissingRegion(MultidimArray< unsigned char > &Mmeasured, const Matrix2D< double > &A, const int missno)
Get binary missing wedge (or pyramid)
Definition: ml_tomo.cpp:1527
pthread_mutex_t mltomo_weightedsum_update_mutex
Definition: ml_tomo.cpp:32
Shift for the image in the Y axis (double)
void addUsageLine(const char *line, bool verbatim=false)
double computeStddev() const
void initZeros(const MultidimArray< T1 > &op)
double computeAvg() const
void annotate_time(TimeStamp *time)
unsigned int randomize_random_generator()
void fillExpDataProjectionDirectionByLR(const MetaData &DFi)
Definition: sampling.cpp:2256
bool containsLabel(const MDLabel label) const override
void maximization(std::vector< MultidimArray< double > > &wsumimgs, std::vector< MultidimArray< double > > &wsumweds, double &wsum_sigma_noise, double &wsum_sigma_offset, MultidimArray< double > &sumw, double &sumfracweight, double &sumw_allrefs, std::vector< MultidimArray< double > > &fsc, int iter)
Update all model parameters.
Definition: ml_tomo.cpp:2936
std::vector< Image< double > > Iref
Definition: ml_tomo.h:133
void removePointsFarAwayFromExperimentalData()
Definition: sampling.cpp:1928
#define PI
Definition: tools.h:43
Current iteration number (int)
void RaisedCosineMask(MultidimArray< double > &mask, double r1, double r2, int mode, double x0, double y0, double z0)
Definition: mask.cpp:36
int getIntParam(const char *param, int arg=0)
FileName fn_root
Definition: ml_tomo.h:90
bool dont_rotate
Definition: ml_tomo.h:180
Incorrect value received.
Definition: xmipp_error.h:195
#define STARTINGZ(v)
void readMissingInfo()
Definition: ml_tomo.cpp:1436
int * n
Name of an image (std::string)
bool do_keep_angles
Definition: ml_tomo.h:115
int dim
Definition: ml_tomo.h:110
#define ZZ(v)
Definition: matrix1d.h:101
void resize(size_t Ydim, size_t Xdim, bool noCopy=false)
Definition: matrix2d.cpp:1022
MDLabel
double sum() const
void postProcessVolume(Image< double > &Vin, double resolution=-1.)
Definition: ml_tomo.cpp:1791
int reg_steps
Definition: ml_tomo.h:230
SymList SL
Definition: sampling.h:138
FileName fn_missing
Definition: ml_tomo.h:90
void formatStringFast(String &str, const char *format,...)
size_t TimeStamp
Definition: xmipp_funcs.h:823
void addParamsLine(const String &line)
std::vector< MissingInfo > all_missing_info
Definition: ml_tomo.h:204
double tilt_rangeF
Definition: ml_tomo.h:238
#define MLTOMO_DATALINELENGTH
Definition: ml_tomo.h:49
void initIdentity()
Definition: matrix2d.h:673
< Score 4 for volumes
bool fix_sigma_offset
Definition: ml_tomo.h:102
size_t nr_images_local
Definition: ml_tomo.h:119
Fourier shell correlation (double)
Image< double > Imask
Definition: ml_tomo.h:185
FileName fn_ref
Definition: ml_tomo.h:90
double ang_search
Definition: ml_tomo.h:150
constexpr int INNER_MASK
Definition: mask.h:47
std::vector< size_t > imgs_id
Definition: ml_tomo.h:249