Xmipp  v3.23.11-Nereus
tomo_detect_missing_wedge.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  *
3  * Authors: Carlos Oscar coss@cnb.csic.es (2009)
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/geometry.h"
28 #include "core/matrix2d.h"
29 #include "core/xmipp_fftw.h"
30 #include "data/numerical_tools.h"
31 
32 // Evaluate plane ----------------------------------------------------------
33 double evaluatePlane(double rot, double tilt,
34  const MultidimArray<double> *V, const MultidimArray<double> *Vmag,
35  double maxFreq, double planeWidth, int direction,
36  MultidimArray<double> *Vdraw=nullptr,
37  bool setPos=false, double rotPos=0, double tiltPos=0)
38 {
39  if (rot<0 || rot>360 || tilt<-90 || tilt>90)
40  return 0;
41 
42  Matrix2D<double> E, Einv;
43  Euler_angles2matrix(rot,tilt,0.,E);
44  Einv=E.transpose();
45 
46  if (setPos)
47  {
48  Matrix2D<double> Epos;
49  Euler_angles2matrix(rotPos,tiltPos,0.,Epos);
50  double angle=acos(E(2,0)*Epos(2,0)+E(2,1)*Epos(2,1)+E(2,2)*Epos(2,2));
51  angle=RAD2DEG(angle);
52  if (fabs(angle)<20 || fabs(180-angle)<20)
53  return 0;
54  }
55 
56  size_t N=XMIPP_MAX(XSIZE(*Vmag),YSIZE(*Vmag)/2);
57  N=XMIPP_MAX(N,ZSIZE(*Vmag)/2);
58  double df=0.5/N;
59  Matrix1D<double> freq(3), freqp(3);
60  Matrix1D<int> idx(3);
61  double sumNeg=0, sumPos=0;
62  int Nneg=0, Npos=0;
63  double maxFreq2=maxFreq*maxFreq;
64  auto iPlaneWidth=(int)ceil(planeWidth);
65  for (int ix=0; ix<=N; ix++)
66  {
67  XX(freq)=ix*df;
68  double fx2=XX(freq)*XX(freq);
69  if (fx2>maxFreq2)
70  continue;
71  for (int iy=-(int)N; iy<=N; iy++)
72  {
73  YY(freq)=iy*df;
74  double fx2fy2=fx2+YY(freq)*YY(freq);
75  if (fx2fy2>maxFreq2)
76  continue;
77  for (int iz=-iPlaneWidth; iz<=iPlaneWidth; iz++)
78  {
79  if (iz==0 || ix==0 || iy==0)
80  continue;
81 
82  // Frequency in the coordinate system of the plane
83  ZZ(freq)=iz*df;
84 
85  // Frequency in the coordinate system of the volume
87  M3x3_BY_V3x1(freqp,Einv,freq);
88  bool inverted=false;
89  if (XX(freqp)<0)
90  {
91  XX(freqp)=-XX(freqp);
92  YY(freqp)=-YY(freqp);
93  ZZ(freqp)=-ZZ(freqp);
94  inverted=true;
95  }
96 
97  // Get the corresponding index
98  DIGFREQ2FFT_IDX(ZZ(freqp), ZSIZE(*V), ZZ(idx));
99  DIGFREQ2FFT_IDX(YY(freqp), YSIZE(*V), YY(idx));
100  DIGFREQ2FFT_IDX(XX(freqp), XSIZE(*V), XX(idx));
101  if (XX(idx) < STARTINGX(*Vmag) || XX(idx) > FINISHINGX(*Vmag) ||
102  YY(idx) < STARTINGY(*Vmag) || YY(idx) > FINISHINGY(*Vmag) ||
103  ZZ(idx) < STARTINGZ(*Vmag) || ZZ(idx) > FINISHINGZ(*Vmag))
104  continue;
105 
106  // Make the corresponding sums
107  bool negativeSum;
108  if (direction==1)
109  negativeSum=iz<0;
110  else
111  negativeSum=iz>0;
112  double val=A3D_ELEM(*Vmag,ZZ(idx),YY(idx),XX(idx));
113  if ((negativeSum && !inverted) || (!negativeSum && inverted)) // XOR
114  {
115  sumNeg+=val;
116  Nneg++;
117  if (Vdraw!=nullptr)
118  (*Vdraw)(idx)=2*direction*val;
119  }
120  else
121  {
122  sumPos+=val;
123  Npos++;
124  if (Vdraw!=nullptr)
125  (*Vdraw)(idx)=1.0/2.0*direction*val;
126  }
127  }
128  }
129  }
130  if (fabs(Nneg-Npos)/(0.5*(Nneg+Npos))>0.5)
131  // If there is a difference of more than 50%
132  return 1e38;
133  if (Nneg!=0)
134  sumNeg/=Nneg;
135  else
136  return 1e38;
137  if (Npos!=0)
138  sumPos/=Npos;
139  else
140  return 1e38;
141 
142  return -(sumPos-sumNeg);
143 }
144 
145 // Look for plane ----------------------------------------------------------
146 class WedgeSolver: public DESolver
147 {
148 public:
149  WedgeSolver(int dim,int pop,
150  const MultidimArray<double> *_V, const MultidimArray<double> *_Vmag,
151  double _maxFreq, double _planeWidth, int _direction):
152  DESolver(dim,pop)
153  {
154  count=0;
155  V=_V;
156  Vmag=_Vmag;
157  maxFreq=_maxFreq;
158  planeWidth=_planeWidth;
159  direction=_direction;
160  setPos=false;
161  }
162 
164  {
165  V = nullptr;
166  Vmag = nullptr;
167  }
168 
169  double EnergyFunction(double trial[],bool &bAtSolution)
170  {
171  double result=evaluatePlane(trial[0],trial[1],V,Vmag,
173  if (count++ % (5*nPop) == 0)
174  std::cout << "Evaluations= " << count/nPop
175  << " energy= " << Energy()
176  << " rot= " << Solution()[0]
177  << " tilt= " << Solution()[1]
178  << std::endl;
179  bAtSolution=false;
180  return result;
181  }
182 public:
183  int count;
186  double maxFreq;
187  double planeWidth;
189  bool setPos;
190  double rotPos;
191  double tiltPos;
192 };
193 
195 double wrapperFitnessDetectMissingWedge(double *p, void* extraArgs)
196 {
197  bool dummy;
198  auto *wegde_solver=(WedgeSolver *) extraArgs;
199  return wegde_solver->EnergyFunction(p+1,dummy);
200 }
201 
203  double maxFreq, double planeWidth, int direction,
204  double &rot, double &tilt,
205  bool setPos=false, double rotPos=0, double tiltPos=0)
206 {
207  // Optimize with DE
208  int length=2;
209  int Npop=50;
210 
211  double min_allowed[] = {0,-90};
212  double max_allowed[] = {360,90};
213 
214  auto * solver = new WedgeSolver(length,length*Npop,V,Vmag,maxFreq,planeWidth,direction);
215  solver->Setup( min_allowed, max_allowed, stBest2Bin, 0.5, 0.8);
216 
217  if (setPos)
218  {
219  solver->setPos=true;
220  solver->rotPos=rotPos;
221  solver->tiltPos=tiltPos;
222  }
223 
224  solver->Solve(50);
225 
226  double * bestSolution = solver->Solution();
227 
228  // Refine with Powell
229  Matrix1D<double> x(2), steps(2);
230  double fitness;
231  int iter;
232  steps.initConstant(1);
233  x(0)=bestSolution[0];
234  x(1)=bestSolution[1];
235  powellOptimizer(x,1,2,&wrapperFitnessDetectMissingWedge,solver,0.01,fitness,iter,steps,true);
236  rot=x(0);
237  tilt=x(1);
238 
239  delete solver;
240 
241  solver = nullptr;
242 }
243 
244 // Draw wedge --------------------------------------------------------------
245 void drawWedge(double rotPos, double tiltPos, double rotNeg, double tiltNeg,
246  const MultidimArray<double> *V,
248 {
249  Matrix2D<double> Epos, Eneg;
250  Euler_angles2matrix(rotPos,tiltPos,0.,Epos);
251  Euler_angles2matrix(rotNeg,tiltNeg,0.,Eneg);
252 
253  Matrix1D<double> freq(3), freqPos, freqNeg;
254  Matrix1D<int> idx(3);
255  Vdraw->initZeros(*Vmag);
257  {
258  // Frequency in the coordinate system of the volume
259  VECTOR_R3(idx,j,i,k);
260  FFT_idx2digfreq(*V,idx,freq);
261 
262  // Frequency in the coordinate system of the plane
263  freqPos=Epos*freq;
264  freqNeg=Eneg*freq;
265  if (ZZ(freqPos)<0 || ZZ(freqNeg)>0)
266  (*Vdraw)(k,i,j)+=1;
267  }
268 }
269 
270 // Read from command line --------------------------------------------------
272 {
273  fn_vol = getParam("-i");
274  maxFreq = getDoubleParam("--maxFreq");
275  planeWidth = getDoubleParam("--width");
276  saveMarks = checkParam("--saveMarks");
277  saveMask = checkParam("--saveMask");
278 }
279 
280 // Produce side info -------------------------------------------------------
282 {
283  V.read(fn_vol);
284  FourierTransformer transformer;
286  transformer.FourierTransform(MULTIDIM_ARRAY(V),Vfft,false);
287  Vmag = new MultidimArray<double>();
288  Vmag->resize(Vfft);
290  (*Vmag)(k,i,j)=20*log10(abs(Vfft(k,i,j)));
291 }
292 
293 // Show --------------------------------------------------------------------
295 {
296  std::cout << "Detecting a missing wedge\n";
297  std::cout << "Input volume: " << fn_vol << std::endl
298  << "Maximum Freq.: " << maxFreq << std::endl
299  << "Plane width: " << planeWidth << std::endl
300  << "saveMarks: " << saveMarks << std::endl
301  << "saveMask: " << saveMask << std::endl
302  ;
303 }
304 
305 // Usage -------------------------------------------------------------------
307 {
308  addUsageLine("Detect the orientation of the missing wedge in a tomogram. ");
309  addUsageLine("+For doing so it fits a couple of planes along which there is a maximum ");
310  addUsageLine("+variation between the energy of the Fourier transform on its left and ");
311  addUsageLine("+on its right. The missing wedge is coded with four angles (two for each ");
312  addUsageLine("+plane). You may also produce a mask with 1 where the missing wedge is, ");
313  addUsageLine("+and 0 where the data has been actually measured. Finally, you can also ");
314  addUsageLine("+produce a marked magnitude volume (i.e., the magnitude of the Fourier ");
315  addUsageLine("+transform where the position of the two planes have been marked). ");
316  addParamsLine(" -i <file> : Input tomogram");
317  addParamsLine(" [--maxFreq <f=0.25>] : Maximum frequency to fit the plane (normalized to 0.5)");
318  addParamsLine(" [--width <w=2>] : Width of the probe plane");
319  addParamsLine(" [--saveMarks] : Save the magnitude of the FFT with");
320  addParamsLine(" : marks showing the two planes");
321  addParamsLine(" [--saveMask] : Save a mask for the FFT of this tomogram");
322  addParamsLine(" : 1=Missing wedge, 0=non missing wedge");
323  addExampleLine("xmipp_tomo_detect_missing_wedge -i tomogram.vol");
324 }
325 
326 // Run ---------------------------------------------------------------------
328 {
329  produceSideInfo();
330  FileName fn_root=V.name().withoutExtension();
331 
333 
334  // Detect one of the planes
336 
337  auto * Vdraw = new Image<double>();
338 
339  if (saveMarks)
340  {
341  (*Vdraw)()=(*Vmag);
342 
344  1, &(*Vdraw)());
345  }
346 
347  // Detect the other plane
348  lookForPlane(mdaV, Vmag, maxFreq, planeWidth, -1, rotNeg, tiltNeg, true, rotPos, tiltPos);
349 
350  if (saveMarks)
351  {
352  evaluatePlane(rotNeg, tiltNeg, mdaV, Vmag, maxFreq, planeWidth,
353  -1, &(*Vdraw)());
354  Vdraw->write(fn_root+"_marks.vol");
355  }
356 
357  if (saveMask)
358  {
359  Vdraw->clear();
360  drawWedge(rotPos, tiltPos, rotNeg, tiltNeg, mdaV, Vmag, &(*Vdraw)());
361  Vdraw->write(fn_root+"_mask.vol");
362  }
363 
364  std::cout << "Plane1: " << rotPos << " " << tiltPos << std::endl;
365  std::cout << "Plane2: " << rotNeg << " " << tiltNeg << std::endl;
366 
367  delete Vdraw;
368  delete Vmag;
369 }
double Energy() const
Call these functions after Solve() to get results.
#define YSIZE(v)
void readParams()
Read parameters from command line.
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 * bestSolution
#define FINISHINGX(v)
void Euler_angles2matrix(T alpha, T beta, T gamma, Matrix2D< T > &A, bool homogeneous)
Definition: geometry.cpp:624
double EnergyFunction(double trial[], bool &bAtSolution)
void drawWedge(double rotPos, double tiltPos, double rotNeg, double tiltNeg, const MultidimArray< double > *V, const MultidimArray< double > *Vmag, MultidimArray< double > *Vdraw)
#define MULTIDIM_ARRAY(v)
void abs(Image< double > &op)
void powellOptimizer(Matrix1D< double > &p, int i0, int n, double(*f)(double *x, void *), void *prm, double ftol, double &fret, int &iter, const Matrix1D< double > &steps, bool show)
void lookForPlane(const MultidimArray< double > *V, const MultidimArray< double > *Vmag, double maxFreq, double planeWidth, int direction, double &rot, double &tilt, bool setPos=false, double rotPos=0, double tiltPos=0)
Matrix2D< T > transpose() const
Definition: matrix2d.cpp:1314
#define FINISHINGZ(v)
glob_prnt iter
#define DIGFREQ2FFT_IDX(freq, size, idx)
Definition: xmipp_fft.h:61
void FFT_idx2digfreq(T &v, const Matrix1D< int > &idx, Matrix1D< double > &freq)
Definition: xmipp_fft.h:80
#define STARTINGX(v)
doublereal * x
#define i
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
#define STARTINGY(v)
#define A3D_ELEM(V, k, i, j)
#define FOR_ALL_ELEMENTS_IN_ARRAY3D(V)
#define XX(v)
Definition: matrix1d.h:85
#define XSIZE(v)
constexpr int stBest2Bin
#define ZSIZE(v)
__host__ __device__ float length(float2 v)
void show() const
Show parameters.
const MultidimArray< double > * Vmag
void direction(const MultidimArray< double > &orMap, MultidimArray< double > &qualityMap, double lambda, int size, MultidimArray< double > &dirMap, int x, int y)
void log10(Image< double > &op)
double dummy
double wrapperFitnessDetectMissingWedge(double *p, void *extraArgs)
void FourierTransform(T &v, T1 &V, bool getCopy=true)
Definition: xmipp_fftw.h:166
WedgeSolver(int dim, int pop, const MultidimArray< double > *_V, const MultidimArray< double > *_Vmag, double _maxFreq, double _planeWidth, int _direction)
#define j
#define M3x3_BY_V3x1(a, M, b)
Definition: matrix2d.h:170
double steps
#define YY(v)
Definition: matrix1d.h:93
#define FINISHINGY(v)
double evaluatePlane(double rot, double tilt, const MultidimArray< double > *V, const MultidimArray< double > *Vmag, double maxFreq, double planeWidth, int direction, MultidimArray< double > *Vdraw=nullptr, bool setPos=false, double rotPos=0, double tiltPos=0)
#define RAD2DEG(r)
Definition: xmipp_macros.h:320
const MultidimArray< double > * V
#define VECTOR_R3(v, x, y, z)
Definition: matrix1d.h:124
void initZeros(const MultidimArray< T1 > &op)
double * Solution(void)
Return best solution.
void initConstant(T val)
Definition: matrix1d.cpp:83
#define STARTINGZ(v)
double fitness(double *p)
#define ZZ(v)
Definition: matrix1d.h:101
#define SPEED_UP_temps012
Definition: xmipp_macros.h:403
void produceSideInfo()
Produce side info.
void pop(struct stack_T *stack)
Definition: stack.cpp:59