Xmipp  v3.23.11-Nereus
parallel_forward_art_zernike3d.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  *
3  * Authors: David Herreros Calero dherreros@cnb.csic.es
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 <core/transformations.h>
30 #include <data/projection.h>
31 #include <data/mask.h>
32 #include <numeric>
33 #include "data/cpu.h"
34 #include <fstream>
35 #include <iterator>
36 
37 // Empty constructor =======================================================
39 {
40  resume = false;
41  produces_a_metadata = true;
43  showOptimization = false;
44 }
45 
47 
48 // Read arguments ==========================================================
50 {
52  fnVolR = getParam("--ref");
53  fnMaskRF = getParam("--maskf");
54  fnMaskRB = getParam("--maskb");
55  fnOutDir = getParam("--odir");
56  RmaxDef = getIntParam("--RDef");
57  phaseFlipped = checkParam("--phaseFlipped");
58  useCTF = checkParam("--useCTF");
59  Ts = getDoubleParam("--sampling");
60  L1 = getIntParam("--l1");
61  L2 = getIntParam("--l2");
62  loop_step = getIntParam("--step");
63  useZernike = checkParam("--useZernike");
64  lambda = getDoubleParam("--regularization");
65  resume = checkParam("--resume");
66  niter = getIntParam("--niter");
67  save_iter = getIntParam("--save_iter");
68  sort_last_N = getIntParam("--sort_last");
69  FileName outPath = getParam("-o");
70  outPath = outPath.afterLastOf("/");
71  fnVolO = fnOutDir + "/" + outPath;
72 
73  std::string aux;
74  aux = getParam("--sigma");
75  // Transform string of values separated by white spaces into substrings stored in a vector
76  std::stringstream ss(aux);
77  std::istream_iterator<std::string> begin(ss);
78  std::istream_iterator<std::string> end;
79  std::vector<std::string> vstrings(begin, end);
80  sigma.resize(vstrings.size());
81  std::transform(vstrings.begin(), vstrings.end(), sigma.begin(), [](const std::string& val)
82  {
83  return std::stod(val);
84  });
85 
86  // Parallelization
87  int threads = getIntParam("--thr");
88  if (0 >= threads)
89  {
90  threads = CPU::findCores();
91  }
92  m_threadPool.resize(threads);
93 }
94 
95 // Show ====================================================================
97 {
98  if (!verbose)
99  return;
101  std::cout
102  << "Output directory: " << fnOutDir << std::endl
103  << "Reference volume: " << fnVolR << std::endl
104  << "Forward model mask: " << fnMaskRF << std::endl
105  << "Backward model mask: " << fnMaskRB << std::endl
106  << "Sampling: " << Ts << std::endl
107  << "Max. Radius Deform. " << RmaxDef << std::endl
108  << "Zernike Degree: " << L1 << std::endl
109  << "SH Degree: " << L2 << std::endl
110  << "Step: " << loop_step << std::endl
111  << "Correct CTF: " << useCTF << std::endl
112  << "Correct heretogeneity: " << useZernike << std::endl
113  << "Phase flipped: " << phaseFlipped << std::endl
114  << "Regularization: " << lambda << std::endl
115  << "Number of iterations: " << niter << std::endl
116  << "Save every # iterations: " << save_iter << std::endl;
117 }
118 
119 // usage ===================================================================
121 {
122  addUsageLine("Template-based canonical volume reconstruction through Zernike3D coefficients");
123  defaultComments["-i"].clear();
124  defaultComments["-i"].addComment("Metadata with initial alignment");
125  defaultComments["-o"].clear();
126  defaultComments["-o"].addComment("Refined volume");
128  addParamsLine(" [--ref <volume=\"\">] : Reference volume");
129  addParamsLine(" [--maskf <m=\"\">] : ART forward model reconstruction mask");
130  addParamsLine(" [--maskb <m=\"\">] : ART backward model reconstruction mask");
131  addParamsLine(" [--odir <outputDir=\".\">] : Output directory");
132  addParamsLine(" [--sampling <Ts=1>] : Sampling rate (A/pixel)");
133  addParamsLine(" [--RDef <r=-1>] : Maximum radius of the deformation (px). -1=Half of volume size");
134  addParamsLine(" [--l1 <l1=3>] : Degree Zernike Polynomials=1,2,3,...");
135  addParamsLine(" [--l2 <l2=2>] : Harmonical depth of the deformation=1,2,3,...");
136  addParamsLine(" [--blobr <b=4>] : Blob radius for forward mapping splatting");
137  addParamsLine(" [--step <step=1>] : Voxel index step");
138  addParamsLine(" [--sigma <Matrix1D=\"2\">] : Gaussian sigma");
139  addParamsLine(" [--useZernike] : Correct heterogeneity with Zernike3D coefficients");
140  addParamsLine(" [--useCTF] : Correct CTF during ART reconstruction");
141  addParamsLine(" [--phaseFlipped] : Input images have been phase flipped");
142  addParamsLine(" [--regularization <l=0.01>] : ART regularization weight");
143  addParamsLine(" [--niter <n=1>] : Number of ART iterations");
144  addParamsLine(" [--save_iter <s=0>] : Save intermidiate volume after #save_iter iterations");
145  addParamsLine(" [--sort_last <N=2>] : The algorithm sorts projections in the most orthogonally possible way. ");
146  addParamsLine(" : The most orthogonal way is defined as choosing the projection which maximizes the ");
147  addParamsLine(" : dot product with the N previous inserted projections. Use -1 to sort with all ");
148  addParamsLine(" : previous projections");
149  addParamsLine(" [--resume] : Resume processing");
150  addParamsLine(" [--thr <N=-1>] : Maximal number of the processing CPU threads");
151  addExampleLine("A typical use is:", false);
152  addExampleLine("xmipp_parallel_forward_art_zernike3d -i anglesFromContinuousAssignment.xmd --ref reference.vol -o assigned_anglesAndDeformations.xmd --l1 3 --l2 2");
153 }
154 
156 {
157 
158  // Check that metadata has all information neede
159  if (!getInputMd()->containsLabel(MDL_ANGLE_ROT) ||
160  !getInputMd()->containsLabel(MDL_ANGLE_TILT) ||
161  !getInputMd()->containsLabel(MDL_ANGLE_PSI))
162  {
163  REPORT_ERROR(ERR_MD_MISSINGLABEL, "Input metadata projection angles are missing. Exiting...");
164  }
165 
166  if (fnVolR != "")
167  {
168  V.read(fnVolR);
169  }
170  else
171  {
172  FileName fn_first_image;
173  Image<double> first_image;
174  getInputMd()->getRow(1)->getValue(MDL_IMAGE, fn_first_image);
175  first_image.read(fn_first_image);
176  size_t Xdim_first = XSIZE(first_image());
177  V().initZeros(Xdim_first, Xdim_first, Xdim_first);
178  }
179  V().setXmippOrigin();
180 
181  Xdim = XSIZE(V());
182 
183  p_busy_elem.resize(Xdim*Xdim);
184  for (auto& p : p_busy_elem) {
185  p = std::make_unique<std::atomic<double*>>(nullptr);
186  }
187 
188  w_busy_elem.resize(Xdim*Xdim);
189  for (auto& p : w_busy_elem) {
190  p = std::make_unique<std::atomic<double*>>(nullptr);
191  }
192 
193  Vout().initZeros(V());
194  Vout().setXmippOrigin();
195 
196  if (resume && fnVolO.exists())
197  {
199  }
200  else
201  {
202  Vrefined() = V();
203  }
204  // Vrefined().initZeros(V());
205  Vrefined().setXmippOrigin();
206 
207  if (RmaxDef < 0)
208  RmaxDef = Xdim / 2;
209 
210  // Transformation matrix
211  A.initIdentity(3);
212 
213  // CTF Filter
216  FilterCTF.ctf.enable_CTFnoise = false;
217  FilterCTF.ctf.enable_CTF = true;
218 
219  // Area where Zernike3D basis is computed (and volume is updated)
220  // Read Reference mask if avalaible (otherwise sphere of radius RmaxDef is used)
221  Mask mask;
222  mask.type = BINARY_CIRCULAR_MASK;
223  mask.mode = INNER_MASK;
224  if (fnMaskRF != "")
225  {
226  Image<double> aux;
227  aux.read(fnMaskRF);
228  typeCast(aux(), VRecMaskF);
230  double Rmax2 = RmaxDef * RmaxDef;
231  for (int k = STARTINGZ(VRecMaskF); k <= FINISHINGZ(VRecMaskF); k++)
232  {
233  for (int i = STARTINGY(VRecMaskF); i <= FINISHINGY(VRecMaskF); i++)
234  {
235  for (int j = STARTINGX(VRecMaskF); j <= FINISHINGX(VRecMaskF); j++)
236  {
237  double r2 = k * k + i * i + j * j;
238  if (r2 >= Rmax2)
239  A3D_ELEM(VRecMaskF, k, i, j) = 0;
240  }
241  }
242  }
243  }
244  else
245  {
246  mask.R1 = RmaxDef;
247  mask.generate_mask(V());
248  VRecMaskF = mask.get_binary_mask();
250  }
251 
252 
253  // Mask determining reconstruction area
254  if (fnMaskRB != "")
255  {
256  Image<double> aux;
257  aux.read(fnMaskRB);
258  typeCast(aux(), VRecMaskB);
260  double Rmax2 = RmaxDef * RmaxDef;
261  for (int k = STARTINGZ(VRecMaskB); k <= FINISHINGZ(VRecMaskB); k++)
262  {
263  for (int i = STARTINGY(VRecMaskB); i <= FINISHINGY(VRecMaskB); i++)
264  {
265  for (int j = STARTINGX(VRecMaskB); j <= FINISHINGX(VRecMaskB); j++)
266  {
267  double r2 = k * k + i * i + j * j;
268  if (r2 >= Rmax2)
269  A3D_ELEM(VRecMaskB, k, i, j) = 0;
270  }
271  }
272  }
273  }
274  else
275  {
276  mask.R1 = RmaxDef;
277  mask.generate_mask(V());
278  VRecMaskB = mask.get_binary_mask();
280  }
281 
282  // Init P and W vector of images
283  P.resize(sigma.size());
284  W.resize(sigma.size());
285 
286  // Area Zernike3D in 2D
287  mask.R1 = RmaxDef;
288  mask.generate_mask(XSIZE(V()), XSIZE(V()));
289  mask2D = mask.get_binary_mask();
291 
292  vecSize = 0;
294  fillVectorTerms(L1, L2, vL1, vN, vL2, vM);
295 
296  // createWorkFiles();
297  initX = STARTINGX(Vrefined());
298  endX = FINISHINGX(Vrefined());
299  initY = STARTINGY(Vrefined());
300  endY = FINISHINGY(Vrefined());
301  initZ = STARTINGZ(Vrefined());
302  endZ = FINISHINGZ(Vrefined());
303 
308 }
309 
311 {
312  recoverVol();
313  Vout.write(fnVolO);
314 }
315 
316 // Predict =================================================================
317 void ProgParallelForwardArtZernike3D::processImage(const FileName &fnImg, const FileName &fnImgOut, const MDRow &rowIn, MDRow &rowOut)
318 {
319  flagEnabled = 1;
320 
321  int img_enabled;
322  rowIn.getValue(MDL_ENABLED, img_enabled);
323  if (img_enabled == -1) return;
324 
325  rowIn.getValue(MDL_ANGLE_ROT, rot);
326  rowIn.getValue(MDL_ANGLE_TILT, tilt);
327  rowIn.getValue(MDL_ANGLE_PSI, psi);
328  rowIn.getValueOrDefault(MDL_SHIFT_X, shiftX, 0.0);
329  rowIn.getValueOrDefault(MDL_SHIFT_Y, shiftY, 0.0);
330  std::vector<double> vectortemp;
331  if (useZernike)
332  {
333  rowIn.getValue(MDL_SPH_COEFFICIENTS, vectortemp);
334  std::vector<double> vec(vectortemp.begin(), vectortemp.end());
335  clnm = vec;
336  }
337  rowIn.getValueOrDefault(MDL_FLIP, flip, false);
338 
340  {
341  hasCTF = true;
342  FilterCTF.ctf.readFromMdRow(rowIn, false);
343  FilterCTF.ctf.Tm = Ts;
345  }
346  else
347  hasCTF = false;
348  MAT_ELEM(A, 0, 2) = shiftX;
349  MAT_ELEM(A, 1, 2) = shiftY;
350  MAT_ELEM(A, 0, 0) = 1;
351  MAT_ELEM(A, 0, 1) = 0;
352  MAT_ELEM(A, 1, 0) = 0;
353  MAT_ELEM(A, 1, 1) = 1;
354 
355  if (verbose >= 2)
356  std::cout << "Processing " << fnImg << std::endl;
357 
358  I.read(fnImg);
359  I().setXmippOrigin();
360 
361  // Forward Model
362  artModel<Direction::Forward>();
363 
364  // ART update
365  artModel<Direction::Backward>();
366 }
367 
369 {
370  for (int h = 0; h <= l2; h++)
371  {
372  int numSPH = 2 * h + 1;
373  int count = l1 - h + 1;
374  int numEven = (count >> 1) + (count & 1 && !(h & 1));
375  if (h % 2 == 0)
376  {
377  vecSize += numSPH * numEven;
378  }
379  else
380  {
381  vecSize += numSPH * (l1 - h + 1 - numEven);
382  }
383  }
384 }
385 
388 {
389  int idx = 0;
390  vL1.initZeros(vecSize);
391  vN.initZeros(vecSize);
392  vL2.initZeros(vecSize);
393  vM.initZeros(vecSize);
394  for (int h = 0; h <= l2; h++)
395  {
396  int totalSPH = 2 * h + 1;
397  int aux = std::floor(totalSPH / 2);
398  for (int l = h; l <= l1; l += 2)
399  {
400  for (int m = 0; m < totalSPH; m++)
401  {
402  VEC_ELEM(vL1, idx) = l;
403  VEC_ELEM(vN, idx) = h;
404  VEC_ELEM(vL2, idx) = h;
405  VEC_ELEM(vM, idx) = m - aux;
406  idx++;
407  }
408  }
409  }
410 }
411 
412 void ProgParallelForwardArtZernike3D::splattingAtPos(std::array<double, 2> r, double weight,
414  MultidimArray<double> &mV, double &sg)
415 {
416  int i = round(r[1]);
417  int j = round(r[0]);
418  if (!mP.outside(i, j))
419  {
420  int idy = (i)-STARTINGY(mP);
421  int idx = (j)-STARTINGX(mP);
422  int idn = (idy) * (mP).xdim + (idx);
423  while ((*p_busy_elem[idn]) == &A2D_ELEM(mP, i, j));
424  (*p_busy_elem[idn]).exchange(&A2D_ELEM(mP, i, j));
425  (*w_busy_elem[idn]).exchange(&A2D_ELEM(mW, i, j));
426  A2D_ELEM(mP, i, j) += weight;
427  A2D_ELEM(mW, i, j) += 1.0;
428  (*p_busy_elem[idn]).exchange(nullptr);
429  (*w_busy_elem[idn]).exchange(nullptr);
430  }
431 }
432 
434 {
435  // Find the part of the volume that must be updated
436  auto &mVout = Vout();
437  const auto &mV = Vrefined();
438  mVout.initZeros(mV);
439  mVout = mV;
440 }
441 
442 void ProgParallelForwardArtZernike3D::run()
443 {
444  FileName fnImg, fnImgOut, fullBaseName;
445  getOutputMd().clear(); //this allows multiple runs of the same Program object
446 
447  //Perform particular preprocessing
448  preProcess();
449 
450  startProcessing();
451 
452  sortOrthogonal();
453 
454  if (!oroot.empty())
455  {
456  if (oext.empty())
458  oextBaseName = oext;
459  fullBaseName = oroot.removeFileFormat();
460  baseName = fullBaseName.getBaseName();
461  pathBaseName = fullBaseName.getDir();
462  }
463 
464  size_t objId;
465  size_t objIndex;
466  current_save_iter = 1;
467  num_images = 1;
468  current_image = 1;
470  {
471  std::cout << "Running iteration " << current_iter + 1 << " with lambda=" << lambda << std::endl;
472  objId = 0;
473  objIndex = 0;
474  time_bar_done = 0;
476  {
477  objId = A1D_ELEM(ordered_list, i) + 1;
478  ++objIndex;
479  auto rowIn = getInputMd()->getRow(objId);
480  if (rowIn == nullptr) continue;
481  rowIn->getValue(image_label, fnImg);
482  rowIn->getValue(MDL_ITEM_ID, num_images);
483  if (verbose > 2)
484  std::cout << "Current image ID: " << num_images << std::endl;
485 
486  if (fnImg.empty())
487  break;
488 
489  fnImgOut = fnImg;
490 
491  MDRowVec rowOut;
492 
493  processImage(fnImg, fnImgOut, *rowIn.get(), rowOut);
494 
495  checkPoint();
496  showProgress();
497 
498  // Save refined volume every num_images
499  if (current_save_iter == save_iter && save_iter > 0)
500  {
501  recoverVol();
502  Vout.write(fnVolO.removeAllExtensions() + "_partial.mrc");
503  current_save_iter = 1;
504  }
506  current_image++;
507  }
508  current_image = 1;
509  current_save_iter = 1;
510 
511  recoverVol();
512  Vout.write(fnVolO.removeAllExtensions() + "_iter" + std::to_string(current_iter + 1) + ".mrc");
513  }
514  wait();
515 
516  /* Generate name to save mdOut when output are independent images. It uses as prefix
517  * the dirBaseName in order not overwriting files when repeating same command on
518  * different directories. If baseName is set it is used, otherwise, input name is used.
519  * Then, the suffix _oext is added.*/
520  if (fn_out.empty())
521  {
522  if (!oroot.empty())
523  {
524  if (!baseName.empty())
525  fn_out = findAndReplace(pathBaseName, "/", "_") + baseName + "_" + oextBaseName + ".xmd";
526  else
527  fn_out = findAndReplace(pathBaseName, "/", "_") + fn_in.getBaseName() + "_" + oextBaseName + ".xmd";
528  }
529  else if (input_is_metadata)
530  fn_out = fn_in;
531  }
532 
534 
535  postProcess();
536 
537  /* Reset the default values of the program in case
538  * to be reused.*/
539  init();
540 }
541 
542 void ProgParallelForwardArtZernike3D::sortOrthogonal()
543 {
544  int i, j;
545  size_t numIMG = getInputMd()->size();
546  MultidimArray<short> chosen(numIMG);
547  chosen.initZeros(numIMG);
548  MultidimArray<double> product(numIMG);
549  product.initZeros(numIMG);
550  double min_prod = MAXFLOAT;
551  ;
552  int min_prod_proj = 0;
553  std::vector<double> rot;
554  std::vector<double> tilt;
555  Matrix2D<double> v(numIMG, 3);
556  v.initZeros(numIMG, 3);
557  Matrix2D<double> euler;
560 
561  // Initialization
562  ordered_list.resize(numIMG);
563  for (i = 0; i < numIMG; i++)
564  {
566  // Initially no image is chosen
567  A1D_ELEM(chosen, i) = 0;
568 
569  // Compute the Euler matrix for each image and keep only
570  // the third row of each one
571  Euler_angles2matrix(rot[i], tilt[i], 0., euler);
572  euler.getRow(2, z);
573  v.setRow(i, z);
574  }
575 
576  // Pick first projection as the first one to be presented
577  i = 0;
578  A1D_ELEM(chosen, i) = 1;
579  A1D_ELEM(ordered_list, 0) = i;
580 
581  // Choose the rest of projections
582  std::cout << "Sorting projections orthogonally...\n"
583  << std::endl;
584  Matrix1D<double> rowj, rowi_1, rowi_N_1;
585  for (i = 1; i < numIMG; i++)
586  {
587  // Compute the product of not already chosen vectors with the just
588  // chosen one, and select that which has minimum product
589  min_prod = MAXFLOAT;
590  v.getRow(A1D_ELEM(ordered_list, i - 1), rowi_1);
591  if (sort_last_N != -1 && i > sort_last_N)
592  v.getRow(A1D_ELEM(ordered_list, i - sort_last_N - 1), rowi_N_1);
593  for (j = 0; j < numIMG; j++)
594  {
595  if (!A1D_ELEM(chosen, j))
596  {
597  v.getRow(j, rowj);
598  A1D_ELEM(product, j) += ABS(dotProduct(rowi_1, rowj));
599  if (sort_last_N != -1 && i > sort_last_N)
600  A1D_ELEM(product, j) -= ABS(dotProduct(rowi_N_1, rowj));
601  if (A1D_ELEM(product, j) < min_prod)
602  {
603  min_prod = A1D_ELEM(product, j);
604  min_prod_proj = j;
605  }
606  }
607  }
608 
609  // Store the chosen vector and mark it as chosen
610  A1D_ELEM(ordered_list, i) = min_prod_proj;
611  A1D_ELEM(chosen, min_prod_proj) = 1;
612  }
613 }
614 
615 template <ProgParallelForwardArtZernike3D::Direction DIRECTION>
616 void ProgParallelForwardArtZernike3D::artModel()
617 {
618  if (DIRECTION == Direction::Forward)
619  {
620  Image<double> I_shifted;
621  for (int i=0; i<sigma.size(); i++)
622  {
623  P[i]().initZeros((int)XSIZE(I()), (int)XSIZE(I()));
624  P[i]().setXmippOrigin();
625  W[i]().initZeros((int)XSIZE(I()), (int)XSIZE(I()));
626  W[i]().setXmippOrigin();
627  }
628  Idiff().initZeros((int)XSIZE(I()), (int)XSIZE(I()));
629  Idiff().setXmippOrigin();
630  I_shifted().initZeros((int)XSIZE(I()), (int)XSIZE(I()));
631  I_shifted().setXmippOrigin();
632 
633  if (useZernike)
634  zernikeModel<true, Direction::Forward>();
635  else
636  zernikeModel<false, Direction::Forward>();
637 
638  for (int i=0; i<sigma.size(); i++)
639  {
640  filter.w1=sigma[i];
641  filter2.w1=sigma[i];
642  filter.generateMask(P[i]());
643  filter.applyMaskSpace(P[i]());
644  filter2.generateMask(W[i]());
646  }
647 
648  if (hasCTF)
649  {
650  if (phaseFlipped)
654  }
655  if (flip)
656  {
657  MAT_ELEM(A, 0, 0) *= -1;
658  MAT_ELEM(A, 0, 1) *= -1;
659  MAT_ELEM(A, 0, 2) *= -1;
660  }
661 
663  xmipp_transformation::IS_NOT_INV, xmipp_transformation::DONT_WRAP, 0.);
664 
665  // Compute difference image and divide by weights
666  double error = 0.0;
667  double N = 0.0;
668  const auto &mIsh = I_shifted();
669  auto &mId = Idiff();
670  double c = 1.0;
672  {
673  auto diffVal = A2D_ELEM(mIsh, i, j);
674  double sumMw = 0.0;
675  for (int ids = 0; ids < sigma.size(); ids++)
676  {
677  const auto &mP = P[ids]();
678  const auto &mW = W[ids]();
679  const auto sg = sigma[ids];
680  if (sigma.size() > 1)
681  c = sg * sg;
682  diffVal -= c * A2D_ELEM(mP, i, j);
683  sumMw += c * c * A2D_ELEM(mW, i, j);
684  }
685  if (sumMw > 0.0)
686  {
687  A2D_ELEM(mId, i, j) = lambda * (diffVal) / XMIPP_MAX(sumMw, 1.0);
688  error += (diffVal) * (diffVal);
689  N++;
690  }
691  }
692 
693  if (verbose >= 3)
694  {
695  for (int ids = 0; ids < sigma.size(); ids++)
696  {
697  P[ids].write(fnOutDir + "/PPPtheo_sigma" + std::to_string(sigma[ids]) + ".xmp");
698  W[ids].write(fnOutDir + "/PPPweight_sigma" + std::to_string(sigma[ids]) + ".xmp");
699  }
700  Idiff.write(fnOutDir + "/PPPcorr.xmp");
701  std::cout << "Press any key" << std::endl;
702  char c;
703  std::cin >> c;
704  }
705 
706  // Creo que Carlos no usa un RMSE si no un MSE
707  error = std::sqrt(error / N);
708  if (verbose >= 2)
709  std::cout << "Error for image " << num_images << " (" << current_image << ") in iteration " << current_iter + 1 << " : " << error << std::endl;
710  }
711  else if (DIRECTION == Direction::Backward)
712  {
713  if (useZernike)
714  zernikeModel<true, Direction::Backward>();
715  else
716  zernikeModel<false, Direction::Backward>();
717  }
718 }
719 
720 template <bool USESZERNIKE, ProgParallelForwardArtZernike3D::Direction DIRECTION>
721 void ProgParallelForwardArtZernike3D::zernikeModel()
722 {
723  auto &mV = Vrefined();
724  const auto lastZ = FINISHINGZ(mV);
725  const int step = DIRECTION == Direction::Forward ? loop_step : 1;
726 
727  // Parallelization
728  auto futures = std::vector<std::future<void>>();
729  futures.reserve(mV.zdim);
730  auto routine_forward = [this](int thrId, int k) {
731  forwardModel(k, USESZERNIKE);
732  };
733 
734  auto routine_backward = [this](int thrId, int k) {
735  backwardModel(k, USESZERNIKE);
736  };
737 
738  for (int k = STARTINGZ(mV); k <= lastZ; k += step)
739  {
740  if (DIRECTION == Direction::Forward)
741  futures.emplace_back(m_threadPool.push(routine_forward, k));
742  else if (DIRECTION == Direction::Backward)
743  futures.emplace_back(m_threadPool.push(routine_backward, k));
744  }
745 
746  for (auto &f : futures)
747  {
748  f.get();
749  }
750 }
751 
752 void ProgParallelForwardArtZernike3D::forwardModel(int k, bool usesZernike)
753 {
754  auto &mV = Vrefined();
755  const size_t idxY0 = usesZernike ? (clnm.size() / 3) : 0;
756  const size_t idxZ0 = usesZernike ? (2 * idxY0) : 0;
757  const double RmaxF = usesZernike ? RmaxDef : 0;
758  const double RmaxF2 = usesZernike ? (RmaxF * RmaxF) : 0;
759  const double iRmaxF = usesZernike ? (1.0 / RmaxF) : 0;
760  // Rotation Matrix
761  constexpr size_t matrixSize = 3;
762  const Matrix2D<double> R = [this]()
763  {
764  auto tmp = Matrix2D<double>();
765  tmp.initIdentity(matrixSize);
766  Euler_angles2matrix(rot, tilt, psi, tmp, false);
767  return tmp;
768  }();
769 
770  const auto lastY = FINISHINGY(mV);
771  const auto lastX = FINISHINGX(mV);
772  const int step = loop_step;
773  for (int i = STARTINGY(mV); i <= lastY; i += step)
774  {
775  for (int j = STARTINGX(mV); j <= lastX; j += step)
776  {
777  double gx = 0.0, gy = 0.0, gz = 0.0;
778  if (A3D_ELEM(VRecMaskF, k, i, j) != 0)
779  {
780  int img_idx = 0;
781  if (sigma.size() > 1)
782  {
783  double sigma_mask = A3D_ELEM(VRecMaskF, k, i, j);
784  auto it = find(sigma.begin(), sigma.end(), sigma_mask);
785  img_idx = it - sigma.begin();
786  }
787  auto &mP = P[img_idx]();
788  auto &mW = W[img_idx]();
789  if (usesZernike)
790  {
791  auto k2 = k * k;
792  auto kr = k * iRmaxF;
793  auto k2i2 = k2 + i * i;
794  auto ir = i * iRmaxF;
795  auto r2 = k2i2 + j * j;
796  auto jr = j * iRmaxF;
797  auto rr = sqrt(r2) * iRmaxF;
798  for (size_t idx = 0; idx < idxY0; idx++)
799  {
800  auto l1 = VEC_ELEM(vL1, idx);
801  auto n = VEC_ELEM(vN, idx);
802  auto l2 = VEC_ELEM(vL2, idx);
803  auto m = VEC_ELEM(vM, idx);
804  if (rr > 0 || l2 == 0)
805  {
806  auto zsph = ZernikeSphericalHarmonics(l1, n, l2, m, jr, ir, kr, rr);
807  gx += clnm[idx] * (zsph);
808  gy += clnm[idx + idxY0] * (zsph);
809  gz += clnm[idx + idxZ0] * (zsph);
810  }
811  }
812  }
813 
814  auto r_x = j + gx;
815  auto r_y = i + gy;
816  auto r_z = k + gz;
817 
818  auto pos = std::array<double, 2>{};
819  pos[0] = R.mdata[0] * r_x + R.mdata[1] * r_y + R.mdata[2] * r_z;
820  pos[1] = R.mdata[3] * r_x + R.mdata[4] * r_y + R.mdata[5] * r_z;
821  double voxel_mV = A3D_ELEM(mV, k, i, j);
822  splattingAtPos(pos, voxel_mV, mP, mW, mV, sigma[img_idx]);
823  }
824  }
825  }
826 }
827 
828 void ProgParallelForwardArtZernike3D::backwardModel(int k, bool usesZernike)
829 {
830  auto &mId = Idiff();
831  auto &mV = Vrefined();
832  const size_t idxY0 = usesZernike ? (clnm.size() / 3) : 0;
833  const size_t idxZ0 = usesZernike ? (2 * idxY0) : 0;
834  const double RmaxF = usesZernike ? RmaxDef : 0;
835  const double RmaxF2 = usesZernike ? (RmaxF * RmaxF) : 0;
836  const double iRmaxF = usesZernike ? (1.0 / RmaxF) : 0;
837  // Rotation Matrix
838  constexpr size_t matrixSize = 3;
839  const Matrix2D<double> R = [this]()
840  {
841  auto tmp = Matrix2D<double>();
842  tmp.initIdentity(matrixSize);
843  Euler_angles2matrix(rot, tilt, psi, tmp, false);
844  return tmp;
845  }();
846 
847  const auto lastY = FINISHINGY(mV);
848  const auto lastX = FINISHINGX(mV);
849  const int step = 1;
850  for (int i = STARTINGY(mV); i <= lastY; i += step)
851  {
852  for (int j = STARTINGX(mV); j <= lastX; j += step)
853  {
854  double gx = 0.0, gy = 0.0, gz = 0.0;
855  if (A3D_ELEM(VRecMaskB, k, i, j) != 0)
856  {
857  if (usesZernike)
858  {
859  auto k2 = k * k;
860  auto kr = k * iRmaxF;
861  auto k2i2 = k2 + i * i;
862  auto ir = i * iRmaxF;
863  auto r2 = k2i2 + j * j;
864  auto jr = j * iRmaxF;
865  auto rr = sqrt(r2) * iRmaxF;
866  for (size_t idx = 0; idx < idxY0; idx++)
867  {
868  auto l1 = VEC_ELEM(vL1, idx);
869  auto n = VEC_ELEM(vN, idx);
870  auto l2 = VEC_ELEM(vL2, idx);
871  auto m = VEC_ELEM(vM, idx);
872  if (rr > 0 || l2 == 0)
873  {
874  auto zsph = ZernikeSphericalHarmonics(l1, n, l2, m, jr, ir, kr, rr);
875  gx += clnm[idx] * (zsph);
876  gy += clnm[idx + idxY0] * (zsph);
877  gz += clnm[idx + idxZ0] * (zsph);
878  }
879  }
880  }
881 
882  auto r_x = j + gx;
883  auto r_y = i + gy;
884  auto r_z = k + gz;
885 
886  auto pos_x = R.mdata[0] * r_x + R.mdata[1] * r_y + R.mdata[2] * r_z;
887  auto pos_y = R.mdata[3] * r_x + R.mdata[4] * r_y + R.mdata[5] * r_z;
888  double voxel = mId.interpolatedElement2D(pos_x, pos_y);
889  A3D_ELEM(mV, k, i, j) += voxel;
890  }
891  }
892  }
893 }
Rotation angle of an image (double,degrees)
#define A2D_ELEM(v, i, j)
#define VEC_ELEM(v, i)
Definition: matrix1d.h:245
Defocus U (Angstroms)
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
std::vector< std::unique_ptr< std::atomic< double * > > > w_busy_elem
double getDoubleParam(const char *param, int arg=0)
__host__ __device__ float2 floor(const float2 v)
CTFDescription ctf
#define FINISHINGX(v)
#define CTFINV
#define REPORT_ERROR(nerr, ErrormMsg)
Definition: xmipp_error.h:211
FileName removeFileFormat() const
void Euler_angles2matrix(T alpha, T beta, T gamma, Matrix2D< T > &A, bool homogeneous)
Definition: geometry.cpp:624
doublereal * c
Definition: mask.h:360
auto push(F &&f, Rest &&... rest) -> std::future< decltype(f(0, rest...))>
Definition: ctpl.h:152
void sqrt(Image< double > &op)
std::vector< SelLine >::iterator find(std::vector< SelLine > &text, const std::string &img_name)
Definition: selfile.cpp:553
Tilting angle of an image (double,degrees)
Shift for the image in the X axis (double)
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 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 fillVectorTerms(int l1, int l2, Matrix1D< int > &vL1, Matrix1D< int > &vN, Matrix1D< int > &vL2, Matrix1D< int > &vM)
Zernike and SPH coefficients allocation.
Special label to be used when gathering MDs in MpiMetadataPrograms.
T * mdata
Definition: matrix2d.h:395
Name for the CTF Model (std::string)
FileName removeAllExtensions() const
#define FINISHINGZ(v)
void numCoefficients(int l1, int l2, int &vecSize)
Length of coefficients vector.
static unsigned findCores()
Definition: cpu.h:41
void resize(int nThreads)
Definition: ctpl.h:70
#define STARTINGX(v)
#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
Unique identifier for items inside a list or set (std::size_t)
#define FOR_ALL_ELEMENTS_IN_ARRAY2D(m)
FileName afterLastOf(const String &str) const
bool enable_CTF
Enable CTF part.
Definition: ctf.h:275
#define STARTINGY(v)
#define MAT_ELEM(m, i, j)
Definition: matrix2d.h:116
#define A3D_ELEM(V, k, i, j)
void clear() override
T & getValue(MDLabel label)
~ProgParallelForwardArtZernike3D()
Destructor.
FileName fn_in
Filenames of input and output Metadata.
const char * getParam(const char *param, int arg=0)
#define REALGAUSSIANZ
virtual void wait()
Wait for the distributor to finish.
double * f
double R1
Definition: mask.h:413
Flip the image? (bool)
String findAndReplace(const String &tInput, const String &tFind, const String &tReplace)
#define XSIZE(v)
#define RAISED_COSINE
double Tm
Sampling rate (A/pixel)
Definition: ctf.h:240
Missing expected label.
Definition: xmipp_error.h:158
int type
Definition: mask.h:402
#define ABS(x)
Definition: xmipp_macros.h:142
double z
void addExampleLine(const char *example, bool verbatim=true)
virtual std::unique_ptr< MDRow > getRow(size_t id)=0
void readFromMdRow(const MDRow &row, bool disable_if_not_K=true)
Definition: ctf.cpp:1172
int verbose
Verbosity level.
virtual size_t size() const =0
MDLabel image_label
MDLabel to be used to read/write images, usually will be MDL_IMAGE.
bool exists() const
void initZeros()
Definition: matrix1d.h:592
std::vector< T > getColumnValues(const MDLabel label) const
#define MAXFLOAT
Definition: data_types.h:47
#define j
int m
const T & getValueOrDefault(MDLabel label, const T &def) const
virtual void checkPoint()
For very long programs, it may be needed to write checkpoints.
#define FINISHINGY(v)
void show() const override
#define FOR_ALL_ELEMENTS_IN_ARRAY1D(v)
void generate_mask(bool apply_geo=false)
Definition: mask.cpp:1577
int round(double x)
Definition: ap.cpp:7245
void setRow(size_t i, const Matrix1D< T > &v)
Definition: matrix2d.cpp:910
virtual bool containsLabel(MDLabel label) const =0
T dotProduct(const Matrix1D< T > &v1, const Matrix1D< T > &v2)
Definition: matrix1d.h:1140
void typeCast(const Matrix1D< T1 > &v1, Matrix1D< T2 > &v2)
Definition: matrix1d.h:1227
bool outside(int k, int i, int j) const
#define BINARY_CIRCULAR_MASK
Definition: mask.h:365
double ZernikeSphericalHarmonics(int n, int m, double xr, double yr, double zr, double r)
void produceSideInfo()
Produce Side information.
Definition: ctf.cpp:1392
Deformation coefficients.
void initZeros()
Definition: matrix2d.h:626
String getFileFormat() const
FileName getDir() const
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)
float r2
std::vector< std::unique_ptr< std::atomic< double * > > > p_busy_elem
bool each_image_produces_an_output
Indicate that an output is produced for each image in the input.
std::string to_string(bond_type bondType)
Definition: compound.cpp:43
Shift for the image in the Y axis (double)
void addUsageLine(const char *line, bool verbatim=false)
void initZeros(const MultidimArray< T1 > &op)
bool enable_CTFnoise
Enable CTFnoise part.
Definition: ctf.h:273
const MultidimArray< int > & get_binary_mask() const
Definition: mask.h:707
void processImage(const FileName &fnImg, const FileName &fnImgOut, const MDRow &rowIn, MDRow &rowOut)
#define REALGAUSSIANZ2
int getIntParam(const char *param, int arg=0)
void generateMask(MultidimArray< double > &v)
void getRow(size_t i, Matrix1D< T > &v) const
Definition: matrix2d.cpp:871
bool input_is_metadata
Input is a metadata.
#define STARTINGZ(v)
FileName getBaseName() const
int * n
Name of an image (std::string)
bool produces_a_metadata
Indicate that the unique final output file is a Metadata.
#define LOWPASS
void addParamsLine(const String &line)
int ir
void readParams()
Read argument from command line.
void initIdentity()
Definition: matrix2d.h:673
int mode
Definition: mask.h:407
void applyMaskSpace(MultidimArray< double > &v)
FileName oext
Output extension and root.
std::map< String, CommentList > defaultComments
Definition: xmipp_program.h:83
constexpr int INNER_MASK
Definition: mask.h:47