Xmipp  v3.23.11-Nereus
reconstruct_art_pseudo.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  *
3  * Authors: Carlos Oscar Sorzano coss@cnb.csic.es
4  * Slavica Jonic Slavica.Jonic@impmc.jussieu.fr
5  *
6  * Unidad de Bioinformatica del 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 #include <fstream>
28 #include "reconstruct_art_pseudo.h"
29 #include "core/histogram.h"
30 #include "core/geometry.h"
31 #include "core/xmipp_image.h"
32 #include "core/xmipp_funcs.h"
33 
34 constexpr int FORWARD = 1;
35 constexpr int BACKWARD = -1;
36 
38 void project_Pseudo(const std::vector< Matrix1D<double> > &atomPosition,
39  std::vector<double> &atomWeight, double sigma,
41  Matrix2D<double> &Euler, double shiftX, double shiftY,
42  const std::vector<double> &lambda,
43  const std::vector< Matrix2D<double> > &NMA,
44  int direction, const Matrix1D<double> &gaussianProjectionTable,
45  const Matrix1D<double> &gaussianProjectionTable2)
46 {
47  // Project all pseudo atoms ............................................
48  int nmax=atomPosition.size();
49  Matrix1D<double> actprj(3);
50  double sigma4=4*sigma;
51  Matrix1D<double> actualAtomPosition;
52  int lambdaSize=lambda.size();
53  for (int n=0; n<nmax; n++)
54  {
55  actualAtomPosition=atomPosition[n];
56  double weight=atomWeight[n];
57  for (int mode=0; mode<lambdaSize; mode++)
58  {
59  const Matrix2D<double> &NMAmode=NMA[mode];
60  double lambdam=lambda[mode];
61  FOR_ALL_ELEMENTS_IN_MATRIX1D(actualAtomPosition)
62  VEC_ELEM(actualAtomPosition,i)+=
63  lambdam*MAT_ELEM(NMAmode,n,i);
64  }
65 
66  Uproject_to_plane(actualAtomPosition, Euler, actprj);
67  XX(actprj)+=shiftX;
68  YY(actprj)+=shiftY;
69 #ifdef DEBUG
70 
71  bool condition = true;
72  if (condition)
73  {
74  std::cout << "Projecting point " << atomPositions[n].transpose() << std::endl;
75  std::cout << "Vol there = " << atomWeight[n] << std::endl;
76  std::cout << " Center of the basis proj (2D) " << XX(actprj) << "," << YY(actprj) << std::endl;
77  }
78 #endif
79 
80  // Search for integer corners for this basis
81  int XX_corner1 = CEIL(XMIPP_MAX(STARTINGX(proj), XX(actprj) - sigma4));
82  int YY_corner1 = CEIL(XMIPP_MAX(STARTINGY(proj), YY(actprj) - sigma4));
83  int XX_corner2 = FLOOR(XMIPP_MIN(FINISHINGX(proj), XX(actprj) + sigma4));
84  int YY_corner2 = FLOOR(XMIPP_MIN(FINISHINGY(proj), YY(actprj) + sigma4));
85 
86 #ifdef DEBUG
87 
88  if (condition)
89  {
90  std::cout << "Clipped and rounded Corner 1 " << XX_corner1
91  << " " << YY_corner1 << " " << std::endl;
92  std::cout << "Clipped and rounded Corner 2 " << XX_corner2
93  << " " << YY_corner2 << " " << std::endl;
94  }
95 #endif
96 
97  // Check if the basis falls outside the projection plane
98  if (XX_corner1 <= XX_corner2 && YY_corner1 <= YY_corner2)
99  {
100  double vol_corr=0;
101 
102  // Effectively project this basis
103  for (int y = YY_corner1; y <= YY_corner2; y++)
104  {
105  double y_diff2=y-YY(actprj);
106  y_diff2=y_diff2*y_diff2;
107  for (int x = XX_corner1; x <= XX_corner2; x++)
108  {
109  double x_diff2=x-XX(actprj);
110  x_diff2=x_diff2*x_diff2;
111  double r=sqrt(x_diff2+y_diff2);
112  double didx=r*1000;
113  int idx=ROUND(didx);
114  double a = VEC_ELEM(gaussianProjectionTable,idx);
115  double a2 = VEC_ELEM(gaussianProjectionTable2,idx);
116 #ifdef DEBUG
117 
118  if (condition)
119  std::cout << "=" << a << " , " << a2;
120 #endif
121 
122  if (direction==FORWARD)
123  {
124  A2D_ELEM(proj, y, x) += weight * a;
125  A2D_ELEM(norm_proj, y, x) += a2;
126 #ifdef DEBUG
127 
128  if (condition)
129  {
130  std::cout << " proj= " << A2D_ELEM(proj, y, x)
131  << " norm_proj=" << A2D_ELEM(norm_proj, y, x) << std::endl;
132  std::cout.flush();
133  }
134 #endif
135 
136  }
137  else
138  {
139  vol_corr += A2D_ELEM(norm_proj, y, x) * a;
140 #ifdef DEBUG
141 
142  if (condition)
143  {
144  std::cout << " corr_img= " << A2D_ELEM(norm_proj, y, x)
145  << " correction=" << vol_corr << std::endl;
146  std::cout.flush();
147  }
148 #endif
149 
150  }
151  }
152  }
153 
154  if (direction==BACKWARD)
155  {
156  atomWeight[n] += vol_corr;
157 #ifdef DEBUG
158 
159  if (condition)
160  {
161  std::cout << "\nFinal value at ( " << n << ") = "
162  << atomWeight[n] << std::endl;
163  }
164 #endif
165 
166  }
167  } // If not collapsed
168  }
169 }
170 
172 {
173  if (verbose > 0)
174  {
175  std::cout << " =======================================================" << std::endl;
176  std::cout << " ART reconstruction method using pseudo atomic structure" << std::endl;
177  std::cout << " =======================================================" << std::endl;
178  std::cout << "Input images: " << fnDoc << std::endl;
179  std::cout << "Pseudoatoms: " << fnPseudo << std::endl;
180  std::cout << "Sigma: " << sigma << std::endl;
181  std::cout << "Sampling rate: " << sampling << std::endl;
182  if (!fnNMA.empty())
183  std::cout << "NMA: " << fnNMA << std::endl;
184  std::cout << "Output rootname: " << fnRoot << std::endl;
185  std::cout << "Lambda ART: " << lambdaART << std::endl;
186  std::cout << "N. Iterations: " << Nit << std::endl;
187  std::cout << "\n -----------------------------------------------------" << std::endl;
188  }
189 }
190 
192 {
193  addUsageLine("Generate 3D reconstructions from projections using ART on pseudoatoms.");
194  addUsageLine("+This program reconstructs based on irregular grids given by pseudo atomic structures. ");
195  addUsageLine("+In case of regular grids, please refer to other programs as reconstruct_art ");
196  addUsageLine("+or reconstruct_fourier. Optionally, a deformation file generated by Nodal Mode ");
197  addUsageLine("+Alignment (NMA) can be passed with --nma parameter.");
198 
199  addSeeAlsoLine("volume_to_pseudoatoms, nma_alignment");
200 
201  addParamsLine(" -i <md_file> : Metadata file with input projections");
202  addParamsLine(" --oroot <rootname> : Output rootname");
203  addParamsLine(" alias -o;");
204  addParamsLine(" --pseudo <pseudofile> : Pseudo atomic structure (PDB format)");
205  addParamsLine(" alias -p;");
206  addParamsLine(" [--sigma <s=-1>] : Pseudoatom sigma. By default, from pseudo file");
207  addParamsLine(" [--sampling_rate <Ts=1>] : Pixel size (Angstrom)");
208  addParamsLine(" alias -s;");
209  addParamsLine(" [-l <lambda=0.1>] : Relaxation factor");
210  addParamsLine(" [-n <N=1>] : Number of iterations");
211  addParamsLine(" [--nma <selfile=\"\">] : Selfile with NMA");
212 
213  addExampleLine("Reconstruct with NMA file and relaxation factor of 0.2:", false);
214  addExampleLine("xmipp_reconstruct_art_pseudo -i projections.xmd -o art_rec --nma nmafile.xmd -l 0.2");
215 }
216 
218 {
219  fnDoc = getParam("-i");
220  fnPseudo = getParam("--pseudo");
221  fnRoot = getParam("--oroot");
222  lambdaART = getDoubleParam("-l");
223  Nit = getIntParam("-n");
224  sigma = getDoubleParam("--sigma");
225  fnNMA = getParam("--nma");
226  sampling = getDoubleParam("--sampling_rate");
227 }
228 
230 {
231  DF.read(fnDoc);
232  std::ifstream fhPseudo;
233  fhPseudo.open(fnPseudo.c_str());
234  if (!fhPseudo)
236  while (!fhPseudo.eof())
237  {
238  std::string line;
239  getline(fhPseudo, line);
240  if (line.length() == 0)
241  continue;
242  if (line.substr(7,13)=="fixedGaussian" && sigma<0)
243  {
244  std::vector < std::string> results;
245  splitString(line," ",results);
246  sigma=textToFloat(results[2]);
247  sigma/=sampling;
248  }
249  else if (line.substr(0,4)=="ATOM")
250  {
251  Matrix1D<double> v(3);
252  v(0)=textToFloat(line.substr(30,8));
253  v(1)=textToFloat(line.substr(38,8));
254  v(2)=textToFloat(line.substr(46,8));
255  v/=sampling;
256  atomPosition.push_back(v);
257  atomWeight.push_back(0);
258  }
259  }
260  fhPseudo.close();
261 
262  double sigma4=4*sigma;
263  gaussianProjectionTable.resize(CEIL(sigma4*sqrt(2)*1000));
269 
270  // NMA
271  if (!fnNMA.empty())
272  {
273  MetaDataVec DFNMA(fnNMA);
274  DFNMA.removeDisabled();
275  for (size_t objId : DFNMA.ids())
276  {
278  mode.initZeros(atomPosition.size(),3);
279  FileName fnMode;
280  DFNMA.getValue( MDL_NMA_MODEFILE, fnMode,objId);
281  mode.read(fnMode);
282  NMA.push_back(mode);
283  }
284  }
285 }
286 
288 {
289  show();
290  produceSideInfo();
291  Image<double> Iexp;
292  for (int it=0; it<Nit; it++)
293  {
294  double itError=0;
295  for (size_t objId : DF.ids())
296  {
297  FileName fnExp;
298  DF.getValue( MDL_IMAGE, fnExp,objId);
299  double rot;
300  DF.getValue( MDL_ANGLE_ROT, rot,objId);
301  double tilt;
302  DF.getValue( MDL_ANGLE_TILT, tilt,objId);
303  double psi;
304  DF.getValue( MDL_ANGLE_PSI, psi,objId);
305  double shiftX;
306  DF.getValue( MDL_SHIFT_X, shiftX,objId);
307  double shiftY;
308  DF.getValue( MDL_SHIFT_Y, shiftY,objId);
309  std::vector<double> lambda;
310  if (NMA.size()>0)
311  DF.getValue( MDL_NMA, lambda,objId);
312 
313  Iexp.read(fnExp);
314  Iexp().setXmippOrigin();
315  itError+=ART_single_step(Iexp(),rot,tilt,psi,-shiftX,-shiftY,lambda);
316  }
317  if (DF.size()>0)
318  itError/=DF.size();
319  std::cerr << "Error at iteration " << it << " = " << itError << std::endl;
320  }
321  writePseudo();
322 }
323 
325 {
326  // Convert from pseudoatoms to volume
327  Image<double> V;
328  size_t objId = DF.firstRowId();
329  FileName fnExp;
330  DF.getValue( MDL_IMAGE, fnExp, objId);
331  Image<double> I;
332  I.read(fnExp,HEADER);
333  V().resize(XSIZE(I()),XSIZE(I()),XSIZE(I()));
334  V().setXmippOrigin();
335 
336  int nmax=atomPosition.size();
337  double sigma4=4*sigma;
338  for (int n=0; n<nmax; n++)
339  {
340  int XX_corner1 = CEIL(XMIPP_MAX(STARTINGX(V()), XX(atomPosition[n]) - sigma4));
341  int YY_corner1 = CEIL(XMIPP_MAX(STARTINGY(V()), YY(atomPosition[n]) - sigma4));
342  int ZZ_corner1 = CEIL(XMIPP_MAX(STARTINGY(V()), ZZ(atomPosition[n]) - sigma4));
343  int XX_corner2 = FLOOR(XMIPP_MIN(FINISHINGX(V()), XX(atomPosition[n]) + sigma4));
344  int YY_corner2 = FLOOR(XMIPP_MIN(FINISHINGY(V()), YY(atomPosition[n]) + sigma4));
345  int ZZ_corner2 = FLOOR(XMIPP_MIN(FINISHINGY(V()), ZZ(atomPosition[n]) + sigma4));
346  if (XX_corner1 <= XX_corner2 && YY_corner1 <= YY_corner2 &&
347  ZZ_corner1 <= ZZ_corner2)
348  {
349  for (int z = ZZ_corner1; z <= ZZ_corner2; z++)
350  for (int y = YY_corner1; y <= YY_corner2; y++)
351  for (int x = XX_corner1; x <= XX_corner2; x++)
352  V(z,y,x)+=atomWeight[n]*
356  }
357  }
358  V.write(fnRoot+".vol");
359 
360  // Histogram of the intensities
361  MultidimArray<double> intensities(atomWeight);
362  Histogram1D hist;
363  compute_hist(intensities, hist, 100);
364  hist.write(fnRoot+"_intensities.hist");
365 }
366 
368  double rot, double tilt, double psi, double shiftX, double shiftY,
369  const std::vector<double> &lambda)
370 {
371  MultidimArray<double> Itheo, Icorr, Idiff;
372  Itheo.initZeros(Iexp);
373  Icorr.initZeros(Iexp);
375  Euler_angles2matrix(rot, tilt, psi, Euler);
377  Euler, shiftX, shiftY, lambda, NMA, FORWARD,
379  Idiff.initZeros(Iexp);
380 
381  double mean_error=0;
383  {
384  // Compute difference image and error
385  DIRECT_A2D_ELEM(Idiff, i, j) = DIRECT_A2D_ELEM(Iexp, i, j) - DIRECT_A2D_ELEM(Itheo, i, j);
386  mean_error += DIRECT_A2D_ELEM(Idiff, i, j) * DIRECT_A2D_ELEM(Idiff, i, j);
387 
388  // Compute the correction image
389  DIRECT_A2D_ELEM(Icorr, i, j) = XMIPP_MAX(DIRECT_A2D_ELEM(Icorr, i, j), 1);
390  DIRECT_A2D_ELEM(Icorr, i, j) =
391  lambdaART * DIRECT_A2D_ELEM(Idiff, i, j) / DIRECT_A2D_ELEM(Icorr, i, j);
392  }
393  mean_error /= YXSIZE(Iexp);
394 
396  Euler, shiftX, shiftY, lambda, NMA, BACKWARD,
398  return mean_error;
399 }
int * nmax
Rotation angle of an image (double,degrees)
#define A2D_ELEM(v, i, j)
#define VEC_ELEM(v, i)
Definition: matrix1d.h:245
#define XMIPP_MAX(x, y)
Definition: xmipp_macros.h:193
double getDoubleParam(const char *param, int arg=0)
constexpr int BACKWARD
void read(const FileName &inFile, const std::vector< MDLabel > *desiredLabels=nullptr, bool decomposeStack=true) override
#define FINISHINGX(v)
#define REPORT_ERROR(nerr, ErrormMsg)
Definition: xmipp_error.h:211
size_t size() const
Definition: matrix1d.h:508
#define FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY2D(m)
void Euler_angles2matrix(T alpha, T beta, T gamma, Matrix2D< T > &A, bool homogeneous)
Definition: geometry.cpp:624
void sqrt(Image< double > &op)
Tilting angle of an image (double,degrees)
static double * y
Shift for the image in the X axis (double)
#define DIRECT_A2D_ELEM(v, i, j)
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)
Special label to be used when gathering MDs in MpiMetadataPrograms.
Matrix1D< double > gaussianProjectionTable
int Nit
Number of iterations.
void project_Pseudo(const std::vector< Matrix1D< double > > &atomPosition, std::vector< double > &atomWeight, double sigma, MultidimArray< double > &proj, MultidimArray< double > &norm_proj, Matrix2D< double > &Euler, double shiftX, double shiftY, const std::vector< double > &lambda, const std::vector< Matrix2D< double > > &NMA, int direction, const Matrix1D< double > &gaussianProjectionTable, const Matrix1D< double > &gaussianProjectionTable2)
constexpr int FORWARD
double sigma
Sigma of atoms.
virtual IdIteratorProxy< false > ids()
#define STARTINGX(v)
doublereal * x
size_t size() const override
#define i
void addSeeAlsoLine(const char *seeAlso)
#define STARTINGY(v)
#define MAT_ELEM(m, i, j)
Definition: matrix2d.h:116
#define FOR_ALL_ELEMENTS_IN_MATRIX1D(v)
Definition: matrix1d.h:72
#define FLOOR(x)
Definition: xmipp_macros.h:240
const char * getParam(const char *param, int arg=0)
void compute_hist(const MultidimArrayGeneric &array, Histogram1D &hist, int no_steps)
Definition: histogram.cpp:572
double * lambda
#define XX(v)
Definition: matrix1d.h:85
#define CEIL(x)
Definition: xmipp_macros.h:225
float textToFloat(const char *str)
std::vector< double > atomWeight
int splitString(const String &input, const String &delimiter, StringVector &results, bool includeEmpties)
size_t firstRowId() const override
double sampling
Sampling rate.
void resize(size_t Xdim, bool copy=true)
Definition: matrix1d.h:410
#define XSIZE(v)
Definition: euler.h:39
Normal mode displacements (vector double)
double z
void addExampleLine(const char *example, bool verbatim=true)
File or directory does not exist.
Definition: xmipp_error.h:136
#define ROUND(x)
Definition: xmipp_macros.h:210
std::vector< Matrix2D< double > > NMA
double lambdaART
Lambda.
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
Matrix1D< double > gaussianProjectionTable2
#define XMIPP_MIN(x, y)
Definition: xmipp_macros.h:181
FileName fnRoot
Output filename.
#define j
#define YY(v)
Definition: matrix1d.h:93
bool getValue(MDObject &mdValueOut, size_t id) const override
FileName fnDoc
Selfile with the input images.
#define FINISHINGY(v)
virtual void removeDisabled()
void read(const FileName &fn)
Definition: matrix2d.cpp:101
double psi(const double x)
void write(const FileName &fn, MDLabel=MDL_X, MDLabel=MDL_COUNT)
Definition: histogram.cpp:129
FileName fnPseudo
Pseudoatom filename.
void initZeros()
Definition: matrix2d.h:626
int read(const FileName &name, DataMode datamode=DATA, size_t select_img=ALL_IMAGES, bool mapData=false, int mode=WRITE_READONLY)
Shift for the image in the Y axis (double)
void addUsageLine(const char *line, bool verbatim=false)
void initZeros(const MultidimArray< T1 > &op)
int getIntParam(const char *param, int arg=0)
#define YXSIZE(v)
File with an NMA mode.
void Uproject_to_plane(const Matrix1D< double > &point, const Matrix1D< double > &direction, double distance, Matrix1D< double > &result)
Definition: geometry.cpp:39
int * n
Name of an image (std::string)
FileName fnNMA
Selfile with the input NMAs.
std::vector< Matrix1D< double > > atomPosition
#define ZZ(v)
Definition: matrix1d.h:101
doublereal * a
void addParamsLine(const String &line)
double ART_single_step(const MultidimArray< double > &Iexp, double rot, double tilt, double psi, double shiftX, double shiftY, const std::vector< double > &lambda)
double gaussian1D(double x, double sigma, double mu)