Xmipp  v3.23.11-Nereus
mpi_classify_CL2D.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  *
3  * Authors: Carlos Oscar coss@cnb.csic.es (2009)
4  *
5  * Unidad de Bioinformatica of 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 
26 #include <algorithm>
27 #include "mpi_classify_CL2D.h"
28 #include "xmipp_mpi.h"
29 #include "core/transformations.h"
31 #include "data/filters.h"
32 #include "data/mask.h"
33 
34 // Pointer to parameters
36 FILE * _logCL2D = NULL;
37 
38 //#define DEBUG_WITH_LOG
39 #ifdef DEBUG_WITH_LOG
40 #define CREATE_LOG() _logCL2D = fopen(formatString("nodo%02d.log", node->rank).c_str(), "w+")
41 #define LOG(msg) do{fprintf(_logCL2D, "%s\t%s\n", getCurrentTimeString(), msg); fflush(_logCL2D); }while(0)
42 #define CLOSE_LOG() fclose(_logCL2D)
43 #else
44 #define CREATE_LOG() ;
45 #define LOG(msg) ;
46 #define CLOSE_LOG() ;
47 #endif
48 
49 /* CL2D Assigned basics ------------------------------------------------ */
50 std::ostream & operator <<(std::ostream &out, const CL2DAssignment& assigned)
51 {
52  out << "(" << assigned.objId << ", " << assigned.corr << ")";
53  return out;
54 }
55 
57 {
58  flip = false;
59  likelihood = corr = psi = shiftx = shifty = 0;
60  objId = BAD_OBJID;
61 }
62 
64 {
65  double scale;
67 }
68 
70 {
71  corr = alignment.corr;
72  likelihood = alignment.likelihood;
73  flip = alignment.flip;
74  psi = alignment.psi;
75  shiftx = alignment.shiftx;
76  shifty = alignment.shifty;
77 }
78 
80 {
81  return d1.objId < d2.objId;
82 }
83 
84 /* CL2DClass basics ---------------------------------------------------- */
86 {
87  plans = NULL;
88  P.initZeros(prm->Ydim, prm->Xdim);
89  P.setXmippOrigin();
90  Pupdate = P;
91 }
92 
94 {
95  *this=other;
96 }
97 
99 {
100  plans = NULL;
101 
102  CL2DAssignment assignment;
103  assignment.corr = 1;
104  Pupdate = other.P;
105  nextListImg.push_back(assignment);
106  transferUpdate();
107 
108  currentListImg = other.currentListImg;
109  histClass = other.histClass;
110  histNonClass = other.histNonClass;
111  neighboursIdx = other.neighboursIdx;
112 
113  return *this;
114 }
115 
117 {
118  delete plans;
119 }
120 
122  const CL2DAssignment &assigned,
123  bool force)
124 {
125  if ((assigned.corr > 0 && assigned.objId != BAD_OBJID) || force)
126  {
127  Pupdate += I;
128  nextListImg.push_back(assigned);
129  }
130 }
131 
132 //#define DEBUG
133 void CL2DClass::transferUpdate(bool centerReference)
134 {
135  if (nextListImg.size() > 0)
136  {
137  // Take from Pupdate
138  double iNq = 1.0 / nextListImg.size();
139  Pupdate *= iNq;
140  if (prm->normalizeImages)
141  Pupdate.statisticsAdjust(0., 1.);
142  P = Pupdate;
144  if (!DIRECT_MULTIDIM_ELEM(prm->mask,n))
145  DIRECT_MULTIDIM_ELEM(P,n) = 0;
146  Pupdate.initZeros(P);
147 
148  // Make sure the image is centered
149  if (centerReference && prm->alignImages)
150  centerImage(P,corrAux,rotAux);
152  if (!DIRECT_A2D_ELEM(prm->mask,i,j))
153  DIRECT_A2D_ELEM(P,i,j) = 0;
154 
155  // Compute the polar Fourier transform of the full image
156  polarFourierTransform<true>(P, polarFourierP, false, XSIZE(P) / 5,
157  XSIZE(P) / 2-2, plans, 1);
158  size_t finalSize = 2 * polarFourierP.getSampleNoOuterRing() - 1;
159  if (XSIZE(rotationalCorr) != finalSize)
160  rotationalCorr.resize(finalSize);
161  rotAux.local_transformer.setReal(rotationalCorr);
162 
163  // Take the list of images
164  currentListImg = nextListImg;
165  nextListImg.clear();
166 
167  // Update the histogram of corrs of elements inside and outside the class
168  if (!prm->classicalMultiref)
169  {
170  MultidimArray<double> classCorr, nonClassCorr;
171 
172  classCorr.resizeNoCopy(currentListImg.size());
174  DIRECT_A1D_ELEM(classCorr,i) = currentListImg[i].corr;
175 
176  nonClassCorr.resizeNoCopy(nextNonClassCorr.size());
178  DIRECT_A1D_ELEM(nonClassCorr,i) = nextNonClassCorr[i];
179  nextNonClassCorr.clear();
180 
181  double minC=0., maxC=0.;
182  classCorr.computeDoubleMinMax(minC, maxC);
183  double minN=0., maxN=0.;
184  nonClassCorr.computeDoubleMinMax(minN, maxN);
185  double c0 = XMIPP_MIN(minC,minN);
186  double cF = XMIPP_MAX(maxC,maxN);
187  compute_hist(classCorr, histClass, c0, cF, 200);
188  compute_hist(nonClassCorr, histNonClass, c0, cF, 200);
189  histClass += 1; // Laplace correction
190  histNonClass += 1;
191  histClass /= histClass.sum();
192  histNonClass /= histNonClass.sum();
193  }
194 
195 #ifdef DEBUG
196  histClass.write("PPPclass.txt");
197  histNonClass.write("PPPnonClass.txt");
198  std::cout << "Histograms have been written. Press any key\n";
199  char c;
200  std::cin >> c;
201 #endif
202 
203  }
204  else
205  {
206  currentListImg.clear();
207  P.initZeros();
208  }
209 }
210 #undef DEBUG
211 
212 constexpr double SHIFT_THRESHOLD = 0.95; // Shift threshold in pixels.
213 constexpr float ROTATE_THRESHOLD = 1.0 ; // Rotate threshold in degrees.
214 
215 constexpr double INITIAL_SHIFT_THRESHOLD = SHIFT_THRESHOLD + 1.0; // Shift threshold in pixels.
216 constexpr float INITIAL_ROTATE_THRESHOLD = ROTATE_THRESHOLD + 1.0 ; // Rotate threshold in degrees.
217 
218 //#define DEBUG
219 //#define DEBUG_MORE
221  bool reverse)
222 {
223  if (reverse)
224  {
225  I.selfReverseX();
226  I.setXmippOrigin();
227  }
228 
229  Matrix2D<double> ARS, ASR, R(3, 3), INV;
230  ARS.initIdentity(3);
231  ASR = ARS;
232  INV = ARS; // avoid creating a new transformation matrix per applyGeometry call
233  MultidimArray<double> IauxSR = I, IauxRS = I;
234 // Mcorr.resizeNoCopy(I);
235  Polar<std::complex<double> > polarFourierI;
236  corrAux.transformer1.FourierTransform(P, corrAux.FFT1, false);
237 #ifdef DEBUG_MORE
238  Image<double> save2;
239  save2()=P;
240  save2.write("PPPI1.xmp");
241 #endif
242 
243  // Align the image with the node
244  if (prm->alignImages)
245  {
246  double shiftXSR=INITIAL_SHIFT_THRESHOLD, shiftYSR=INITIAL_SHIFT_THRESHOLD, bestRotSR=INITIAL_ROTATE_THRESHOLD;
247  double shiftXRS=INITIAL_SHIFT_THRESHOLD, shiftYRS=INITIAL_SHIFT_THRESHOLD, bestRotRS=INITIAL_ROTATE_THRESHOLD;
248 
249  for (int i = 0; i < 3; i++)
250  {
251  // Shift then rotate
252  if (((shiftXSR > SHIFT_THRESHOLD) || (shiftXSR < (-SHIFT_THRESHOLD))) ||
253  ((shiftYSR > SHIFT_THRESHOLD) || (shiftYSR < (-SHIFT_THRESHOLD))))
254  {
255  bestShift(P, corrAux.FFT1, IauxSR, shiftXSR, shiftYSR, corrAux);
256  MAT_ELEM(ASR,0,2) += shiftXSR;
257  MAT_ELEM(ASR,1,2) += shiftYSR;
258  ASR.inv(INV);
259  applyGeometry(xmipp_transformation::LINEAR, IauxSR, I, INV, xmipp_transformation::IS_INV, xmipp_transformation::WRAP);
260  }
261 
262  #ifdef DEBUG_MORE
263  save2()=IauxSR;
264  save2.write("PPPIauxSR_afterShift.xmp");
265  std::cout << "ASR\n" << ASR << std::endl;
266  #endif
267 
269  if (bestRotSR > ROTATE_THRESHOLD)
270  {
271  polarFourierTransform<true>(IauxSR, fitBasic_aux, polarFourierI, true,
272  XSIZE(P) / 5, XSIZE(P) / 2-2, plans, 1);
273 
274  bestRotSR = best_rotation(polarFourierP, polarFourierI, rotAux);
275  rotation2DMatrix(bestRotSR, R);
276  M3x3_BY_M3x3(ASR,R,ASR);
277  ASR.inv(INV);
278  applyGeometry(xmipp_transformation::LINEAR, IauxSR, I, INV, xmipp_transformation::IS_INV, xmipp_transformation::WRAP);
279  }
280 
281  #ifdef DEBUG_MORE
282  save2()=IauxSR;
283  save2.write("PPPIauxSR_afterShiftAndRotation.xmp");
284  std::cout << "ASR\n" << ASR << std::endl;
285  #endif
286 
287  // Rotate then shift
288  if (bestRotRS > ROTATE_THRESHOLD)
289  {
290  polarFourierTransform<true>(IauxRS, fitBasic_aux, polarFourierI, true,
291  XSIZE(P) / 5, XSIZE(P) / 2-2, plans, 1);
292 
293  bestRotRS = best_rotation(polarFourierP, polarFourierI, rotAux);
294  rotation2DMatrix(bestRotRS, R);
295  M3x3_BY_M3x3(ARS,R,ARS);
296  ARS.inv(INV);
297  applyGeometry(xmipp_transformation::LINEAR, IauxRS, I, INV, xmipp_transformation::IS_INV, xmipp_transformation::WRAP);
298  }
299 
300 #ifdef DEBUG_MORE
301  save2()=IauxRS;
302  save2.write("PPPIauxRS_afterRotation.xmp");
303  std::cout << "ARS\n" << ARS << std::endl;
304 #endif
305 
306  if (((shiftXRS > SHIFT_THRESHOLD) || (shiftXRS < (-SHIFT_THRESHOLD))) ||
307  ((shiftYRS > SHIFT_THRESHOLD) || (shiftYRS < (-SHIFT_THRESHOLD))))
308  {
309  bestShift(P, corrAux.FFT1, IauxRS, shiftXRS, shiftYRS, corrAux);
310  MAT_ELEM(ARS,0,2) += shiftXRS;
311  MAT_ELEM(ARS,1,2) += shiftYRS;
312  ARS.inv(INV);
313  applyGeometry(xmipp_transformation::LINEAR, IauxRS, I, INV, xmipp_transformation::IS_INV, xmipp_transformation::WRAP);
314  }
315 
316  #ifdef DEBUG_MORE
317  save2()=IauxRS;
318  save2.write("PPPIauxRS_afterRotationAndShift.xmp");
319  std::cout << "ARS\n" << ARS << std::endl;
320 
321  char c;
322  std::cout << "Press any key\n";
323  std::cin >> c;
324  #endif
325  }
326  }
327 
328  // Compute the correntropy
329  double corrRS=0.0, corrSR=0.0;
330  MultidimArray<int> &imask = prm->mask;
331  if (prm->useThresholdMask)
332  {
333  imask.initZeros(IauxRS);
335  if (DIRECT_MULTIDIM_ELEM(IauxRS,n)>prm->threshold)
336  DIRECT_MULTIDIM_ELEM(imask,n)=1;
338  if (DIRECT_MULTIDIM_ELEM(IauxSR,n)>prm->threshold)
339  DIRECT_MULTIDIM_ELEM(imask,n)=1;
340  }
341  if (prm->useCorrelation)
342  {
343  corrRS = corrSR = 0;
344  long N = 0;
346  {
347  if (DIRECT_MULTIDIM_ELEM(imask,n))
348  {
349  double Pval = DIRECT_MULTIDIM_ELEM(P, n);
350  corrRS += Pval * DIRECT_MULTIDIM_ELEM(IauxRS, n);
351  corrSR += Pval * DIRECT_MULTIDIM_ELEM(IauxSR, n);
352  ++N;
353  }
354  }
355  if (0 == N) {
356  REPORT_ERROR(ERR_UNCLASSIFIED, "This should never happen. If you know how to reproduce"
357  "this issue, please contact developers.");
358  }
359  corrRS /= N;
360  corrSR /= N;
361  }
362  else
363  {
364  corrRS = fastCorrentropy(P, IauxRS, prm->sigma,
365  prm->gaussianInterpolator, imask);
366  corrSR = fastCorrentropy(P, IauxSR, prm->sigma,
367  prm->gaussianInterpolator, imask);
368  }
369 #ifdef DEBUG_MORE
370  std::cout << "corrRS=" << corrRS << std::endl;
371  std::cout << "corrSR=" << corrSR << std::endl;
372 #endif
373 
374 
375  // Prepare result
376  if (reverse)
377  {
378  // COSS: Check that this is correct
379  MAT_ELEM(ARS,0,0) *= -1;
380  MAT_ELEM(ARS,1,0) *= -1;
381  MAT_ELEM(ASR,0,0) *= -1;
382  MAT_ELEM(ASR,1,0) *= -1;
383  }
384 
385  CL2DAssignment candidateRS, candidateSR;
386  candidateRS.readAlignment(ARS);
387  candidateSR.readAlignment(ASR);
388  if (candidateRS.shiftx * candidateRS.shiftx +
389  candidateRS.shifty * candidateRS.shifty > prm->maxShift2)
390  candidateRS.corr = 0;
391  else
392  candidateRS.corr = corrRS;
393  if (candidateSR.shiftx * candidateSR.shiftx +
394  candidateSR.shifty * candidateSR.shifty > prm->maxShift2)
395  candidateSR.corr = 0;
396  else
397  candidateSR.corr = corrSR;
398 
399  if (candidateRS.corr >= candidateSR.corr)
400  {
401  I = IauxRS;
402  result.copyAlignment(candidateRS);
403  }
404  else if (candidateSR.corr > candidateRS.corr)
405  {
406  I = IauxSR;
407  result.copyAlignment(candidateSR);
408  }
409  else
410  // This is for NaNs, Infs, ...
411  result.corr = 0;
412 
413 #ifdef DEBUG
414 
415  Image<double> save;
416  save()=P;
417  save.write("PPPI1.xmp");
418  save()=I;
419  save.write("PPPI2.xmp");
420  save()=P-I;
421  save.write("PPPdiff.xmp");
422  std::cout << "sigma=" << prm->sigma << " corr=" << result.corr
423  << ". Press" << std::endl;
424  char c;
425  std::cin >> c;
426 #endif
427 }
428 #undef DEBUG
429 #undef DEBUG_MORE
430 
432 {
433  if (currentListImg.size() == 0)
434  return;
435 
436  // Try this image
437  MultidimArray<double> Idirect = I;
438  CL2DAssignment resultDirect;
439  fitBasic(Idirect, resultDirect);
440 
441  // Try its mirror
442  CL2DAssignment resultMirror;
443  MultidimArray<double> Imirror;
444  if (prm->mirrorImages)
445  {
446  Imirror=I;
447  fitBasic(Imirror, resultMirror, true);
448  }
449  else
450  resultMirror.corr=-1e38;
451 
452  if (resultMirror.corr > resultDirect.corr)
453  {
454  I = Imirror;
455  result.copyAlignment(resultMirror);
456  }
457  else
458  {
459  I = Idirect;
460  result.copyAlignment(resultDirect);
461  }
462 
463  result.likelihood = 0;
464  if (!prm->classicalMultiref)
465  {
466  // Find the likelihood
467  int idx;
468  histClass.val2index(result.corr, idx);
469  if (idx < 0)
470  return;
471  double likelihoodClass = 0;
472  for (int i = 0; i <= idx; i++)
473  likelihoodClass += DIRECT_A1D_ELEM(histClass,i);
474  histNonClass.val2index(result.corr, idx);
475  if (idx < 0)
476  return;
477  double likelihoodNonClass = 0;
478  for (int i = 0; i <= idx; i++)
479  likelihoodNonClass += DIRECT_A1D_ELEM(histNonClass,i);
480  result.likelihood = likelihoodClass * likelihoodNonClass;
481  }
482 }
483 
484 /* Look for K neighbours in a list ----------------------------------------- */
485 //#define DEBUG
486 void CL2DClass::lookForNeighbours(const std::vector<CL2DClass *> listP, int K)
487 {
488  int Q = listP.size();
489  neighboursIdx.clear();
490  if (K == Q)
491  {
492  // As many neighbours as codes
493  for (int q = 0; q < Q; q++)
494  neighboursIdx.push_back(q);
495  }
496  else
497  {
498  MultidimArray<double> distanceCode;
499  distanceCode.initZeros(Q);
500  CL2DAssignment assignment;
502  for (int q = 0; q < Q; q++)
503  {
504  if (listP[q] == this)
505  distanceCode(q) = 1;
506  else
507  {
508  I = listP[q]->P;
509  fit(I, assignment);
510  A1D_ELEM(distanceCode,q) = assignment.corr;
511  }
512  }
513 
514  MultidimArray<int> idx;
515  distanceCode.indexSort(idx);
516  for (int k = 0; k < K; k++)
517  neighboursIdx.push_back(idx(Q - k - 1) - 1);
518  }
519 #ifdef DEBUG
520  Image<double> save;
521  save()=P;
522  save.write("PPPthis.xmp");
523  for (int k=0; k<K; k++)
524  {
525  save()=listP[neighboursIdx[k]]->P;
526  save.write((std::string)"PPPneigh"+integerToString(k,1));
527  }
528  std::cout << "Neighbours saved. Press any key\n";
529  char c;
530  std::cin >> c;
531 #endif
532 }
533 #undef DEBUG
534 
535 /* Share assignments and classes -------------------------------------- */
536 void CL2D::shareAssignments(bool shareAssignment, bool shareUpdates,
537  bool shareNonCorr)
538 {
539  if (shareAssignment)
540  {
541  // Put assignment in common
542  std::vector<int> nodeRef;
543  if (SF->containsLabel(MDL_REF))
544  SF->getColumnValues(MDL_REF, nodeRef);
545  else
546  nodeRef.resize(SF->size(), -1);
547 
548  MPI_Allreduce(MPI_IN_PLACE, &(nodeRef[0]), nodeRef.size(), MPI_INT,
549  MPI_MAX, MPI_COMM_WORLD);
550  SF->setColumnValues(MDL_REF, nodeRef);
551 #ifdef DEBUG_WITH_LOG
552  FileName fnImg;
553  for (size_t objId : SF->id())
554  {
555  int classRef;
556  SF->getValue(MDL_IMAGE,fnImg,objId);
557  SF->getValue(MDL_REF,classRef,objId);
558  LOG(formatString("Image %s: class: %d",fnImg.c_str(),classRef).c_str());
559  }
560 #endif
561  }
562 
563  // Share code updates
564  if (shareUpdates)
565  {
566  std::vector<CL2DAssignment> auxList;
567  std::vector<double> auxList2;
568  int Q = P.size();
569  for (int q = 0; q < Q; q++)
570  {
571  MPI_Allreduce(MPI_IN_PLACE, MULTIDIM_ARRAY(P[q]->Pupdate),
572  MULTIDIM_SIZE(P[q]->Pupdate), MPI_DOUBLE, MPI_SUM,
573  MPI_COMM_WORLD);
574 
575  // Share nextClassCorr and nextNonClassCorr
576  std::vector<double> receivedNonClassCorr;
577  std::vector<CL2DAssignment> receivedNextListImage;
578  int listSize;
579  for (size_t rank = 0; rank < prm->node->size; rank++)
580  {
581  if (rank == prm->node->rank)
582  {
583  listSize = P[q]->nextListImg.size();
584  MPI_Bcast(&listSize, 1, MPI_INT, rank, MPI_COMM_WORLD);
585  MPI_Bcast(&(P[q]->nextListImg[0]),
586  P[q]->nextListImg.size() * sizeof(CL2DAssignment),
587  MPI_CHAR, rank, MPI_COMM_WORLD);
588  if (shareNonCorr)
589  {
590  listSize = P[q]->nextNonClassCorr.size();
591  MPI_Bcast(&listSize, 1, MPI_INT, rank, MPI_COMM_WORLD);
592  MPI_Bcast(&(P[q]->nextNonClassCorr[0]),
593  P[q]->nextNonClassCorr.size(), MPI_DOUBLE,
594  rank, MPI_COMM_WORLD);
595  }
596  }
597  else
598  {
599  MPI_Bcast(&listSize, 1, MPI_INT, rank, MPI_COMM_WORLD);
600  auxList.resize(listSize);
601  MPI_Bcast(&(auxList[0]), listSize * sizeof(CL2DAssignment),
602  MPI_CHAR, rank, MPI_COMM_WORLD);
603  receivedNextListImage.reserve(
604  receivedNextListImage.size() + listSize);
605  for (int j = 0; j < listSize; j++)
606  receivedNextListImage.push_back(auxList[j]);
607  if (shareNonCorr)
608  {
609  MPI_Bcast(&listSize, 1, MPI_INT, rank, MPI_COMM_WORLD);
610  auxList2.resize(listSize);
611  MPI_Bcast(&(auxList2[0]), listSize, MPI_DOUBLE, rank,
612  MPI_COMM_WORLD);
613  receivedNonClassCorr.reserve(
614  receivedNonClassCorr.size() + listSize);
615  for (int j = 0; j < listSize; j++)
616  receivedNonClassCorr.push_back(auxList2[j]);
617  }
618  }
619  }
620  // This is important to ensure that all nodes have all images in the same order
621  std::sort(receivedNextListImage.begin(),receivedNextListImage.end(),CL2DAssignmentComparator);
622 
623  // Copy the received elements
624  listSize = receivedNextListImage.size();
625  P[q]->nextListImg.reserve(P[q]->nextListImg.size() + listSize);
626  for (int j = 0; j < listSize; j++)
627  P[q]->nextListImg.push_back(receivedNextListImage[j]);
628  listSize = receivedNonClassCorr.size();
629  P[q]->nextNonClassCorr.reserve(
630  P[q]->nextNonClassCorr.size() + listSize);
631  for (int j = 0; j < listSize; j++)
632  P[q]->nextNonClassCorr.push_back(receivedNonClassCorr[j]);
633  }
634 
635  transferUpdates();
636  }
637 }
638 
640  CL2DClass *node2) const
641 {
642  // Share assignment
643  int imax = VEC_XSIZE(assignment);
644  MPI_Allreduce(MPI_IN_PLACE, MATRIX1D_ARRAY(assignment), imax, MPI_INT,
645  MPI_MAX, MPI_COMM_WORLD);
646 
647  // Share code updates
648  std::vector<CL2DAssignment> auxList;
649  std::vector<double> auxList2;
650  CL2DClass *node = NULL;
651  for (int q = 0; q < 2; q++)
652  {
653  if (q == 0)
654  node = node1;
655  else
656  node = node2;
657  MPI_Allreduce(MPI_IN_PLACE, MULTIDIM_ARRAY(node->Pupdate),
658  MULTIDIM_SIZE(node->Pupdate), MPI_DOUBLE, MPI_SUM,
659  MPI_COMM_WORLD);
660 
661  // Share nextClassCorr and nextNonClassCorr
662  std::vector<double> receivedNonClassCorr;
663  std::vector<CL2DAssignment> receivedNextListImage;
664  int listSize;
665  for (size_t rank = 0; rank < prm->node->size; rank++)
666  {
667  if (rank == prm->node->rank)
668  {
669  // Transmit node 1 next list of images
670  listSize = node->nextListImg.size();
671  MPI_Bcast(&listSize, 1, MPI_INT, rank, MPI_COMM_WORLD);
672  MPI_Bcast(&(node->nextListImg[0]),
673  node->nextListImg.size() * sizeof(CL2DAssignment),
674  MPI_CHAR, rank, MPI_COMM_WORLD);
675  // Transmit node 1 non class corr
676  listSize = node->nextNonClassCorr.size();
677  MPI_Bcast(&listSize, 1, MPI_INT, rank, MPI_COMM_WORLD);
678  MPI_Bcast(&(node->nextNonClassCorr[0]),
679  node->nextNonClassCorr.size(), MPI_DOUBLE, rank,
680  MPI_COMM_WORLD);
681  }
682  else
683  {
684  // Receive node 1 next list of images
685  MPI_Bcast(&listSize, 1, MPI_INT, rank, MPI_COMM_WORLD);
686  auxList.resize(listSize);
687  MPI_Bcast(&(auxList[0]), listSize * sizeof(CL2DAssignment),
688  MPI_CHAR, rank, MPI_COMM_WORLD);
689  receivedNextListImage.reserve(
690  receivedNextListImage.size() + listSize);
691  for (int j = 0; j < listSize; j++)
692  receivedNextListImage.push_back(auxList[j]);
693  // Receive node 1 non class corr
694  MPI_Bcast(&listSize, 1, MPI_INT, rank, MPI_COMM_WORLD);
695  auxList2.resize(listSize);
696  MPI_Bcast(&(auxList2[0]), listSize, MPI_DOUBLE, rank,
697  MPI_COMM_WORLD);
698  receivedNonClassCorr.reserve(
699  receivedNonClassCorr.size() + listSize);
700  for (int j = 0; j < listSize; j++)
701  receivedNonClassCorr.push_back(auxList2[j]);
702  }
703  }
704  // This is important to ensure that all nodes have all images in the same order
705  std::sort(receivedNextListImage.begin(),receivedNextListImage.end(),CL2DAssignmentComparator);
706 
707  // Copy the received elements
708  listSize = receivedNextListImage.size();
709  node->nextListImg.reserve(node->nextListImg.size() + listSize);
710  for (int j = 0; j < listSize; j++)
711  node->nextListImg.push_back(receivedNextListImage[j]);
712  listSize = receivedNonClassCorr.size();
713  node->nextNonClassCorr.reserve(node->nextNonClassCorr.size() + listSize);
714  for (int j = 0; j < listSize; j++)
715  node->nextNonClassCorr.push_back(receivedNonClassCorr[j]);
716  }
717 
718  node1->transferUpdate();
719  node2->transferUpdate();
720 }
721 
722 /* Destructor --------------------------------------------------------- */
724 {
725  int qmax=P.size();
726  for (int q=0; q<qmax; q++)
727  delete P[q];
728 }
729 
730 /* Read image --------------------------------------------------------- */
731 void CL2D::readImage(Image<double> &I, size_t objId, bool applyGeo) const
732 {
733  if (applyGeo)
734  I.readApplyGeo(*SF, objId);
735  else
736  {
737  FileName fnImg;
738  SF->getValue(MDL_IMAGE, fnImg, objId);
739  I.read(fnImg);
740  }
741  I().setXmippOrigin();
742  if (prm->normalizeImages)
743  I().statisticsAdjust(0., 1.);
744 }
745 
746 /* CL2D initialization ------------------------------------------------ */
747 //#define DEBUG
749  std::vector<MultidimArray<double> > &_codes0)
750 {
751  if (prm->node->rank == 1)
752  std::cout << "Initializing ...\n";
753 
754  SF = &_SF;
755  Nimgs = SF->size();
756 
757  // Start with _Ncodes0 codevectors
758  CL2DAssignment assignment;
759  assignment.corr = 1;
760  bool initialCodesGiven = _codes0.size() > 0;
761  for (int q = 0; q < prm->Ncodes0; q++)
762  {
763  P.push_back(new CL2DClass());
764  if (initialCodesGiven)
765  {
766  P[q]->Pupdate = _codes0[q];
767  P[q]->nextListImg.push_back(assignment);
768  P[q]->transferUpdate(false);
769  }
770  }
771 
772  // Estimate sigma and if no previous classes have been given,
773  // assign randomly
774  prm->sigma = 0;
775  if (prm->node->rank == 1)
776  init_progress_bar(Nimgs);
777  Image<double> I;
778  MultidimArray<double> Iaux, Ibest;
779  bool oldUseCorrelation = prm->useCorrelation;
780  prm->useCorrelation = true; // Since we cannot make the assignment before calculating sigma
781  CL2DAssignment bestAssignment;
782  size_t idx=0;
783  SF->fillConstant(MDL_REF,"-1");
784  for (size_t _ : prm->SF.ids())
785  {
786  if ((idx+1)%prm->node->size==prm->node->rank)
787  {
788  int q = -1;
789  if (!initialCodesGiven)
790  q = idx % (prm->Ncodes0);
791  size_t objId = prm->objId[idx];
792  readImage(I, objId, true);
793 
794  // Measure the variance of the signal outside a circular mask
795  double avg, stddev;
796  I().computeAvgStdev_within_binary_mask(prm->mask, avg, stddev);
797  prm->sigma += stddev;
798 
799  // Put it randomly in one of the classes
800  bestAssignment.objId = assignment.objId = objId;
801  if (!initialCodesGiven)
802  {
803  bestAssignment.corr = 1;
804  P[q]->updateProjection(I(), bestAssignment);
805  }
806  else
807  {
808  bestAssignment.corr = 0;
809  q = -1;
810  for (int qp = 0; qp < prm->Ncodes0; qp++)
811  {
812  Iaux = I();
813  P[qp]->fit(Iaux, assignment);
814  if (assignment.corr > bestAssignment.corr)
815  {
816  bestAssignment = assignment;
817  Ibest = Iaux;
818  q = qp;
819  }
820  }
821  if (q != -1)
822  P[q]->updateProjection(Ibest, bestAssignment);
823  }
824  SF->setValue(MDL_REF, q + 1, objId);
825  if (idx % 100 == 0 && prm->node->rank == 1)
826  progress_bar(idx);
827  }
828  idx++;
829  }
830  prm->node->barrierWait();
831  if (prm->node->rank == 1)
832  progress_bar(Nimgs);
833  prm->useCorrelation = oldUseCorrelation;
834 
835  // Put sigma in common
836  MPI_Allreduce(MPI_IN_PLACE, &(prm->sigma), 1, MPI_DOUBLE, MPI_SUM,
837  MPI_COMM_WORLD);
838  prm->sigma *= sqrt(2.0) / Nimgs;
839 
840  // Share all assignments
841  shareAssignments(true, true, false);
842 
843  // Now compute the histogram of corr values
844  if (!prm->classicalMultiref)
845  {
846  if (prm->node->rank == 1)
847  {
848  std::cout << "Computing histogram of correlation values\n";
849  init_progress_bar(Nimgs);
850  }
851 
852  CL2DAssignment inClass, outClass;
853  size_t idx=0;
854  for (size_t _ : prm->SF.ids())
855  {
856  if ((idx+1)%prm->node->size==prm->node->rank)
857  {
858  size_t objId = prm->objId[idx];
859  readImage(I, objId, false);
860 
861  int q;
862  SF->getValue(MDL_REF, q, objId);
863  if (q == -1)
864  continue;
865  q -= 1;
866 
867  outClass.objId = inClass.objId = objId;
868  if (q != -1)
869  {
870  Iaux = I();
871  P[q]->fit(Iaux, inClass);
872  P[q]->updateProjection(Iaux, inClass);
873  if (prm->Ncodes0 > 1)
874  for (int qp = 0; qp < prm->Ncodes0; qp++)
875  {
876  if (qp == q)
877  continue;
878  Iaux = I();
879  P[qp]->fit(Iaux, outClass);
880  P[qp]->updateNonProjection(outClass.corr);
881  }
882  }
883  if (prm->node->rank == 1 && idx % 100 == 0)
884  progress_bar(idx);
885  }
886  idx++;
887  }
888  prm->node->barrierWait();
889  if (prm->node->rank == 1)
890  progress_bar(Nimgs);
891 
892  shareAssignments(false, true, true);
893  }
894 }
895 #undef DEBUG
896 
897 /* CL2D write --------------------------------------------------------- */
898 void CL2D::write(const FileName &fnODir, const FileName &fnRoot, int level) const
899 {
900  int Q = P.size();
901  MetaDataVec SFout;
902  Image<double> I;
903  FileName fnResultsDir=formatString("%s/level_%02d",fnODir.c_str(),level);
904  FileName fnOut = formatString("%s/%s_classes.stk",fnResultsDir.c_str(),fnRoot.c_str()), fnClass;
905  fnOut.deleteFile();
906  for (int q = 0; q < Q; q++)
907  {
908  fnClass.compose(q + 1, fnOut);
909  I() = P[q]->P;
910  I.write(fnClass, q, true, WRITE_APPEND);
911  size_t id = SFout.addObject();
912  SFout.setValue(MDL_REF, q + 1, id);
913  SFout.setValue(MDL_IMAGE, fnClass, id);
914  SFout.setValue(MDL_CLASS_COUNT,P[q]->currentListImg.size(), id);
915  }
916  FileName fnSFout = formatString("%s/%s_classes.xmd",fnResultsDir.c_str(),fnRoot.c_str());
917  SFout.write("classes@"+fnSFout, MD_APPEND);
918 
919  // Make the selfiles of each class
920  FileName fnImg;
921 
922  for (int q = 0; q < Q; q++)
923  {
924  MetaDataVec SFq;
925  std::vector<CL2DAssignment> &currentListImg = P[q]->currentListImg;
926  int imax = currentListImg.size();
927  for (int i = 0; i < imax; i++)
928  {
929  const CL2DAssignment &assignment = currentListImg[i];
930  MDRowSql row = SF->getRowSql(assignment.objId);
931  row.setValue(MDL_FLIP, assignment.flip);
932  row.setValue(MDL_SHIFT_X, assignment.shiftx);
933  row.setValue(MDL_SHIFT_Y, assignment.shifty);
934  row.setValue(MDL_ANGLE_PSI, assignment.psi);
935  SFq.addRow(row);
936  }
937  MetaDataVec SFq_sorted;
938  SFq_sorted.sort(SFq, MDL_IMAGE);
939  SFq_sorted.write(formatString("class%06d_images@%s",q+1,fnSFout.c_str()),MD_APPEND);
940  }
941 }
942 
943 //#define DEBUG
944 void CL2D::lookNode(MultidimArray<double> &I, int oldnode, int &newnode,
945  CL2DAssignment &bestAssignment)
946 {
947 #ifdef DEBUG
948  std::cout << "Looking for node. Oldnode=" << oldnode << std::endl;
949 #endif
950  int Q = P.size();
951  int bestq = -1;
952  MultidimArray<double> bestImg, Iaux;
953  Matrix1D<double> corrList;
954  corrList.resizeNoCopy(Q);
955  CL2DAssignment assignment;
956  bestAssignment.likelihood = bestAssignment.corr = 0;
957  size_t objId = bestAssignment.objId;
958  for (int q = 0; q < Q; q++)
959  {
960  // Check if q is neighbour of the oldnode
961  bool proceed = false;
962  if (oldnode >= 0)
963  {
964  if (oldnode<Q)
965  {
966  int imax = P[oldnode]->neighboursIdx.size();
967  for (int i = 0; i < imax; i++)
968  {
969  if (P[oldnode]->neighboursIdx[i] == q)
970  {
971  proceed = true;
972  break;
973  }
974  }
975  if (!proceed)
976  {
977  double threshold = 3.0 * P[oldnode]->currentListImg.size();
978  threshold = XMIPP_MAX(threshold,1000);
979  threshold = (double) (XMIPP_MIN(threshold,Nimgs)) / Nimgs;
980  proceed = (rnd_unif(0, 1) < threshold);
981  }
982  }
983  else
984  {
985  // In some strange conditions we may loose the reference to its neighbours
986  proceed = true;
987  }
988  }
989  else
990  proceed = true;
991 
992  if (proceed) {
993  // Try this image
994  Iaux = I;
995  P[q]->fit(Iaux, assignment);
996  VEC_ELEM(corrList,q) = assignment.corr;
997 #ifdef DEBUG
998  std::cout << " Proceeding with node " << q << " corr=" << assignment.corr << std::endl;
999 #endif
1000  if ((!prm->classicalMultiref && assignment.likelihood > bestAssignment.likelihood) ||
1001  (prm->classicalMultiref && assignment.corr > bestAssignment.corr) ||
1002  prm->classifyAllImages && bestAssignment.corr==0) {
1003  bestq = q;
1004  bestImg = Iaux;
1005  bestAssignment = assignment;
1006  }
1007  }
1008  }
1009 
1010  I = bestImg;
1011  newnode = bestq;
1012  bestAssignment.objId = objId;
1013 
1014  // Assign it to the new node and remove it from the rest
1015  // of nodes if it was among the best
1016 #ifdef DEBUG
1017  std::cout << " New node=" << newnode << std::endl;
1018 #endif
1019  if (newnode != -1)
1020  {
1021  P[newnode]->updateProjection(I, bestAssignment);
1022  if (!prm->classicalMultiref)
1023  for (int q = 0; q < Q; q++)
1024  if (q != newnode && corrList(q) > 0)
1025  P[q]->updateNonProjection(corrList(q));
1026  }
1027 }
1028 #undef DEBUG
1029 
1031 {
1032  int Q = P.size();
1033  for (int q = 0; q < Q; q++)
1034  P[q]->transferUpdate();
1035 }
1036 
1037 /* Run CL2D ------------------------------------------------------------------ */
1038 //#define DEBUG
1039 void CL2D::run(const FileName &fnODir, const FileName &fnOut, int level)
1040 {
1041  size_t Q = P.size();
1042 
1043  if (prm->node->rank == 1)
1044  std::cout << "Quantizing with " << Q << " codes...\n";
1045 #ifdef DEBUG
1046  Image<double> save;
1047  for (int q=0; q<Q; q++)
1048  {
1049  save()=P[q]->P;
1050  save.write(formatString("PPPclass%04d.xmp",q));
1051  }
1052  std::cout << "Classes written. Press any key" << std::endl;
1053  char c; std::cin >> c;
1054 #endif
1055 
1056  std::vector<int> oldAssignment, newAssignment;
1057 
1058  int iter = 1;
1059  bool goOn = true;
1060  MetaDataVec MDChanges;
1061  Image<double> I;
1062  int progressStep = XMIPP_MAX(1,Nimgs/60);
1063  CL2DAssignment assignment;
1064  FileName fnResultsDir=formatString("%s/level_%02d",fnODir.c_str(),level);
1065  fnResultsDir.makePath(0755);
1066  while (goOn)
1067  {
1068  if (prm->node->rank == 1)
1069  {
1070  std::cout << "Iteration " << iter << " ...\n";
1071  init_progress_bar(Nimgs);
1072  }
1073 
1074  size_t K = std::min((size_t)prm->Nneighbours+1,Q);
1075  if (K == 0)
1076  K = Q;
1077  for (size_t q = 0; q < Q; q++)
1078  P[q]->lookForNeighbours(P, K);
1079 
1080  int node;
1081  double corrSum = 0;
1082  SF->getColumnValues(MDL_REF, oldAssignment);
1083  int *ptrOld = &(oldAssignment[0]);
1084  for (size_t n = 0; n < Nimgs; ++n, ++ptrOld)
1085  *ptrOld -= 1;
1086  SF->fillConstant(MDL_REF, "-1");
1087  size_t idx=0;
1088  for (size_t _ : prm->SF.ids())
1089  {
1090  if ((idx+1)%prm->node->size==prm->node->rank)
1091  {
1092  size_t objId = prm->objId[idx];
1093  readImage(I, objId, false);
1094  LOG(((String)"Processing image: "+I.name()).c_str());
1095 
1096  assignment.objId = objId;
1097  lookNode(I(), oldAssignment[idx], node, assignment);
1098  SF->setValue(MDL_REF, node + 1, objId);
1099  corrSum += assignment.corr;
1100  if (prm->node->rank == 1 && idx % progressStep == 0)
1101  progress_bar(idx);
1102  }
1103  idx++;
1104  }
1105  prm->node->barrierWait();
1106 
1107  // Gather all pieces computed by nodes
1108  MPI_Allreduce(MPI_IN_PLACE, &corrSum, 1, MPI_DOUBLE, MPI_SUM,
1109  MPI_COMM_WORLD);
1110  shareAssignments(true, true, true);
1111 
1112  // Some report
1113  size_t idMdChanges=0;
1114  int finish=0;
1115  if (prm->node->rank == 1)
1116  {
1117  progress_bar(Nimgs);
1118  double avgSimilarity = corrSum / Nimgs;
1119  if (avgSimilarity==0)
1120  {
1121  std::cerr << "The average correlation is 0.0, make sure that the maximum allowed shift is enough\n";
1122 
1123  //MPI_Abort(MPI_COMM_WORLD,ERR_UNCLASSIFIED);
1124  finish=1;
1125  }
1126  std::cout << "\nAverage correlation with input vectors=" << avgSimilarity << std::endl;
1127  idMdChanges = MDChanges.addObject();
1128  MDChanges.setValue(MDL_ITER, iter, idMdChanges);
1129  MDChanges.setValue(MDL_CL2D_SIMILARITY, avgSimilarity, idMdChanges);
1130  }
1131  MPI_Bcast(&finish,1, MPI_INT, 1, MPI_COMM_WORLD);
1132  if (finish)
1133  {
1134  MPI_Finalize();
1135  exit(ERR_UNCLASSIFIED);
1136  }
1137 
1138 
1139  // Count changes
1140  SF->getColumnValues(MDL_REF, newAssignment);
1141  int *ptrNew = &(newAssignment[0]);
1142  for (size_t n = 0; n < Nimgs; ++n, ++ptrNew)
1143  *ptrNew -= 1;
1144  size_t Nchanges = 0;
1145  if (iter > 1)
1146  {
1147  int *ptrNew = &(newAssignment[0]);
1148  ptrOld = &(oldAssignment[0]);
1149  for (size_t n = 0; n < Nimgs; ++n, ++ptrNew, ++ptrOld)
1150  if (*ptrNew != *ptrOld)
1151  ++Nchanges;
1152  }
1153  if (prm->node->rank == 1)
1154  {
1155  FileName fnClasses=formatString("%s/%s_classes.xmd",fnResultsDir.c_str(),fnOut.c_str());
1156  if (iter==1)
1157  {
1159  dummy.write(formatString("classes@%s",fnClasses.c_str()));
1160  }
1161 
1162  std::cout << "Number of assignment changes=" << Nchanges
1163  << std::endl;
1164  MDChanges.setValue(MDL_CL2D_CHANGES, (int)Nchanges, idMdChanges);
1165  MDChanges.write(formatString("info@%s",fnClasses.c_str()),MD_APPEND);
1166  }
1167 
1168  // Check if there are empty nodes
1169  if (Q > 1)
1170  {
1171  bool smallNodes;
1172  do
1173  {
1174  smallNodes = false;
1175  int largestNode = -1, sizeLargestNode = -1, smallNode = -1;
1176  size_t sizeSmallestNode = Nimgs + 1;
1177  for (size_t q = 0; q < Q; q++)
1178  {
1179  if (P[q]->currentListImg.size() < sizeSmallestNode)
1180  {
1181  smallNode = q;
1182  sizeSmallestNode = P[q]->currentListImg.size();
1183  }
1184  if ((int) (P[q]->currentListImg.size()) > sizeLargestNode)
1185  {
1186  sizeLargestNode = P[q]->currentListImg.size();
1187  largestNode = q;
1188  }
1189  }
1190  if (sizeLargestNode==0)
1191  REPORT_ERROR(ERR_UNCLASSIFIED,"All classes are of size 0: normally this happens when images are too noisy");
1192  if (largestNode == -1 || smallNode == -1)
1193  break;
1194  if (sizeSmallestNode < prm->PminSize * Nimgs / Q * 0.01 && sizeSmallestNode<0.25*sizeLargestNode)
1195  {
1196  if (prm->node->rank == 1 && prm->verbose)
1197  std::cout << "Splitting node " << largestNode << " (size=" << sizeLargestNode << ") "
1198  << " by overwriting " << smallNode << " (size=" << sizeSmallestNode << ")" << std::endl;
1199  smallNodes = true;
1200 
1201  // Clear the old assignment of the images in the small node
1202  std::vector<CL2DAssignment> &currentListImgSmall =
1203  P[smallNode]->currentListImg;
1204  size_t iimax = currentListImgSmall.size();
1205  for (size_t ii = 0; ii < iimax; ii++)
1206  SF->setValue(MDL_REF, -1, currentListImgSmall[ii].objId);
1207  delete P[smallNode];
1208 
1209  // Clear the old assignment of the images in the large node
1210  std::vector<CL2DAssignment> &currentListImgLargest =
1211  P[largestNode]->currentListImg;
1212  iimax = currentListImgLargest.size();
1213  for (size_t ii = 0; ii < iimax; ii++)
1214  SF->setValue(MDL_REF, -1,
1215  currentListImgLargest[ii].objId);
1216 
1217  // Now split the largest node
1218  auto *node1 = new CL2DClass();
1219  auto *node2 = new CL2DClass();
1220  std::vector<size_t> splitAssignment;
1221  splitNode(P[largestNode], node1, node2, splitAssignment);
1222  delete P[largestNode];
1223 
1224  // Keep the results of the split
1225  P[largestNode] = node1;
1226  P[smallNode] = node2;
1227  iimax = splitAssignment.size();
1228  for (size_t ii = 0; ii < iimax; ii += 2)
1229  {
1230  if (splitAssignment[ii + 1] == 1)
1231  SF->setValue(MDL_REF, largestNode + 1,
1232  splitAssignment[ii]);
1233  else
1234  SF->setValue(MDL_REF, smallNode + 1,
1235  splitAssignment[ii]);
1236  }
1237  }
1238  }
1239  while (smallNodes);
1240  }
1241 
1242  if (prm->node->rank == 1)
1243  write(fnODir,fnOut,level);
1244 
1245  if ((iter > 1 && Nchanges < 0.005 * Nimgs && Q > 1) || iter >= prm->Niter)
1246  goOn = false;
1247  iter++;
1248  }
1249 
1250  std::sort(P.begin(), P.end(), SDescendingClusterSort());
1251 }
1252 #undef DEBUG
1253 
1254 /* Clean ------------------------------------------------------------------- */
1256 {
1257  int retval = 0;
1258  std::vector<CL2DClass *>::iterator ptr = P.begin();
1259  while (ptr != P.end())
1260  if ((*ptr)->currentListImg.size() == 0)
1261  {
1262  ptr = P.erase(ptr);
1263  retval++;
1264  }
1265  else
1266  ptr++;
1267  return retval;
1268 }
1269 
1270 /* Split ------------------------------------------------------------------- */
1271 //#define DEBUG
1273  std::vector<size_t> &splitAssignment) const
1274 {
1275  const CL2DClass* firstNode=node;
1276  std::vector<CL2DClass *> toDelete;
1277  Matrix1D<int> newAssignment, oldAssignment, firstSplitAssignment;
1278  Image<double> I;
1279  MultidimArray<double> Iaux1, Iaux2, corrList;
1280  MultidimArray<int> idx;
1281  CL2DAssignment assignment, assignment1, assignment2;
1282  CL2DClass *firstSplitNode1 = NULL;
1283  CL2DClass *firstSplitNode2 = NULL;
1284  size_t minAllowedSize = 0;
1285 
1286  bool oldclassicalMultiref = prm->classicalMultiref;
1287  prm->classicalMultiref = false;
1288  bool finish;
1289  bool success = true;
1290  int splitTrials=0;
1291  do
1292  {
1293  minAllowedSize = (size_t)(prm->PminSize/2 * 0.01 * node->currentListImg.size());
1294 
1295  // Sort the currentListImg to make sure that all nodes have the same order
1297 #ifdef DEBUG
1298  std::cout << "Splitting node " << node << "(" << node->currentListImg.size() << ") into " << node1 << " and " << node2 << std::endl;
1299  Image<double> save;
1300  save()=node->P;
1301  save.write("PPPnodeToSplit.xmp");
1302 #endif
1303  finish = true;
1304  node2->neighboursIdx = node1->neighboursIdx = node->neighboursIdx;
1305  node2->P = node1->P = node->P;
1306 
1307  size_t imax = node->currentListImg.size();
1308  if (imax < minAllowedSize)
1309  {
1310  toDelete.push_back(node1);
1311  toDelete.push_back(node2);
1312 #ifdef DEBUG
1313  std::cout << "Pushing to delete " << node1 << std::endl;
1314  std::cout << "Pushing to delete " << node2 << std::endl;
1315 #endif
1316  success = false;
1317  break;
1318  }
1319 
1320  // Compute the corr histogram
1321  if (prm->node->rank == 1 && prm->verbose >= 2)
1322  std::cerr << "Calculating corr distribution at split ..."
1323  << std::endl;
1324  corrList.initZeros(imax);
1325  for (size_t i = 0; i < imax; i++)
1326  {
1327  if ((i + 1) % (prm->node->size) == prm->node->rank)
1328  {
1329  readImage(I, node->currentListImg[i].objId, false);
1330  node->fit(I(), assignment);
1331  A1D_ELEM(corrList,i) = assignment.corr;
1332  }
1333  if (prm->node->rank == 1 && i % 25 == 0 && prm->verbose >= 2)
1334  progress_bar(i);
1335  }
1336  if (prm->node->rank == 1 && prm->verbose >= 2)
1337  progress_bar(imax);
1338  MPI_Allreduce(MPI_IN_PLACE, MULTIDIM_ARRAY(corrList), imax, MPI_DOUBLE,
1339  MPI_MAX, MPI_COMM_WORLD);
1340  newAssignment.initZeros(imax);
1341 
1342  // Compute threshold
1343  corrList.indexSort(idx);
1344  double corrThreshold = corrList(idx(XSIZE(idx)/2)-1);
1345 #ifdef DEBUG
1346  corrList.printStats();
1347  std::cout << " corrThreshold= " << corrThreshold << std::endl;
1348 #endif
1349  if (corrThreshold == 0)
1350  {
1351  if (firstSplitNode1 != NULL)
1352  {
1353  toDelete.push_back(node1);
1354  toDelete.push_back(node2);
1355 #ifdef DEBUG
1356  std::cout << "Pushing to delete " << node1 << std::endl;
1357  std::cout << "Pushing to delete " << node2 << std::endl;
1358 #endif
1359  success = false;
1360  break;
1361  }
1362  else
1363  {
1364  // Split at random
1365  for (size_t i = 0; i < imax; i++)
1366  {
1367  assignment.objId = node->currentListImg[i].objId;
1368  readImage(I, assignment.objId, false);
1369  node->fit(I(), assignment);
1370  if ((i + 1) % 2 == 0)
1371  {
1372  node1->updateProjection(I(), assignment,true);
1373  VEC_ELEM(newAssignment,i) = 1;
1374  node2->updateNonProjection(assignment.corr, true);
1375  }
1376  else
1377  {
1378  node2->updateProjection(I(), assignment,true);
1379  VEC_ELEM(newAssignment,i) = 2;
1380  node1->updateNonProjection(assignment.corr, true);
1381  }
1382  }
1383  node1->transferUpdate();
1384  node2->transferUpdate();
1385 #ifdef DEBUG
1386  std::cout << "Splitting at random " << node1->currentListImg.size() << " " << node2->currentListImg.size() << std::endl;
1387  save()=node1->P;
1388  save.write("PPPnode1.xmp");
1389  save()=node2->P;
1390  save.write("PPPnode2.xmp");
1391  std::cout << "Press any key" << std::endl;
1392  char c; std::cin >> c;
1393 #endif
1394  success = true;
1395  break;
1396  }
1397  }
1398  else
1399  {
1400  // Split according to corr
1401  if (prm->node->rank == 1 && prm->verbose >= 2)
1402  std::cerr << "Splitting by corr threshold ..." << std::endl;
1403  for (size_t i = 0; i < imax; i++)
1404  {
1405  if ((i + 1) % (prm->node->size) == prm->node->rank)
1406  {
1407  assignment.objId = node->currentListImg[i].objId;
1408  readImage(I, assignment.objId, false);
1409  node->fit(I(), assignment);
1410  if (assignment.corr < corrThreshold)
1411  {
1412  node1->updateProjection(I(), assignment);
1413  VEC_ELEM(newAssignment,i) = 1;
1414  node2->updateNonProjection(assignment.corr);
1415  }
1416  else
1417  {
1418  node2->updateProjection(I(), assignment);
1419  VEC_ELEM(newAssignment,i) = 2;
1420  node1->updateNonProjection(assignment.corr);
1421  }
1422  }
1423  if (prm->node->rank == 1 && i % 25 == 0 && prm->verbose >= 2)
1424  progress_bar(i);
1425  }
1426  if (prm->node->rank == 1 && prm->verbose >= 2)
1427  progress_bar(imax);
1428  shareSplitAssignments(newAssignment, node1, node2);
1429  }
1430 
1431 #ifdef DEBUG
1432  std::cout << "After first split Node1: " << node1->currentListImg.size() << " Node2 " << node2->currentListImg.size() << std::endl;
1433  save()=node1->P;
1434  save.write("PPPnode1.xmp");
1435  save()=node2->P;
1436  save.write("PPPnode2.xmp");
1437  std::cout << "Press any key" << std::endl;
1438  char c; std::cin >> c;
1439 #endif
1440 
1441  // Backup the first split in case it fails
1442  if (firstSplitNode1 == NULL)
1443  {
1444 #ifdef DEBUG
1445  std::cout << "Creating backup\n";
1446 #endif
1447  firstSplitAssignment = newAssignment;
1448  firstSplitNode1 = new CL2DClass(*node1);
1449  firstSplitNode2 = new CL2DClass(*node2);
1450  }
1451 
1452  // Split iterations
1453  for (int it = 0; it < prm->Niter; it++)
1454  {
1455  if (prm->node->rank == 1 && prm->verbose >= 2)
1456  {
1457  init_progress_bar(imax);
1458  }
1459 
1460  oldAssignment = newAssignment;
1461  newAssignment.initZeros();
1462  for (size_t i = 0; i < imax; i++)
1463  {
1464  if ((i + 1) % (prm->node->size) == prm->node->rank)
1465  {
1466  // Read image
1467  assignment1.objId = assignment2.objId = assignment.objId
1468  = node->currentListImg[i].objId;
1469  readImage(I, assignment.objId, false);
1470 
1471  Iaux1 = I();
1472  node1->fit(Iaux1, assignment1);
1473  Iaux2 = I();
1474  node2->fit(Iaux2, assignment2);
1475 
1476  //std::cout << "Image " << i << " Likelihood: " << assignment1.likelihood << " " << assignment2.likelihood << std::endl;
1477  //std::cout << "Image " << i << " Corr: " << assignment1.corr << " " << assignment2.corr << std::endl;
1478  if (assignment1.likelihood > assignment2.likelihood && !prm->classicalSplit)
1479  {
1480  node1->updateProjection(Iaux1, assignment1);
1481  VEC_ELEM(newAssignment,i) = 1;
1482  node2->updateNonProjection(assignment2.corr);
1483  //std::cout << "Assigned to 1" << std::endl;
1484  }
1485  else if (assignment2.likelihood > assignment1.likelihood && !prm->classicalSplit)
1486  {
1487  node2->updateProjection(Iaux2, assignment2);
1488  VEC_ELEM(newAssignment,i) = 2;
1489  node1->updateNonProjection(assignment1.corr);
1490  //std::cout << "Assigned to 2" << std::endl;
1491  }
1492  else if (prm->classifyAllImages || prm->classicalSplit)
1493  {
1494  if (assignment1.corr > assignment2.corr)
1495  {
1496  node1->updateProjection(Iaux1, assignment1);
1497  VEC_ELEM(newAssignment,i) = 1;
1498  node2->updateNonProjection(assignment2.corr);
1499  //std::cout << "Assigned to 1" << std::endl;
1500  }
1501  else if (assignment2.corr > assignment1.corr)
1502  {
1503  node2->updateProjection(Iaux2, assignment2);
1504  VEC_ELEM(newAssignment,i) = 2;
1505  node1->updateNonProjection(assignment1.corr);
1506  //std::cout << "Assigned to 2" << std::endl;
1507  }
1508  }
1509  }
1510  if (prm->node->rank == 1 && i % 25 == 0 && prm->verbose >= 2)
1511  progress_bar(i);
1512  }
1513  if (prm->node->rank == 1 && prm->verbose >= 2)
1514  progress_bar(imax);
1515  shareSplitAssignments(newAssignment, node1, node2);
1516 
1517 #ifdef DEBUG
1518  std::cout << "After refinement iteration: " << it << " Node1: " << node1->currentListImg.size() << " Node2 " << node2->currentListImg.size() << std::endl;
1519  save()=node1->P;
1520  save.write("PPPnode1.xmp");
1521  save()=node2->P;
1522  save.write("PPPnode2.xmp");
1523  std::cout << "Press any key" << std::endl;
1524  std::cin >> c;
1525 #endif
1526 
1527  int Nchanges = 0;
1528  FOR_ALL_ELEMENTS_IN_MATRIX1D(newAssignment)
1529  if (newAssignment(i) != oldAssignment(i))
1530  Nchanges++;
1531  if (prm->node->rank == 1 && prm->verbose >= 2)
1532  std::cout << "Number of assignment split changes=" << Nchanges
1533  << std::endl;
1534 
1535  // Check if one of the nodes is too small
1536  if (node1->currentListImg.size() < minAllowedSize
1537  || node2->currentListImg.size() < minAllowedSize
1538  || Nchanges < 0.005 * imax)
1539  break;
1540  }
1541 
1542  if (node1->currentListImg.size() < minAllowedSize && node2->currentListImg.size() < minAllowedSize)
1543  {
1544  if (prm->node->rank == 1 && prm->verbose >= 2)
1545  std::cout << "Removing both nodes, they are too small. Current size: "
1546  << node1->currentListImg.size() << " Minimum allowed: "
1547  << minAllowedSize << "...\n";
1548  if (node1 != node)
1549  delete node1;
1550  if (node2 != node)
1551  delete node2;
1552  success = false;
1553  finish = true;
1554  }
1555  else if (node1->currentListImg.size() < minAllowedSize)
1556  {
1557  if (prm->node->rank == 1 && prm->verbose >= 2)
1558  std::cout << "Removing node1, it's too small "
1559  << node1->currentListImg.size() << " "
1560  << minAllowedSize << "...\n";
1561  if (node1 != node)
1562  delete node1;
1563  node1 = new CL2DClass();
1564  toDelete.push_back(node2);
1565 #ifdef DEBUG
1566  std::cout << "Pushing to delete " << node2 << std::endl;
1567 #endif
1568  node = node2;
1569  node2 = new CL2DClass();
1570  finish = false;
1571  }
1572  else if (node2->currentListImg.size() < minAllowedSize)
1573  {
1574  if (prm->node->rank == 1 && prm->verbose >= 2)
1575  std::cout << "Removing node2, it's too small "
1576  << node2->currentListImg.size() << " "
1577  << minAllowedSize << "...\n";
1578  if (node2 != node)
1579  delete node2;
1580  node2 = new CL2DClass();
1581  toDelete.push_back(node1);
1582 #ifdef DEBUG
1583  std::cout << "Pushing to delete " << node1 << std::endl;
1584 #endif
1585  node = node1;
1586  node1 = new CL2DClass();
1587  finish = false;
1588  }
1589  splitTrials++;
1590  if (splitTrials>=prm->NSplitTrials)
1591  {
1592  success = false;
1593  finish = true;
1594  }
1595  }
1596  while (!finish);
1597  for (size_t i = 0; i < toDelete.size(); i++)
1598  if (toDelete[i] != firstNode)
1599  {
1600 #ifdef DEBUG
1601  std::cout << "deleting from list " << toDelete[i] << std::endl;
1602 #endif
1603  delete toDelete[i];
1604  }
1605 
1606  if (success)
1607  {
1608  for (size_t i = 0; i < node1->currentListImg.size(); i++)
1609  {
1610  splitAssignment.push_back(node1->currentListImg[i].objId);
1611  splitAssignment.push_back(1);
1612  }
1613  for (size_t i = 0; i < node2->currentListImg.size(); i++)
1614  {
1615  splitAssignment.push_back(node2->currentListImg[i].objId);
1616  splitAssignment.push_back(2);
1617  }
1618  delete firstSplitNode1;
1619  delete firstSplitNode2;
1620  }
1621  else
1622  {
1623  node1 = firstSplitNode1;
1624  node2 = firstSplitNode2;
1625  splitAssignment.reserve(VEC_XSIZE(firstSplitAssignment));
1626  FOR_ALL_ELEMENTS_IN_MATRIX1D(firstSplitAssignment)
1627  splitAssignment.push_back(VEC_ELEM(firstSplitAssignment,i));
1628  }
1629  prm->classicalMultiref = oldclassicalMultiref;
1630 }
1631 #undef DEBUG
1632 
1634 {
1635  std::sort(P.begin(), P.end(), SDescendingClusterSort());
1636  int Q = P.size();
1637  P.push_back(new CL2DClass());
1638  P.push_back(new CL2DClass());
1639  std::vector<size_t> splitAssignment;
1640  splitNode(P[0], P[Q], P[Q + 1], splitAssignment);
1641  delete P[0];
1642  P[0] = NULL;
1643  P.erase(P.begin());
1644 }
1645 
1646 /* MPI constructor --------------------------------------------------------- */
1648 {
1649  node = new MpiNode(argc, argv);
1650  if (!node->isMaster())
1651  verbose = 0;
1652 }
1653 
1654 /* Destructor -------------------------------------------------------------- */
1656 {
1657  delete node;
1658 }
1659 
1660 /* VQPrm I/O --------------------------------------------------------------- */
1662 {
1663  fnSel = getParam("-i");
1664  fnOut = getParam("--oroot");
1665  fnODir = getParam("--odir");
1666  fnCodes0 = getParam("--ref0");
1667  Niter = getIntParam("--iter");
1668  Nneighbours = getIntParam("--neigh");
1669  Ncodes0 = getIntParam("--nref0");
1670  Ncodes = getIntParam("--nref");
1671  PminSize = getDoubleParam("--minsize");
1672  String aux;
1673  aux = getParam("--distance");
1674  useCorrelation = aux == "correlation";
1675  classicalMultiref = checkParam("--classicalMultiref");
1676  classicalSplit = checkParam("--classicalSplit");
1677  NSplitTrials = getIntParam("--maxSplitTrials");
1678  maxShift = getDoubleParam("--maxShift");
1679  classifyAllImages = checkParam("--classifyAllImages");
1680  normalizeImages = !checkParam("--dontNormalizeImages");
1681  mirrorImages = !checkParam("--dontMirrorImages");
1682  useThresholdMask = checkParam("--useThresholdMask");
1683  if (useThresholdMask)
1684  threshold=getDoubleParam("--useThresholdMask");
1685  alignImages = !checkParam("--dontAlign");
1686 
1687  prm = this; // FIXME HACK because of the global variable. Solve it properly
1688 }
1689 
1691  if (!verbose)
1692  return;
1693  std::cout << "Input images: " << fnSel << std::endl
1694  << "Output root: " << fnOut << std::endl
1695  << "Output dir: " << fnODir << std::endl
1696  << "Iterations: " << Niter << std::endl
1697  << "CodesSel0: " << fnCodes0 << std::endl
1698  << "Codes0: " << Ncodes0 << std::endl
1699  << "Codes: " << Ncodes << std::endl
1700  << "Neighbours: " << Nneighbours << std::endl
1701  << "Minimum node size: " << PminSize << std::endl
1702  << "Use Correlation: " << useCorrelation << std::endl
1703  << "Classical Multiref: " << classicalMultiref << std::endl
1704  << "Classical Split: " << classicalSplit << std::endl
1705  << "Max. Split trials: " << NSplitTrials << std::endl
1706  << "Maximum shift: " << maxShift << std::endl
1707  << "Classify all images: " << classifyAllImages << std::endl
1708  << "Normalize images: " << normalizeImages << std::endl
1709  << "Mirror images: " << mirrorImages << std::endl
1710  << "Align images: " << alignImages << std::endl
1711  ;
1712  if (useThresholdMask)
1713  std::cout << "Threshold mask: " << threshold << std::endl;
1714 }
1715 
1717 {
1718  addUsageLine("Divide a selfile into the desired number of classes. ");
1719  addUsageLine("+Vector quantization with correntropy and a probabilistic criterion is used for creating the subdivisions.");
1720  addUsageLine("+Correlation and the standard maximum correlation criterion can also be used and normally produce good results.");
1721  addUsageLine("+Correntropy and the probabilistic clustering criterion are recommended for images with very low SNR or cases in which the correlation have clear difficulties to converge.");
1722  addUsageLine("+");
1723  addUsageLine("+The algorithm is fully described in [[http://www.ncbi.nlm.nih.gov/pubmed/20362059][this article]].");
1724  addUsageLine("+");
1725  addUsageLine("+An interesting convergence criterion is the number of images changing classes between iterations. If a low percentage of the image change class, then the clustering is rather stable and clear.");
1726  addUsageLine("+If many images change class, it is likely that there is not enough SNR to determine so many classes. It is recommended to reduce the number of classes");
1727  addSeeAlsoLine("mpi_image_sort");
1728  addParamsLine(" -i <selfile> : Selfile with the input images");
1729  addParamsLine(" [--odir <dir=\".\">] : Output directory");
1730  addParamsLine(" [--oroot <root=class>] : Output rootname, by default, class");
1731  addParamsLine(" [--iter <N=20>] : Number of iterations");
1732  addParamsLine(" [--nref0 <N=2>] : Initial number of code vectors");
1733  addParamsLine("or --ref0 <selfile=\"\"> : Selfile with initial code vectors");
1734  addParamsLine(" [--nref <N=16>] : Final number of code vectors");
1735  addParamsLine(" [--neigh+ <N=4>] : Number of neighbour code vectors");
1736  addParamsLine(" : Set -1 for all");
1737  addParamsLine(" [--minsize+ <N=20>] : Percentage minimum node size");
1738  addParamsLine(" : Let's say that we have 1000 images and we are currently estimating 2 classes.");
1739  addParamsLine(" : On average each class should have about 500 images. ");
1740  addParamsLine(" : If one of the classes drops below 20% (by default) of 500,");
1741  addParamsLine(" : then that class is removed and the remaining class is splitted in two. ");
1742  addParamsLine(" : The same reasoning is applied when the number of classes is 4, but 20% ");
1743  addParamsLine(" : is calculated now on 250 (=1000/4).");
1744  addParamsLine(" [--distance <type=correntropy>] : Distance type");
1745  addParamsLine(" where <type>");
1746  addParamsLine(" correntropy correlation: See CL2D paper for the definition of correntropy");
1747  addParamsLine(" [--classicalMultiref] : Instead of enhanced clustering");
1748  addParamsLine(" [--classicalSplit] : Instead of enhanced clustering at the split iterations");
1749  addParamsLine(" [--maxSplitTrials <n=5>] : Maximum number of trials to split before giving up");
1750  addParamsLine(" [--maxShift <d=10>] : Maximum allowed shift");
1751  addParamsLine(" [--classifyAllImages] : By default, some images may not be classified. Use this option to classify them all.");
1752  addParamsLine(" [--dontNormalizeImages] : By default, input images are normalized to have 0 mean and standard deviation 1");
1753  addParamsLine(" [--dontMirrorImages] : By default, input images are studied unmirrored and mirrored");
1754  addParamsLine(" [--useThresholdMask <t>] : Use a mask to compare images. Remove pixels whose value is smaller or equal t");
1755  addParamsLine(" [--dontAlign] : Do not center the class representatives");
1756  addExampleLine("mpirun -np 3 `which xmipp_mpi_classify_CL2D` -i images.stk --nref 256 --oroot class --odir CL2Dresults --iter 10");
1757 }
1758 
1760 {
1761  if (!useCorrelation)
1762  normalizeImages=false;
1763 
1764  maxShift2 = maxShift * maxShift;
1765 
1766  gaussianInterpolator.initialize(6, 60000, false);
1767 
1768  // Get image dimensions
1769  SF.read(fnSel);
1770  SF.removeDisabled();
1771 
1772  size_t Zdim, Ndim;
1773  getImageSize(SF, Xdim, Ydim, Zdim, Ndim);
1774 
1775  // Prepare the Task distributor
1776  SF.findObjects(objId);
1777  // size_t Nimgs = objId.size();
1778 
1779  // Prepare mask for evaluating the noise outside
1780  mask.resize(prm->Ydim, prm->Xdim);
1781  mask.setXmippOrigin();
1782  BinaryCircularMask(mask, prm->Xdim / 2, INNER_MASK);
1783 
1784  // Read input code vectors if available
1785  std::vector<MultidimArray<double> > codes0;
1786  if (fnCodes0 != "")
1787  {
1788  Image<double> I;
1789  MetaDataVec SFCodes(fnCodes0);
1790 
1791  size_t Xdim0, Ydim0, Zdim0, Ndim0;
1792  getImageSize(SFCodes, Xdim0, Ydim0, Zdim0, Ndim0);
1793  if (Xdim0!=Xdim || Ydim0!=Ydim)
1794  REPORT_ERROR(ERR_MULTIDIM_SIZE,"Input reference and images are not of the same size");
1795 
1796  for (size_t objId : SFCodes.ids())
1797  {
1798  I.readApplyGeo(SFCodes, objId);
1799  I().setXmippOrigin();
1800  codes0.push_back(I());
1801  }
1802  Ncodes0 = codes0.size();
1803  }
1804  vq.initialize(SF, codes0);
1805 }
1806 
1808 {
1809  CREATE_LOG();
1810  show();
1811  produceSideInfo();
1812 
1813  // Run all iterations
1814  int level = 0;
1815  int Q = vq.P.size();
1816  bool originalClassicalMultiref=classicalMultiref;
1817  if (Q==1)
1818  classicalMultiref=true;
1819  vq.run(fnODir, fnOut, level);
1820 
1821  while (Q < Ncodes)
1822  {
1823  if (node->rank == 1)
1824  std::cout << "Spliting nodes ...\n";
1825 
1826  int Nclean = vq.cleanEmptyNodes();
1827  int Nsplits = XMIPP_MIN(Q,Ncodes-Q) + Nclean;
1828 
1829  for (int i = 0; i < Nsplits; i++)
1830  {
1831  vq.splitFirstNode();
1832  if (node->rank == 1)
1833  std::cout << "Currently there are " << vq.P.size() << " nodes"
1834  << std::endl;
1835  }
1836 
1837  Q = vq.P.size();
1838  level++;
1839  classicalMultiref=originalClassicalMultiref || Q==1;
1840  vq.run(fnODir, fnOut, level);
1841  }
1842  if (node->rank == 1)
1843  {
1844  std::sort(vq.P.begin(), vq.P.end(), SDescendingClusterSort());
1845  Q = vq.P.size();
1846  MetaDataDb SFq, SFclassified, SFaux, SFaux2;
1847  for (int q = 0; q < Q; q++)
1848  {
1849  SFq.read(formatString("class%06d_images@%s/level_%02d/%s_classes.xmd",q+1,fnODir.c_str(),level,fnOut.c_str()));
1850  SFq.fillConstant(MDL_REF, integerToString(q + 1));
1851  SFq.fillConstant(MDL_ENABLED, "1");
1852  SFclassified.unionAll(SFq);
1853  }
1854  SFaux = SF;
1855  SFaux.subtraction(SFclassified, MDL_IMAGE);
1856  SFaux.fillConstant(MDL_ENABLED, "-1");
1857  SFaux2.join1(SFclassified, SF, MDL_IMAGE, LEFT);
1858  SFclassified.clear();
1859  SFaux2.unionAll(SFaux);
1860  SFaux.clear();
1861  SFaux.sort(SFaux2, MDL_IMAGE);
1862  SFaux.write(fnODir+"/images.xmd");
1863  }
1864  CLOSE_LOG();
1865 }
size_t size
Definition: xmipp_mpi.h:52
Just to locate unclassified errors.
Definition: xmipp_error.h:192
std::vector< CL2DAssignment > nextListImg
void init_progress_bar(long total)
void subtraction(const MetaDataDb &mdIn, const MDLabel label)
MultidimArray< double > P
bool CL2DAssignmentComparator(const CL2DAssignment &d1, const CL2DAssignment &d2)
void min(Image< double > &op1, const Image< double > &op2)
#define VEC_ELEM(v, i)
Definition: matrix1d.h:245
int Nneighbours
Number of neighbours.
#define XMIPP_MAX(x, y)
Definition: xmipp_macros.h:193
#define SPEED_UP_tempsDouble
Definition: xmipp_macros.h:413
void sort(const MetaDataVec &MDin, const MDLabel sortLabel, bool asc=true, int limit=-1, int offset=0)
void updateProjection(const MultidimArray< double > &I, const CL2DAssignment &assigned, bool force=false)
void transformationMatrix2Parameters2D(const Matrix2D< T > &A, bool &flip, T &scale, T &shiftX, T &shiftY, T &psi)
void write(std::ostream &os, const datablock &db)
Definition: cif2pdb.cpp:3747
double alignImages(const MultidimArray< double > &Iref, const AlignmentTransforms &IrefTransforms, MultidimArray< double > &I, Matrix2D< double > &M, bool wrap, AlignmentAux &aux, CorrelationAux &aux2, RotationalCorrelationAux &aux3)
Definition: filters.cpp:2047
constexpr float INITIAL_ROTATE_THRESHOLD
#define REPORT_ERROR(nerr, ErrormMsg)
Definition: xmipp_error.h:211
int Niter
Number of iterations.
#define FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY2D(m)
#define VEC_XSIZE(m)
Definition: matrix1d.h:77
doublereal * c
#define MULTIDIM_SIZE(v)
void resizeNoCopy(const MultidimArray< T1 > &v)
int NSplitTrials
MaxTrials to split.
Histogram1D histClass
void sqrt(Image< double > &op)
void BinaryCircularMask(MultidimArray< int > &mask, double radius, int mode, double x0, double y0, double z0)
Definition: mask.cpp:193
int Ncodes0
Initial number of code vectors.
void write(const FileName &fnODir, const FileName &fnRoot, int level) const
Write the nodes.
Shift for the image in the X axis (double)
double PminSize
Minimum size of a node.
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)
#define DIRECT_A2D_ELEM(v, i, j)
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)
#define A1D_ELEM(v, i)
void getImageSize(const MetaData &md, size_t &Xdim, size_t &Ydim, size_t &Zdim, size_t &Ndim, MDLabel image_label)
#define MULTIDIM_ARRAY(v)
void inv(Matrix2D< T > &result) const
Definition: matrix2d.cpp:663
Special label to be used when gathering MDs in MpiMetadataPrograms.
const FileName & name() const
double fastCorrentropy(const MultidimArray< double > &x, const MultidimArray< double > &y, double sigma, const GaussianInterpolator &G, const MultidimArray< int > &mask)
Definition: filters.cpp:1244
void write(const FileName &outFile, WriteModeMetaData mode=MD_OVERWRITE) const
void splitNode(CL2DClass *node, CL2DClass *&node1, CL2DClass *&node2, std::vector< size_t > &finalAssignment) const
String integerToString(int I, int _width, char fill_with)
Incorrect MultidimArray size.
Definition: xmipp_error.h:174
void show() const
Show.
glob_prnt iter
virtual IdIteratorProxy< false > ids()
bool classicalMultiref
Classical Multiref.
#define FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY1D(v)
void run(const FileName &fnODir, const FileName &fnOut, int level)
void barrierWait()
Definition: xmipp_mpi.cpp:171
bool classifyAllImages
Clasify all images.
int readApplyGeo(const FileName &name, const MDRow &row, const ApplyGeoParams &params=DefaultApplyGeoParams)
size_t size() const override
#define i
Is this image enabled? (int [-1 or 1])
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
size_t addRow(const MDRow &row) override
void shareAssignments(bool shareAssignment, bool shareUpdates, bool shareNonCorr)
Share assignments.
bool normalizeImages
Normalize input images.
Matrix2D< double > centerImage(MultidimArray< double > &I, CorrelationAux &aux, RotationalCorrelationAux &aux2, int Niter, bool limitShift)
Definition: filters.cpp:3277
void fillConstant(MDLabel label, const String &value) override
#define MAT_ELEM(m, i, j)
Definition: matrix2d.h:116
MultidimArray< double > Pupdate
void threshold(double *phi, unsigned long nvox, double limit)
Definition: lib_vwk.cpp:524
double rnd_unif()
std::vector< size_t > objId
void copyAlignment(const CL2DAssignment &alignment)
Copy alignment.
std::ostream & operator<<(std::ostream &out, const CL2DAssignment &assigned)
Show.
#define FOR_ALL_ELEMENTS_IN_MATRIX1D(v)
Definition: matrix1d.h:72
void fit(MultidimArray< double > &I, CL2DAssignment &result)
#define DIRECT_A1D_ELEM(v, i)
void fitBasic(MultidimArray< double > &I, CL2DAssignment &result, bool reverse=false)
double best_rotation(const Polar< std::complex< double > > &I1, const Polar< std::complex< double > > &I2, RotationalCorrelationAux &aux)
Definition: polar.cpp:212
MpiNode * node
void compute_hist(const MultidimArrayGeneric &array, Histogram1D &hist, int no_steps)
Definition: histogram.cpp:572
std::vector< double > nextNonClassCorr
constexpr double INITIAL_SHIFT_THRESHOLD
bool setValue(const MDObject &mdValueIn, size_t id)
size_t addObject() override
void shareSplitAssignments(Matrix1D< int > &assignment, CL2DClass *node1, CL2DClass *node2) const
Share split assignment.
ProgClassifyCL2D(int argc, char **argv)
MPI constructor.
void setValue(const MDObject &object) override
FileName fnOut
#define M3x3_BY_M3x3(A, B, C)
Definition: matrix2d.h:182
Flip the image? (bool)
void lookNode(MultidimArray< double > &I, int oldnode, int &newnode, CL2DAssignment &bestAssignment)
bool alignImages
Don&#39;t align images.
void lookForNeighbours(const std::vector< CL2DClass *> listP, int K)
Look for K-nearest neighbours.
void transferUpdates()
#define XSIZE(v)
void progress_bar(long rlen)
Number of changes between iterations.
void updateNonProjection(double corr, bool force=false)
void computeDoubleMinMax(double &minval, double &maxval) const
#define FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(v)
void clear() override
Definition: metadata_db.cpp:54
int makePath(mode_t mode=0755) const
double sigma
Noise in the images.
#define DIRECT_MULTIDIM_ELEM(v, n)
bool useCorrelation
Use Correlation instead of Correntropy.
int verbose
Verbosity level.
void write(const FileName &outFile, WriteModeMetaData mode=MD_OVERWRITE) const override
double dummy
void initialize(MetaDataDb &_SF, std::vector< MultidimArray< double > > &_codes0)
Initialize.
void transferUpdate(bool centerReference=true)
Average cross-correlation for the image (double)
void initZeros()
Definition: matrix1d.h:592
void printStats(std::ostream &out=std::cout) const
void sort(struct DCEL_T *dcel)
Definition: sorting.cpp:18
size_t size() const override
#define XMIPP_MIN(x, y)
Definition: xmipp_macros.h:181
void rotation2DMatrix(T ang, Matrix2D< T > &result, bool homogeneous)
#define j
size_t rank
Definition: xmipp_mpi.h:52
#define CREATE_LOG()
template void polarFourierTransform< true >(MultidimArray< double > const &, Polar< double > &, Polar< std::complex< double > > &, bool, int, int, Polar_fftw_plans *&, int)
Class to which the image belongs (int)
void readImage(Image< double > &I, size_t objId, bool applyGeo) const
Read Image.
void sort(MetaDataDb &MDin, const MDLabel sortLabel, bool asc=true, int limit=-1, int offset=0)
Definition: polar.h:67
std::vector< CL2DAssignment > currentListImg
#define MATRIX1D_ARRAY(v)
Definition: matrix1d.h:58
Number of images assigned to the same class as this image.
bool mirrorImages
Mirror.
std::string String
Definition: xmipp_strings.h:34
String formatString(const char *format,...)
bool useThresholdMask
Use threshold mask.
void read(const FileName &inFile, const std::vector< MDLabel > *desiredLabels=NULL, bool decomposeStack=true) override
bool classicalSplit
Use ClassicalCriterion at split.
void resizeNoCopy(int Xdim)
Definition: matrix1d.h:458
template float bestShift(MultidimArray< float > &, float &, float &, const MultidimArray< int > *, int)
void join1(const MetaDataDb &mdInLeft, const MetaDataDb &mdInRight, const MDLabel label, JoinType type=LEFT)
void unionAll(const MetaDataDb &mdIn)
void produceSideInfo()
Produce side info.
~ProgClassifyCL2D()
Destructor.
bool isMaster() const
Definition: xmipp_mpi.cpp:166
#define LOG(msg)
int read(const FileName &name, DataMode datamode=DATA, size_t select_img=ALL_IMAGES, bool mapData=false, int mode=WRITE_READONLY)
constexpr int K
double threshold
Threshold to use.
ProgClassifyCL2D * prm
FILE * _logCL2D
Shift for the image in the Y axis (double)
void initZeros(const MultidimArray< T1 > &op)
std::vector< int > neighboursIdx
MultidimArray< int > mask
Mask for the background.
GaussianInterpolator gaussianInterpolator
Current iteration number (int)
#define CLOSE_LOG()
void splitFirstNode()
int cleanEmptyNodes()
CL2DClass & operator=(const CL2DClass &other)
int * n
Name of an image (std::string)
constexpr float ROTATE_THRESHOLD
Histogram1D histNonClass
constexpr double SHIFT_THRESHOLD
void defineParams()
Usage.
void indexSort(MultidimArray< int > &indx) const
void readAlignment(const Matrix2D< double > &M)
Read alignment parameters.
void initIdentity()
Definition: matrix2d.h:673
#define BAD_OBJID
Definition: metadata_base.h:55
constexpr int INNER_MASK
Definition: mask.h:47
CL2DAssignment()
Empty constructor.