Persistence 1D inc. Reconstruct1D  1.1
Finding extrema in one dimensional data, filtering them by persistence and reconstructing smooth functions
 All Classes Namespaces Files Functions Variables Macros Pages
persistence1d_driver.cpp
Go to the documentation of this file.
1 /*! \file persistence1d_driver.cpp
2  * Use this program to run Persistence1D on data in text files.
3  *
4  * This file contains a sample code for using Persistence1D on data in text files, and
5  * can be used to directly run Persistence1D on data in a single text file.
6  *
7  * Command line: persistence1d_driver.exe <filename> [threshold] [-MATLAB]
8  * - filename is the path to a data text file.
9  * Data is assumed to be formatted as a single float-compatible value per row.
10  * - [Optional] threshold is a floating point value. Acceptable threshold value >= 0
11  * - [Optional] -MATLAB - output indices match Matlab 1-indexing convention.
12  * Output: - Indices of extrema, written to a text file, one value per row.
13  Indices of paired extrema are written in following rows.
14  * Indices are ordered according to their persistence, from most to least persistence.
15  * Even rows contain indices of minima.
16  * Odd rows contain indices of maxima.
17  * Global minimum is not paired and is not written to file.
18  * Output filename: <filename>_res.txt
19  *
20  */
21 
22 
23 #include "persistence1d.hpp"
24 
25 #include <fstream>
26 #include <string>
27 
28 #define MATLAB "-MATLAB"
29 
30 using namespace std;
31 using namespace p1d;
32 
33 
34 /*!
35  Tries to open the input file and read its contents to a float vector.
36 
37  Input is assumed to be formatted as one number per line, in float compatible notation.
38 
39  Ignores any lines which do not conform to this assumption.
40 
41  Number of data entries is assumed to be smaller than vector's class maximum size - this is not checked!
42 
43  @param[in] filename Name of input file with float data.
44  @param[out] data Data is written to this vector.
45 */
46 bool ReadFileToVector (char * filename, vector<float> & data);
47 /*!
48  Writes indices of extrema features to file, sorted according to their persistence.
49 
50  If no features were found, writes an empty file.
51 
52  Overwrites any existing file with the same name.
53 
54  @param[in] filename Name of output file.
55  @param[out] pairs Data to write.
56 
57 */
58 void WriteMinMaxPairsToFile (char * filename, vector<TPairedExtrema> pairs);
59 /*!
60  Parses user command line.
61  Checks if the user set a threshold value or wants MATLAB indexing.
62 */
63 bool ParseCmdLine(int argc, char* argv[], float &threshold, bool & matlabIndexing);
64 
65 /*!
66  Main function - reads a file specified as a command line argument. runs persistence,
67  writes the indices of extrema to a file called inputfilename_res.txt.
68 
69  Overwrites files with the same name.
70 
71  Input file name is assumed to end with a three letter extension.
72 */
73 int main(int argc, char* argv[])
74 {
75  vector<float> data;
76  vector<int> indices;
77  float threshold;
78  vector <TPairedExtrema> pairs;
79  bool matlabIndexing;
80  Persistence1D p;
81 
82  if (argc < 2)
83  {
84  cout << "No filename" << endl;
85  cout << "Usage: " << argv[0] << " <filename> [threshold] [-MATLAB]" << endl;
86  return false;
87  }
88 
89  //filename processing, easier done here.
90  char * filename = argv[1];
91  char * outfilename = new char[strlen(filename) + strlen("_res.txt")];
92  strcpy(outfilename, filename);
93 
94  outfilename[strlen(filename)-4] = '\0';
95  strcat(outfilename, "_res.txt");
96 
97  if (!ParseCmdLine(argc, argv, threshold, matlabIndexing))
98  {
99  cout << "Usage: " << argv[0] << " <filename> [threshold] [-MATLAB]" << endl;
100  return -1;
101  }
102 
103  if(!ReadFileToVector(filename, data))
104  {
105  cout << "Error reading data to file." << endl;
106  return -2;
107  }
108 
109  p.RunPersistence(data);
110  p.GetPairedExtrema(pairs, threshold , matlabIndexing);
111  WriteMinMaxPairsToFile(outfilename, pairs);
112 
113  delete outfilename;
114 
115  return 0;
116 }
117 
118 bool ReadFileToVector (char * filename, vector<float> & data)
119 {
120  ifstream datafile;
121 
122  //check the datadfile actually exists
123  datafile.open(filename, ifstream::in);
124 
125 
126  if(!datafile)
127  {
128  cout << "Cannot open file " << filename << " for reading" << endl;
129  return false;
130  }
131 
132  float currdata;
133 
134  while(datafile >> currdata)
135  {
136  data.push_back(currdata);
137  }
138 
139  datafile.close();
140  return true;
141 }
142 void WriteMinMaxPairsToFile (char * filename, vector<TPairedExtrema> pairs)
143 {
144  ofstream datafile;
145  datafile.open(filename);
146 
147  if (!datafile)
148  {
149  cout << "Cannot open file " << filename << " for writing." << endl;
150  return;
151  }
152 
153  for (vector<TPairedExtrema>::iterator p = pairs.begin(); p != pairs.end(); p++)
154  {
155  datafile << to_string((long long)(*p).MinIndex) << endl;
156  datafile << to_string((long long)(*p).MaxIndex) << endl;
157  }
158 
159  datafile.close();
160 }
161 bool ParseCmdLine(int argc, char* argv[], float &threshold, bool & matlabIndexing)
162 {
163  bool noErrors = true;
164 
165  threshold = 0.0;
166  matlabIndexing = false;
167 
168  //now let's find out if anyone wants MATLAB indexing or threshold values
169  for (int counter = 2; counter < argc ; counter ++)
170  {
171  if (argv[counter][0]=='-' && matlabIndexing == false)
172  {
173  if (strcmp(argv[counter],"-MATLAB") == 0 ||
174  strcmp(argv[counter],"-Matlab") == 0 ||
175  strcmp(argv[counter],"-matlab") == 0 )
176  {
177  //turn on matlab indexing
178  matlabIndexing = true;
179  }
180  else
181  {
182  cout << "Possibly misspelled Matlab flag or negative values for threshold." << endl;
183  noErrors = false;
184  }
185  }
186  else if ( argv[counter][0] == '0') //different from nullptr
187  {
188  //this doesn't throw exceptions, AKAIK
189  threshold = (float)atof(argv[counter]);
190 
191  //string begins with 0,
192  //so it's ok that atof returns 0
193  //not much can be done about other errors, will set threshold to 0
194 
195  //check that value is positive - this really should not happen
196  if (threshold < 0)
197  {
198  cout << "Error. Threshold value should be >= 0. Rerun with valid threshold value or leave out to get all features.\n";
199  noErrors = false;
200  }
201  }
202  else
203  {
204  //this doesn't throw exceptions, AKAIK
205  threshold = (float)atof(argv[counter]);
206 
207  //the string does not include a 0, but atof returns 0.
208  //string cannot be converted to threshold value
209  if (threshold == 0.0)
210  {
211  cout << "Cannot convert threshold value to number.\n" << endl;
212  noErrors = false;
213  }
214  else if (threshold < 0)
215  {
216  cout << "Error. Threshold value should be >= 0. Rerun with valid threshold value or leave out to get all features.\n";
217  noErrors = false;
218  }
219  }
220 
221  }
222  return noErrors;
223 }