Xmipp  v3.23.11-Nereus
volume_correct_bfactor.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  *
3  * Author: Sjors H.W. Scheres (scheres@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 
26 #include <fstream>
27 #include "volume_correct_bfactor.h"
28 #include "core/xmipp_image.h"
29 #include "core/xmipp_fftw.h"
30 
32 {
33  addUsageLine("Sharpen a volume by applying a negative B-factor");
34  addUsageLine("+The high-resolution features are enhanced, thereby correcting ");
35  addUsageLine("+the envelope functions of the microscope, detector etc. Three ");
36  addUsageLine("+modes are available:");
37  addUsageLine("+");
38  addUsageLine("+1. An automated mode based on methodology developed by [[http://www.ncbi.nlm.nih.gov/pubmed/14568533][Rosenthal and Henderson]]");
39  addUsageLine("+");
40  addUsageLine("+2. Based on the fall-off in a reference map (possibly obtained using xmipp_volume_from_pdb)");
41  addUsageLine("+");
42  addUsageLine("+3. An user-provided (ad hoc) B-factor");
43  addSeeAlsoLine("volume_from_pdb, resolution_fsc");
45  addParamsLine(" --auto : Use automated B-factor fit in flat Wilson region");
46  addParamsLine(" : Note: do not use the automated mode for maps with resolutions");
47  addParamsLine(" : lower than 12-15 Angstroms!");
48  addParamsLine(" or --ref <fn_ref> <mode=bfactorref> : Fit B-factor according to the reference ");
49  addParamsLine(" where <mode>");
50  addParamsLine(" bfactorref : Fit B-factor");
51  addParamsLine(" allpoints : Adjust power spectrum to reference");
52  addParamsLine(" or --adhoc <B> : Use a user-provided (negative) B-factor");
53  addParamsLine("== Specific parameters == ");
54  addParamsLine(" --sampling <float> : Pixel size of the input volume (in Angstroms/pixel) ");
55  addParamsLine(" --maxres <float> : High-resolution limit for B-factor correction (in Ang.) ");
56  addParamsLine(" -o <filename> : Output file Name with corrected volume ");
57  addParamsLine(" [--fit_minres+ <f=15>] : Low-resolution limit (in Ang.) for fit in --auto or --ref ");
58  addParamsLine(" [--fit_maxres+ <f=-1>] : High-resolution limit (in Ang.) for fit in --auto or --ref,");
59  addParamsLine(" : -1 means maximum resolution ");
60  addParamsLine(" [--fsc+ <fscFile=\"\">] : FSC file produced by xmipp_resolution_fsc");
61  addExampleLine("xmipp_correct_bfactor -i volume.vol -o correctedVolume.vol --auto --sampling 1.4 --maxres 10");
62  addExampleLine("To plot the Guinier file you may use:",false);
63  addExampleLine("gnuplot");
64  addExampleLine("set xlabel \"d^(-2)\"");
65  addExampleLine("plot \"correctedVolume.vol.guinier\" using 1:2 title \"log F\" with line, \"correctedVolume.vol.guinier\" using 1:4 title \"Corrected log F\"with line");
66 }
67 
69 {
70  produces_an_output = true;
71 
73  if (checkParam("--ref"))
74  {
75  fn_ref= getParam("--ref");
76  String strMode=getParam("--ref",1);
77  bMode = strMode=="allpoints" ? MODES::ALLPOINTS_REF : MODES::BFACTOR_REF;
78  }
79  else if (checkParam("--adhoc"))
80  {
82  adhocB = getDoubleParam("--adhoc");
83  }
84  else if (checkParam("--auto"))
86  else
87  REPORT_ERROR(ERR_DEBUG_IMPOSIBLE, "This should not happens, review program definition");
88  sampling_rate = getDoubleParam("--sampling");
89  apply_maxres = getDoubleParam("--maxres");
90  fit_minres = getDoubleParam("--fit_minres");
91  fit_maxres = getDoubleParam("--fit_maxres");
92  fn_fsc = getParam("--fsc");
93 
94  if (fit_maxres < 0.)
96 }
97 
99 {
101  std::cout << "Pixel size : " << sampling_rate << " Angstrom" << std::endl;
102  std::cout << "Maximum resolution: " << apply_maxres << " Angstrom" << std::endl;
104  {
105  std::cerr<<"Fit within resolutions: " << fit_minres << " - " << fit_maxres << " Angstrom" << std::endl;
106  }
107  if (bMode == MODES::BFACTOR_REF)
108  {
109  std::cout << "Adjust B-factor according to reference "<<fn_ref<<std::endl;
110  }
111  else if (bMode == MODES::BFACTOR_ADHOC)
112  {
113  std::cout << "Apply ad-hoc B-factor of "<< adhocB <<" squared Angstroms" << std::endl;
114  }
115  else
116  {
117  std::cout << "Use automated B-factor fit (Rosenthal and Henderson, 2003) " << std::endl;
118  }
119  if (fn_fsc != "")
120  std::cout << "Use signal-to-noise weight based on "<< fn_fsc <<std::endl;
121 }
122 
123 void ProgVolumeCorrectBfactor::processImage(const FileName &fnImg, const FileName &fnImgOut, const MDRow &rowIn, MDRow &rowOut)
124 {
125  Image<double> vol;
126  vol.read(fnImg);
127  vol().checkDimensionWithDebug(3,__FILE__,__LINE__);
128  FileName fn_guinier = fn_out + ".guinier";
129  bfactor_correction(vol(), fn_guinier);
130  vol.write(fn_out);
131 }
132 
134 {
135  fit_minres = -1.;
136  fit_maxres = -1.;
137  apply_maxres = -1.;
138  sampling_rate = 1.;
140  xsize = -1;
141  fn_ref = "";
142  fn_fsc = "";
143  adhocB = 0.;
144 }
145 
146 void ProgVolumeCorrectBfactor::make_guinier_plot(MultidimArray< std::complex< double > > &FT1,
147  std::vector<fit_point2D> &guinier)
148 {
149  MultidimArray< int > radial_count(xsize);
151  Matrix1D<double> f(3);
152  fit_point2D onepoint;
153 
154  lnF.initZeros();
155  for (size_t k=0; k<ZSIZE(FT1); k++)
156  {
157  FFT_IDX2DIGFREQ(k,ZSIZE(FT1),ZZ(f));
158  double z2=ZZ(f)*ZZ(f);
159  for (size_t i=0; i<YSIZE(FT1); i++)
160  {
161  FFT_IDX2DIGFREQ(i,YSIZE(FT1),YY(f));
162  double y2z2=z2+YY(f)*YY(f);
163  for (size_t j=0; j<XSIZE(FT1); j++)
164  {
166  double R2=y2z2+XX(f)*XX(f);
167  if (R2>0.25)
168  continue;
169  double R=sqrt(R2);
170  int idx=ROUND(R*xsize);
171  A1D_ELEM(lnF,idx) += abs(dAkij(FT1, k, i, j));
172  ++A1D_ELEM(radial_count,idx);
173  }
174  }
175  }
176 
177  guinier.clear();
178  for (size_t i = 0; i < XSIZE(radial_count); i++)
179  {
180  double res = (xsize * sampling_rate)/(double)i;
181  if (res >= apply_maxres)
182  {
183  onepoint.x = 1. / (res * res);
184  if (lnF(i)>0.)
185  {
186  onepoint.y = log ( lnF(i) / radial_count(i) );
187  if (res <= fit_minres && res >= fit_maxres)
188  {
189  onepoint.w = 1.;
190  }
191  else
192  {
193  onepoint.w = 0.;
194  }
195  }
196  else
197  {
198  onepoint.y = 0.;
199  onepoint.w = 0.;
200  }
201  guinier.push_back(onepoint);
202  }
203  }
204 }
205 
206 /*
207 void ProgVolumeCorrectBfactor::get_snr_weights_old(std::vector<double> &snr)
208 {
209  std::ifstream fh;
210  std::string line;
211  float ires, fsc, noise, res;
212  int line_no = 0;
213 
214  snr.clear();
215 
216  fh.open((fn_fsc).c_str(), std::ios::in);
217  if (!fh)
218  REPORT_ERROR(ERR_IO_NOTEXIST, fn_fsc);
219 
220  // Count the number of lines
221  fh.peek();
222  getline(fh, line);
223  while (!fh.eof())
224  {
225  getline(fh, line);
226  sscanf(line.c_str(), "%f %f %f %f", &ires, &fsc, &noise, &res);
227  double mysnr = XMIPP_MAX((double)(2*fsc) / (1+fsc), 0.);
228  snr.push_back( sqrt(mysnr) );
229  line_no++;
230  fh.peek();
231  }
232 
233  fh.close();
234 
235  if (line_no != xsize/2)
236  {
237  std::cerr<<"line_no = "<<line_no <<" neq xsize/2= "<<xsize/2<<std::endl;
238  REPORT_ERROR(ERR_VALUE_INCORRECT,"ERROR: invalid FSC file");
239  }
240 }
241 */
242 
243 void ProgVolumeCorrectBfactor::get_snr_weights(std::vector<double> &snr)
244 {
245 
246  MetaDataVec md;
247  md.read(fn_fsc);
248 
249  double fsc;
250  int line_no = 0;
251 
252  snr.clear();
253 
254  for (size_t objId : md.ids())
255  {
256  md.getValue(MDL_RESOLUTION_FRC, fsc, objId);
257  double mysnr = XMIPP_MAX( (2*fsc) / (1+fsc), 0.);
258  snr.push_back( sqrt(mysnr) );
259  }
260 }
261 
262 
263 void ProgVolumeCorrectBfactor::apply_snr_weights(MultidimArray< std::complex< double > > &FT1,
264  std::vector<double> &snr)
265 {
266 
267  Matrix1D<double> f(3);
269  {
271  FFT_IDX2DIGFREQ(i,YSIZE(FT1),YY(f));
272  FFT_IDX2DIGFREQ(k,ZSIZE(FT1),ZZ(f));
273  double R = f.module();
274  if (sampling_rate / R >= apply_maxres)
275  {
276  int idx=ROUND(R*xsize);
277  dAkij(FT1, k, i, j) *= snr[idx];
278  }
279  }
280 }
281 
282 void ProgVolumeCorrectBfactor::apply_bfactor(MultidimArray< std::complex< double > > &FT1,
283  double bfactor)
284 {
285  Matrix1D<double> f(3);
286  double isampling_rate=1.0/sampling_rate;
288  {
290  FFT_IDX2DIGFREQ(i,YSIZE(FT1),YY(f));
291  FFT_IDX2DIGFREQ(k,ZSIZE(FT1),ZZ(f));
292  double R = f.module() * isampling_rate;
293  if (1./R >= apply_maxres)
294  {
295  dAkij(FT1, k, i, j) *= exp( -0.25* bfactor * R * R);
296  }
297  }
298 }
299 
300 void ProgVolumeCorrectBfactor::apply_allpoints(MultidimArray< std::complex< double > > &FT1,
301  std::vector<fit_point2D> &guinier_diff)
302 {
303  Matrix1D<double> f(3);
305  {
307  FFT_IDX2DIGFREQ(i,YSIZE(FT1),YY(f));
308  FFT_IDX2DIGFREQ(k,ZSIZE(FT1),ZZ(f));
309  double R=f.module();
310  if (R>0.5)
311  continue;
312  size_t idx=lround(R*xsize);
313  if (idx < guinier_diff.size() && guinier_diff[idx].w > 0.)
314  {
315  dAkij(FT1, k, i, j) *= exp( -guinier_diff[idx].y );
316  }
317  }
318 }
319 
321  std::vector<fit_point2D> &guinierin,
322  std::vector<fit_point2D> &guinierweighted,
323  std::vector<fit_point2D> &guiniernew,
324  double intercept,
325  std::vector<fit_point2D> &guinierref)
326 {
327  std::ofstream fh;
328  fh.open(fn_guinier.c_str(), std::ios::out);
329  if (!fh)
330  REPORT_ERROR(ERR_IO_NOWRITE, fn_guinier);
331 
332  fh << "# 1/d^2 lnF weighted-lnF corrected-lnF (model)\n";
333  for (size_t i = 0; i < guinierin.size(); i++)
334  {
335  fh << (guinierin[i]).x << " " << (guinierin[i]).y << " " << (guinierweighted[i]).y << " " <<(guiniernew[i]).y;
337  fh << " " << intercept;
339  {
340  fh << " " << (guinierref[i]).y + intercept;
341  }
342  fh << std::endl;
343  }
344  fh.close();
345 }
346 
348  const FileName &fn_guinier)
349 {
351  FourierTransformer transformer;
352  double slope;
353  double intercept = 0.;
354  std::vector<fit_point2D> guinierin, guinierweighted, guinierref, guinierdiff;
355  std::vector<double> snr;
356 
357  // Transform
358  xsize=XSIZE(m1);
359  transformer.FourierTransform(m1, FT1, true);
360  make_guinier_plot(FT1,guinierin);
361 
362  // Get SNR weights and apply to guinier1
363  if (fn_fsc != "")
364  {
365  get_snr_weights(snr);
366  apply_snr_weights(FT1,snr);
367  make_guinier_plot(FT1,guinierweighted);
368  }
369  else
370  guinierweighted=guinierin;
371 
372  if (bMode == MODES::BFACTOR_AUTO)
373  {
374  least_squares_line_fit(guinierweighted, slope, intercept);
375  std::cerr<<" Fitted slope= "<<slope<<" intercept= "<<intercept<<std::endl;
376  adhocB = 4. * slope;
377  }
379  {
380  Image<double> ref;
381  ref.read(fn_ref);
382  ref().setXmippOrigin();
383  transformer.FourierTransform(ref(), FT2, true);
384  make_guinier_plot(FT2,guinierref);
385  guinierdiff = guinierweighted;
386  for (size_t i = 0; i < guinierdiff.size(); i++)
387  {
388  (guinierdiff[i]).y -= (guinierref[i]).y;
389  }
390  if (bMode == MODES::BFACTOR_REF)
391  {
392  least_squares_line_fit(guinierdiff, slope, intercept);
393  std::cerr<<" Fitted slope= "<<slope<<" intercept= "<<intercept<<std::endl;
394  adhocB = 4. * slope;
395  }
396  }
397 
399  {
400  // Now apply the allpoints correction
401  std::cerr<<"Adjust power spectrum to that of reference "<<std::endl;
402  apply_allpoints(FT1,guinierdiff);
403  }
404  else
405  {
406  // Now apply the B-factor
407  std::cerr<<"Applying B-factor of "<< adhocB << " squared Angstroms"<<std::endl;
408  apply_bfactor(FT1,adhocB);
409  }
410  // Now backtransform
411  transformer.inverseFourierTransform(FT1,m1);
412 
413  // Write Guinier-plot
414  std::vector<fit_point2D> guiniernew;
415  make_guinier_plot(FT1,guiniernew);
416  write_guinierfile(fn_guinier, guinierin, guinierweighted, guiniernew, intercept, guinierref);
417 }
void bfactor_correction(MultidimArray< double > &m1, const FileName &fn_guinier)
void processImage(const FileName &fnImg, const FileName &fnImgOut, const MDRow &rowIn, MDRow &rowOut)
#define YSIZE(v)
void write_guinierfile(const FileName &fn_guinier, std::vector< fit_point2D > &guinierin, std::vector< fit_point2D > &guinierweighted, std::vector< fit_point2D > &guiniernew, double intercept, std::vector< fit_point2D > &guinierref)
#define XMIPP_MAX(x, y)
Definition: xmipp_macros.h:193
double module() const
Definition: matrix1d.h:983
double getDoubleParam(const char *param, int arg=0)
void inverseFourierTransform()
Definition: xmipp_fftw.cpp:329
void read(const FileName &inFile, const std::vector< MDLabel > *desiredLabels=nullptr, bool decomposeStack=true) override
#define REPORT_ERROR(nerr, ErrormMsg)
Definition: xmipp_error.h:211
Just for debugging, situation that can&#39;t happens.
Definition: xmipp_error.h:120
void sqrt(Image< double > &op)
static double * y
Couldn&#39;t write to file.
Definition: xmipp_error.h:140
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)
#define A1D_ELEM(v, i)
void abs(Image< double > &op)
#define FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY3D(V)
virtual IdIteratorProxy< false > ids()
double x
x coordinate
Definition: geometry.h:234
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
void addSeeAlsoLine(const char *seeAlso)
void apply_allpoints(MultidimArray< std::complex< double > > &FT1, std::vector< fit_point2D > &guinier_diff)
void make_guinier_plot(MultidimArray< std::complex< double > > &m1, std::vector< fit_point2D > &guinier)
void log(Image< double > &op)
const char * getParam(const char *param, int arg=0)
#define XX(v)
Definition: matrix1d.h:85
void least_squares_line_fit(const std::vector< fit_point2D > &IN_points, double &line_a, double &line_b)
Definition: geometry.cpp:212
double * f
#define XSIZE(v)
#define dAkij(V, k, i, j)
bool produces_an_output
Indicate that a unique final output is produced.
#define ZSIZE(v)
void addExampleLine(const char *example, bool verbatim=true)
#define ROUND(x)
Definition: xmipp_macros.h:210
double y
y coordinate (assumed to be a function of x)
Definition: geometry.h:236
void FourierTransform(T &v, T1 &V, bool getCopy=true)
Definition: xmipp_fftw.h:166
__device__ float FFT_IDX2DIGFREQ(int idx, int size)
void apply_snr_weights(MultidimArray< std::complex< double > > &FT1, std::vector< double > &snr)
#define j
double w
Weight of the point in the Least-Squares problem.
Definition: geometry.h:238
#define YY(v)
Definition: matrix1d.h:93
bool getValue(MDObject &mdValueOut, size_t id) const override
void get_snr_weights(std::vector< double > &snr)
void show() const override
std::string String
Definition: xmipp_strings.h:34
void apply_bfactor(MultidimArray< std::complex< double > > &FT1, double bfactor)
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)
void addUsageLine(const char *line, bool verbatim=false)
void initZeros(const MultidimArray< T1 > &op)
#define ZZ(v)
Definition: matrix1d.h:101
void addParamsLine(const String &line)
Fourier shell correlation (double)