Xmipp  v3.23.11-Nereus
volume_initial_simulated_annealing.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  *
3  * Authors: Carlos Oscar S. Sorzano (coss@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 <data/filters.h>
28 
29 // Define params
31 {
32  //usage
33  addUsageLine("Generate 3D reconstructions from projections using random orientations");
34  //params
35  addParamsLine(" -i <md_file> : Metadata file with input projections");
36  addParamsLine(" [--oroot <volume_file=\"rec_random\">] : Filename for output rootname");
37  addParamsLine(" [--sym <symfile=c1>] : Enforce symmetry in projections");
38  addParamsLine(" [--randomIter <N=10>] : Number of iterations with random assignment");
39  addParamsLine(" [--greedyIter <N=0>] : Number of iterations with greedy assignment");
40  addParamsLine(" [--rejection <p=25>] : Percentage of images to reject for reconstruction");
41  addParamsLine(" [--initial <file=\"\">] : Initial volume if available");
42  addParamsLine(" [--keepIntermediateVolumes] : Keep the volume of each iteration");
43  addParamsLine(" [--dontApplyPositive] : Do not apply positive constraint in the random iterations");
44  addParamsLine(" [--T0 <T=0.1>] : Initial temperature for simulated annealing");
45  addParamsLine(" [--thr <n=1>] : Number of threads");
46  addParamsLine(" [--angularSampling <a=5>] : Angular sampling in degrees for generating the projection gallery");
47 }
48 
49 // Read arguments ==========================================================
51 {
52  fnIn = getParam("-i");
53  fnRoot = getParam("--oroot");
54  fnSym = getParam("--sym");
55  T0 = getDoubleParam("--T0");
56  NiterRandom = getIntParam("--randomIter");
57  NiterGreedy = getIntParam("--greedyIter");
58  rejection = getDoubleParam("--rejection");
59  fnInit = getParam("--initial");
60  Nthr = getIntParam("--thr");
61  positiveConstraint = !checkParam("--dontApplyPositive");
62  keepIntermediateVolumes = checkParam("--keepIntermediateVolumes");
63  angularSampling=getDoubleParam("--angularSampling");
64 }
65 
66 // Show ====================================================================
68 {
69  if (verbose > 0)
70  {
71  std::cout << "Input metadata : " << fnIn << std::endl;
72  std::cout << "Output rootname : " << fnRoot << std::endl;
73  std::cout << "T0 : " << T0 << std::endl;
74  std::cout << "Number of random iterations : " << NiterRandom << std::endl;
75  std::cout << "Number of greedy iterations : " << NiterGreedy << std::endl;
76  std::cout << "Rejection percentage : " << rejection << std::endl;
77  std::cout << "Number of threads : " << Nthr << std::endl;
78  std::cout << "Apply positive constraint : " << positiveConstraint << std::endl;
79  std::cout << "Keep intermediate volumes : " << keepIntermediateVolumes << std::endl;
80  std::cout << "Angular sampling : " << angularSampling << std::endl;
81  if (fnSym != "")
82  std::cout << "Symmetry for projections : " << fnSym << std::endl;
83  if (fnInit !="")
84  std::cout << "Initial volume : " << fnInit << std::endl;
85  }
86 }
87 
88 // Alignment of a single image ============================================
89 //#define DEBUG
90 void alignSingleImage(size_t nImg, ProgVolumeInitialSimulatedAnnealing &prm, MetaData &mdReconstruction, double &newCorr, double &improvementFraction)
91 {
92  MultidimArray<double> mGalleryProjection, mCurrentImage, mCurrentImageAligned;
94 
95  mCurrentImage.aliasImageInStack(prm.inputImages(),nImg);
96  mCurrentImage.setXmippOrigin();
97 
98  MultidimArray<double> allCorrs;
99  allCorrs.resizeNoCopy(prm.mdGallery.size());
100 
101  size_t improvementCount=0;
102  double oldCorr=prm.mdInp[nImg].maxcc;
103 #ifdef DEBUG
104  FileName fnImg;
105  prm.mdIn.getValue(MDL_IMAGE,fnImg,id);
106  std::cout << "Image: " << fnImg << " oldCorr=" << oldCorr << std::endl;
107 #endif
108  std::vector< Matrix2D<double> > allM;
109  for (size_t nGallery=0; nGallery<XSIZE(allCorrs); ++nGallery)
110  {
111  mCurrentImageAligned=mCurrentImage;
112  mGalleryProjection.aliasImageInStack(prm.gallery(),nGallery);
113  mGalleryProjection.setXmippOrigin();
114  double corr=alignImagesConsideringMirrors(mGalleryProjection,mCurrentImageAligned,M,xmipp_transformation::DONT_WRAP);
115 #ifdef DEBUG
116  mdGallery.getValue(MDL_MAXCC,corr,__iter.objId);
117 #endif
118  A1D_ELEM(allCorrs,nGallery)=corr;
119  allM.push_back(M);
120  if (corr>oldCorr)
121  {
122  ++improvementCount;
123 #ifdef DEBUG
124  prm.mdGallery.getValue(MDL_IMAGE,fnImg,__iter.objId);
125  std::cout << " Matching Gallery: " << fnImg << " " << corr << std::endl;
126 #endif
127  }
128  }
129  improvementFraction=(double)improvementCount/NSIZE(prm.gallery());
130 #ifdef DEBUG
131  mdGallery.write("PPPgallery.xmd");
132  std::cout << " oldcorr=" << oldCorr << std::endl;
133 #endif
134 
135  MultidimArray<double> scaledCorrs;
136  allCorrs.cumlativeDensityFunction(scaledCorrs);
137  double bestCorr, bestAngleRot, bestAngleTilt, bestAnglePsi, bestShiftX, bestShiftY, bestWeight;
138  bool bestFlip;
139  bestCorr=-1;
140  double correctionFactor=1;
141  double currentT=prm.T0*(1.0-((double)prm.iter)/prm.NiterRandom);
142  double icurrentT=1.0/currentT;
143  for (size_t nGallery=0; nGallery<XSIZE(allCorrs); ++nGallery)
144  {
145  bool getThis=(A1D_ELEM(allCorrs,nGallery)>oldCorr) || (improvementCount==0 && A1D_ELEM(scaledCorrs,nGallery)>=0.98);
146  if (A1D_ELEM(allCorrs,nGallery)<oldCorr && !getThis && prm.iter<=prm.NiterRandom)
147  {
148  // Simulated annealing
149  double diff=oldCorr-A1D_ELEM(allCorrs,nGallery);
150  double p=rnd_unif();
151  getThis=(p<exp(-diff*icurrentT));
152  }
153  if (getThis)
154  {
155  bool flip;
156  double scale, shiftX, shiftY, anglePsi;
157  transformationMatrix2Parameters2D(allM[nGallery],flip,scale,shiftX,shiftY,anglePsi);
158  anglePsi*=-1;
159  double weight=A1D_ELEM(scaledCorrs,nGallery)*correctionFactor;
160  double corr=A1D_ELEM(allCorrs,nGallery);
161  double angleRot=prm.mdGallery[nGallery].rot;
162  double angleTilt=prm.mdGallery[nGallery].tilt;
163 #ifdef DEBUG
164  fnImg=prm.mdGallery[nGallery].fnImg;
165  std::cout << " Getting Gallery: " << fnImg << " corr=" << corr << " cdf=" << weight << " rot=" << angleRot
166  << " tilt=" << angleTilt << std::endl;
167 #endif
168 
169  if (prm.iter<=prm.NiterRandom)
170  {
171  size_t recId=mdReconstruction.addObject();
172  FileName fnImg;
173  fnImg=prm.mdInp[nImg].fnImg;
174  mdReconstruction.setValue(MDL_IMAGE,fnImg,recId);
175  mdReconstruction.setValue(MDL_ENABLED,1,recId);
176  mdReconstruction.setValue(MDL_MAXCC,corr,recId);
177  mdReconstruction.setValue(MDL_ANGLE_ROT,angleRot,recId);
178  mdReconstruction.setValue(MDL_ANGLE_TILT,angleTilt,recId);
179  mdReconstruction.setValue(MDL_ANGLE_PSI,anglePsi,recId);
180  mdReconstruction.setValue(MDL_SHIFT_X,shiftX,recId);
181  mdReconstruction.setValue(MDL_SHIFT_Y,shiftY,recId);
182  mdReconstruction.setValue(MDL_FLIP,flip,recId);
183  mdReconstruction.setValue(MDL_WEIGHT,weight,recId);
184  }
185  if (corr>bestCorr)
186  {
187  bestCorr=corr;
188  bestAngleRot=angleRot;
189  bestAngleTilt=angleTilt;
190  bestAnglePsi=anglePsi;
191  bestShiftX=shiftX;
192  bestShiftY=shiftY;
193  bestFlip=flip;
194  bestWeight=weight;
195  }
196  }
197 
198  ++nGallery;
199  }
200 
201  if (prm.iter>prm.NiterRandom)
202  {
203  size_t recId=mdReconstruction.addObject();
204  FileName fnImg;
205  fnImg=prm.mdInp[nImg].fnImg;
206  mdReconstruction.setValue(MDL_IMAGE,fnImg,recId);
207  mdReconstruction.setValue(MDL_ENABLED,1,recId);
208  mdReconstruction.setValue(MDL_MAXCC,bestCorr,recId);
209  mdReconstruction.setValue(MDL_ANGLE_ROT,bestAngleRot,recId);
210  mdReconstruction.setValue(MDL_ANGLE_TILT,bestAngleTilt,recId);
211  mdReconstruction.setValue(MDL_ANGLE_PSI,bestAnglePsi,recId);
212  mdReconstruction.setValue(MDL_SHIFT_X,bestShiftX,recId);
213  mdReconstruction.setValue(MDL_SHIFT_Y,bestShiftY,recId);
214  mdReconstruction.setValue(MDL_FLIP,bestFlip,recId);
215  mdReconstruction.setValue(MDL_WEIGHT,bestWeight,recId);
216  }
217  newCorr=bestCorr;
218 #ifdef DEBUG
219  mdReconstruction.write("PPPreconstruction.xmd");
220  std::cout << "Press any key" << std::endl;
221  char c;
222  std::cin >> c;
223 #endif
224 }
225 #undef DEBUG
226 
227 // Subset alignment =======================================================
229 {
232 
233  results.sumCorr=results.sumImprovement=0.0;
234  results.mdReconstruction.clear();
235  auto nMax=(int)prm.mdInp.size();
236  for (int nImg=0; nImg<nMax; ++nImg)
237  {
238  if ((nImg+1)%prm.Nthr==thArg.thread_id)
239  {
240  double corr, improvement;
241  alignSingleImage(nImg, prm, results.mdReconstruction, corr, improvement);
242  results.sumCorr+=corr;
243  results.sumImprovement+=improvement;
244  prm.mdInp[nImg].maxcc=corr;
245  }
246 
247  if (thArg.thread_id==0)
248  progress_bar(nImg+1);
249  }
250 
251  // Update all MAXCC
252  prm.mutexMaxCC.lock();
253 
255  prm.sumCorr+=results.sumCorr;
256  prm.sumImprovement+=results.sumImprovement;
257 
258  prm.mutexMaxCC.unlock();
259 }
260 
261 // Main routine ------------------------------------------------------------
263 {
264  show();
265  produceSideinfo();
266 
267  bool finish=false;
268  iter=1;
269  ThreadManager thMgr(Nthr,this);
270  do
271  {
272  // Generate projections from the volume
274 
275  // Align the input images to the projections
279  thMgr.run(threadAlignSubset);
281  size_t nImg=0;
282  for (size_t objId : mdIn.ids())
283  mdIn.setValue(MDL_MAXCC,mdInp[nImg++].maxcc,objId);
284  std::cout << "Iter " << iter << " avg.correlation=" << sumCorr/mdIn.size()
285  << " avg.improvement=" << sumImprovement/mdIn.size() << std::endl;
286 
287  // Remove too good and too bad images
289 
290  // Reconstruct
292 
293  finish=(iter==(NiterRandom+NiterGreedy));
294  iter++;
295  } while (!finish);
296  deleteFile(fnRoot+"_gallery_sampling.xmd");
297  deleteFile(fnRoot+"_gallery.stk");
298  deleteFile(fnRoot+"_gallery.doc");
299 }
300 
302 {
303  MetaDataVec mdAux;
304  mdAux=mdReconstruction;
305  mdAux.removeDisabled();
306 
307  std::vector<double> correlations;
308  mdAux.getColumnValues(MDL_MAXCC,correlations);
309  std::sort(correlations.begin(),correlations.end());
310  auto skip=(size_t)floor(correlations.size()*(rejection/100.0));
311  double minCorr=correlations[skip];
312  //double maxCorr=correlations[correlations.size()-skip/4-1];
313 
314  std::vector<double> weights;
315  mdAux.getColumnValues(MDL_WEIGHT,weights);
316  std::sort(weights.begin(),weights.end());
317  double minWeight=weights[skip];
318  //double maxWeight=weights[weights.size()-skip/4-1];
319 
320  for (size_t objId : mdAux.ids())
321  {
322  double cc, weight;
323  mdAux.getValue(MDL_MAXCC,cc,objId);
324  if (cc<minCorr) // COSS || cc>maxCorr)
325  mdAux.setValue(MDL_ENABLED,-1,objId);
326  mdAux.getValue(MDL_WEIGHT,weight,objId);
327  if (weight<minWeight) // COSS || weight>maxWeight)
328  mdAux.setValue(MDL_ENABLED,-1,objId);
329  }
330  mdAux.removeDisabled();
331  mdAux.write(fnAngles);
332 }
333 
335 {
336  String args=formatString("-i %s -o %s --sym %s --weight --thr %d -v 0",fnAngles.c_str(),fnVolume.c_str(),fnSym.c_str(),Nthr);
337  String cmd=(String)"xmipp_reconstruct_fourier "+args;
338  if (system(cmd.c_str())==-1)
339  REPORT_ERROR(ERR_UNCLASSIFIED,"Cannot open shell");
340 
341  args=formatString("-i %s --mask circular %d -v 0",fnVolume.c_str(),-XSIZE(inputImages())/2);
342  cmd=(String)"xmipp_transform_mask "+args;
343  if (system(cmd.c_str())==-1)
344  REPORT_ERROR(ERR_UNCLASSIFIED,"Cannot open shell");
345 
347  {
348  args=formatString("-i %s --select below 0 --substitute value 0 -v 0",fnVolume.c_str());
349  cmd=(String)"xmipp_transform_threshold "+args;
350  if (system(cmd.c_str())==-1)
351  REPORT_ERROR(ERR_UNCLASSIFIED,"Cannot open shell");
352  }
353 
355  {
356  cmd=formatString("cp %s %s_iter%02d.vol",fnVolume.c_str(),fnRoot.c_str(),iter);
357  if (system(cmd.c_str())==-1)
358  REPORT_ERROR(ERR_UNCLASSIFIED,"Cannot open shell");
359  }
360 }
361 
363 {
364  String args=formatString("-i %s -o %s --sampling_rate %f --sym %s --compute_neighbors --angular_distance -1 --experimental_images %s -v 0",
365  fnVolume.c_str(),fnGallery.c_str(),angularSampling,fnSym.c_str(),fnAngles.c_str());
366  String cmd=(String)"xmipp_angular_project_library "+args;
367  if (system(cmd.c_str())==-1)
368  REPORT_ERROR(ERR_UNCLASSIFIED,"Cannot open shell");
370  mdGallery.clear();
371  for (size_t objId : mdAux.ids())
372  {
373  GalleryImage I;
374  mdAux.getValue(MDL_IMAGE,I.fnImg,objId);
375  mdAux.getValue(MDL_ANGLE_ROT,I.rot,objId);
376  mdAux.getValue(MDL_ANGLE_TILT,I.tilt,objId);
377  mdGallery.push_back(I);
378  }
380 }
381 
383 {
384  mdIn.read(fnIn);
386 
387  mdIn.fillConstant(MDL_MAXCC,"0.0");
388  mdIn.fillRandom(MDL_ANGLE_ROT,"uniform",0,360);
389  mdIn.fillRandom(MDL_ANGLE_TILT,"uniform",0,180);
390  mdIn.fillRandom(MDL_ANGLE_PSI,"uniform",0,360);
394 
395  fnAngles=fnRoot+".xmd";
396  fnVolume=fnRoot+".vol";
397  fnGallery=fnRoot+"_gallery.stk";
398  fnGalleryMetaData=fnRoot+"_gallery.doc";
399 
400  size_t xdim, ydim, zdim, ndim;
401  getImageSize(mdIn,xdim, ydim, zdim, ndim);
402  inputImages().resizeNoCopy(mdIn.size(), 1, ydim, xdim);
403 
404  Image<double> I;
405  size_t n=0;
406  MultidimArray<double> mCurrentImage;
407  for (size_t objId : mdIn.ids())
408  {
409  InputImage Ip;
410  mdIn.getValue(MDL_IMAGE,Ip.fnImg,objId);
411  Ip.maxcc=0.0;
412  mdInp.push_back(Ip);
413  I.read(Ip.fnImg);
414  mCurrentImage.aliasImageInStack(inputImages(),n++);
415  memcpy(MULTIDIM_ARRAY(mCurrentImage),MULTIDIM_ARRAY(I()),MULTIDIM_SIZE(mCurrentImage)*sizeof(double));
416  }
417 
419  iter=0;
420  if (fnInit=="")
422  else
423  {
424  if (system(formatString("cp %s %s",fnInit.c_str(),fnVolume.c_str()).c_str())==-1)
425  REPORT_ERROR(ERR_UNCLASSIFIED,"Cannot open shell");
426  }
427 
429 }
void run(ThreadFunction function, void *data=NULL)
#define NSIZE(v)
Just to locate unclassified errors.
Definition: xmipp_error.h:192
void generateProjections()
Generate projections from the current volume.
void init_progress_bar(long total)
Rotation angle of an image (double,degrees)
virtual size_t addObject()=0
void cumlativeDensityFunction(MultidimArray< double > &cdf)
double getDoubleParam(const char *param, int arg=0)
void readParams()
Read arguments from command line.
__host__ __device__ float2 floor(const float2 v)
void transformationMatrix2Parameters2D(const Matrix2D< T > &A, bool &flip, T &scale, T &shiftX, T &shiftY, T &psi)
#define REPORT_ERROR(nerr, ErrormMsg)
Definition: xmipp_error.h:211
doublereal * c
#define MULTIDIM_SIZE(v)
ThreadManager * thMgr
void resizeNoCopy(const MultidimArray< T1 > &v)
void aliasImageInStack(const MultidimArray< T > &m, size_t select_image)
bool getValue(MDObject &mdValueOut, size_t id) const override
virtual void write(const FileName &outFile, WriteModeMetaData mode=MD_OVERWRITE) const =0
Tilting angle of an image (double,degrees)
Shift for the image in the X axis (double)
#define A1D_ELEM(v, i)
void getImageSize(const MetaData &md, size_t &Xdim, size_t &Ydim, size_t &Zdim, size_t &Ndim, MDLabel image_label)
#define MULTIDIM_ARRAY(v)
Special label to be used when gathering MDs in MpiMetadataPrograms.
void reconstructCurrent()
Reconstruct current volume.
void write(const FileName &outFile, WriteModeMetaData mode=MD_OVERWRITE) const
virtual IdIteratorProxy< false > ids()
void produceSideinfo()
Produce side info: fill arrays with relevant transformation matrices.
void deleteFile(const char *line)
Definition: tools.cpp:280
Is this image enabled? (int [-1 or 1])
void fillConstant(MDLabel label, const String &value) override
double rnd_unif()
const char * getParam(const char *param, int arg=0)
bool setValue(const MDObject &mdValueIn, size_t id)
Flip the image? (bool)
#define XSIZE(v)
void progress_bar(long rlen)
void clear() override
Definition: metadata_db.cpp:54
Maximum cross-correlation for the image (double)
int verbose
Verbosity level.
void write(const FileName &outFile, WriteModeMetaData mode=MD_OVERWRITE) const override
void * workClass
The class in which threads will be working.
void sort(struct DCEL_T *dcel)
Definition: sorting.cpp:18
size_t size() const override
size_t correlations(const Dimensions &d)
bool getValue(MDObject &mdValueOut, size_t id) const override
bool setValue(const MDLabel label, const T &valueIn, size_t id)
void getColumnValues(const MDLabel label, std::vector< MDObject > &valuesOut) const override
bool setValue(const MDObject &mdValueIn, size_t id) override
Definition: metadata_db.cpp:90
virtual void removeDisabled()
std::string String
Definition: xmipp_strings.h:34
String formatString(const char *format,...)
void read(const FileName &inFile, const std::vector< MDLabel > *desiredLabels=NULL, bool decomposeStack=true) override
int thread_id
The thread id.
virtual void unlock()
bool checkParam(const char *param)
void unionAll(const MetaDataDb &mdIn)
int read(const FileName &name, DataMode datamode=DATA, size_t select_img=ALL_IMAGES, bool mapData=false, int mode=WRITE_READONLY)
ProgClassifyCL2D * prm
Shift for the image in the Y axis (double)
void addUsageLine(const char *line, bool verbatim=false)
int getIntParam(const char *param, int arg=0)
double alignImagesConsideringMirrors(const MultidimArray< double > &Iref, const AlignmentTransforms &IrefTransforms, MultidimArray< double > &I, Matrix2D< double > &M, AlignmentAux &aux, CorrelationAux &aux2, RotationalCorrelationAux &aux3, bool wrap, const MultidimArray< int > *mask)
Definition: filters.cpp:2150
int * n
Name of an image (std::string)
void fillRandom(MDLabel label, const String &mode, double op1, double op2, double op3=0.) override
void addParamsLine(const String &line)
virtual void lock()
void defineParams()
Read arguments from command line.
< Score 4 for volumes
void threadAlignSubset(ThreadArgument &thArg)
void alignSingleImage(size_t nImg, ProgVolumeInitialSimulatedAnnealing &prm, MetaData &mdReconstruction, double &newCorr, double &improvementFraction)