Xmipp  v3.23.11-Nereus
tomo_tiltseries_dose_filter.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  *
3  * Authors: Roberto Marabini roberto@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 
28 
29 #include "data/fourier_filter.h"
30 
31 #define OUTSIDE_WRAP 0
32 #define OUTSIDE_AVG 1
33 #define OUTSIDE_VALUE 2
34 
36  fnTs = getParam("-i");
37  fnOut = getParam("-o");
38  sampling = getDoubleParam("--sampling");
39  accVoltage = getDoubleParam("--voltage");
40 }
41 
42 
44 {
45  if (!verbose)
46  return;
47  std::cout << "Input movie: " << fnTs
48  << std::endl << "Output movie: "
49  << fnOut << std::endl
50  << "Sampling: " << sampling << std::endl
51  << "Acceleration_Voltage (kV): " << accVoltage << std::endl;
52 }
53 
54 
56  addUsageLine("AThis algorithm applies a dose filter based on Grant & Grigorief eLife 2015. The result will be a low pass filtered tilt series based on the applied dose.");
57  addParamsLine(" -i <tiltseries> : Metadata with the input tilt series");
58  addParamsLine(" [-o <fn=\"out.mrcs\">] : Output path for the filtered tilt series.");
59  addParamsLine(" [--sampling <Ts=1>] : Sampling rate (A/pixel)");
60  addParamsLine(" [--voltage <voltage=300>] : Acceleration voltage (kV) min_value=200.0e0,max_value=300.0e0)");
61  addExampleLine("Example", false);
62  addExampleLine("xmipp_tomo_tiltseries_dose_filter -i tiltseries.xmd -o . --sampling 2.2 --dosePerImage 2 --voltage 300");
63  addExampleLine("xmipp_tomo_tiltseries_dose_filter -i tiltseries.xmd -o . --sampling 2.2 --voltage 300");
64 }
65 
66 
67 double ProgTomoTSFilterDose::doseFilter(double dose_at_end_of_frame, double critical_dose)
68 {
69  return exp((-0.5 * dose_at_end_of_frame) / critical_dose);
70 }
71 
72 
73 double ProgTomoTSFilterDose::criticalDose(double spatial_frequency)
74 {
75  return ((critical_dose_a * pow(spatial_frequency, critical_dose_b)) + critical_dose_c) * voltage_scaling_factor;
76 }
77 
79 {
81  critical_dose_a = 0.24499;
82  critical_dose_b = -1.6649;
83  critical_dose_c = 2.8141;
84  // init with a very large number
86 
87  // Defining the scaling factor given the acceleration voltage. The methods considers only two voltage 200keV and 300keV
88  // Any other voltage would result in an error
89  if (accVoltage < 301 && accVoltage > 299.)
90  {
91  accVoltage = 300.0;
93  }
94  else
95  {
96  if (accVoltage < 201.0 && accVoltage > 199.0)
97  {
98  accVoltage = 200.0;
100  }
101  else
102  {
103  REPORT_ERROR(ERR_ARG_INCORRECT, "Bad acceleration voltage (must be 200 or 300 kV");
104  }
105 
106  }
107 
108 }
109 
110 void ProgTomoTSFilterDose::applyDoseFilterToImage(int Ydim, int Xdim, const MultidimArray<std::complex<double> > &FFT1, const double dose_finish)
111 {
112  double ux, uy;
113  double yy;
114  double current_critical_dose, current_optimal_dose;
115  int sizeX_2 = Xdim / 2;
116  double ixsize = 1.0 / Xdim;
117  int sizeY_2 = Ydim / 2;
118  double iysize = 1.0 / Ydim;
119 
120  for (long int i = 0; i < YSIZE(FFT1); i++) //i->y,j->x xmipp convention is oposite summove
121  {
122  FFT_IDX2DIGFREQ_FAST(i, Ydim, sizeY_2, iysize, uy);
123 
124  yy = uy * uy;
125  for (long int j = 0; j < XSIZE(FFT1); j++)
126  {
127  FFT_IDX2DIGFREQ_FAST(j, Xdim, sizeX_2, ixsize, ux);
128 
129  if (i == 0 && j == 0)
130  {
131  current_critical_dose = critical_dose_at_dc;
132  }
133  else
134  {
135  current_critical_dose = criticalDose(sqrt(ux * ux + yy) / sampling);
136  }
137 
138  current_optimal_dose = 2.51284 * current_critical_dose; //This is the optimal dose given the critical dose (see Grant, Grigorief eLife 2015)
139 
140  DIRECT_A2D_ELEM(FFT1, i, j ) *= doseFilter(dose_finish, current_critical_dose);
141 
142 
143  }
144  }
145 }
146 
147 
149 {
150  size_t Xdim, Ydim, Zdim, Ndim;
151 
152  //if input is an stack create a metadata.
153  if (fnTs.isMetaData())
154  mdts.read(fnTs);
155  else
156  {
157  REPORT_ERROR(ERR_ARG_INCORRECT, "The input must be a metadata with the image filenames and the accumulated dose");
158  }
159 }
160 
161 
163 {
164 
165  show();
166 
167  initParameters();
168 
169  MetaDataVec mdts;
170 
171  readInputData(mdts);
172 
173  std::cout << " Starting filtering..."<< std::endl;
174 
175 
176  FourierTransformer transformer;
177  FileName fnti;
178  FileName fnOutFrame;
179 
180  Image<double> tiltImage;
181  MultidimArray<double> &ptrtiltImage = tiltImage();
182 
183  int mode = WRITE_OVERWRITE;
184  double doseTi;
185 
186  FileName fnk;
187  std::vector<FileName> ti_fn;
188  std::vector<double> ti_dose;
189 
190  for (size_t objId : mdts.ids())
191  {
192  mdts.getValue(MDL_IMAGE, fnti, objId);
193 
194  mdts.getValue(MDL_DOSE, doseTi, objId);
195 
196  ti_fn.push_back(fnti);
197  ti_dose.push_back(doseTi);
198  }
199 
200  FileName fnTsOut;
201 
202  size_t n = 0;
204 
205  for (size_t objId : mdts.ids())
206  {
207  mdts.getValue(MDL_IMAGE, fnti, objId);
208  mdts.getValue(MDL_DOSE, doseTi, objId);
209 
210  tiltImage.read(fnti);
211 
212  // Now do the Fourier transform and filter
213  transformer.FourierTransform(ptrtiltImage, FFT1, false);
214 
215  applyDoseFilterToImage((int) YSIZE(ptrtiltImage), (int) XSIZE(ptrtiltImage), FFT1, doseTi);
216 
217  transformer.inverseFourierTransform();
218 
219  fnTsOut = fnOut;
220  tiltImage.write(fnTsOut, n+FIRST_IMAGE, true, mode);
221  mode = WRITE_APPEND;
222 
223  ++n;
224 
225  }
226 }
#define YSIZE(v)
double getDoubleParam(const char *param, int arg=0)
double criticalDose(double spatial_frequency)
Given a spatial frequency, return the critical dose in electrons per square Angstroms.
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
void applyDoseFilterToImage(int Ydim, int Xdim, const MultidimArray< std::complex< double > > &FFT1, const double dose_finish)
Apply a dose filter to the image Fourier transform.
void sqrt(Image< double > &op)
#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)
virtual IdIteratorProxy< false > ids()
#define i
double doseFilter(double dose_at_end_of_frame, double critical_dose)
Compute the dose filter, which is the signal attenuation.
#define FFT_IDX2DIGFREQ_FAST(idx, size, size_2, isize, freq)
Definition: xmipp_fft.h:54
void readParams()
Read argument from command line.
const char * getParam(const char *param, int arg=0)
Incorrect argument received.
Definition: xmipp_error.h:113
#define XSIZE(v)
void max(Image< double > &op1, const Image< double > &op2)
void addExampleLine(const char *example, bool verbatim=true)
int verbose
Verbosity level.
void mode
void FourierTransform(T &v, T1 &V, bool getCopy=true)
Definition: xmipp_fftw.h:166
#define j
void defineParams()
Define parameters.
bool getValue(MDObject &mdValueOut, size_t id) const override
bool isMetaData(bool failIfNotExists=true) const
int read(const FileName &name, DataMode datamode=DATA, size_t select_img=ALL_IMAGES, bool mapData=false, int mode=WRITE_READONLY)
#define FIRST_IMAGE
void addUsageLine(const char *line, bool verbatim=false)
int * n
Name of an image (std::string)
void readInputData(MetaDataVec &md)
void addParamsLine(const String &line)
Dose e/A^2 (double)