Xmipp  v3.23.11-Nereus
volume_find_symmetry.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  *
3  * Authors: Carlos Oscar coss@cnb.csic.es (2002)
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 <core/args.h>
27 #include <data/mask.h>
28 #include <data/filters.h>
29 #include <core/geometry.h>
30 #include <core/symmetries.h>
31 #include <core/xmipp_program.h>
32 #include <core/xmipp_threads.h>
33 #include <data/symmetries.h>
34 
35 #include <cstdio>
36 
37 // Prototypes
39 double evaluateSymmetryWrapper(double *p, void *prm);
40 
42 {
43 public:
44  int rot_sym;
45  bool useSplines;
49  double tilt0, tiltF, step_tilt;
51  bool local;
55  int Cn;
56 
57  // Define parameters
58  void defineParams()
59  {
60  addUsageLine("Find a symmetry rotational axis.");
61  addUsageLine("+The output is of the form");
62  addUsageLine("+Symmetry axis (rot,tilt)= 10 20 --> 0.33682 0.059391 0.93969",true);
63  addUsageLine("+The angles represent the rot and tilt angles of the symmetry axis ");
64  addUsageLine("+see [[http://xmipp.cnb.csic.es/twiki/bin/view/Xmipp/Conventions#Euler_Angles][the note on Euler angles]] ");
65  addUsageLine("+convention in Xmipp). The rest of the numbers is the axis itself in X, Y, Z ");
66  addUsageLine("+coordinates. In this way, the symmetry axis is a line that passes through the ");
67  addUsageLine("+center of the volume and whose direction is this vector.");
68  addUsageLine("+It is important that the volume is correctly centered.");
69  addSeeAlsoLine("volume_center, transform_geometry");
70  addParamsLine(" -i <volumeFile> : Volume to process");
71  addParamsLine("[-o+ <file=\"\">] : Metadata with the orientation of the symmetry axis");
72  addParamsLine(" : In helical mode, there is a file called output.xmp ");
73  addParamsLine(" : with the correlation map (vertical axis is the rotation, ");
74  addParamsLine(" : horizontal axis is the translation)");
75  addParamsLine("[--thr <N=1>] : Number of threads");
76  addParamsLine("--sym <mode> : Symmetry mode");
77  addParamsLine(" where <mode>");
78  addParamsLine(" rot <n> : Order of the rotational axis");
79  addParamsLine(" helical : Helical symmetry.");
80  addParamsLine(" helicalDihedral : Helical-Dihedral symmetry.");
81  addParamsLine("[--sym2 <Cn=C1>] : Additional Cn symmetry. Only for helical and helicalDihedral");
82  addParamsLine("==Locate rotational axis==");
83  addParamsLine("[--rot <rot0=0> <rotF=355> <step=5>]: Limits for rotational angle search");
84  addParamsLine("[--tilt <tilt0=0> <tiltF=90> <step=5>]: Limits for tilt angle search");
85  addParamsLine("[--localRot <rot0> <tilt0>] : Perform a local search around this angle");
86  addParamsLine("[--useSplines+] : Use cubic B-Splines for the interpolations");
87  addParamsLine("==Locate helical parameters==");
88  addParamsLine("[-z <z0=1> <zF=10> <zstep=0.5>] : Search space for the shift in Z (in Angstroms)");
89  addParamsLine("[--sampling <T=1>] : Sampling rate in A/pix");
90  addParamsLine("[--rotHelical <rot0=-357> <rotF=357> <step=3>]: Search space for rotation around Z");
91  addParamsLine("[--localHelical <z> <rot>] : Perform a local search around this angle and shift");
92  addParamsLine("[--heightFraction <f=1>] : Use this fraction of the volume");
93  mask_prm.defineParams(this,INT_MASK,nullptr,"Restrict the comparison to the mask area.",true);
94  addExampleLine("A typical application for a rotational symmetry axis is ",false);
95  addExampleLine("xmipp_volume_center -i volume.vol");
96  addExampleLine("xmipp_volume_find_symmetry -i volume.vol --sym rot 3");
97  addExampleLine("Presume the symmetry axis is in rot=20, tilt=10. To align vertically the axis use",false);
98  addExampleLine("xmipp_transform_geometry -i volume.vol --rotate_volume euler 20 10 0");
99  addExampleLine("For locating the helical parameters use",false);
100  addExampleLine("xmipp_volume_find_symmetry -i volume --sym helical -z 0 6 1 --mask circular -32 --thr 2 -o parameters.xmd");
101  }
102 
103  // Read parameters
104  void readParams()
105  {
106  fn_input = getParam("-i");
107  fn_output = getParam("-o");
108  String mode;
109  mode=getParam("--sym");
110  if (mode=="helical")
111  helical=true;
112  else if (mode=="helicalDihedral")
113  helicalDihedral=true;
114  else
115  {
116  helical=false;
117  helicalDihedral=false;
118  rot_sym = getIntParam("--sym",1);
119  }
120  useSplines = checkParam("--useSplines");
121  if (helical || helicalDihedral)
122  {
123  Ts=getDoubleParam("--sampling");
124  heightFraction=getDoubleParam("--heightFraction");
125  local=checkParam("--localHelical");
126  if (local)
127  {
128  zLocal=getDoubleParam("--localHelical",0)/Ts;
129  rotLocal=getDoubleParam("--localHelical",1);
130  }
131  z0=getDoubleParam("-z",0)/Ts;
132  zF=getDoubleParam("-z",1)/Ts;
133  step_z=getDoubleParam("-z",2)/Ts;
134  rot0=getDoubleParam("--rotHelical",0);
135  rotF=getDoubleParam("--rotHelical",1);
136  step_rot=getDoubleParam("--rotHelical",2);
137  sym2 = getParam("--sym2");
138  Cn=std::stoi(sym2.substr(1));
139  }
140  else
141  {
142  local=checkParam("--localRot");
143  if (local)
144  {
145  rot0=getDoubleParam("--localRot",0);
146  tilt0=getDoubleParam("--localRot",1);
147  }
148  else
149  {
150  rot0=getDoubleParam("--rot",0);
151  rotF=getDoubleParam("--rot",1);
152  step_rot=getDoubleParam("--rot",2);
153  tilt0=getDoubleParam("--tilt",0);
154  tiltF=getDoubleParam("--tilt",1);
155  step_tilt=getDoubleParam("--tilt",2);
156  }
157  }
158  mask_prm.allowed_data_types = INT_MASK;
159  if (checkParam("--mask"))
160  mask_prm.readParams(this);
161  numberOfThreads=getIntParam("--thr");
162  }
163 
164  void threadEvaluateSymmetry(int thrId)
165  {
166  Matrix1D<double> p(2);
167  DIRECT_A1D_ELEM(vbest_corr,thrId) = 0;
168  DIRECT_A1D_ELEM(vbest_rot,thrId) = 0;
169  if (helical || helicalDihedral)
170  DIRECT_A1D_ELEM(vbest_z,thrId) = 0;
171  else
172  DIRECT_A1D_ELEM(vbest_tilt,thrId) = 0;
173  size_t first, last;
174  if (thrId==0)
176  while (td->getTasks(first, last))
177  {
178  for (size_t i=first; i<=last; i++)
179  {
180  XX(p)=rotVector[i];
181  if (helical || helicalDihedral)
182  YY(p)=zVector[i];
183  else
184  YY(p)=tiltVector[i];
185  double corr=-evaluateSymmetry(MATRIX1D_ARRAY(p)-1);
186  if (helical || helicalDihedral)
188  if (corr > DIRECT_A1D_ELEM(vbest_corr,thrId))
189  {
190  DIRECT_A1D_ELEM(vbest_corr,thrId) = corr;
191  DIRECT_A1D_ELEM(vbest_rot,thrId) = XX(p);
192  if (helical || helicalDihedral)
193  DIRECT_A1D_ELEM(vbest_z,thrId) = YY(p);
194  else
195  DIRECT_A1D_ELEM(vbest_tilt,thrId) = YY(p);
196  }
197  }
198  if (thrId==0)
199  progress_bar(last);
200  }
201  if (thrId==0)
202  progress_bar(rotVector.size());
203  }
204 
205  void run()
206  {
207  // Read input volume
208  volume.read(fn_input);
209  volume().setXmippOrigin();
210  mask_prm.generate_mask(volume());
211  double best_corr, best_rot, best_tilt, best_z;
212  td=nullptr;
213 
214  if (!helical && !helicalDihedral)
215  {
216  // Look for the rotational symmetry axis
217  if (!local)
218  {
219  if (verbose>0)
220  std::cerr << "Searching symmetry axis ...\n";
221  for (double rot = rot0; rot <= rotF; rot += step_rot)
222  for (double tilt = tilt0; tilt <= tiltF; tilt += step_tilt) {
223  rotVector.push_back(rot);
224  tiltVector.push_back(tilt);
225  }
226  vbest_corr.resizeNoCopy(numberOfThreads);
227  vbest_corr.initConstant(-1e38);
228  vbest_rot.initZeros(numberOfThreads);
229  vbest_tilt.initZeros(numberOfThreads);
230  td = new ThreadTaskDistributor(rotVector.size(), 5);
231  ThreadManager thMgr(numberOfThreads,this);
232  thMgr.run(globalThreadEvaluateSymmetry);
233  best_corr=-1e38;
235  if (vbest_corr(i)>best_corr)
236  {
237  best_corr=vbest_corr(i);
238  best_rot=vbest_rot(i);
239  best_tilt=vbest_tilt(i);
240  }
241  }
242  else
243  {
244  Matrix1D<double> p(2), steps(2);
245  p(0)=rot0;
246  p(1)=tilt0;
247  double fitness;
248  int iter;
249  steps.initConstant(1);
250  powellOptimizer(p,1,2,&evaluateSymmetryWrapper,this,0.01,
251  fitness,iter,steps,true);
252  best_rot=p(0);
253  best_tilt=p(1);
254  }
256  Matrix1D<double> sym_axis;
257  Euler_angles2matrix(best_rot, best_tilt, 0., Euler);
258  Euler.getRow(2, sym_axis);
259  if (verbose!=0)
260  std::cout << "Symmetry axis (rot,tilt)= " << best_rot << " "
261  << best_tilt << " --> " << sym_axis << std::endl;
262  if (fn_output!="")
263  {
264  std::vector<double> direction;
265  direction.push_back(XX(sym_axis));
266  direction.push_back(YY(sym_axis));
267  direction.push_back(ZZ(sym_axis));
268 
269  MetaDataVec MD;
270  size_t id=MD.addObject();
271  MD.setValue(MDL_ANGLE_ROT,best_rot,id);
272  MD.setValue(MDL_ANGLE_TILT,best_tilt,id);
273  MD.setValue(MDL_DIRECTION,direction,id);
274  MD.write(fn_output);
275  }
276  }
277  else
278  {
279  // If helical or helical dihedral
280  if (heightFraction<=1.0)
281  {
282  int zFirst=FIRST_XMIPP_INDEX(round(heightFraction*ZSIZE(volume())));
283  int zLast=LAST_XMIPP_INDEX(round(heightFraction*ZSIZE(volume())));
284  MultidimArray<int> &mask=mask_prm.get_binary_mask();
286  if (k<zFirst || k>zLast)
287  A3D_ELEM(mask,k,i,j)=0;
288  }
289 
290  if (!local)
291  {
292  int ydim=0, xdim=0;
293  for (double rot = rot0; rot <= rotF; rot += step_rot)
294  {
295  ydim++;
296  for (double z = z0; z <= zF; z += step_z)
297  {
298  if (ydim==1)
299  xdim++;
300  rotVector.push_back(rot);
301  zVector.push_back(z);
302  }
303  }
304  vbest_corr.resizeNoCopy(numberOfThreads);
305  vbest_corr.initConstant(-1e38);
306  vbest_rot.initZeros(numberOfThreads);
307  vbest_z.initZeros(numberOfThreads);
308  helicalCorrelation().initZeros(ydim,xdim);
309  td = new ThreadTaskDistributor(rotVector.size(), 5);
310  ThreadManager thMgr(numberOfThreads,this);
311  thMgr.run(globalThreadEvaluateSymmetry);
312  best_corr=-1e38;
314  if (vbest_corr(i)>best_corr)
315  {
316  best_corr=vbest_corr(i);
317  best_rot=vbest_rot(i);
318  best_z=vbest_z(i);
319  }
320  }
321  else
322  {
323  Matrix1D<double> p(2), steps(2);
324  p(0)=rotLocal;
325  p(1)=zLocal;
326  double fitness;
327  int iter;
328  steps.initConstant(1);
329  powellOptimizer(p,1,2,&evaluateSymmetryWrapper,this,0.01,
330  fitness,iter,steps,true);
331  best_rot=p(0);
332  best_z=p(1);
333  best_corr=-fitness;
334 
335  }
336  if (verbose!=0)
337  std::cout << "Symmetry parameters (z,rot)= " << best_z*Ts << " " << best_rot << " correlation=" << best_corr << std::endl;
338  if (fn_output!="")
339  {
340  MetaDataVec MD;
341  size_t id=MD.addObject();
342  MD.setValue(MDL_ANGLE_ROT,best_rot,id);
343  MD.setValue(MDL_SHIFT_Z,best_z*Ts,id);
344  MD.write(fn_output);
345  if (!local)
346  helicalCorrelation.write(fn_output.removeAllExtensions()+".xmp");
347  }
348  }
349  delete td;
350  }
351 
353  std::vector<double> rotVector, tiltVector, zVector;
357 
358  /* Evaluate symmetry ------------------------------------------------------- */
359  double evaluateSymmetry(double *p)
360  {
361  MultidimArray<double> volume_sym, volume_aux;
362  const MultidimArray<double> &mVolume=volume();
363  Matrix2D<double> sym_matrix;
364  if (!helical && !helicalDihedral)
365  {
367  Matrix1D<double> sym_axis;
368 
369  double rot=p[1];
370  double tilt=p[2];
371 
372  // Compute symmetry axis
373  Euler_angles2matrix(rot, tilt, 0., Euler);
374  Euler.getRow(2, sym_axis);
375  sym_axis.selfTranspose();
376 
377  // Symmetrize along this axis
378  volume_sym = volume();
379  for (int n = 1; n < rot_sym; n++)
380  {
381  rotation3DMatrix(360.0 / rot_sym * n, sym_axis, sym_matrix);
382  if (useSplines)
383  applyGeometry(xmipp_transformation::BSPLINE3, volume_aux, mVolume, sym_matrix,
384  xmipp_transformation::IS_NOT_INV, xmipp_transformation::DONT_WRAP);
385  else
386  applyGeometry(xmipp_transformation::LINEAR, volume_aux, mVolume, sym_matrix,
387  xmipp_transformation::IS_NOT_INV, xmipp_transformation::DONT_WRAP);
388  volume_sym += volume_aux;
389  }
390  return -correlationIndex(mVolume, volume_sym, &mask_prm.get_binary_mask());
391  }
392  else
393  {
394  double rotHelical=p[1];
395  double zHelical=p[2];
396  if (zHelical<0 || zHelical>ZSIZE(mVolume)*0.4)
397  return 1e38;
398  if (zHelical<z0 || zHelical>zF || rotHelical<rot0 || rotHelical>rotF)
399  return 1e38;
400  symmetry_Helical(volume_sym, mVolume, zHelical, DEG2RAD(rotHelical), 0, &mask_prm.get_binary_mask(), helicalDihedral, heightFraction,Cn);
401  double corr=correlationIndex(mVolume, volume_sym, &mask_prm.get_binary_mask());
402 //#define DEBUG
403 #ifdef DEBUG
404 
405  Image<double> save;
406  save()=mVolume;
407  save.write("PPPvol.vol");
408  save()=volume_sym;
409  save.write("PPPvolsym.vol");
410  typeCast(mask_prm.get_binary_mask(),save());
411  save.write("PPPmask.vol");
412  std::cout << p[1] << " " << p[2] << " " << p[3] << " -> " << corr << std::endl;
413  char c;
414  std::cin >> c;
415 #endif
416  return -corr;
417  }
418  }
419 };
420 
422 {
423  ((ProgVolumeFindSymmetry*)thArg.workClass)->threadEvaluateSymmetry(thArg.thread_id);
424 }
425 
426 double evaluateSymmetryWrapper(double *p, void *prm)
427 {
428  return ((ProgVolumeFindSymmetry*)prm)->evaluateSymmetry(p);
429 }
std::vector< double > zVector
void init_progress_bar(long total)
Rotation angle of an image (double,degrees)
double getDoubleParam(const char *param, int arg=0)
void threadEvaluateSymmetry(int thrId)
void Euler_angles2matrix(T alpha, T beta, T gamma, Matrix2D< T > &A, bool homogeneous)
Definition: geometry.cpp:624
doublereal * c
ThreadManager * thMgr
#define DEG2RAD(d)
Definition: xmipp_macros.h:312
MultidimArray< double > vbest_z
void resizeNoCopy(const MultidimArray< T1 > &v)
Definition: mask.h:360
Tilting angle of an image (double,degrees)
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)
bool getTasks(size_t &first, size_t &last)
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)
MultidimArray< double > vbest_rot
double correlationIndex(const MultidimArray< T > &x, const MultidimArray< T > &y, const MultidimArray< int > *mask=NULL, MultidimArray< double > *Contributions=NULL)
int allowed_data_types
Definition: mask.h:495
void initConstant(T val)
void write(const FileName &outFile, WriteModeMetaData mode=MD_OVERWRITE) const
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)
FileName removeAllExtensions() const
glob_prnt iter
std::vector< double > rotVector
void selfTranspose()
Definition: matrix1d.h:944
MultidimArray< double > vbest_tilt
#define i
double evaluateSymmetryWrapper(double *p, void *prm)
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
void addSeeAlsoLine(const char *seeAlso)
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
void rotation3DMatrix(double ang, char axis, Matrix2D< double > &result, bool homogeneous)
#define A3D_ELEM(V, k, i, j)
glob_log first
#define DIRECT_A1D_ELEM(v, i)
#define FOR_ALL_ELEMENTS_IN_ARRAY3D(V)
std::vector< double > tiltVector
double evaluateSymmetry(double *p)
const char * getParam(const char *param, int arg=0)
#define XX(v)
Definition: matrix1d.h:85
bool setValue(const MDObject &mdValueIn, size_t id)
size_t addObject() override
void progress_bar(long rlen)
void symmetry_Helical(MultidimArray< double > &Vout, const MultidimArray< double > &Vin, double zHelical, double rotHelical, double rot0, MultidimArray< int > *mask, bool dihedral, double heightFraction, int Cn)
void write(const FileName &fn) const
Definition: euler.h:39
#define ZSIZE(v)
double z
#define DIRECT_MULTIDIM_ELEM(v, n)
void addExampleLine(const char *example, bool verbatim=true)
ThreadTaskDistributor * td
void readParams(XmippProgram *program)
Definition: mask.cpp:1284
MultidimArray< double > vbest_corr
void direction(const MultidimArray< double > &orMap, MultidimArray< double > &qualityMap, double lambda, int size, MultidimArray< double > &dirMap, int x, int y)
int verbose
Verbosity level.
void mode
void * workClass
The class in which threads will be working.
#define j
double steps
#define YY(v)
Definition: matrix1d.h:93
#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
#define MATRIX1D_ARRAY(v)
Definition: matrix1d.h:58
void typeCast(const Matrix1D< T1 > &v1, Matrix1D< T2 > &v2)
Definition: matrix1d.h:1227
#define FIRST_XMIPP_INDEX(size)
Definition: xmipp_macros.h:439
std::string String
Definition: xmipp_strings.h:34
void globalThreadEvaluateSymmetry(ThreadArgument &thArg)
#define INT_MASK
Definition: mask.h:385
Shift for the image in the Z axis (double)
int thread_id
The thread id.
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)
ProgClassifyCL2D * prm
Direction in 3D.
void addUsageLine(const char *line, bool verbatim=false)
void initZeros(const MultidimArray< T1 > &op)
#define LAST_XMIPP_INDEX(size)
Definition: xmipp_macros.h:448
const MultidimArray< int > & get_binary_mask() const
Definition: mask.h:707
int getIntParam(const char *param, int arg=0)
void getRow(size_t i, Matrix1D< T > &v) const
Definition: matrix2d.cpp:871
void initConstant(T val)
Definition: matrix1d.cpp:83
int * n
double fitness(double *p)
#define ZZ(v)
Definition: matrix1d.h:101
void addParamsLine(const String &line)