Xmipp  v3.23.11-Nereus
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 
26 #include "forward_art_zernike3d.h"
27 #include <core/transformations.h>
30 #include <data/projection.h>
31 #include <data/mask.h>
32 #include <numeric>
33 
34 // Empty constructor =======================================================
36 {
37  resume = false;
38  produces_a_metadata = true;
40  showOptimization = false;
41 }
42 
44 
45 // Read arguments ==========================================================
47 {
49  fnVolR = getParam("--ref");
50  fnMaskR = getParam("--mask");
51  fnOutDir = getParam("--odir");
52  RmaxDef = getIntParam("--RDef");
53  phaseFlipped = checkParam("--phaseFlipped");
54  useCTF = checkParam("--useCTF");
55  Ts = getDoubleParam("--sampling");
56  L1 = getIntParam("--l1");
57  L2 = getIntParam("--l2");
58  blob_r = getDoubleParam("--blobr");
59  loop_step = getIntParam("--step");
60  sigma = getDoubleParam("--sigma");
61  useZernike = checkParam("--useZernike");
62  lambda = getDoubleParam("--regularization");
63  resume = checkParam("--resume");
64  niter = getIntParam("--niter");
65  save_iter = getIntParam("--save_iter");
66  sort_last_N = getIntParam("--sort_last");
67  FileName outPath = getParam("-o");
68  outPath = outPath.afterLastOf("/");
69  fnVolO = fnOutDir + "/" + outPath;
70 }
71 
72 // Show ====================================================================
74 {
75  if (!verbose)
76  return;
78  std::cout
79  << "Output directory: " << fnOutDir << std::endl
80  << "Reference volume: " << fnVolR << std::endl
81  << "Reference mask: " << fnMaskR << std::endl
82  << "Sampling: " << Ts << std::endl
83  << "Max. Radius Deform. " << RmaxDef << std::endl
84  << "Zernike Degree: " << L1 << std::endl
85  << "SH Degree: " << L2 << std::endl
86  << "Blob radius: " << blob_r << std::endl
87  << "Step: " << loop_step << std::endl
88  << "Correct CTF: " << useCTF << std::endl
89  << "Correct heretogeneity: " << useZernike << std::endl
90  << "Phase flipped: " << phaseFlipped << std::endl
91  << "Regularization: " << lambda << std::endl
92  << "Number of iterations: " << niter << std::endl
93  << "Save every # iterations: " << save_iter << std::endl;
94 }
95 
96 // usage ===================================================================
98 {
99  addUsageLine("Template-based canonical volume reconstruction through Zernike3D coefficients");
100  defaultComments["-i"].clear();
101  defaultComments["-i"].addComment("Metadata with initial alignment");
102  defaultComments["-o"].clear();
103  defaultComments["-o"].addComment("Refined volume");
105  addParamsLine(" [--ref <volume=\"\">] : Reference volume");
106  addParamsLine(" [--mask <m=\"\">] : Mask reference volume");
107  addParamsLine(" [--odir <outputDir=\".\">] : Output directory");
108  addParamsLine(" [--sampling <Ts=1>] : Sampling rate (A/pixel)");
109  addParamsLine(" [--RDef <r=-1>] : Maximum radius of the deformation (px). -1=Half of volume size");
110  addParamsLine(" [--l1 <l1=3>] : Degree Zernike Polynomials=1,2,3,...");
111  addParamsLine(" [--l2 <l2=2>] : Harmonical depth of the deformation=1,2,3,...");
112  addParamsLine(" [--blobr <b=4>] : Blob radius for forward mapping splatting");
113  addParamsLine(" [--step <step=1>] : Voxel index step");
114  addParamsLine(" [--sigma <step=0.25>] : Gaussian sigma");
115  addParamsLine(" [--useZernike] : Correct heterogeneity with Zernike3D coefficients");
116  addParamsLine(" [--useCTF] : Correct CTF during ART reconstruction");
117  addParamsLine(" [--phaseFlipped] : Input images have been phase flipped");
118  addParamsLine(" [--regularization <l=0.01>] : ART regularization weight");
119  addParamsLine(" [--niter <n=1>] : Number of ART iterations");
120  addParamsLine(" [--save_iter <s=0>] : Save intermidiate volume after #save_iter iterations");
121  addParamsLine(" [--sort_last <N=2>] : The algorithm sorts projections in the most orthogonally possible way. ");
122  addParamsLine(" : The most orthogonal way is defined as choosing the projection which maximizes the ");
123  addParamsLine(" : dot product with the N previous inserted projections. Use -1 to sort with all ");
124  addParamsLine(" : previous projections");
125  addParamsLine(" [--resume] : Resume processing");
126  addExampleLine("A typical use is:", false);
127  addExampleLine("xmipp_forward_art_zernike3d -i anglesFromContinuousAssignment.xmd --ref reference.vol -o assigned_anglesAndDeformations.xmd --l1 3 --l2 2");
128 }
129 
131 {
132 
133  // Check that metadata has all information neede
134  if (!getInputMd()->containsLabel(MDL_ANGLE_ROT) ||
135  !getInputMd()->containsLabel(MDL_ANGLE_TILT) ||
136  !getInputMd()->containsLabel(MDL_ANGLE_PSI))
137  {
138  REPORT_ERROR(ERR_MD_MISSINGLABEL, "Input metadata projection angles are missing. Exiting...");
139  }
140 
141  if (fnVolR != "")
142  {
143  V.read(fnVolR);
144  }
145  else
146  {
147  FileName fn_first_image;
148  Image<double> first_image;
149  getInputMd()->getRow(1)->getValue(MDL_IMAGE, fn_first_image);
150  first_image.read(fn_first_image);
151  size_t Xdim_first = XSIZE(first_image());
152  V().initZeros(Xdim_first, Xdim_first, Xdim_first);
153  }
154  V().setXmippOrigin();
155 
156  Xdim = XSIZE(V());
157 
158  Vout().initZeros(V());
159  Vout().setXmippOrigin();
160 
161  if (resume && fnVolO.exists())
162  {
164  }
165  else
166  {
167  Vrefined() = V();
168  }
169  Vrefined().setXmippOrigin();
170 
171  if (RmaxDef < 0)
172  RmaxDef = Xdim / 2;
173 
174  // Transformation matrix
175  A.initIdentity(3);
176 
177  // CTF Filter
180  FilterCTF.ctf.enable_CTFnoise = false;
181  FilterCTF.ctf.enable_CTF = true;
182 
183  // Area where Zernike3D basis is computed (and volume is updated)
184  // Read Reference mask if avalaible (otherwise sphere of radius RmaxDef is used)
185  Mask mask;
186  mask.type = BINARY_CIRCULAR_MASK;
187  mask.mode = INNER_MASK;
188  if (fnMaskR != "")
189  {
190  Image<double> aux;
191  aux.read(fnMaskR);
192  typeCast(aux(), Vmask);
194  double Rmax2 = RmaxDef * RmaxDef;
195  for (int k = STARTINGZ(Vmask); k <= FINISHINGZ(Vmask); k++)
196  {
197  for (int i = STARTINGY(Vmask); i <= FINISHINGY(Vmask); i++)
198  {
199  for (int j = STARTINGX(Vmask); j <= FINISHINGX(Vmask); j++)
200  {
201  double r2 = k * k + i * i + j * j;
202  if (r2 >= Rmax2)
203  A3D_ELEM(Vmask, k, i, j) = 0;
204  }
205  }
206  }
207  }
208  else
209  {
210  mask.R1 = RmaxDef;
211  mask.generate_mask(V());
212  Vmask = mask.get_binary_mask();
214  }
215 
216  // Area Zernike3D in 2D
217  mask.R1 = RmaxDef;
218  mask.generate_mask(XSIZE(V()), XSIZE(V()));
219  mask2D = mask.get_binary_mask();
221 
222  vecSize = 0;
224  fillVectorTerms(L1, L2, vL1, vN, vL2, vM);
225 
226  // createWorkFiles();
227  initX = STARTINGX(Vrefined());
228  endX = FINISHINGX(Vrefined());
229  initY = STARTINGY(Vrefined());
230  endY = FINISHINGY(Vrefined());
231  initZ = STARTINGZ(Vrefined());
232  endZ = FINISHINGZ(Vrefined());
233 
236  filter.w1=sigma;
239  filter2.w1=sigma;
240 
241  // Blob
242  blob.radius = blob_r; // Blob radius in voxels
243  blob.order = 2; // Order of the Bessel function
244  blob.alpha = 3.6; // Smoothness parameter
245 
246  sigma4 = 2 * sigma;
253 }
254 
256 {
257  recoverVol();
258  Vout.write(fnVolO);
259 }
260 
261 // Predict =================================================================
262 void ProgForwardArtZernike3D::processImage(const FileName &fnImg, const FileName &fnImgOut, const MDRow &rowIn, MDRow &rowOut)
263 {
264  flagEnabled = 1;
265 
266  int img_enabled;
267  rowIn.getValue(MDL_ENABLED, img_enabled);
268  if (img_enabled == -1) return;
269 
270  rowIn.getValue(MDL_ANGLE_ROT, rot);
271  rowIn.getValue(MDL_ANGLE_TILT, tilt);
272  rowIn.getValue(MDL_ANGLE_PSI, psi);
273  rowIn.getValueOrDefault(MDL_SHIFT_X, shiftX, 0.0);
274  rowIn.getValueOrDefault(MDL_SHIFT_Y, shiftY, 0.0);
275  std::vector<double> vectortemp;
276  if (useZernike)
277  {
278  rowIn.getValue(MDL_SPH_COEFFICIENTS, vectortemp);
279  std::vector<double> vec(vectortemp.begin(), vectortemp.end());
280  clnm = vec;
281  }
282  rowIn.getValueOrDefault(MDL_FLIP, flip, false);
283 
285  {
286  hasCTF = true;
287  FilterCTF.ctf.readFromMdRow(rowIn, false);
288  FilterCTF.ctf.Tm = Ts;
290  }
291  else
292  hasCTF = false;
293  MAT_ELEM(A, 0, 2) = shiftX;
294  MAT_ELEM(A, 1, 2) = shiftY;
295  MAT_ELEM(A, 0, 0) = 1;
296  MAT_ELEM(A, 0, 1) = 0;
297  MAT_ELEM(A, 1, 0) = 0;
298  MAT_ELEM(A, 1, 1) = 1;
299 
300  if (verbose >= 2)
301  std::cout << "Processing " << fnImg << std::endl;
302 
303  I.read(fnImg);
304  I().setXmippOrigin();
305 
306  // Forward Model
307  artModel<Direction::Forward>();
308 
309  // ART update
310  artModel<Direction::Backward>();
311 }
312 
314 {
315  for (int h = 0; h <= l2; h++)
316  {
317  int numSPH = 2 * h + 1;
318  int count = l1 - h + 1;
319  int numEven = (count >> 1) + (count & 1 && !(h & 1));
320  if (h % 2 == 0)
321  {
322  vecSize += numSPH * numEven;
323  }
324  else
325  {
326  vecSize += numSPH * (l1 - h + 1 - numEven);
327  }
328  }
329 }
330 
333 {
334  int idx = 0;
335  vL1.initZeros(vecSize);
336  vN.initZeros(vecSize);
337  vL2.initZeros(vecSize);
338  vM.initZeros(vecSize);
339  for (int h = 0; h <= l2; h++)
340  {
341  int totalSPH = 2 * h + 1;
342  int aux = std::floor(totalSPH / 2);
343  for (int l = h; l <= l1; l += 2)
344  {
345  for (int m = 0; m < totalSPH; m++)
346  {
347  VEC_ELEM(vL1, idx) = l;
348  VEC_ELEM(vN, idx) = h;
349  VEC_ELEM(vL2, idx) = h;
350  VEC_ELEM(vM, idx) = m - aux;
351  idx++;
352  }
353  }
354  }
355 }
356 
357 void ProgForwardArtZernike3D::splattingAtPos(std::array<double, 2> r, double weight,
360 {
361  int i = round(r[1]);
362  int j = round(r[0]);
363  if (!mP.outside(i, j))
364  {
365  double m = 1. / loop_step;
366  double a = m * ABS(i - r[1]);
367  double b = m * ABS(j - r[0]);
368  double gw = 1 - a - b + a * b;
369  A2D_ELEM(mP, i, j) += weight * gw;
370  A2D_ELEM(mW, i, j) += gw * gw;
371  }
372 }
373 
374 void ProgForwardArtZernike3D::updateVoxel(std::array<double, 3> r, double &voxel, MultidimArray<double> &mV)
375 {
376  // Find the part of the volume that must be updated
377  double x_pos = r[0];
378  double y_pos = r[1];
379  double z_pos = r[2];
380  double hsigma4 = 1.5 * sqrt(2);
381  double hsigma = sigma / 4;
382  int k0 = XMIPP_MAX(FLOOR(z_pos - hsigma4), STARTINGZ(mV));
383  int kF = XMIPP_MIN(CEIL(z_pos + hsigma4), FINISHINGZ(mV));
384  int i0 = XMIPP_MAX(FLOOR(y_pos - hsigma4), STARTINGY(mV));
385  int iF = XMIPP_MIN(CEIL(y_pos + hsigma4), FINISHINGY(mV));
386  int j0 = XMIPP_MAX(FLOOR(x_pos - hsigma4), STARTINGX(mV));
387  int jF = XMIPP_MIN(CEIL(x_pos + hsigma4), FINISHINGX(mV));
388  auto alpha = blob.alpha;
389  auto order = blob.order;
390  // Perform splatting at this position r
391  // ? Probably we can loop only a quarter of the region and use the symmetry to make this faster?
392  for (int k = k0; k <= kF; k++)
393  {
394  for (int i = i0; i <= iF; i++)
395  {
396  for (int j = j0; j <= jF; j++)
397  {
398  A3D_ELEM(mV, k, i, j) += voxel * gaussian1D(k-z_pos,hsigma)*
399  gaussian1D(i-y_pos,hsigma)*
400  gaussian1D(j-x_pos,hsigma);
401  }
402  }
403  }
404 }
405 
407 {
408  // Find the part of the volume that must be updated
409  auto &mVout = Vout();
410  const auto &mV = Vrefined();
411  mVout.initZeros(mV);
412  mVout = mV;
413 }
414 
415 void ProgForwardArtZernike3D::run()
416 {
417  FileName fnImg, fnImgOut, fullBaseName;
418  getOutputMd().clear(); //this allows multiple runs of the same Program object
419 
420  //Perform particular preprocessing
421  preProcess();
422 
423  startProcessing();
424 
425  sortOrthogonal();
426 
427  if (!oroot.empty())
428  {
429  if (oext.empty())
431  oextBaseName = oext;
432  fullBaseName = oroot.removeFileFormat();
433  baseName = fullBaseName.getBaseName();
434  pathBaseName = fullBaseName.getDir();
435  }
436 
437  size_t objId;
438  size_t objIndex;
439  current_save_iter = 1;
440  num_images = 1;
441  current_image = 1;
443  {
444  std::cout << "Running iteration " << current_iter + 1 << " with lambda=" << lambda << std::endl;
445  objId = 0;
446  objIndex = 0;
447  time_bar_done = 0;
449  {
450  objId = A1D_ELEM(ordered_list, i) + 1;
451  ++objIndex;
452  auto rowIn = getInputMd()->getRow(objId);
453  if (rowIn == nullptr) continue;
454  rowIn->getValue(image_label, fnImg);
455  rowIn->getValue(MDL_ITEM_ID, num_images);
456  if (verbose > 2)
457  std::cout << "Current image ID: " << num_images << std::endl;
458 
459  if (fnImg.empty())
460  break;
461 
462  fnImgOut = fnImg;
463 
464  MDRowVec rowOut;
465 
466  processImage(fnImg, fnImgOut, *rowIn.get(), rowOut);
467 
468  checkPoint();
469  showProgress();
470 
471  // Save refined volume every num_images
472  if (current_save_iter == save_iter && save_iter > 0)
473  {
474  recoverVol();
475  Vout.write(fnVolO.removeAllExtensions() + "_partial.mrc");
476  current_save_iter = 1;
477  }
479  current_image++;
480  }
481  current_image = 1;
482  current_save_iter = 1;
483 
484  recoverVol();
485  Vout.write(fnVolO.removeAllExtensions() + "_iter" + std::to_string(current_iter + 1) + ".mrc");
486 
487  }
488  wait();
489 
490  /* Generate name to save mdOut when output are independent images. It uses as prefix
491  * the dirBaseName in order not overwriting files when repeating same command on
492  * different directories. If baseName is set it is used, otherwise, input name is used.
493  * Then, the suffix _oext is added.*/
494  if (fn_out.empty())
495  {
496  if (!oroot.empty())
497  {
498  if (!baseName.empty())
499  fn_out = findAndReplace(pathBaseName, "/", "_") + baseName + "_" + oextBaseName + ".xmd";
500  else
501  fn_out = findAndReplace(pathBaseName, "/", "_") + fn_in.getBaseName() + "_" + oextBaseName + ".xmd";
502  }
503  else if (input_is_metadata)
504  fn_out = fn_in;
505  }
506 
508 
509  postProcess();
510 
511  /* Reset the default values of the program in case
512  * to be reused.*/
513  init();
514 }
515 
516 void ProgForwardArtZernike3D::sortOrthogonal()
517 {
518  int i, j;
519  size_t numIMG = getInputMd()->size();
520  MultidimArray<short> chosen(numIMG);
521  chosen.initZeros(numIMG);
522  MultidimArray<double> product(numIMG);
523  product.initZeros(numIMG);
524  double min_prod = MAXFLOAT;
525  ;
526  int min_prod_proj = 0;
527  std::vector<double> rot;
528  std::vector<double> tilt;
529  Matrix2D<double> v(numIMG, 3);
530  v.initZeros(numIMG, 3);
531  Matrix2D<double> euler;
534 
535  // Initialization
536  ordered_list.resize(numIMG);
537  for (i = 0; i < numIMG; i++)
538  {
540  // Initially no image is chosen
541  A1D_ELEM(chosen, i) = 0;
542 
543  // Compute the Euler matrix for each image and keep only
544  // the third row of each one
545  Euler_angles2matrix(rot[i], tilt[i], 0., euler);
546  euler.getRow(2, z);
547  v.setRow(i, z);
548  }
549 
550  // Pick first projection as the first one to be presented
551  i = 0;
552  A1D_ELEM(chosen, i) = 1;
553  A1D_ELEM(ordered_list, 0) = i;
554 
555  // Choose the rest of projections
556  std::cout << "Sorting projections orthogonally...\n"
557  << std::endl;
558  Matrix1D<double> rowj, rowi_1, rowi_N_1;
559  for (i = 1; i < numIMG; i++)
560  {
561  // Compute the product of not already chosen vectors with the just
562  // chosen one, and select that which has minimum product
563  min_prod = MAXFLOAT;
564  v.getRow(A1D_ELEM(ordered_list, i - 1), rowi_1);
565  if (sort_last_N != -1 && i > sort_last_N)
566  v.getRow(A1D_ELEM(ordered_list, i - sort_last_N - 1), rowi_N_1);
567  for (j = 0; j < numIMG; j++)
568  {
569  if (!A1D_ELEM(chosen, j))
570  {
571  v.getRow(j, rowj);
572  A1D_ELEM(product, j) += ABS(dotProduct(rowi_1, rowj));
573  if (sort_last_N != -1 && i > sort_last_N)
574  A1D_ELEM(product, j) -= ABS(dotProduct(rowi_N_1, rowj));
575  if (A1D_ELEM(product, j) < min_prod)
576  {
577  min_prod = A1D_ELEM(product, j);
578  min_prod_proj = j;
579  }
580  }
581  }
582 
583  // Store the chosen vector and mark it as chosen
584  A1D_ELEM(ordered_list, i) = min_prod_proj;
585  A1D_ELEM(chosen, min_prod_proj) = 1;
586  }
587 }
588 
589 template <ProgForwardArtZernike3D::Direction DIRECTION>
590 void ProgForwardArtZernike3D::artModel()
591 {
592  if (DIRECTION == Direction::Forward)
593  {
594  Image<double> I_shifted;
595  P().initZeros((int)XSIZE(I()), (int)XSIZE(I()));
596  P().setXmippOrigin();
597  W().initZeros((int)XSIZE(I()), (int)XSIZE(I()));
598  W().setXmippOrigin();
599  Idiff().initZeros((int)XSIZE(I()), (int)XSIZE(I()));
600  Idiff().setXmippOrigin();
601  I_shifted().initZeros((int)XSIZE(I()), (int)XSIZE(I()));
602  I_shifted().setXmippOrigin();
603 
604  if (useZernike)
605  zernikeModel<true, Direction::Forward>();
606  else
607  zernikeModel<false, Direction::Forward>();
608 
609  filter.generateMask(P());
613  if (hasCTF)
614  {
615  // updateCTFImage(defocusU, defocusV, defocusAngle);
616  if (phaseFlipped)
620  }
621  if (flip)
622  {
623  MAT_ELEM(A, 0, 0) *= -1;
624  MAT_ELEM(A, 0, 1) *= -1;
625  MAT_ELEM(A, 0, 2) *= -1;
626  }
627 
629  xmipp_transformation::IS_NOT_INV, xmipp_transformation::DONT_WRAP, 0.);
630 
631  // Compute difference image and divide by weights
632  double error = 0.0;
633  double N = 0.0;
634  const auto &mP = P();
635  const auto &mW = W();
636  const auto &mIsh = I_shifted();
637  auto &mId = Idiff();
639  {
640  if (A2D_ELEM(mW, i, j) > 0)
641  {
642  auto diffVal = A2D_ELEM(mIsh, i, j) - A2D_ELEM(mP, i, j);
643  A2D_ELEM(mId, i, j) = lambda * (diffVal) / XMIPP_MAX(A2D_ELEM(mW, i, j), 1.0);
644  error += (diffVal) * (diffVal);
645  N++;
646  }
647  }
648 
649  if (verbose >= 3)
650  {
651  P.write(fnOutDir + "/PPPtheo.xmp");
652  W.write(fnOutDir + "/PPPweight.xmp");
653  Idiff.write(fnOutDir + "/PPPcorr.xmp");
654  std::cout << "Press any key" << std::endl;
655  char c;
656  std::cin >> c;
657  }
658 
659  // Creo que Carlos no usa un RMSE si no un MSE
660  error = std::sqrt(error / N);
661  if (verbose >= 2)
662  std::cout << "Error for image " << num_images << " (" << current_image << ") in iteration " << current_iter + 1 << " : " << error << std::endl;
663  }
664  else if (DIRECTION == Direction::Backward)
665  {
666  if (useZernike)
667  zernikeModel<true, Direction::Backward>();
668  else
669  zernikeModel<false, Direction::Backward>();
670  }
671 }
672 
673 template <bool USESZERNIKE, ProgForwardArtZernike3D::Direction DIRECTION>
674 void ProgForwardArtZernike3D::zernikeModel()
675 {
676  auto &mId = Idiff();
677  auto &mV = Vrefined();
678  auto &mP = P();
679  auto &mW = W();
680  const size_t idxY0 = USESZERNIKE ? (clnm.size() / 3) : 0;
681  const size_t idxZ0 = USESZERNIKE ? (2 * idxY0) : 0;
682  const double RmaxF = USESZERNIKE ? RmaxDef : 0;
683  const double RmaxF2 = USESZERNIKE ? (RmaxF * RmaxF) : 0;
684  const double iRmaxF = USESZERNIKE ? (1.0 / RmaxF) : 0;
685  // Rotation Matrix
686  constexpr size_t matrixSize = 3;
687  const Matrix2D<double> R = [this]()
688  {
689  auto tmp = Matrix2D<double>();
690  tmp.initIdentity(matrixSize);
691  Euler_angles2matrix(rot, tilt, psi, tmp, false);
692  return tmp;
693  }();
694 
695  const auto lastZ = FINISHINGZ(mV);
696  const auto lastY = FINISHINGY(mV);
697  const auto lastX = FINISHINGX(mV);
698  const int step = DIRECTION == Direction::Forward ? loop_step : 1;
699  // const int step = loop_step;
700 
701  for (int k = STARTINGZ(mV); k <= lastZ; k += step)
702  {
703  for (int i = STARTINGY(mV); i <= lastY; i += step)
704  {
705  for (int j = STARTINGX(mV); j <= lastX; j += step)
706  {
707  double gx = 0.0, gy = 0.0, gz = 0.0;
708  if (A3D_ELEM(Vmask, k, i, j) > 0.01)
709  {
710  if (USESZERNIKE) {
711  auto k2 = k * k;
712  auto kr = k * iRmaxF;
713  auto k2i2 = k2 + i * i;
714  auto ir = i * iRmaxF;
715  auto r2 = k2i2 + j * j;
716  auto jr = j * iRmaxF;
717  auto rr = sqrt(r2) * iRmaxF;
718  for (size_t idx = 0; idx < idxY0; idx++)
719  {
720  auto l1 = VEC_ELEM(vL1, idx);
721  auto n = VEC_ELEM(vN, idx);
722  auto l2 = VEC_ELEM(vL2, idx);
723  auto m = VEC_ELEM(vM, idx);
724  if (rr > 0 || l2 == 0)
725  {
726  auto zsph = ZernikeSphericalHarmonics(l1, n, l2, m, jr, ir, kr, rr);
727  gx += clnm[idx] * (zsph);
728  gy += clnm[idx + idxY0] * (zsph);
729  gz += clnm[idx + idxZ0] * (zsph);
730  }
731  }
732  }
733 
734  auto r_x = j + gx;
735  auto r_y = i + gy;
736  auto r_z = k + gz;
737 
738  if (DIRECTION == Direction::Forward)
739  {
740  auto pos = std::array<double, 2>{};
741  pos[0] = R.mdata[0] * r_x + R.mdata[1] * r_y + R.mdata[2] * r_z;
742  pos[1] = R.mdata[3] * r_x + R.mdata[4] * r_y + R.mdata[5] * r_z;
743  double voxel_mV = A3D_ELEM(mV, k, i, j);
744  splattingAtPos(pos, voxel_mV, mP, mW, mV);
745  }
746  else if (DIRECTION == Direction::Backward)
747  {
748  auto pos_x = R.mdata[0] * r_x + R.mdata[1] * r_y + R.mdata[2] * r_z;
749  auto pos_y = R.mdata[3] * r_x + R.mdata[4] * r_y + R.mdata[5] * r_z;
750  double voxel = mId.interpolatedElement2D(pos_x, pos_y);
751  A3D_ELEM(mV, k, i, j) += voxel;
752  }
753  }
754  }
755  }
756  }
757 }
758 
760 {
761  double m = 1 / sigma;
762  if (0. < x && x < sigma)
763  return m * (sigma - x);
764  else if (-sigma < x && x <= 0.)
765  return m * (sigma + x);
766  else
767  return 0.;
768 }
Matrix1D< double > gaussianProjectionTable
std::vector< double > clnm
void defineParams()
Define parameters.
Rotation angle of an image (double,degrees)
#define A2D_ELEM(v, i, j)
void readParams()
Read argument from command line.
#define VEC_ELEM(v, i)
Definition: matrix1d.h:245
double alpha
Smoothness parameter.
Definition: blobs.h:121
Defocus U (Angstroms)
void processImage(const FileName &fnImg, const FileName &fnImgOut, const MDRow &rowIn, MDRow &rowOut)
void resize(size_t Ndim, size_t Zdim, size_t Ydim, size_t Xdim, bool copy=true)
#define XMIPP_MAX(x, y)
Definition: xmipp_macros.h:193
double 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
void sqrt(Image< double > &op)
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)
~ProgForwardArtZernike3D()
Destructor.
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)
MultidimArray< int > Vmask
#define STARTINGX(v)
doublereal * x
#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)
Matrix1D< double > gaussianProjectionTable2
FileName afterLastOf(const String &str) const
FileName fnOutDir
Output directory.
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
#define FOR_ALL_ELEMENTS_IN_MATRIX1D(v)
Definition: matrix1d.h:72
doublereal * b
T & getValue(MDLabel label)
#define FLOOR(x)
Definition: xmipp_macros.h:240
FileName fn_in
Filenames of input and output Metadata.
const char * getParam(const char *param, int arg=0)
MultidimArray< size_t > ordered_list
#define REALGAUSSIANZ
virtual void wait()
Wait for the distributor to finish.
#define CEIL(x)
Definition: xmipp_macros.h:225
void fillVectorTerms(int l1, int l2, Matrix1D< int > &vL1, Matrix1D< int > &vN, Matrix1D< int > &vL2, Matrix1D< int > &vM)
Zernike and SPH coefficients allocation.
MultidimArray< int > mask2D
double R1
Definition: mask.h:413
Flip the image? (bool)
String findAndReplace(const String &tInput, const String &tFind, const String &tReplace)
void resize(size_t Xdim, bool copy=true)
Definition: matrix1d.h:410
#define XSIZE(v)
ProgForwardArtZernike3D()
Empty constructor.
#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
void numCoefficients(int l1, int l2, int &vecSize)
Length of coefficients vector.
std::vector< T > getColumnValues(const MDLabel label) const
#define XMIPP_MIN(x, y)
Definition: xmipp_macros.h:181
#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.
int order
Derivation order and Bessel function order.
Definition: blobs.h:118
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
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
#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
double radius
Spatial radius in Universal System units.
Definition: blobs.h:115
int * n
Name of an image (std::string)
bool produces_a_metadata
Indicate that the unique final output file is a Metadata.
doublereal * a
#define LOWPASS
void addParamsLine(const String &line)
int ir
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
double gaussian1D(double x, double sigma, double mu)