libatomprobe
Library for Atom Probe Tomography (APT) computation
pulse-filter.cpp
Go to the documentation of this file.
1 /* pulse-filter.cpp : Implements the pulse filtering method of Yao et al, MethodsX, 2016; 3: 268–273.
2  * Copyright (C) 2017 Daniel Haley
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17 #include <atomprobe/atomprobe.h>
18 
19 #include <gsl/gsl_histogram2d.h>
20 
21 
22 #include <iostream>
23 #include <cstdlib>
24 #include <vector>
25 #include <fstream>
26 
27 
28 using std::cerr;
29 using std::endl;
30 using std::vector;
31 using namespace AtomProbe;
32 
33 enum
34 {
39 };
40 
41 
42 bool convertToPos(const vector<EPOS_ENTRY> &epos, vector<IonHit> &pos)
43 {
44  try
45  {
46  pos.resize(epos.size());
47  }
48  catch(std::bad_alloc)
49  {
50  return false;
51  }
52 #pragma omp parallel for
53  for(size_t ui=0;ui<epos.size();ui++)
54  {
55  pos[ui].setPos(epos[ui].xDetector,
56  epos[ui].yDetector,
57  epos[ui].z);
58  pos[ui].setMassToCharge( epos[ui].hitMultiplicity);
59  }
60 
61  return true;
62 }
63 
64 bool dumpHistogram(gsl_histogram2d *h, const char *outFile)
65 {
66  std::ofstream of(outFile);
67 
68  if(!of)
69  return false;
70 
71  for(unsigned int ui=0;ui<h->nx; ui++)
72  {
73  for(unsigned int uj=0;uj<h->ny; uj++)
74  {
75  of<< gsl_histogram2d_get(h,ui,uj) << " ";
76  }
77  of << endl;
78  }
79 
80  return true;
81 }
82 
83 
84 void filterEposByPulse(const vector<EPOS_ENTRY> &input, unsigned int filterCount,
85  vector<EPOS_ENTRY> &output)
86 {
87  for(unsigned int ui=0;ui<input.size(); ui++)
88  {
89  //If we reach an ion with a small deltaPulse count,
90  // then we retain it. a deltaPulse of zero means its all the
91  // same ion
92  while(ui < input.size() &&
93  input[ui].deltaPulse <filterCount)
94  {
95  output.push_back(input[ui]);
96  ui++;
97  }
98  }
99 }
100 
101 
102 int main(int argc, const char *argv[])
103 {
104 
105  if(argc !=4)
106  {
107  cerr << "USAGE: " << argv[0] << " EPOSFILE SAMPLES OUTPUTPOS" << endl;
108  cerr << endl;
109  cerr << " This filters an epos file by the number of pulses between evaporation events. Only events with less than SAMPLES pulses between them are kept" << endl;
110 
111  cerr << "See Yao et al, MethodsX, 2016, 3:268-273" << endl;
112  return ERR_BAD_ARGS;
113  }
114 
115 
116  unsigned int filterCount;
117  if(stream_cast(filterCount,argv[2]))
118  {
119  cerr << "Unable to interpret filter count value" << endl;
120  return ERR_BAD_ARGS;
121 
122  }
123 
124  if(!filterCount)
125  {
126  cerr << "filter count must be positive" << endl;
127  return ERR_BAD_ARGS;
128  }
129 
130  cerr << "Filtering EPOS file....";
131  unsigned int CHUNK_SIZE=4096;
132 
133  ProgressBar pb;
134  pb.setLength(50);
135  pb.init();
136 
137  unsigned int outputSize=0,chunkOffset=0,totalEntries=0,entriesLeft;
138  vector<EPOS_ENTRY> eposEntries,eposOutput;
139  EPOS_ENTRY lastEntry;
140  do
141  {
142  vector<EPOS_ENTRY> thisEposOutput;
143 
144 
145  unsigned int errCode;
146  if((errCode=chunkLoadEposFile(eposEntries,argv[1],
147  CHUNK_SIZE,chunkOffset,entriesLeft)))
148  {
149  cerr << endl << "\tError reading epos, " << argv[1] << " : " << RECORDREAD_ERR_STRINGS[errCode] << endl;
150  return ERR_BAD_EPOS_READ;
151  }
152 
153  //include the tail entry from last run, if applicable
154  if(chunkOffset)
155  {
156  //FIXME:Unclear if this is correct. We would need
157  // all of the entries which were not nMultiples==0?
158  eposEntries.insert(eposEntries.begin(),lastEntry);
159  }
160 
161  //Update our offset
162  chunkOffset++;
163 
164  //Record the last entry, as we need it later
165  lastEntry = eposEntries.back();
166 
167  //Filter the epos files
168  totalEntries+=eposEntries.size();
169  filterEposByPulse(eposEntries,filterCount,thisEposOutput);
170 
171  //If there is more to process, do not include the
172  // last entry in the processing chain in our results, as we need
173  // it to fix the "seam" in the chain of pulses of epos
174  // files, by appending it before filtering
175 
176  if(thisEposOutput.size() &&
177  (thisEposOutput.back() == lastEntry) && entriesLeft)
178  thisEposOutput.pop_back();
179 
180  //Convert epos to pos
181  vector<IonHit> ionHits;
182  ionHits.resize(thisEposOutput.size());
183 
184  for(auto ui=0;ui<thisEposOutput.size();ui++)
185  thisEposOutput[ui].getIonHit(ionHits[ui]);
186 
187  //Append to the pos file
188  const bool APPEND=true;
189  if(savePosFile(ionHits,argv[3],APPEND))
190  {
191  cerr << "Error writing pos file" << endl;
192  return 2;
193 
194  }
195 
196  outputSize+=thisEposOutput.size();
197  thisEposOutput.clear();
198 
199 
200  //Update progress
201  pb.update(100.0f*(float)chunkOffset/(float)(chunkOffset+entriesLeft/CHUNK_SIZE));
202  }while(entriesLeft);
203 
204  //Finalise progress bar
205  pb.finish();
206 
207  //Report back to user
208  cerr << "\tFiltered " << totalEntries << " entries." << endl;
209  cerr << outputSize<< " entries after filtering." << endl;
210 
211 
212 
213 }
const char * RECORDREAD_ERR_STRINGS[]
Definition: dataFiles.cpp:82
bool convertToPos(const vector< EPOS_ENTRY > &epos, vector< IonHit > &pos)
unsigned int savePosFile(const std::vector< Point3D > &points, float mass, const char *name, bool append=false)
Save a vector of Point3Ds into a pos file, using a fixed mass, return nonzero on error.
Definition: dataFiles.cpp:499
int main(int argc, const char *argv[])
void finish()
Finalise the progress bar. It is not necessary for the progress to be set to 100%, this is done for you.
Definition: progress.cpp:52
void init()
Draw the initial progress bar.
Definition: progress.cpp:35
Definition: ionHit.h:113
void setLength(unsigned int l)
Set the number of markers in the progress bar.
Definition: progress.h:40
bool dumpHistogram(gsl_histogram2d *h, const char *outFile)
bool stream_cast(T1 &result, const T2 &obj)
Template function to cast and object to another by the stringstream.
Definition: stringFuncs.h:32
void update(unsigned int newProgress)
Draw the progress bar as needed, using the given progress value [0,100].
Definition: progress.cpp:58
size_t chunkLoadEposFile(std::vector< EPOS_ENTRY > &outData, const char *filename, unsigned int chunkSize, unsigned int chunkOffset, unsigned int &nEntriesLeft)
Load an "EPOS" file, with a maximum chunk size.
Definition: dataFiles.cpp:765
void filterEposByPulse(const vector< EPOS_ENTRY > &input, unsigned int filterCount, vector< EPOS_ENTRY > &output)