Xmipp  v3.23.11-Nereus
multireference_aligneability.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Authors: Javier Vargas (jvargas@cnb.csic.es) (2016)
3  *
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 
27 #include "validation_nontilt.h"
28 #include <cstdlib>
29 #include <ctime>
30 #include <algorithm>
31 #include <fstream>
32 #include "data/sampling.h"
33 #include "project.h"
34 #include <string>
35 #include "core/metadata_sql.h"
36 
38 {
39  rank=0;
40  Nprocessors=1;
41 }
42 
44 {
45  fnParticles = getParam("-i");
46  fnParticlesRef = getParam("-i2");
47  fnInit = getParam("--volume");
48  fin = getParam("--angles_file");
49  finRef = getParam("--angles_file_ref");
50  fnGallery = getParam("--gallery");
51  fnSym = getParam("--sym");
52  fnDir = getParam("--odir");
53  donNotUseWeights= checkParam("--dontUseWeights");
54  check_mirror = false;
55  check_mirror = checkParam("--check_mirrors");
56 }
57 
59 {
60  addUsageLine("This function takes a volume and a set of projections with orientations. The volume is projected into the set of projection directions defining the "
61  "the reference projections. Thus, using the projections and references, calculation of the particle alignment precision and accuracy is carried out");
62  addParamsLine(" [ -i <md_file> ] : Input metadata with images and their angles to be validated against the volume");
63  addParamsLine(" [ -i2 <md_file> ] : Input metadata of reference particles obtained projecting the volume at the same orientations that the input particles");
64  addParamsLine(" [--volume <md_file=\"\">] : Input volume to be validated");
65  addParamsLine(" [--angles_file <file=\".\">] : Input metadata with particle projections at several orientations from (usually) Significant");
66  addParamsLine(" [--angles_file_ref <file=\".\">] : Input reference metadata with projections and orientations obtained projecting the volume at the several orientations from (usually) Significant");
67  addParamsLine(" [--gallery <file=\".\">] : Reference Gallery of projections ");
68  addParamsLine(" [--sym <symfile=c1>] : Enforce symmetry in projections"); //TODO the input will be two doc files one from the exp and the other from refs
69  addParamsLine(" [--odir <outputDir=\".\">] : Output directory");
70  addParamsLine(" [--check_mirrors] : Correct for mirrors in the alignment precision and accuracy estimation. In this case the precision of the projection axis without direction is computed");
71  addParamsLine(" [--dontUseWeights] : Do not use the particle weigths in the clusterability calculation ");
72 
73 }
74 
76 {
77  //xmipp_multireference_aligneability --volume 1BRD.vol --sym c3 --odir testMultiReference/ --angles_file testMultiReference/angles_iter001_00.xmd --angles_file_ref testMultiReference/gallery_alignment/angles_iter001_00.xmd &
79 
80  MetaDataVec mdOutQ;
81  MetaDataDb mdExp, mdExpSort, mdProj, mdGallery, mdInputParticles, mdInputParticlesRef;
82  size_t maxNImg;
83  FileName fnOutCL, fnOutQ;
84  fnOutCL = fnDir+"/pruned_particles_alignability.xmd";
85  fnOutQ = fnDir+"/validationAlignability.xmd";
86 
87  SL.readSymmetryFile(fnSym.c_str());
88 
89  mdInputParticles.read(fnParticles);
90  mdInputParticlesRef.read(fnParticles);
91  mdProj.read(finRef);
92  mdExp.read(fin);
93  mdGallery.read(fnGallery);
94 
95  mdExpSort.sort(mdExp,MDL_IMAGE_IDX,true,-1,0);
96  size_t sz = mdExp.size();
97  mdExpSort.getValue(MDL_IMAGE_IDX,maxNImg,sz);
98 
99  String expression;
100  MDRowSql row,rowInput,rowInputRef;
101 
102  double validationAlignabilityPrecision, validationAlignabilityAccuracy, validationAlignability, validationMirror;
103  validationAlignabilityPrecision = 0;
104  validationAlignabilityAccuracy = 0;
105  validationAlignability = 0;
106  validationMirror = 0;
107 
108  if (rank==0)
109  init_progress_bar(maxNImg);
110 
111  MetaDataVec tempMdExp, tempMdProj;
112  double sum_w_exp;
113  double sum_w_proj;
114  double sum_noise;
115  double error_mirror_exp;
116  double error_mirror_proj;
117 
118  sum_w_exp = 0;
119  sum_w_proj = 0;
120  sum_noise = 0;
121  error_mirror_exp = 0;
122  error_mirror_proj = 0;
123 
124  expression = formatString("imageIndex == %lu",maxNImg);
125  tempMdExp.importObjects(mdExp, MDExpression(expression));
126  size_t numProjs = tempMdExp.size();
127  tempMdExp.clear();
128 
129  //Noise
130  calc_sumw2(numProjs, sum_noise, mdGallery);
131 
132  double rankPrec = 0.;
133  double rankAccNoMirror = 0.;
134  double rankAccMirror = 0.;
135 
136  double accuracy = 0.;
137  double accuracyRef = 0.;
138  double accuracyMirror = 0.;
139  double accuracyMirrorRef = 0.;
140 
141  FileName imagePath;
142 
143  for (size_t i=0; i<=maxNImg;i++)
144  {
145  if ((i+1)%Nprocessors==rank)
146  {
147  expression = formatString("imageIndex == %lu",i);
148  tempMdExp.importObjects(mdExp, MDExpression(expression));
149  tempMdProj.importObjects(mdProj, MDExpression(expression));
150  mdInputParticles.getRow(rowInput,i+1);
151  mdInputParticles.getRow(rowInputRef,i+1);
152 
153 
154  if ( (tempMdExp.size()==0) || (tempMdProj.size()==0))
155  continue;
156 
157  calc_sumu(tempMdExp, sum_w_exp, error_mirror_exp);
158  calc_sumu(tempMdProj, sum_w_proj, error_mirror_proj);
159 
160  obtainAngularAccuracy(tempMdExp, rowInput, accuracy, accuracyMirror);
161  obtainAngularAccuracy(tempMdProj, rowInputRef, accuracyRef, accuracyMirrorRef);
162 
163 #ifdef DEBUG
164 
165  std::cout << " " << std::endl;
166  std::cout << "accuracy " << accuracy << std::endl;
167  std::cout << "accuracyRef " << accuracyRef << std::endl;
168  std::cout << "accuracy2f " << accuracyRef/accuracy << std::endl;
169 
170 
171 
172 #endif
173 #undef DEBUG
174 
175  rankPrec = 1/(sum_w_proj-sum_noise)*(sum_w_exp-sum_noise);
176  rankAccMirror = 1/(accuracyRef-sum_noise)*(accuracy-sum_noise);
177  rankAccNoMirror = 1/(accuracyMirrorRef-sum_noise)*(accuracyMirror-sum_noise);
178 
179  tempMdExp.getValue(MDL_IMAGE,imagePath,1);
180  rowInput.setValue(MDL_IMAGE,imagePath);
181  rowInput.setValue(MDL_IMAGE_IDX,i);
182  rowInput.setValue(MDL_SCORE_BY_ALIGNABILITY_PRECISION, rankPrec);
183  rowInput.setValue(MDL_SCORE_BY_ALIGNABILITY_ACCURACY, rankAccMirror);
184  rowInput.setValue(MDL_SCORE_BY_MIRROR, rankAccNoMirror);
188  rowInput.setValue(MDL_SCORE_BY_ALIGNABILITY_ACCURACY_REF,accuracyRef);
189  rowInput.setValue(MDL_SCORE_BY_ALIGNABILITY_NOISE,sum_noise);
190 
191  mdPartialParticles.addRow(rowInput);
192 
193  rowInput.clear();
194  rowInputRef.clear();
195  tempMdExp.clear();
196  tempMdProj.clear();
197 
198  if (rank==0)
199  progress_bar(i+1);
200  }
201  }
202 
203  synchronize();
204  gatherResults();
205 
206 
207  if (rank == 0)
208  {
209  mdPartialParticles.write(fnOutCL);
210  row.clear();
211 
212  for (size_t objId : mdPartialParticles.ids())
213  {
216  mdPartialParticles.getValue(MDL_SCORE_BY_MIRROR,rankAccNoMirror,objId);
217 
218  validationAlignabilityPrecision += (rankPrec>0.5);
219  validationAlignabilityAccuracy += (rankAccMirror > 0.5);
220  validationAlignability += ( (rankAccMirror > 0.5) && (rankPrec>0.5));
221  validationMirror += (rankAccNoMirror> 0.5);
222 
223  }
224 
225  validationAlignabilityPrecision /= (maxNImg+1);
226  validationAlignabilityAccuracy /= (maxNImg+1);
227  validationAlignability /= (maxNImg+1);
228  validationMirror /= (maxNImg+1);
229 
231  row.setValue(MDL_WEIGHT_PRECISION_ALIGNABILITY,validationAlignabilityPrecision);
232  row.setValue(MDL_WEIGHT_ACCURACY_ALIGNABILITY,validationAlignabilityAccuracy);
233  row.setValue(MDL_WEIGHT_ALIGNABILITY,validationAlignability);
234  row.setValue(MDL_WEIGHT_PRECISION_MIRROR,validationMirror);
235 
236  mdOutQ.addRow(row);
237  mdOutQ.write(fnOutQ);
238 
239  }
240 
241 }
242 
243 
244 void MultireferenceAligneability::write_projection_file()
245 {
246 
247  String xdim= integerToString(Xdim);
248  String ydim= integerToString(Ydim);
249  FileName filnam=fnDir+"/params";
250  std::ofstream myfile;
251  myfile.open(filnam.c_str());
252  myfile << "# XMIPP_STAR_1 *\n";
253  myfile << "# \n";
254  myfile << "data_block1 \n";
255  myfile << "_dimensions2D '"+xdim+" "+ydim+"' \n";
256  myfile << "_projAngleFile "+fin+" \n";
257  myfile << "_noisePixelLevel '0 0' \n"; //where the variance is the first number and the second one is the mean
258  myfile.close();
259 }
260 
261 void MultireferenceAligneability::calc_sumu(const MetaData & tempMd, double & sum_W, double & mirrorProb)
262 {
263  double a;
264  double rotRef,tiltRef,psiRef, wRef;
265  double rot,tilt,psi;
266  double w2;
267  double W;
268  double sumW;
269 
270  W = 0;
271  sumW = 0;
272  sum_W = 0;
273  mirrorProb = 0;
274 
275  for (size_t objId : tempMd.ids())
276  {
277  tempMd.getValue(MDL_ANGLE_ROT,rotRef,objId);
278  tempMd.getValue(MDL_ANGLE_TILT,tiltRef,objId);
279  tempMd.getValue(MDL_ANGLE_PSI,psiRef,objId);
280  tempMd.getValue(MDL_MAXCC,wRef,objId);
281 
282  for (size_t objId2 : tempMd.ids())
283  {
284  tempMd.getValue(MDL_ANGLE_ROT,rot,objId2);
285  tempMd.getValue(MDL_ANGLE_TILT,tilt,objId2);
286  tempMd.getValue(MDL_ANGLE_PSI,psi,objId2);
287  tempMd.getValue(MDL_MAXCC,w2,objId2);
288 
289 
290 #ifdef DEBUG
291 {
292 
293  std::cout << xx << " " << yy << " " << zz << " " << mirror << std::endl;
294 
295 }
296 #endif
297 #undef DEBUG
298 
299  a = SL.computeDistance(rotRef, tiltRef, psiRef,
300  rot, tilt, psi, true,check_mirror, false);
301 
302  if (donNotUseWeights)
303  {
304  W += a;
305  sumW += 1;
306  }
307 
308  else
309  {
310  W += a*(wRef*w2);
311  sumW += (wRef*w2);
312  }
313  }
314  }
315 
316  sum_W = (W / sumW);
317 
318 #ifdef DEBUG
319 {
320  std::cout << sum_W << std::endl;
321  char c;
322  std::getchar();
323 }
324 #endif
325 #undef DEBUG
326 
327 }
328 
329 void MultireferenceAligneability::calc_sumw(const size_t num, double & sumw)
330 {
331  size_t trials=500;
332  double xRan,yRan,zRan;
333  double x,y;
334  auto * xRanArray = new double[num];
335  auto * yRanArray = new double[num];
336  auto * zRanArray = new double[num];
337 
338  sumw=0;
339 
340  for (size_t n=0; n < trials; n++)
341  {
342  for (size_t nS=0; nS<num; nS++)
343  {
344  /*
345  x = sin(tilt*PI/180)*cos(rot*PI/180);
346  y = sin(tilt*PI/180)*sin(rot*PI/180);
347  z = std::abs(cos(tilt*PI/180));
348  */
349 
350  //http://mathworld.wolfram.com/SpherePointPicking.html
351  x = 2*(double(std::rand())-RAND_MAX/2)/RAND_MAX;
352  y = 2*(double(std::rand())-RAND_MAX/2)/RAND_MAX;
353 
354  while (x*x+y*y >= 1 )
355  {
356  x = 2*(std::rand()-RAND_MAX/2)/RAND_MAX;
357  y = 2*(std::rand()-RAND_MAX/2)/RAND_MAX;
358  }
359 
360  xRan = 2*x*std::sqrt(1-x*x-y*y);
361  yRan = 2*y*std::sqrt(1-x*x-y*y);
362  zRan = std::abs(1-2*(x*x+y*y));
363 
364  xRanArray[nS] = xRan;
365  yRanArray[nS] = yRan;
366  zRanArray[nS] = zRan;
367  }
368 
369  double WRan = 0.;
370  for (size_t nS1=0; nS1<num; nS1++)
371  {
372  double a;
373  for (size_t nS2=0; nS2<num; nS2++)
374  {
375  a = std::abs(std::acos(xRanArray[nS1]*xRanArray[nS2]+yRanArray[nS1]*yRanArray[nS2]+zRanArray[nS1]*zRanArray[nS2]));
376  if (a != 0)
377  WRan += a;
378  }
379  }
380 
381  sumw += WRan;
382  }
383 
384  sumw /= trials;
385  delete[] xRanArray;
386  delete[] yRanArray;
387  delete[] zRanArray;
388 }
389 
390 
391 
392 void MultireferenceAligneability::calc_sumw2(const size_t num, double & sumw, const MetaData & mdGallery)
393 {
394  //In the distance calculation the distance of a point with itself gives no distance.
395  const size_t numGallery= mdGallery.size()+1;
396  const double trials = 500;
397  size_t indx;
398  auto * indxArray = new size_t[numGallery];
399  double sumWRan;
400  auto * rotArray = new double[num];
401  auto * tiltArray = new double[num];
402  auto * psiArray = new double[num];
403  double rot,tilt,psi;
404  sumWRan = 0;
405 
406  if (numGallery < num)
407  REPORT_ERROR(ERR_ARG_INCORRECT, "The gallery size is smaller than the number of orientations per particle. Increase the angular sampling of the gallery");
408 
409  for (size_t n=0; n<trials; n++)
410  {
411  size_t currentIndx = 0;
412 
413  for (size_t i=1; i<numGallery; i++)
414  indxArray[i]=i;
415 
416  while ( currentIndx < num )
417  {
418  indx = (size_t) (double( std::rand())*(numGallery-1))/RAND_MAX+1;
419 
420  while ( (indx == 0) || (indxArray[indx] == -1) )
421  indx = (size_t) (double( std::rand())*(numGallery-1))/RAND_MAX;
422 
423  indxArray[indx] = -1;
424 
425  mdGallery.getValue(MDL_ANGLE_ROT,rot,indx);
426  mdGallery.getValue(MDL_ANGLE_TILT,tilt,indx);
427  mdGallery.getValue(MDL_ANGLE_PSI,psi,indx);
428 
429  rotArray[currentIndx] = rot;
430  tiltArray[currentIndx] = tilt;
431  psiArray[currentIndx] = psi;
432  currentIndx++;
433  }
434 
435 
436 #ifdef DEBUG
437 {
438  for (int var = 0; var < num; var++)
439  {
440  std::cout << rotArray[var] << " " << tiltArray[var] << " " << psiArray[var] << std::endl;
441  }
442 
443  char c;
444  std::getchar();
445 }
446 #endif
447 #undef DEBUG
448 
449  double a = 0;
450  for (size_t nS1=0; nS1<num; nS1++)
451  {
452  for (size_t nS2=0; nS2<num; nS2++)
453  {
454  a += SL.computeDistance(rotArray[nS1],tiltArray[nS1],psiArray[nS1],rotArray[nS2],tiltArray[nS2],psiArray[nS2], true, check_mirror, false);
455  }
456 
457  }
458 
459  sumWRan += a;
460  }
461 
462  sumw = ( sumWRan / (trials*(num-1)*(num-1)) );
463 
464 
465 #ifdef DEBUG
466  std::cout << " " << std::endl;
467  std::cout << " sumw : " << sumw << std::endl;
468  std::cout << " " << std::endl;
469  std::getchar();
470 #endif
471 #undef DEBUG
472 
473  delete[] tiltArray;
474  delete[] rotArray;
475  delete[] psiArray;
476  delete[] indxArray;
477 
478 
479 }
480 
481 void MultireferenceAligneability::obtainAngularAccuracy(const MetaData & tempMd, const MDRow & row, double & accuracy, double & accuracyMirror)
482 {
483  double rot, tilt, psi, w;
484  double rotAux, tiltAux, psiAux;
485  double rotRef, tiltRef, psiRef, wRef;
486  bool mirror;;
487  double sumOfW;
488  double tempAccuracy, tempAccuracyMirror;
489 
490 
491  //First for the reference:
492  row.getValue(MDL_ANGLE_ROT,rotRef);
493  row.getValue(MDL_ANGLE_TILT,tiltRef);
494  row.getValue(MDL_ANGLE_PSI,psiRef);
495  row.getValue(MDL_MAXCC,wRef);
496  row.getValue(MDL_FLIP,mirror);
497 
498  accuracyMirror = 0;
499  accuracy = 0;
500  sumOfW = 0;
501 
502  for (size_t objId : tempMd.ids())
503  {
504  tempMd.getValue(MDL_ANGLE_ROT,rot,objId);
505  tempMd.getValue(MDL_ANGLE_TILT,tilt,objId);
506  tempMd.getValue(MDL_ANGLE_PSI,psi,objId);
507  tempMd.getValue(MDL_MAXCC,w,objId);
508  tempMd.getValue(MDL_FLIP,mirror,objId);
509 
510  rotAux = rot;
511  tiltAux = tilt;
512  psiAux = psi;
513 
514  sumOfW += w;
515 
516 
517 
518 // tempAccuracy = SL.computeDistance(rotRef, tiltRef, psiRef,
519 // rotAux, tiltAux, psiAux, false,true, false);
520 
521 
522  tempAccuracy = SL.computeDistance(rotRef, tiltRef, psiRef,
523  rotAux, tiltAux, psiAux, true, check_mirror, false);
524 
525  tempAccuracyMirror = SL.computeDistance(rotRef, tiltRef, psiRef,
526  rot, tilt, psi, true,true, false);
527 
528  accuracy += tempAccuracy*w;
529  accuracyMirror += tempAccuracyMirror*w;
530 
531 
532 #ifdef DEBUG
533  std::cout << " tempAccuracy : " << " " << tempAccuracy << " " << std::endl;
534  std::cout << " tempAccuracyMirror: " << tempAccuracyMirror << std::endl;
535 
536 #endif
537 #undef DEBUG
538 
539 
540 #ifdef DEBUG
541  std::cout << tilt << " " << rot << " " << std::endl;
542  std::cout << "weight: " << w << " " << "arco: " << tempAccuracy/(w) << " " << std::endl;
543 
544 #endif
545 
546  }
547 
548  accuracy /= sumOfW;
549  accuracyMirror /= sumOfW;
550 
551 #ifdef DEBUG
552  std::cout << " accuracy : " << " " << accuracy << " " << std::endl;
553  std::cout << " accuracyMirror: " << accuracyMirror << std::endl;
554  std::cout << "-------------" << std::endl;
555 
556 
557 #endif
558 #undef DEBUG
559 
560 
561 #ifdef DEBUG
562 
563  std::cout << " " << std::endl;
564  std::cout << accuracy << std::endl;
565  std::cout << "-----------" << std::endl;
566 
567 #endif
568 
569 }
570 
571 
void init_progress_bar(long total)
Rotation angle of an image (double,degrees)
score by alignability (double)
Weight due to Alignability Precision and Accuracy.
Weight due to Alignability Precision.
#define REPORT_ERROR(nerr, ErrormMsg)
Definition: xmipp_error.h:211
score by alignability experimental particles (double)
doublereal * c
Index of an image within a list (size_t)
void clear() override
score by alignability references (double)
void sqrt(Image< double > &op)
bool getValue(MDObject &mdValueOut, size_t id) const override
Tilting angle of an image (double,degrees)
static double * y
int readSymmetryFile(FileName fn_sym, double accuracy=SYM_ACCURACY)
Definition: symmetries.cpp:33
score by alignability (double)
Special label to be used when gathering MDs in MpiMetadataPrograms.
doublereal * w
void abs(Image< double > &op)
void write(const FileName &outFile, WriteModeMetaData mode=MD_OVERWRITE) const
String integerToString(int I, int _width, char fill_with)
virtual IdIteratorProxy< false > ids()
virtual bool getValue(MDObject &mdValueOut, size_t id) const =0
doublereal * x
size_t size() const override
#define i
size_t addRow(const MDRow &row) override
void clear() override
std::unique_ptr< MDRow > getRow(size_t id) override
score by alignability references (double)
double computeDistance(double rot1, double tilt1, double psi1, double &rot2, double &tilt2, double &psi2, bool projdir_mode, bool check_mirrors, bool object_rotation=false, bool write_mirrors=true)
T & getValue(MDLabel label)
const char * getParam(const char *param, int arg=0)
size_t addRow(const MDRow &row) override
void setValue(const MDObject &object) override
Incorrect argument received.
Definition: xmipp_error.h:113
void importObjects(const MetaData &md, const std::vector< size_t > &objectsToAdd, bool doClear=true) override
Flip the image? (bool)
void progress_bar(long rlen)
Maximum cross-correlation for the image (double)
void write(const FileName &outFile, WriteModeMetaData mode=MD_OVERWRITE) const override
virtual size_t size() const =0
score by alignability experimental particles (double)
size_t size() const override
bool getValue(MDObject &mdValueOut, size_t id) const override
score by alignability noise (double)
void sort(MetaDataDb &MDin, const MDLabel sortLabel, bool asc=true, int limit=-1, int offset=0)
score by mirror (double)
std::string String
Definition: xmipp_strings.h:34
double psi(const double x)
String formatString(const char *format,...)
void read(const FileName &inFile, const std::vector< MDLabel > *desiredLabels=NULL, bool decomposeStack=true) override
Weight due to Mirror Precision.
bool checkParam(const char *param)
Weight due to Alignability Accuracy.
void addUsageLine(const char *line, bool verbatim=false)
unsigned int randomize_random_generator()
int * n
Name of an image (std::string)
doublereal * a
void addParamsLine(const String &line)