Xmipp  v3.23.11-Nereus
reconstruct_ADMM.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  *
3  * Authors: Masih Nilchian (masih.nilchian@epfl.ch)
4  * Carlos Oscar S. Sorzano (coss@cnb.csic.es)
5  *
6  * Unidad de Bioinformatica of Centro Nacional de Biotecnologia , CSIC
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21  * 02111-1307 USA
22  *
23  * All comments concerning this program package may be sent to the
24  * e-mail address 'xmipp@cnb.csic.es'
25  ***************************************************************************/
26 
27 /* TODO:
28  * - Default parameters
29  * - Parallelization
30  * - Symmetrize HtKH and Htb
31  */
32 
33 #include "reconstruct_ADMM.h"
34 #include "symmetrize.h"
36 
37 #define SYMMETRIZE_PROJECTIONS
38 
40 {
41  rank=0;
42  Nprocs=1;
43 }
44 
46 {
47  addUsageLine("Reconstruct with Alternative Direction Method of Multipliers");
48  addParamsLine(" -i <metadata>: Input metadata with images and angles");
49  addParamsLine(" [--oroot <root=reconstruct_admm>]: Rootname for output files");
50  addParamsLine(" [--Htb <volume=\"\">]: Filename of the Htb volume");
51  addParamsLine(" [--HtKH <volume=\"\">]: Filename of the HtKH volume");
52  addParamsLine(" [--firstVolume <volume=\"\">]: Filename of the first initial guess");
53  addParamsLine(" [--kernel <shape=KaiserBessel>]: Kernel shape");
54  addParamsLine(" where <shape>");
55  addParamsLine(" KaiserBessel: Kaiser-Bessel function as kernel");
56  addParamsLine(" [--downsamplingV <Ti=1>]: Downsampling factor for volume");
57  addParamsLine(" [--downsamplingI <Tp=1>]: Downsampling factor for projections");
58  addParamsLine(" [--dontUseWeights]: Do not use weights if available in the input metadata");
59  addParamsLine(" [--dontUseCTF]: Do not use CTF if available in the input metadata");
60  addParamsLine(" : If the CTF information is used, the algorithm assumes that the input images are phase flipped");
61  addParamsLine(" [--sampling <Ts=1>]: The sampling rate is only used to correct for the CTF");
62  addParamsLine(" [--mu <mu=1e-4>]: Augmented Lagrange penalty");
63  addParamsLine(" [--lambda <lambda=1e-5>]: Total variation parameter");
64  addParamsLine(" [--lambda1 <lambda1=1e-7>]: Tikhonov parameter");
65  addParamsLine(" [--cgiter <N=3>]: Conjugate Gradient iterations");
66  addParamsLine(" [--admmiter <N=30>]: ADMM iterations");
67  addParamsLine(" [--positivity]: Positivity constraint");
68  addParamsLine(" [--sym <s=c1>]: Symmetry constraint");
69  addParamsLine(" [--saveIntermediate]: Save Htb and HtKH volumes for posterior calls");
70 
72 }
73 
75 {
76  fnIn=getParam("-i");
77  fnRoot=getParam("--oroot");
78  fnFirst=getParam("--firstVolume");
79  fnHtb=getParam("--Htb");
80  fnHtKH=getParam("--HtKH");
81  kernelShape=getParam("--kernel");
82  if (kernelShape=="KaiserBessel")
83  {
84  a=4; //getDoubleParam("--kernel",1);
85  alpha=19; // getDoubleParam("--kernel",2);
86  }
87  Ti=getDoubleParam("--downsamplingV");
88  Tp=getDoubleParam("--downsamplingI");
89  useWeights=!checkParam("--dontUseWeights");
90  useCTF=!checkParam("--dontUseCTF");
91  Ts=getDoubleParam("--sampling");
92  mu=getDoubleParam("--mu");
93  lambda=getDoubleParam("--lambda");
94  lambda1=getDoubleParam("--lambda1");
95  Ncgiter=getIntParam("--cgiter");
96  Nadmmiter=getIntParam("--admmiter");
97  positivity=checkParam("--positivity");
98  saveIntermediate=checkParam("--saveIntermediate");
99 
100  applyMask=checkParam("--mask");
101  if (applyMask)
102  mask.readParams(this);
103  SL.readSymmetryFile(getParam("--sym"));
104 }
105 
107 {
108  // Read input images
109  mdIn.read(fnIn);
110 
111  // Symmetrize input images
112 #ifdef SYMMETRIZE_PROJECTIONS
113  Matrix2D<double> Lsym(3,3), Rsym(3,3);
114  MetaDataVec mdSym;
115  double rot, tilt, psi, newrot, newtilt, newpsi;
116  for (auto& row : mdIn)
117  {
118  row.getValue(MDL_ANGLE_ROT,rot);
119  row.getValue(MDL_ANGLE_TILT,tilt);
120  row.getValue(MDL_ANGLE_PSI,psi);
121  mdSym.addRow(dynamic_cast<MDRowVec&>(row));
122  for (int isym = 0; isym < SL.symsNo(); isym++)
123  {
124  SL.getMatrices(isym, Lsym, Rsym, false);
125  Euler_apply_transf(Lsym,Rsym,rot,tilt,psi,newrot,newtilt,newpsi);
126  row.setValue(MDL_ANGLE_ROT,newrot);
127  row.setValue(MDL_ANGLE_TILT,newtilt);
128  row.setValue(MDL_ANGLE_PSI,newpsi);
129  mdSym.addRow(dynamic_cast<MDRowVec&>(row));
130  }
131  }
132  mdIn=mdSym;
133  mdSym.clear();
134 #endif
135 
136  // Prepare kernel
137  if (kernelShape=="KaiserBessel")
138  kernel.initializeKernel(alpha,a,0.0001);
140 
141  // Get Htb reconstruction
142  if (fnHtb=="")
143  {
144  constructHtb();
145  if (saveIntermediate && rank==0)
146  CHtb.write(fnRoot+"_Htb.vol");
147  }
148  else
149  {
150  CHtb.read(fnHtb);
151  CHtb().setXmippOrigin();
152  }
153 
154  // Adjust regularization weights
155  //double Nimgs=mdIn.size();
156  //double CHtb_norm=sqrt(CHtb().sum2()/MULTIDIM_SIZE(CHtb()));
157  //COSS mu*=Nimgs/XSIZE(CHtb())*CHtb_norm;
158  //COSS lambda*=Nimgs/XSIZE(CHtb())*CHtb_norm;
159  //COSS lambda1*=Nimgs/XSIZE(CHtb());
160 
161  // Get first volume
162  if (fnFirst=="")
163  Ck().initZeros(CHtb());
164  else
165  {
166  Ck.read(fnFirst);
167  Ck().setXmippOrigin();
168  }
169 
170  // Compute H'*K*H+mu*L^T*L+lambda_1 I
171  Image<double> kernelV;
172  if (fnHtKH=="")
173  {
174  computeHtKH(kernelV());
175  if (saveIntermediate && rank==0)
176  kernelV.write(fnRoot+"_HtKH.vol");
177  }
178  else
179  {
180  kernelV.read(fnHtKH);
181  kernelV().setXmippOrigin();
182  }
183  FourierTransformer transformer;
184  transformer.FourierTransform(kernelV(),fourierKernelV,true);
185 
186  // Add regularization in Fourier space
188 
189  // Resize u and d volumes
190  ux.initZeros(CHtb());
191  ux.setXmippOrigin();
192  uy=ux;
193  uz=ux;
194  dx=ux;
195  dy=ux;
196  dz=ux;
197 
198  // Prepare Lt filters
200  L.resize(ux);
201  kernel.computeGradient(L,'x');
202  transformer.FourierTransform(L,fourierLx);
203  kernel.computeGradient(L,'y');
204  transformer.FourierTransform(L,fourierLy);
205  kernel.computeGradient(L,'z');
206  transformer.FourierTransform(L,fourierLz);
207 
208  ud=ux;
210 
211  // Prepare mask
212  if (applyMask)
214  synchronize();
215 }
216 
218 {
219 
220 }
221 
223 {
224  produceSideInfo();
225  if (rank==0)
226  {
227  std::cout << "Running ADMM iterations ..." << std::endl;
229  for (int iter=0; iter<Nadmmiter; ++iter)
230  {
233  updateUD();
235  }
236  progress_bar(Nadmmiter);
237  produceVolume();
238  Vk.write(fnRoot+".vol");
239  }
240  synchronize();
241 }
242 
244 {
245  size_t xdim, ydim, zdim, ndim;
246  getImageSize(mdIn,xdim,ydim,zdim,ndim);
247  CHtb().initZeros(xdim,xdim,xdim);
248  CHtb().setXmippOrigin();
249 
250  Image<double> I;
251  double rot, tilt, psi;
252  size_t i=0;
253  if (rank==0)
254  {
255  std::cerr << "Performing Htb ...\n";
257  }
258  double weight=1.;
259  ApplyGeoParams geoParams;
260  geoParams.only_apply_shifts=true;
261  geoParams.wrap=xmipp_transformation::DONT_WRAP;
262  for (size_t objId : mdIn.ids())
263  {
264  if ((i+1)%Nprocs==rank)
265  {
266  I.readApplyGeo(mdIn,objId,geoParams);
267  I().setXmippOrigin();
268  mdIn.getValue(MDL_ANGLE_ROT,rot,objId);
269  mdIn.getValue(MDL_ANGLE_TILT,tilt,objId);
270  mdIn.getValue(MDL_ANGLE_PSI,psi,objId);
272  mdIn.getValue(MDL_WEIGHT,weight,objId);
273 
274  project(rot,tilt,psi,I(),true,weight);
275  }
276  i++;
277  if (i%100==0 && rank==0)
278  progress_bar(i);
279  }
280  if (rank==0)
282 
283  // Symmetrize Htb
284 #ifndef SYMMETRIZE_PROJECTIONS
285  MultidimArray<double> CHtbsym;
286  symmetrizeVolume(SL, CHtb(), CHtbsym, false, false, true);
287  CHtb=CHtbsym;
288 #endif
289  shareVolume(CHtb());
290 }
291 
292 void ProgReconsADMM::project(double rot, double tilt, double psi, MultidimArray<double> &P, bool adjoint, double weight)
293 {
295  Euler_angles2matrix(rot,tilt,psi,E,false);
296  Matrix1D<double> r1(3), r2(3);
297  E.getRow(0,r1);
298  E.getRow(1,r2);
299  project(r1,r2,P,adjoint,weight);
300 }
301 
302 void ProgReconsADMM::project(const Matrix1D<double> &r1, const Matrix1D<double> &r2, MultidimArray<double> &P, bool adjoint, double weight)
303 {
304  const MultidimArray<double> &mV=CHtb();
305  if (!adjoint)
306  {
307  P.initZeros(std::ceil(XSIZE(mV)/Tp),std::ceil(YSIZE(mV)/Tp));
308  P.setXmippOrigin();
309  }
310 
311  // Tomographic projection
312  for (int k=STARTINGZ(mV); k<=FINISHINGZ(mV); ++k) {
313  // initial computation
314  double rzn = k;
315  double rzn1= rzn*VEC_ELEM(r1,2);
316  double rzn2= rzn*VEC_ELEM(r2,2);
317  for (int i=STARTINGY(mV); i<=FINISHINGY(mV); ++i) {
318  // initial computation
319  double ryn = i;
320  double ryn1= ryn*VEC_ELEM(r1,1);
321  double ryn2= ryn*VEC_ELEM(r2,1);
322  double sx0=rzn1+ryn1;
323  double sy0=rzn2+ryn2;
324 
325  for (int j=STARTINGX(mV); j<=FINISHINGX(mV); ++j) {
326  double rxn = j;
327  double rxn1= rxn*VEC_ELEM(r1,0);
328  double rxn2= rxn*VEC_ELEM(r2,0);
329 
330  double sx = Ti*(sx0+rxn1);
331  double sy = Ti*(sy0+rxn2);
332 
333  int sxmin = std::floor(sx-kernel.supp);
334  int sxmax = std::ceil(sx+kernel.supp);
335  int symin = std::floor(sy-kernel.supp);
336  int symax = std::ceil(sy+kernel.supp);
337  if (sxmin<STARTINGX(P))
338  sxmin = STARTINGX(P);
339  if (sxmax>FINISHINGX(P))
340  sxmax = FINISHINGX(P);
341  if (symin<STARTINGY(P))
342  symin = STARTINGY(P);
343  if (symax>FINISHINGY(P))
344  symax = FINISHINGY(P);
345 
346  if (adjoint)
347  for (int ii=symin; ii<=symax; ii++) {
348  double u=(ii-sy)*Tp;
349  for (int jj=sxmin; jj<=sxmax; jj++) {
350  double v=(jj-sx)*Tp;
351  A3D_ELEM(mV,k,i,j)+=weight*A2D_ELEM(P,ii,jj)*kernel.projectionValueAt(u,v);
352  }
353  }
354  else
355  for (int ii=symin; ii<=symax; ii++) {
356  double u=(ii-sy)*Tp;
357  for (int jj=sxmin; jj<=sxmax; jj++) {
358  double v=(jj-sx)*Tp;
359  A2D_ELEM(P,ii,jj)+=weight*A3D_ELEM(mV,k,i,j)*kernel.projectionValueAt(u,v);
360  }
361  }
362  }
363  }
364  }
365 }
366 
368 {
369  kernelV.initZeros(2*ZSIZE(CHtb())-1,2*YSIZE(CHtb())-1,2*XSIZE(CHtb())-1);
370  kernelV.setXmippOrigin();
371 
372  if (rank==0)
373  {
374  std::cerr << "Calculating H'KH ...\n";
376  }
377  size_t i=0;
378  double rot, tilt, psi, weight=1;
379  bool hasWeight=mdIn.containsLabel(MDL_WEIGHT) && useWeights;
381  CTFDescription ctf;
382  MultidimArray<double> kernelAutocorr;
383  if (!hasCTF)
384  kernel.getKernelAutocorrelation(kernelAutocorr);
386  Matrix1D<double> r1(3), r2(3);
387  for (size_t objId : mdIn.ids())
388  {
389  if ((i+1)%Nprocs==rank)
390  {
391  // COSS: Read also MIRROR
392  mdIn.getValue(MDL_ANGLE_ROT,rot,objId);
393  mdIn.getValue(MDL_ANGLE_TILT,tilt,objId);
394  mdIn.getValue(MDL_ANGLE_PSI,psi,objId);
395  if (hasWeight)
396  mdIn.getValue(MDL_WEIGHT,weight,objId);
397  if (hasCTF)
398  {
399  ctf.readFromMetadataRow(mdIn,objId);
400  ctf.produceSideInfo();
401  kernel.applyCTFToKernelAutocorrelation(ctf,Ts,kernelAutocorr);
402  }
403  kernelAutocorr.setXmippOrigin();
404 
405  // Update kernel
406  Euler_angles2matrix(rot,tilt,psi,E,false);
407  E.getRow(0,r1);
408  E.getRow(1,r2);
409  double iStep=1.0/kernel.autocorrStep;
410  for (auto k=(kernelV.zinit); k<=(kernelV.zinit + kernelV.zdim - 1); ++k)
411  {
412  double r1_z=k*ZZ(r1);
413  double r2_z=k*ZZ(r2);
414  for (auto i=(kernelV.yinit); i<=(kernelV.yinit + kernelV.ydim - 1); ++i)
415  {
416  double r1_yz=i*YY(r1)+r1_z;
417  double r2_yz=i*YY(r2)+r2_z;
418  for (auto j=(kernelV.xinit); j<=(kernelV.xinit + kernelV.xdim - 1); ++j)
419  {
420  double r1_xyz=j*XX(r1)+r1_yz;
421  double r2_xyz=j*XX(r2)+r2_yz;
422  A3D_ELEM(kernelV,k,i,j)+=weight*kernelAutocorr.interpolatedElement2D(r1_xyz*iStep,r2_xyz*iStep);
423  }
424  }
425  }
426  }
427 
428  i++;
429  if (i%100==0 && rank==0)
430  progress_bar(i);
431  }
432  if (rank==0)
434 
435 #ifndef SYMMETRIZE_PROJECTIONS
436  MultidimArray<double> kernelVsym;
437  symmetrizeVolume(SL, kernelV, kernelVsym, false, false, true);
438  kernelV=kernelVsym;
439 #endif
440 
441  shareVolume(kernelV);
442 }
443 
445  MultidimArray<std::complex<double> >&fourierKernelV, char direction)
446 {
447  kernel.computeGradient(L,direction);
448 
449  transformer.FourierTransform();
450  double K=mu*MULTIDIM_SIZE(L);
451  auto xdim_2=(double)(XSIZE(L)/2);
452  double Kargument=2*PI*xdim_2/XSIZE(L);
454  {
455  // Calculation of L^t*L
456  // -L^2(r)*exp(-i*2*pi*(N/2)/N*(k+i+j)): the last term is a phase shift due to FFT
457  double argument=Kargument*(k+i+j);
458  double s, c;
459  //sincos(argument,&s,&c);
460  s = sin(argument);
461  c = cos(argument);
462  A3D_ELEM(fourierKernelV,k,i,j)+=-A3D_ELEM(transformer.fFourier,k,i,j)*
463  A3D_ELEM(transformer.fFourier,k,i,j)*std::complex<double>(K*c,K*s);
464  }
465 }
466 
468 {
470  L.initZeros(2*ZSIZE(CHtb())-1,2*YSIZE(CHtb())-1,2*XSIZE(CHtb())-1);
471  L.setXmippOrigin();
472  FourierTransformer transformer;
473  transformer.setReal(L);
474 
475  if (mu>0)
476  {
477  addGradientTerm(mu, kernel,L,transformer,fourierKernelV, 'x');
478  addGradientTerm(mu, kernel,L,transformer,fourierKernelV, 'y');
479  addGradientTerm(mu, kernel,L,transformer,fourierKernelV, 'z');
480  }
481 
482  if (lambda1>0)
483  {
484  L.initZeros();
485  L(0,0,0)=lambda1;
486  transformer.FourierTransform();
489  }
490 }
491 
493 {
494  paddedx.initZeros(2*ZSIZE(x)-1,2*YSIZE(x)-1,2*XSIZE(x)-1);
496 
497  // Copy Vk into paddedx
498  for (int k=STARTINGZ(x); k<=FINISHINGZ(x); ++k)
499  for (int i=STARTINGY(x); i<=FINISHINGY(x); ++i)
500  memcpy(&A3D_ELEM(paddedx,k,i,STARTINGX(x)),&A3D_ELEM(x,k,i,STARTINGX(x)),XSIZE(x)*sizeof(double));
501 
502  // Compute Fourier transform of paddedx
505 
506  // Apply kernel
507  double K=MULTIDIM_SIZE(paddedx);
509  {
512  }
513 
514  // Inverse Fourier transform
516  CenterFFT(paddedx,false);
517 
518  // Crop central region
519  AtAx.resize(x);
520  for (int k=STARTINGZ(x); k<=FINISHINGZ(x); ++k)
521  for (int i=STARTINGY(x); i<=FINISHINGY(x); ++i)
522  memcpy(&A3D_ELEM(AtAx,k,i,STARTINGX(x)),&A3D_ELEM(paddedx,k,i,STARTINGX(x)),XSIZE(x)*sizeof(double));
523 }
524 
525 void ProgReconsADMM::applyLFilter(MultidimArray< std::complex<double> > &fourierL, bool adjoint)
526 {
531  CenterFFT(ud,false);
532  if (adjoint)
533  ud*=-1;
534 }
535 
537 {
540  applyLFilter(fourierL,true);
541 }
542 
544 {
545  // Conjugate gradient is solving Ax=b, when A is symmetric (=> positive semidefinite) and we apply it
546  // to the problem
547  // (H^T K H+mu L^TL + lambda I) x = H^Tb + mu L^T(u-d)
548  // Being H the projection operator
549  // K the CTF operator
550  // L the gradient operator
551 
552  // Compute H^tb+mu*L^t(u-d)
555  r=ud;
557  r+=ud;
559  r+=ud;
560  r*=mu;
561 
562  r+=CHtb();
563 
564  // Apply A^tA to the current estimate of the reconstruction
565  MultidimArray<double> AtAVk;
566  applyKernel3D(Ck(),AtAVk);
567 
568  // Compute first residual. This is the negative gradient of ||Ax-b||^2
569  r-=AtAVk;
570  double d=r.sum2();
571 
572  // Search direction
573  MultidimArray<double> p, AtAp;
574  p=r;
575 
576  // Perform CG iterations
577  MultidimArray<double> &mCk=Ck();
578 
579  for (int iter=0; iter<Ncgiter; ++iter)
580  {
581  applyKernel3D(p,AtAp);
582  double alpha=d/p.dotProduct(AtAp);
583 
584  // Update residual and current estimate
586  {
587  DIRECT_MULTIDIM_ELEM(r,n) -=alpha*DIRECT_MULTIDIM_ELEM(AtAp,n);
589  }
590  double newd=r.sum2();
591  double beta=newd/d;
592  d=newd;
593 
594  // Update search direction
597 
598 // Image<double> save;
599 // save()=Vk();
600 // save.write("PPPVk.vol");
601 // std::cout << "Press any key" << std::endl;
602 // char c; std::cin >> c;
603  }
604 }
605 
607 {
608  if (applyMask)
609  mask.apply_mask(Ck(),Ck());
610 
611  if (positivity)
612  {
613  Ck().threshold("below",0.,0.);
614 #ifdef NEVERDEFINED
615  MultidimArray<double> smallKernel3D(generate_mask2*a+1,2*a+1,2*a+1);
616  smallKernel3D.setXmippOrigin();
617  kernel.computeKernel3D(smallKernel3D);
618  smallKernel3D/=sqrt(smallKernel3D.sum2());
619 
620  produceVolume();
621  MultidimArray<double> &mVk=Vk();
622  MultidimArray<double> &mCk=Ck();
623  Ck.write("PPPCkBefore.vol");
624  int k0=STARTINGZ(mVk)+a;
625  int i0=STARTINGY(mVk)+a;
626  int j0=STARTINGX(mVk)+a;
627  int kF=FINISHINGZ(mVk)-a;
628  int iF=FINISHINGY(mVk)-a;
629  int jF=FINISHINGX(mVk)-a;
631  if (k<k0 || k>kF || i<i0 || i>iF || j<j0 || j>jF)
632  A3D_ELEM(mCk,k,i,j)=0.;
633  else if (A3D_ELEM(mVk,k,i,j)<0)
634  {
635  // Calculate dot product
636  double dot=0.;
637  for (int kk=-a; kk<=a; ++kk)
638  for (int ii=-a; ii<=a; ++ii)
639  for (int jj=-a; jj<=a; ++jj)
640  dot+=A3D_ELEM(mCk,k+kk,i+ii,j+jj)*A3D_ELEM(smallKernel3D,kk,ii,jj);
641 
642  // Update C
643  for (int kk=-a; kk<=a; ++kk)
644  for (int ii=-a; ii<=a; ++ii)
645  for (int jj=-a; jj<=a; ++jj)
646  A3D_ELEM(mCk,k+kk,i+ii,j+jj)-=dot*A3D_ELEM(smallKernel3D,kk,ii,jj);
647  }
648  Ck.write("PPPCkAfter.vol");
649 #endif
650  }
651 }
652 
654 {
655  double threshold;
656  if (mu>0)
657  threshold=lambda/mu;
658  else
659  threshold=0;
660 // std::cout << "lambda=" << lambda << std::endl;
661 // std::cout << "mu=" << mu << std::endl;
662 // std::cout << "Threshold=" << threshold << std::endl;
664 
665  // Update gradient and Lagrange parameters
666  ud=Ck(); applyLFilter(fourierLx); LCk=ud;
667  ux=LCk; ux+=dx; ux.threshold("soft",threshold);
668  dx+=LCk; dx-=ux;
669 
670  ud=Ck(); applyLFilter(fourierLy); LCk=ud;
671  uy=LCk; uy+=dy; uy.threshold("soft",threshold);
672  dy+=LCk; dy-=uy;
673 
674  ud=Ck(); applyLFilter(fourierLz); LCk=ud;
675  uz=LCk; uz+=dz; uz.threshold("soft",threshold);
676  dz+=LCk; dz-=uz;
677 }
678 
680 {
681  MultidimArray<double> kernel3D;
682  kernel3D.resize(Ck());
683  kernel.computeKernel3D(kernel3D);
684  convolutionFFT(Ck(),kernel3D,Vk());
685  // Vk()*=kernel3D.sum();
686 }
687 
688 void AdmmKernel::initializeKernel(double _alpha, double a, double _projectionStep)
689 {
690  projectionStep=_projectionStep;
691  supp=a;
692  alpha=_alpha;
693  size_t length=ceil(a/projectionStep)+1;
694  projectionProfile.initZeros(length);
695  double ia=1.0/a;
696  double K=a/bessi2(alpha)*sqrt(2.0*PI/alpha);
697  FOR_ALL_ELEMENTS_IN_MATRIX1D(projectionProfile)
698  {
699  double s=i*projectionStep;
700  double tmp=s*ia;
701  tmp=sqrt(1.0 - tmp*tmp);
702  VEC_ELEM(projectionProfile,i)=K*pow(tmp,2.5)*bessi2_5(alpha*tmp);
703  // function p = KaiserBesselProjection(m, alpha, a, s)
704  // tmp = sqrt(1 - (s/a).^2);
705  // p = a ./ besseli(m, alpha) .* sqrt(2*pi/alpha) .* tmp.^(m+0.5) .* besseli(m+0.5, alpha*tmp);
706  // end
707  }
708 }
709 
710 double AdmmKernel::projectionValueAt(double u, double v) {
711  double r = sqrt(u*u+v*v);
712  if (r > supp) {
713  return 0.;
714  } else {
715  r = r/projectionStep ;
716  int rmin = std::floor(r);
717  int rmax = rmin+1 ;
718  double p = r-rmin;
719  return p * VEC_ELEM(projectionProfile,rmin) + (1-p) * VEC_ELEM(projectionProfile,rmax);
720  }
721 }
722 
723 void AdmmKernel::convolveKernelWithItself(double _autocorrStep)
724 {
725  autocorrStep=_autocorrStep;
726  size_t length=ceil(2.5*supp/autocorrStep)+1;
727  projectionAutocorrWithCTF.initZeros(2*length+1,2*length+1);
728  projectionAutocorrWithCTF.setXmippOrigin();
729  double isupp=1.0/supp;
730  double K=supp/bessi2(alpha)*sqrt(2.0*PI/alpha);
731  FOR_ALL_ELEMENTS_IN_ARRAY2D(projectionAutocorrWithCTF)
732  {
733  double s=sqrt(i*i+j*j)*autocorrStep;
734  double tmp=s*isupp;
735  if (tmp<1)
736  {
737  tmp=sqrt(1.0 - tmp*tmp);
738  A2D_ELEM(projectionAutocorrWithCTF,i,j)=K*pow(tmp,2.5)*bessi2_5(alpha*tmp);
739  }
740  }
741 
742  transformer.FourierTransform(projectionAutocorrWithCTF,FourierProjectionAutocorr);
743  K=MULTIDIM_SIZE(projectionAutocorrWithCTF)*autocorrStep*autocorrStep;
744  FOR_ALL_ELEMENTS_IN_ARRAY2D(FourierProjectionAutocorr)
745  A2D_ELEM(FourierProjectionAutocorr,i,j)*=A2D_ELEM(FourierProjectionAutocorr,i,j)*K;
746 
747 // Debugging code
748 // transformer.inverseFourierTransform();
749 // Image<double> save;
750 // save()=projectionAutocorrWithCTF;
751 // save.write("PPPautocorrelationWithoutCTF.xmp");
752 // std::cout << "Press any key" << std::endl;
753 // char c; std::cin>> c;
754 }
755 
757 {
758  transformer.fFourier=FourierProjectionAutocorr;
759  transformer.inverseFourierTransform();
760  autocorrelation=projectionAutocorrWithCTF;
761  CenterFFT(autocorrelation, false);
762 }
763 
765 {
766  double dig2cont=1.0/Ts;
767  double wx, wy;
768  auto xdim=(int)XSIZE(projectionAutocorrWithCTF);
769  int xdim_2=xdim/2;
770  double ixdim=1.0/xdim;
771  double maxFreq=2*autocorrStep;
772  double maxFreq2=maxFreq*maxFreq;
773  // Initialize Fourier transform to 0
774  memset(&A2D_ELEM(transformer.fFourier,0,0),0,MULTIDIM_SIZE(transformer.fFourier)*sizeof(std::complex<double>));
775  for (int i=((transformer.fFourier).yinit); i<=((transformer.fFourier).yinit + (int)(transformer.fFourier).ydim - 1); ++i)
776  {
777  FFT_IDX2DIGFREQ_FAST(i,xdim,xdim_2,ixdim,wy);
778  if (fabs(wy)>maxFreq)
779  continue;
780  double wy2=wy*wy;
781  wy*=dig2cont;
782  for (int j=((transformer.fFourier).xinit); j<=((transformer.fFourier).xinit + (int)(transformer.fFourier).xdim - 1); ++j)
783  {
784  FFT_IDX2DIGFREQ_FAST(j,xdim,xdim_2,ixdim,wx);
785  if (fabs(wx)>maxFreq)
786  continue;
787  double wx2=wx*wx;
788  if (wy2+wx2>maxFreq2)
789  continue;
790  wx*=dig2cont;
791  ctf.precomputeValues(wx,wy);
792  // A2D_ELEM(transformer.fFourier,i,j)=A2D_ELEM(FourierProjectionAutocorr,i,j)*fabs(ctf.getValueAt());
793  A2D_ELEM(transformer.fFourier,i,j)=fabs(ctf.getValueAt());
794  }
795  }
796  transformer.inverseFourierTransform();
797  autocorrelationWithCTF=projectionAutocorrWithCTF;
798  CenterFFT(autocorrelationWithCTF, false);
799 
800 // Debugging code
801 // Image<double> save;
802 // save()=autocorrelationWithCTF;
803 // save.write("PPPautocorrelationWithCTF.xmp");
804 // std::cout << "Press any key" << std::endl;
805 // char c; std::cin>> c;
806 }
807 
809 {
810  double supp2=supp*supp;
811  double K=-1/(supp2*bessi2(alpha));
812  gradient.initZeros();
813  for (int k=-supp; k<=supp; ++k)
814  {
815  int k2=k*k;
816  for (int i=-supp; i<=supp; ++i)
817  {
818  int i2=i*i;
819  for (int j=-supp; j<=supp; ++j)
820  {
821  int j2=j*j;
822  double r2=k2+i2+j2;
823  if (r2>supp2)
824  continue;
825  double z=alpha*sqrt(1.0-r2/supp2);
826  double value=K*z*bessi1(z);
827  switch (direction)
828  {
829  case 'x': value*=j; break;
830  case 'y': value*=i; break;
831  case 'z': value*=k; break;
832  }
833  if (adjoint)
834  value*=-1;
835  A3D_ELEM(gradient,k,i,j)=value;
836  }
837  }
838  }
839 }
840 
842 {
843  double supp2=supp*supp;
844  double K=1/(bessi2(alpha)*alpha*alpha);
845  kernel.initZeros();
846  for (int k=-supp; k<=supp; ++k)
847  {
848  int k2=k*k;
849  for (int i=-supp; i<=supp; ++i)
850  {
851  int i2=i*i;
852  for (int j=-supp; j<=supp; ++j)
853  {
854  int j2=j*j;
855  double r2=k2+i2+j2;
856  if (r2>supp2)
857  continue;
858  double z=alpha*sqrt(1.0-r2/supp2);
859  double value=K*z*z*bessi2(z);
860  A3D_ELEM(kernel,k,i,j)=value;
861  }
862  }
863  }
864 }
void addGradientTerm(double mu, AdmmKernel &kernel, MultidimArray< double > &L, FourierTransformer &transformer, MultidimArray< std::complex< double > > &fourierKernelV, char direction)
void init_progress_bar(long total)
MultidimArray< std::complex< double > > fourierLx
MultidimArray< double > dx
Rotation angle of an image (double,degrees)
#define YSIZE(v)
#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)
__device__ float bessi1(float x)
double getDoubleParam(const char *param, int arg=0)
void threshold(const String &type, T a, T b=0, MultidimArray< int > *mask=NULL)
MultidimArray< double > dz
__host__ __device__ float2 floor(const float2 v)
void getMatrices(int i, Matrix2D< double > &L, Matrix2D< double > &R, bool homogeneous=true) const
Definition: symmetries.cpp:348
MultidimArray< double > uz
void inverseFourierTransform()
Definition: xmipp_fftw.cpp:329
void read(const FileName &inFile, const std::vector< MDLabel > *desiredLabels=nullptr, bool decomposeStack=true) override
#define FINISHINGX(v)
void Euler_angles2matrix(T alpha, T beta, T gamma, Matrix2D< T > &A, bool homogeneous)
Definition: geometry.cpp:624
doublereal * c
#define MULTIDIM_SIZE(v)
MetaDataVec mdIn
void symmetrizeVolume(const SymList &SL, const MultidimArray< double > &V_in, MultidimArray< double > &V_out, int spline, bool wrap, bool do_outside_avg, bool sum, bool helical, bool dihedral, bool helicalDihedral, double rotHelical, double rotPhaseHelical, double zHelical, double heightFraction, const MultidimArray< double > *mask, int Cn)
Definition: symmetrize.cpp:117
double beta(const double a, const double b)
MultidimArray< std::complex< double > > fFourier
Definition: xmipp_fftw.h:70
void sqrt(Image< double > &op)
double dotProduct(const MultidimArray< T > &op1)
Tilting angle of an image (double,degrees)
double projectionValueAt(double u, double v)
int readSymmetryFile(FileName fn_sym, double accuracy=SYM_ACCURACY)
Definition: symmetries.cpp:33
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)
void getImageSize(const MetaData &md, size_t &Xdim, size_t &Ydim, size_t &Zdim, size_t &Ndim, MDLabel image_label)
void convolveKernelWithItself(double _autocorrStep)
Special label to be used when gathering MDs in MpiMetadataPrograms.
MultidimArray< std::complex< double > > fourierLz
Name for the CTF Model (std::string)
#define FINISHINGZ(v)
int symsNo() const
Definition: symmetries.h:268
glob_prnt iter
virtual IdIteratorProxy< false > ids()
MultidimArray< double > ux
void Euler_apply_transf(const Matrix2D< double > &L, const Matrix2D< double > &R, double rot, double tilt, double psi, double &newrot, double &newtilt, double &newpsi)
Definition: geometry.cpp:1038
#define STARTINGX(v)
doublereal * x
int readApplyGeo(const FileName &name, const MDRow &row, const ApplyGeoParams &params=DefaultApplyGeoParams)
size_t size() const override
#define i
void computeGradient(MultidimArray< double > &gradient, char direction, bool adjoint=false)
ql0001_ & k(htemp+1),(cvec+1),(atemp+1),(bj+1),(bl+1),(bu+1),(x+1),(clamda+1), &iout, infoqp, &zero,(w+1), &lenw,(iw+1), &leniw, &glob_grd.epsmac
size_t addRow(const MDRow &row) override
doublereal * d
#define FOR_ALL_ELEMENTS_IN_ARRAY2D(m)
static void defineParams(XmippProgram *program, int allowed_data_types=ALL_KINDS, const char *prefix=nullptr, const char *comment=nullptr, bool moreOptions=false)
Definition: mask.cpp:1203
T interpolatedElement2D(double x, double y, T outside_value=(T) 0) const
#define STARTINGY(v)
void CenterFFT(MultidimArray< T > &v, bool forward)
Definition: xmipp_fft.h:291
void threshold(double *phi, unsigned long nvox, double limit)
Definition: lib_vwk.cpp:524
#define A3D_ELEM(V, k, i, j)
void clear() override
#define FFT_IDX2DIGFREQ_FAST(idx, size, size_2, isize, freq)
Definition: xmipp_fft.h:54
#define FOR_ALL_ELEMENTS_IN_MATRIX1D(v)
Definition: matrix1d.h:72
void apply_mask(const MultidimArray< T > &I, MultidimArray< T > &result, T subs_val=0, bool apply_geo=false)
Definition: mask.h:635
#define FOR_ALL_ELEMENTS_IN_ARRAY3D(V)
const char * getParam(const char *param, int arg=0)
#define XX(v)
Definition: matrix1d.h:85
double getValueAt(bool show=false) const
Compute CTF at (U,V). Continuous frequencies.
Definition: ctf.h:1050
void setReal(MultidimArray< double > &img)
Definition: xmipp_fftw.cpp:129
void readFromMetadataRow(const MetaData &MD, size_t id, bool disable_if_not_K=true)
Definition: ctf.cpp:1214
void applyCTFToKernelAutocorrelation(CTFDescription &ctf, double Ts, MultidimArray< double > &autocorrelationWithCTF)
MultidimArray< std::complex< double > > fourierLy
#define XSIZE(v)
MultidimArray< double > ud
void progress_bar(long rlen)
MultidimArray< double > uy
Image< double > CHtb
#define FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(v)
FourierTransformer transformerL
__device__ float bessi2(float x)
#define ZSIZE(v)
double z
#define DIRECT_MULTIDIM_ELEM(v, n)
void getKernelAutocorrelation(MultidimArray< double > &autocorrelation)
__host__ __device__ float length(float2 v)
MultidimArray< double > paddedx
void initializeKernel(double alpha, double a, double _projectionStep)
void convolutionFFT(MultidimArray< double > &img, MultidimArray< double > &kernel, MultidimArray< double > &result)
Definition: xmipp_fftw.cpp:457
Image< double > Ck
void readParams(XmippProgram *program)
Definition: mask.cpp:1284
void direction(const MultidimArray< double > &orMap, MultidimArray< double > &qualityMap, double lambda, int size, MultidimArray< double > &dirMap, int x, int y)
void precomputeValues(double X, double Y)
Precompute values for a given frequency.
Definition: ctf.h:1002
void FourierTransform(T &v, T1 &V, bool getCopy=true)
Definition: xmipp_fftw.h:166
MultidimArray< std::complex< double > > fourierKernelV
#define j
void project(double rot, double tilt, double psi, MultidimArray< double > &P, bool adjoint=false, double weight=1.)
#define YY(v)
Definition: matrix1d.h:93
MultidimArray< double > dy
bool getValue(MDObject &mdValueOut, size_t id) const override
double bessi2_5(double x)
double sum2() const
#define FINISHINGY(v)
void generate_mask(bool apply_geo=false)
Definition: mask.cpp:1577
void produceSideInfo()
Produce Side information.
Definition: ctf.cpp:1392
double psi(const double x)
#define INT_MASK
Definition: mask.h:385
void applyLtFilter(MultidimArray< std::complex< double > > &fourierL, MultidimArray< double > &u, MultidimArray< double > &d)
doublereal * u
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)
constexpr int K
float r2
void computeHtKH(MultidimArray< double > &kernelV)
void applyKernel3D(MultidimArray< double > &x, MultidimArray< double > &AtAx)
void addUsageLine(const char *line, bool verbatim=false)
void initZeros(const MultidimArray< T1 > &op)
bool containsLabel(const MDLabel label) const override
FourierTransformer transformerPaddedx
virtual void shareVolume(MultidimArray< double > &V)
#define PI
Definition: tools.h:43
int getIntParam(const char *param, int arg=0)
Image< double > Vk
void getRow(size_t i, Matrix1D< T > &v) const
Definition: matrix2d.cpp:871
#define STARTINGZ(v)
int * n
double autocorrStep
#define ZZ(v)
Definition: matrix1d.h:101
void applyLFilter(MultidimArray< std::complex< double > > &fourierL, bool adjoint=false)
void addParamsLine(const String &line)
< Score 4 for volumes
void computeKernel3D(MultidimArray< double > &kernel)
virtual void synchronize()
float r1
__host__ __device__ float dot(float2 a, float2 b)