Xmipp  v3.23.11-Nereus
forward_art_zernike3d_subtomos.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 
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  t1 = getDoubleParam("--t1");
59  t2 = getDoubleParam("--t2");
60  blob_r = getDoubleParam("--blobr");
61  loop_step = getIntParam("--step");
62  sigma = getDoubleParam("--sigma");
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  // fnDone = fnOutDir + "/sphDone.xmd";
70  fnVolO = fnOutDir + "/Refined.vol";
71 }
72 
73 // Show ====================================================================
75 {
76  if (!verbose)
77  return;
79  std::cout
80  << "Output directory: " << fnOutDir << std::endl
81  << "Reference volume: " << fnVolR << std::endl
82  << "Reference mask: " << fnMaskR << std::endl
83  << "Sampling: " << Ts << std::endl
84  << "Max. Radius Deform. " << RmaxDef << std::endl
85  << "Zernike Degree: " << L1 << std::endl
86  << "SH Degree: " << L2 << std::endl
87  << "Blob radius: " << blob_r << std::endl
88  << "Step: " << loop_step << std::endl
89  << "Correct CTF: " << useCTF << std::endl
90  << "Correct heretogeneity: " << useZernike << std::endl
91  << "Phase flipped: " << phaseFlipped << std::endl
92  << "Regularization: " << lambda << std::endl
93  << "Number of iterations: " << niter << std::endl
94  << "Save every # iterations: " << save_iter << std::endl;
95 }
96 
97 // usage ===================================================================
99 {
100  addUsageLine("Template-based canonical volume reconstruction through Zernike3D coefficients");
101  defaultComments["-i"].clear();
102  defaultComments["-i"].addComment("Metadata with initial alignment");
103  defaultComments["-o"].clear();
104  defaultComments["-o"].addComment("Refined volume");
106  addParamsLine(" [--ref <volume=\"\">] : Reference volume");
107  addParamsLine(" [--mask <m=\"\">] : Mask reference volume");
108  addParamsLine(" [--odir <outputDir=\".\">] : Output directory");
109  addParamsLine(" [--sampling <Ts=1>] : Sampling rate (A/pixel)");
110  addParamsLine(" [--RDef <r=-1>] : Maximum radius of the deformation (px). -1=Half of volume size");
111  addParamsLine(" [--l1 <l1=3>] : Degree Zernike Polynomials=1,2,3,...");
112  addParamsLine(" [--l2 <l2=2>] : Harmonical depth of the deformation=1,2,3,...");
113  addParamsLine(" [--blobr <b=4>] : Blob radius for forward mapping splatting");
114  addParamsLine(" [--step <step=1>] : Voxel index step");
115  addParamsLine(" [--sigma <step=0.25>] : Gaussian sigma");
116  addParamsLine(" [--useZernike] : Correct heterogeneity with Zernike3D coefficients");
117  addParamsLine(" [--useCTF] : Correct CTF during ART reconstruction");
118  addParamsLine(" [--phaseFlipped] : Input images have been phase flipped");
119  addParamsLine(" [--regularization <l=0.01>] : ART regularization weight");
120  addParamsLine(" [--niter <n=1>] : Number of ART iterations");
121  addParamsLine(" [--save_iter <s=0>] : Save intermidiate volume after #save_iter iterations");
122  addParamsLine(" [--sort_last <N=2>] : The algorithm sorts projections in the most orthogonally possible way. ");
123  addParamsLine(" : The most orthogonal way is defined as choosing the projection which maximizes the ");
124  addParamsLine(" : dot product with the N previous inserted projections. Use -1 to sort with all ");
125  addParamsLine(" : previous projections");
126  addParamsLine(" [--t1 <t1=-60>] : First tilt angle range");
127  addParamsLine(" [--t2 <t2=60>] : Second tilt angle range");
128  addParamsLine(" [--resume] : Resume processing");
129  addExampleLine("A typical use is:", false);
130  addExampleLine("xmipp_art_zernike3d -i anglesFromContinuousAssignment.xmd --ref reference.vol -o assigned_anglesAndDeformations.xmd --l1 3 --l2 2");
131 }
132 
133 // // Produce side information ================================================
134 // void ProgForwardArtZernike3DSubtomos::createWorkFiles() {
135 // // w_i = 1 / getInputMd()->size();
136 // if (resume && fnDone.exists()) {
137 // MetaDataDb done(fnDone);
138 // done.read(fnDone);
139 // getOutputMd() = done;
140 // auto *candidates = getInputMd();
141 // MetaDataDb toDo(*candidates);
142 // toDo.subtraction(done, MDL_IMAGE);
143 // toDo.write(fnOutDir + "/sphTodo.xmd");
144 // *candidates = toDo;
145 // }
146 // }
147 
149 {
150 
151  // Check that metadata has all information neede
152  if (!getInputMd()->containsLabel(MDL_ANGLE_ROT) ||
153  !getInputMd()->containsLabel(MDL_ANGLE_TILT) ||
154  !getInputMd()->containsLabel(MDL_ANGLE_PSI))
155  {
156  REPORT_ERROR(ERR_MD_MISSINGLABEL, "Input metadata projection angles are missing. Exiting...");
157  }
158 
159  if (fnVolR != "")
160  {
161  V.read(fnVolR);
162  }
163  else
164  {
165  FileName fn_first_image;
166  Image<double> first_image;
167  getInputMd()->getRow(1)->getValue(MDL_IMAGE, fn_first_image);
168  first_image.read(fn_first_image);
169  size_t Xdim_first = XSIZE(first_image());
170  V().initZeros(Xdim_first, Xdim_first, Xdim_first);
171  }
172  V().setXmippOrigin();
173 
174  Xdim = XSIZE(V());
175 
176  Vout().initZeros(V());
177  Vout().setXmippOrigin();
178 
179  if (resume && fnVolO.exists())
180  {
182  }
183  else
184  {
185  Vrefined() = V();
186  }
187  // Vrefined().initZeros(V());
188  Vrefined().setXmippOrigin();
189 
190  if (RmaxDef < 0)
191  RmaxDef = Xdim / 2;
192 
193  // Transformation matrix
194  A.initIdentity(4);
195 
196  // CTF Filter
199  FilterCTF.ctf.enable_CTFnoise = false;
200  FilterCTF.ctf.enable_CTF = true;
201  // FilterCTF.ctf.produceSideInfo();
202 
203  // Area where Zernike3D basis is computed (and volume is updated)
204  // Read Reference mask if avalaible (otherwise sphere of radius RmaxDef is used)
205  Mask mask;
206  mask.type = BINARY_CIRCULAR_MASK;
207  mask.mode = INNER_MASK;
208  if (fnMaskR != "")
209  {
210  Image<double> aux;
211  aux.read(fnMaskR);
212  typeCast(aux(), Vmask);
214  double Rmax2 = RmaxDef * RmaxDef;
215  for (int k = STARTINGZ(Vmask); k <= FINISHINGZ(Vmask); k++)
216  {
217  for (int i = STARTINGY(Vmask); i <= FINISHINGY(Vmask); i++)
218  {
219  for (int j = STARTINGX(Vmask); j <= FINISHINGX(Vmask); j++)
220  {
221  double r2 = k * k + i * i + j * j;
222  if (r2 >= Rmax2)
223  A3D_ELEM(Vmask, k, i, j) = 0;
224  }
225  }
226  }
227  }
228  else
229  {
230  mask.R1 = RmaxDef;
231  mask.generate_mask(V());
232  Vmask = mask.get_binary_mask();
234  }
235 
236  // Area Zernike3D in 2D
237  mask.R1 = RmaxDef;
238  mask.generate_mask(XSIZE(V()), XSIZE(V()));
239  mask2D = mask.get_binary_mask();
241 
242  vecSize = 0;
244  fillVectorTerms(L1, L2, vL1, vN, vL2, vM);
245 
246  // createWorkFiles();
247  initX = STARTINGX(Vrefined());
248  endX = FINISHINGX(Vrefined());
249  initY = STARTINGY(Vrefined());
250  endY = FINISHINGY(Vrefined());
251  initZ = STARTINGZ(Vrefined());
252  endZ = FINISHINGZ(Vrefined());
253 
254  sigma4 = 4 * sigma; // Test 3
255  double size_vg = CEIL(sigma4 * sqrt(2) * 50);
256  gaussian3d.initZeros(size_vg, size_vg, size_vg);
259  A3D_ELEM(gaussian3d, k, i, j) = gaussian1D(sqrt(k*k + i*i + j*j) / 50.0, sigma);
260  gaussian3d *= gaussian1D(0, sigma);
261 
262  // This could also be a valid option, but we need a large volume to enclose the gaussian +
263  // its missing wedge properly. Since the convolution is a linear operator, it is better to apply
264  // it once the volume has been formed by standard gaussians
265  // Needed gaussian dimensions CEIL(sigma4 * 2.5 * 50)
266  // applyMissingWedge(gaussian3d);
267 
269  W() = gaussian3d;
270  FileName fnMask=fnOutDir+"gaussian_mw.mrc";
271  W.write(fnMask);
272 
273 }
274 
276 {
277  // XmippMetadataProgram::finishProcessing();
278  recoverVol();
279  Vout.write(fnVolO);
280 }
281 
282 // Predict =================================================================
283 //#define DEBUG
284 void ProgForwardArtZernike3DSubtomos::processImage(const FileName &fnImg, const FileName &fnImgOut, const MDRow &rowIn, MDRow &rowOut)
285 {
286  flagEnabled = 1;
287 
288  int img_enabled;
289  rowIn.getValue(MDL_ENABLED, img_enabled);
290  if (img_enabled == -1) return;
291 
292  // double auxRot, auxTilt, auxPsi, auxShiftX, auxShiftY;
293  rowIn.getValue(MDL_ANGLE_ROT, rot);
294  rowIn.getValue(MDL_ANGLE_TILT, tilt);
295  rowIn.getValue(MDL_ANGLE_PSI, psi);
296  rowIn.getValueOrDefault(MDL_SHIFT_X, shiftX, 0.0);
297  rowIn.getValueOrDefault(MDL_SHIFT_Y, shiftY, 0.0);
298  rowIn.getValueOrDefault(MDL_SHIFT_Z, shiftZ, 0.0);
299  std::vector<double> vectortemp;
300  if (useZernike)
301  {
302  rowIn.getValue(MDL_SPH_COEFFICIENTS, vectortemp);
303  std::vector<double> vec(vectortemp.begin(), vectortemp.end());
304  clnm = vec;
305  }
306  rowIn.getValueOrDefault(MDL_FLIP, flip, false);
307 
309  {
310  // std::cout << "Applying CTF" << std::endl;
311  hasCTF = true;
312  FilterCTF.ctf.readFromMdRow(rowIn, false);
313  FilterCTF.ctf.Tm = Ts;
315  }
316  else
317  hasCTF = false;
318  MAT_ELEM(A, 0, 3) = shiftX;
319  MAT_ELEM(A, 1, 3) = shiftY;
320  MAT_ELEM(A, 2, 3) = shiftZ;
321  MAT_ELEM(A, 0, 0) = 1;
322  MAT_ELEM(A, 0, 1) = 0;
323  MAT_ELEM(A, 0, 2) = 0;
324  MAT_ELEM(A, 1, 0) = 0;
325  MAT_ELEM(A, 1, 1) = 1;
326  MAT_ELEM(A, 1, 2) = 0;
327  MAT_ELEM(A, 2, 0) = 0;
328  MAT_ELEM(A, 2, 1) = 0;
329  MAT_ELEM(A, 2, 2) = 1;
330 
331 
332  if (verbose >= 2)
333  std::cout << "Processing " << fnImg << std::endl;
334 
335  I.read(fnImg);
336  I().setXmippOrigin();
337 
338  // Forward Model
339  artModel<Direction::Forward>();
340  // forwardModel();
341 
342  // ART update
343  artModel<Direction::Backward>();
344  // updateART();
345 }
346 #undef DEBUG
347 
348 // void ProgForwardArtZernike3DSubtomos::checkPoint() {
349 // getOutputMd().write(fnDone);
350 // // Vrefined.write(fnVolO);
351 // }
352 
354 {
355  for (int h = 0; h <= l2; h++)
356  {
357  int numSPH = 2 * h + 1;
358  int count = l1 - h + 1;
359  int numEven = (count >> 1) + (count & 1 && !(h & 1));
360  if (h % 2 == 0)
361  {
362  vecSize += numSPH * numEven;
363  }
364  else
365  {
366  vecSize += numSPH * (l1 - h + 1 - numEven);
367  }
368  }
369 }
370 
373 {
374  int idx = 0;
375  vL1.initZeros(vecSize);
376  vN.initZeros(vecSize);
377  vL2.initZeros(vecSize);
378  vM.initZeros(vecSize);
379  for (int h = 0; h <= l2; h++)
380  {
381  int totalSPH = 2 * h + 1;
382  int aux = std::floor(totalSPH / 2);
383  for (int l = h; l <= l1; l += 2)
384  {
385  for (int m = 0; m < totalSPH; m++)
386  {
387  VEC_ELEM(vL1, idx) = l;
388  VEC_ELEM(vN, idx) = h;
389  VEC_ELEM(vL2, idx) = h;
390  VEC_ELEM(vM, idx) = m - aux;
391  idx++;
392  }
393  }
394  }
395 }
396 
397 // void ProgForwardArtZernike3DSubtomos::updateCTFImage(double defocusU, double defocusV, double angle)
398 // {
399 // ctf.K=1; // get pure CTF with no envelope
400 // ctf.produceSideInfo();
401 // }
402 
403 void ProgForwardArtZernike3DSubtomos::splattingAtPos(std::array<double, 3> r, double weight,
406 {
407 // Find the part of the volume that must be updated
408  double x_pos = r[0];
409  double y_pos = r[1];
410  double z_pos = r[2];
411  auto &mG = gaussian3d;
412  int k0 = XMIPP_MAX(FLOOR(z_pos - sigma4), STARTINGZ(mV));
413  int kF = XMIPP_MIN(CEIL(z_pos + sigma4), FINISHINGZ(mV));
414  int i0 = XMIPP_MAX(FLOOR(y_pos - sigma4), STARTINGY(mV));
415  int iF = XMIPP_MIN(CEIL(y_pos + sigma4), FINISHINGY(mV));
416  int j0 = XMIPP_MAX(FLOOR(x_pos - sigma4), STARTINGX(mV));
417  int jF = XMIPP_MIN(CEIL(x_pos + sigma4), FINISHINGX(mV));
418  for (int k = k0; k <= kF; k++)
419  {
420  int k_int = ROUND(50 * (k - z_pos));
421  for (int i = i0; i <= iF; i++)
422  {
423  int i_int = ROUND(50 * (i - y_pos));
424  for (int j = j0; j <= jF; j++)
425  {
426  // double mod = sqrt((x_pos - j) * (x_pos - j) + y2 + k2);
427  // // A3D_ELEM(Vdeformed(),k, i, j) += weight * blob_val(rdiff.module(), blob);
428  // A3D_ELEM(mP, k, i, j) += weight * kaiser_value(mod, blob.radius, blob.alpha, blob.order);
429  int j_int = ROUND(50 * (j - x_pos));
430  if (!gaussian3d.outside(k_int, i_int, j_int))
431  {
432  double gw = A3D_ELEM(mG, k_int, i_int, j_int);
433  A3D_ELEM(mP, k, i, j) += weight * gw;
434  A3D_ELEM(mW, k, i, j) += gw * gw;
435  }
436  }
437  }
438  }
439 }
440 
441 void ProgForwardArtZernike3DSubtomos::updateVoxel(std::array<double, 3> r, double &voxel, MultidimArray<double> &mV)
442 {
443  // Find the part of the volume that must be updated
444  double x_pos = r[0];
445  double y_pos = r[1];
446  double z_pos = r[2];
447  double hsigma4 = 4 * sqrt(2); // 1.5 * sqrt(2)
448  double hsigma = 1; // 1.5 / 4
449  int k0 = XMIPP_MAX(FLOOR(z_pos - hsigma4), STARTINGZ(mV));
450  int kF = XMIPP_MIN(CEIL(z_pos + hsigma4), FINISHINGZ(mV));
451  int i0 = XMIPP_MAX(FLOOR(y_pos - hsigma4), STARTINGY(mV));
452  int iF = XMIPP_MIN(CEIL(y_pos + hsigma4), FINISHINGY(mV));
453  int j0 = XMIPP_MAX(FLOOR(x_pos - hsigma4), STARTINGX(mV));
454  int jF = XMIPP_MIN(CEIL(x_pos + hsigma4), FINISHINGX(mV));
455  auto alpha = blob.alpha;
456  auto order = blob.order;
457  // Perform splatting at this position r
458  // ? Probably we can loop only a quarter of the region and use the symmetry to make this faster?
459  for (int k = k0; k <= kF; k++)
460  {
461  for (int i = i0; i <= iF; i++)
462  {
463  for (int j = j0; j <= jF; j++)
464  {
465  A3D_ELEM(mV, k, i, j) += voxel * gaussian1D(k-z_pos,hsigma)*
466  gaussian1D(i-y_pos,hsigma)*
467  gaussian1D(j-x_pos,hsigma);
468  }
469  }
470  }
471 }
472 
474 {
475  // Find the part of the volume that must be updated
476  auto &mVout = Vout();
477  const auto &mV = Vrefined();
478  mVout.initZeros(mV);
479 
480  const auto lastZ = FINISHINGZ(mV);
481  const auto lastY = FINISHINGY(mV);
482  const auto lastX = FINISHINGX(mV);
483  // const int step = DIRECTION == Direction::Forward ? loop_step : 1;
484  const int step = loop_step;
485  auto pos = std::array<double, 3>{};
486 
487  for (int k = STARTINGZ(mV); k <= lastZ; k++)
488  {
489  for (int i = STARTINGY(mV); i <= lastY; i++)
490  {
491  for (int j = STARTINGX(mV); j <= lastX; j++)
492  {
493  if (A3D_ELEM(Vmask, k, i, j) == 1)
494  {
495  pos[0] = j;
496  pos[1] = i;
497  pos[2] = k;
498  updateVoxel(pos, A3D_ELEM(mV, k, i, j), mVout);
499  }
500  }
501  }
502  }
503 }
504 
505 void ProgForwardArtZernike3DSubtomos::run()
506 {
507  FileName fnImg, fnImgOut, fullBaseName;
508  getOutputMd().clear(); //this allows multiple runs of the same Program object
509 
510  //Perform particular preprocessing
511  preProcess();
512 
513  startProcessing();
514 
515  sortOrthogonal();
516 
517  if (!oroot.empty())
518  {
519  if (oext.empty())
521  oextBaseName = oext;
522  fullBaseName = oroot.removeFileFormat();
523  baseName = fullBaseName.getBaseName();
524  pathBaseName = fullBaseName.getDir();
525  }
526 
527  size_t objId;
528  size_t objIndex;
529  current_save_iter = 1;
530  num_images = 1;
532  {
533  std::cout << "Running iteration " << current_iter + 1 << " with lambda=" << lambda << std::endl;
534  objId = 0;
535  objIndex = 0;
536  time_bar_done = 0;
538  {
539  objId = A1D_ELEM(ordered_list, i) + 1;
540  ++objIndex;
541  auto rowIn = getInputMd()->getRow(objId);
542  if (rowIn == nullptr) continue;
543  rowIn->getValue(image_label, fnImg);
544 
545  if (fnImg.empty())
546  break;
547 
548  fnImgOut = fnImg;
549 
550  MDRowVec rowOut;
551 
552  // if (each_image_produces_an_output)
553  // {
554  // if (!oroot.empty()) // Compose out name to save as independent images
555  // {
556  // if (oext.empty()) // If oext is still empty, then use ext of indep input images
557  // {
558  // if (input_is_stack)
559  // oextBaseName = "spi";
560  // else
561  // oextBaseName = fnImg.getFileFormat();
562  // }
563 
564  // if (!baseName.empty() )
565  // fnImgOut.compose(fullBaseName, objIndex, oextBaseName);
566  // else if (fnImg.isInStack())
567  // fnImgOut.compose(pathBaseName + (fnImg.withoutExtension()).getDecomposedFileName(), objIndex, oextBaseName);
568  // else
569  // fnImgOut = pathBaseName + fnImg.withoutExtension()+ "." + oextBaseName;
570  // }
571  // else if (!fn_out.empty() )
572  // {
573  // if (single_image)
574  // fnImgOut = fn_out;
575  // else
576  // fnImgOut.compose(objIndex, fn_out); // Compose out name to save as stacks
577  // }
578  // else
579  // fnImgOut = fnImg;
580  // setupRowOut(fnImg, *rowIn.get(), fnImgOut, rowOut);
581  // }
582  // else if (produces_a_metadata)
583  // setupRowOut(fnImg, *rowIn.get(), fnImgOut, rowOut);
584 
585  processImage(fnImg, fnImgOut, *rowIn.get(), rowOut);
586 
587  // if (each_image_produces_an_output || produces_a_metadata)
588  // getOutputMd().addRow(rowOut);
589 
590  checkPoint();
591  showProgress();
592 
593  // Save refined volume every num_images
594  if (current_save_iter == save_iter && save_iter > 0)
595  {
596  recoverVol();
597  // Mask mask;
598  // mask.type = BINARY_CIRCULAR_MASK;
599  // mask.mode = INNER_MASK;
600  // mask.R1 = RmaxDef - 2;
601  // mask.generate_mask(Vrefined());
602  // mask.apply_mask(Vrefined(), Vrefined());
603  // Vrefined.write(fnVolO.removeAllExtensions() + "it" + std::to_string(current_iter + 1) + "proj" + std::to_string(num_images) + ".mrc");
604  Vout.write(fnVolO.removeAllExtensions() + "_partial.mrc");
605  current_save_iter = 1;
606  }
608  num_images++;
609  }
610  num_images = 1;
611  current_save_iter = 1;
612 
613  recoverVol();
614  Vout.write(fnVolO.removeAllExtensions() + "_iter" + std::to_string(current_iter + 1) + ".mrc");
615 
616  // Vrefined().threshold("below", 0, 0);
617  // Mask mask;
618  // mask.type = BINARY_CIRCULAR_MASK;
619  // mask.mode = INNER_MASK;
620  // mask.R1 = RmaxDef - 2;
621  // mask.generate_mask(Vrefined());
622  // mask.apply_mask(Vrefined(), Vrefined());
623  }
624  wait();
625 
626  /* Generate name to save mdOut when output are independent images. It uses as prefix
627  * the dirBaseName in order not overwriting files when repeating same command on
628  * different directories. If baseName is set it is used, otherwise, input name is used.
629  * Then, the suffix _oext is added.*/
630  if (fn_out.empty())
631  {
632  if (!oroot.empty())
633  {
634  if (!baseName.empty())
635  fn_out = findAndReplace(pathBaseName, "/", "_") + baseName + "_" + oextBaseName + ".xmd";
636  else
637  fn_out = findAndReplace(pathBaseName, "/", "_") + fn_in.getBaseName() + "_" + oextBaseName + ".xmd";
638  }
639  else if (input_is_metadata)
640  fn_out = fn_in;
641  }
642 
644 
645  postProcess();
646 
647  /* Reset the default values of the program in case
648  * to be reused.*/
649  init();
650 }
651 
652 void ProgForwardArtZernike3DSubtomos::sortOrthogonal()
653 {
654  int i, j;
655  size_t numIMG = getInputMd()->size();
656  MultidimArray<short> chosen(numIMG);
657  chosen.initZeros(numIMG);
658  MultidimArray<double> product(numIMG);
659  product.initZeros(numIMG);
660  double min_prod = MAXDOUBLE;
661  ;
662  int min_prod_proj = 0;
663  std::vector<double> rot;
664  std::vector<double> tilt;
665  Matrix2D<double> v(numIMG, 3);
666  v.initZeros(numIMG, 3);
667  Matrix2D<double> euler;
670 
671  // Initialization
672  ordered_list.resize(numIMG);
673  for (i = 0; i < numIMG; i++)
674  {
676  // Initially no image is chosen
677  A1D_ELEM(chosen, i) = 0;
678 
679  // Compute the Euler matrix for each image and keep only
680  // the third row of each one
681  Euler_angles2matrix(rot[i], tilt[i], 0., euler);
682  euler.getRow(2, z);
683  v.setRow(i, z);
684  }
685 
686  // Pick first projection as the first one to be presented
687  i = 0;
688  A1D_ELEM(chosen, i) = 1;
689  A1D_ELEM(ordered_list, 0) = i;
690 
691  // Choose the rest of projections
692  std::cout << "Sorting projections orthogonally...\n"
693  << std::endl;
694  Matrix1D<double> rowj, rowi_1, rowi_N_1;
695  for (i = 1; i < numIMG; i++)
696  {
697  // Compute the product of not already chosen vectors with the just
698  // chosen one, and select that which has minimum product
699  min_prod = MAXDOUBLE;
700  v.getRow(A1D_ELEM(ordered_list, i - 1), rowi_1);
701  if (sort_last_N != -1 && i > sort_last_N)
702  v.getRow(A1D_ELEM(ordered_list, i - sort_last_N - 1), rowi_N_1);
703  for (j = 0; j < numIMG; j++)
704  {
705  if (!A1D_ELEM(chosen, j))
706  {
707  v.getRow(j, rowj);
708  A1D_ELEM(product, j) += ABS(dotProduct(rowi_1, rowj));
709  if (sort_last_N != -1 && i > sort_last_N)
710  A1D_ELEM(product, j) -= ABS(dotProduct(rowi_N_1, rowj));
711  if (A1D_ELEM(product, j) < min_prod)
712  {
713  min_prod = A1D_ELEM(product, j);
714  min_prod_proj = j;
715  }
716  }
717  }
718 
719  // Store the chosen vector and mark it as chosen
720  A1D_ELEM(ordered_list, i) = min_prod_proj;
721  A1D_ELEM(chosen, min_prod_proj) = 1;
722  }
723 }
724 
725 template <ProgForwardArtZernike3DSubtomos::Direction DIRECTION>
726 void ProgForwardArtZernike3DSubtomos::artModel()
727 {
728  if (DIRECTION == Direction::Forward)
729  {
730  Image<double> I_shifted;
731  P().initZeros((int)XSIZE(I()), (int)XSIZE(I()), (int)XSIZE(I()));
732  P().setXmippOrigin();
733  W().initZeros((int)XSIZE(I()), (int)XSIZE(I()), (int)XSIZE(I()));
734  W().setXmippOrigin();
735  Idiff().initZeros((int)XSIZE(I()), (int)XSIZE(I()), (int)XSIZE(I()));
736  Idiff().setXmippOrigin();
737  I_shifted().initZeros((int)XSIZE(I()), (int)XSIZE(I()), (int)XSIZE(I()));
738  I_shifted().setXmippOrigin();
739 
740  if (useZernike)
741  zernikeModel<true, Direction::Forward>();
742  else
743  zernikeModel<false, Direction::Forward>();
744 
745  if (hasCTF)
746  {
747  // updateCTFImage(defocusU, defocusV, defocusAngle);
748  // FilterCTF.ctf = ctf;
749  if (phaseFlipped)
753  }
754  if (flip)
755  {
756  MAT_ELEM(A, 0, 0) *= -1;
757  MAT_ELEM(A, 0, 1) *= -1;
758  MAT_ELEM(A, 0, 2) *= -1;
759  }
760 
761  applyMissingWedge(P());
762 
764  xmipp_transformation::IS_NOT_INV, xmipp_transformation::DONT_WRAP, 0.);
765 
766  // P.write(fnOutDir + "/PPPtheo.xmp");
767  // I_shifted.write(fnOutDir + "/PPPexp.xmp");
768  // std::cout << "Press any key" << std::endl;
769  // char c; std::cin >> c;
770 
771  // Compute difference image and divide by weights
772  double error = 0.0f;
773  double N = 0.0f;
774  const auto &mP = P();
775  const auto &mW = W();
776  const auto &mIsh = I_shifted();
777  auto &mId = Idiff();
779  {
780  if (A3D_ELEM(mW, k, i, j) > 0)
781  {
782  auto diffVal = A3D_ELEM(mIsh, k, i, j) - A3D_ELEM(mP, k, i, j);
783  A3D_ELEM(mId, k, i, j) = lambda * (diffVal) / XMIPP_MAX(A3D_ELEM(mW, k, i, j), 1.0);
784  error += (diffVal) * (diffVal);
785  N++;
786  }
787  }
788 
789  if (verbose >= 3)
790  {
791  P.write(fnOutDir + "/PPPtheo.mrc");
792  W.write(fnOutDir + "/PPPweight.mrc");
793  Idiff.write(fnOutDir + "/PPPcorr.mrc");
794  I.write(fnOutDir + "/PPPsubtomo.mrc");
795  std::cout << "Press any key" << std::endl;
796  char c;
797  std::cin >> c;
798  }
799 
800  // Creo que Carlos no usa un RMSE si no un MSE
801  error = std::sqrt(error / N);
802  std::cout << "Error for image " << num_images << " in iteration " << current_iter + 1 << " : " << error << std::endl;
803  }
804  else if (DIRECTION == Direction::Backward)
805  {
806  if (useZernike)
807  zernikeModel<true, Direction::Backward>();
808  else
809  zernikeModel<false, Direction::Backward>();
810  }
811 }
812 
813 template <bool USESZERNIKE, ProgForwardArtZernike3DSubtomos::Direction DIRECTION>
814 void ProgForwardArtZernike3DSubtomos::zernikeModel()
815 {
816  auto &mId = Idiff();
817  auto &mV = Vrefined();
818  auto &mP = P();
819  auto &mW = W();
820  const size_t idxY0 = USESZERNIKE ? (clnm.size() / 3) : 0;
821  const size_t idxZ0 = USESZERNIKE ? (2 * idxY0) : 0;
822  const double RmaxF = USESZERNIKE ? RmaxDef : 0;
823  const double RmaxF2 = USESZERNIKE ? (RmaxF * RmaxF) : 0;
824  const double iRmaxF = USESZERNIKE ? (1.0 / RmaxF) : 0;
825  // Rotation Matrix
826  constexpr size_t matrixSize = 3;
827  const Matrix2D<double> R = [this]()
828  {
829  auto tmp = Matrix2D<double>();
830  tmp.initIdentity(matrixSize);
831  Euler_angles2matrix(rot, tilt, psi, tmp, false);
832  return tmp;
833  }();
834 
835  // auto l2Mask = std::vector<size_t>();
836  // for (size_t idx = 0; idx < idxY0; idx++) {
837  // if (0 == VEC_ELEM(vL2, idx)) {
838  // l2Mask.emplace_back(idx);
839  // }
840 
841  // }
842  const auto lastZ = FINISHINGZ(mV);
843  const auto lastY = FINISHINGY(mV);
844  const auto lastX = FINISHINGX(mV);
845  const int step = DIRECTION == Direction::Forward ? loop_step : 1;
846  // const int step = loop_step;
847 
848  for (int k = STARTINGZ(mV); k <= lastZ; k += step)
849  {
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.0f, gy = 0.0f, gz = 0.0f;
855  if (A3D_ELEM(Vmask, k, i, j) > 0.01)
856  {
857  if (USESZERNIKE) {
858  auto k2 = k * k;
859  auto kr = k * iRmaxF;
860  auto k2i2 = k2 + i * i;
861  auto ir = i * iRmaxF;
862  auto r2 = k2i2 + j * j;
863  auto jr = j * iRmaxF;
864  auto rr = sqrt(r2) * iRmaxF;
865  for (size_t idx = 0; idx < idxY0; idx++)
866  {
867  auto l1 = VEC_ELEM(vL1, idx);
868  auto n = VEC_ELEM(vN, idx);
869  auto l2 = VEC_ELEM(vL2, idx);
870  auto m = VEC_ELEM(vM, idx);
871  if (rr > 0 || l2 == 0)
872  {
873  auto zsph = ZernikeSphericalHarmonics(l1, n, l2, m, jr, ir, kr, rr);
874  gx += clnm[idx] * (zsph);
875  gy += clnm[idx + idxY0] * (zsph);
876  gz += clnm[idx + idxZ0] * (zsph);
877  }
878  }
879  }
880 
881  auto r_x = j + gx;
882  auto r_y = i + gy;
883  auto r_z = k + gz;
884 
885  if (DIRECTION == Direction::Forward)
886  {
887  auto pos = std::array<double, 3>{};
888  pos[0] = R.mdata[0] * r_x + R.mdata[1] * r_y + R.mdata[2] * r_z;
889  pos[1] = R.mdata[3] * r_x + R.mdata[4] * r_y + R.mdata[5] * r_z;
890  pos[2] = R.mdata[6] * r_x + R.mdata[7] * r_y + R.mdata[8] * r_z;
891  double voxel_mV = A3D_ELEM(mV, k, i, j);
892  splattingAtPos(pos, voxel_mV, mP, mW, mV);
893  }
894  else if (DIRECTION == Direction::Backward)
895  {
896  // auto pos = std::array<double, 3>{};
897  auto pos_x = R.mdata[0] * r_x + R.mdata[1] * r_y + R.mdata[2] * r_z;
898  auto pos_y = R.mdata[3] * r_x + R.mdata[4] * r_y + R.mdata[5] * r_z;
899  auto pos_z = R.mdata[6] * r_x + R.mdata[7] * r_y + R.mdata[8] * r_z;
900  // pos[0] = j;
901  // pos[1] = i;
902  // pos[2] = k;
903  double voxel = mId.interpolatedElement3D(pos_x, pos_y, pos_z);
904  A3D_ELEM(mV, k, i, j) += voxel;
905  // updateVoxel(pos, voxel, mV);
906  }
907  }
908  }
909  }
910  }
911 }
912 
914 {
915  // gaussian_mw = gaussian3d;
916  // gaussian_mw.setXmippOrigin();
918  MultidimArray<int> maskWedge;
920  R.initIdentity(3);
921  // Euler_angles2matrix(static_cast<double>(rot), static_cast<double>(tilt), static_cast<double>(psi), R, false);
922  transformer.FourierTransform(mV, fg, false);
923  transformer.getFourierAlias(Fourier);
924  maskWedge.initZeros(Fourier);
925  maskWedge.setXmippOrigin();
926  BinaryWedgeMask(maskWedge, t1, t2, R, true);
928  DIRECT_MULTIDIM_ELEM(fg,n) *= DIRECT_MULTIDIM_ELEM(maskWedge,n);
930 }
#define MAXDOUBLE
Definition: data_types.h:51
Rotation angle of an image (double,degrees)
#define VEC_ELEM(v, i)
Definition: matrix1d.h:245
double alpha
Smoothness parameter.
Definition: blobs.h:121
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
void fillVectorTerms(int l1, int l2, Matrix1D< int > &vL1, Matrix1D< int > &vN, Matrix1D< int > &vL2, Matrix1D< int > &vM)
Zernike and SPH coefficients allocation.
double getDoubleParam(const char *param, int arg=0)
__host__ __device__ float2 floor(const float2 v)
CTFDescription ctf
void inverseFourierTransform()
Definition: xmipp_fftw.cpp:329
#define FINISHINGX(v)
#define CTFINV
#define REPORT_ERROR(nerr, ErrormMsg)
Definition: xmipp_error.h:211
FileName removeFileFormat() const
void readParams()
Read argument from command line.
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 BinaryWedgeMask(MultidimArray< int > &mask, double theta0, double thetaF, const Matrix2D< double > &A, bool centerOrigin)
Definition: mask.cpp:524
void processImage(const FileName &fnImg, const FileName &fnImgOut, const MDRow &rowIn, MDRow &rowOut)
void sqrt(Image< double > &op)
void numCoefficients(int l1, int l2, int &vecSize)
Length of coefficients vector.
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)
~ProgForwardArtZernike3DSubtomos()
Destructor.
int l
Definition: svm.h:62
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 applyMissingWedge(MultidimArray< double > &mV)
#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
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_ARRAY3D(V)
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)
virtual void wait()
Wait for the distributor to finish.
#define CEIL(x)
Definition: xmipp_macros.h:225
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
#define FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(v)
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
#define DIRECT_MULTIDIM_ELEM(v, n)
void addExampleLine(const char *example, bool verbatim=true)
virtual std::unique_ptr< MDRow > getRow(size_t id)=0
#define ROUND(x)
Definition: xmipp_macros.h:210
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
void FourierTransform(T &v, T1 &V, bool getCopy=true)
Definition: xmipp_fftw.h:166
#define XMIPP_MIN(x, y)
Definition: xmipp_macros.h:181
#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
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
void getFourierAlias(T &V)
Definition: xmipp_fftw.h:207
#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
Shift for the image in the Z axis (double)
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
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.
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)