source: branches/removing_cpp11_features/mfileio/MMatrix.cc@ 18087

Last change on this file since 18087 was 18087, checked in by smueller, 10 years ago
fields of class MMatrix are now initialized in a method of MMatrix rather than in the class header to support pre C++11 standards
File size: 10.5 KB
Line 
1/* ======================================================================== *\
2!
3! Author(s): Sebastian Mueller and Dominik Neise for the FACT Colaboration
4! 2014 Nov 05
5!
6! Copyright: "THE BEER-WARE LICENSE" (Revision 42):
7!
8! The FACT Colaboration wrote this file. As long as you retain this notice you
9! can do whatever you want with this stuff. If we meet some day, and you think
10! this stuff is worth it, you can buy us a beer in return.
11!
12\* ======================================================================== */
13
14//////////////////////////////////////////////////////////////////////////////
15//
16// MMatrix
17//
18// A generic container to store a matrix of floating point numbers.
19// More precise it is a vector of vectors of floating numbers.
20// The rows can have an individual number of columns.
21// The data structure fM itself is public.
22//
23// A delimiter seperated value text file parser is used to obtain the data
24// from a text file.
25//
26//////////////////////////////////////////////////////////////////////////////
27#include "MMatrix.h"
28
29ClassImp(MMatrix);
30//------------------------------------------------------------------------------
31MMatrix::MMatrix(const char *name, const char *title){
32 if( name == NULL ){
33 std::exception error;
34 *fLog << err;
35 *fLog << "In Source: "<< __FILE__ <<" in line: "<< __LINE__ <<" ";
36 *fLog << "in function: "<< __func__ <<"\n";
37 *fLog << "The name string is pointing to NULL!\n";
38 throw error;
39 }else{
40 fName = name;
41 }
42
43 fTitle = title ? title :
44 "Parameter container storing a vector of vectors to hold floating numbers";
45
46 initialize();
47}
48//------------------------------------------------------------------------------
49void MMatrix::initialize() {
50 fDelimiter = ',';
51 fComment = '#';
52 fFileName = "";
53 fLineNumber = 0;
54}
55//------------------------------------------------------------------------------
56MMatrix::~MMatrix(){ clear(); }
57//------------------------------------------------------------------------------
58void MMatrix::ReadFile(const TString path_to_text_file){
59 // Here a text file is parsed into the internal data structure fM
60 // All errors which might occur during parsing result in exceptions.
61 // Right before the exception a info text is printed using the error logger.
62
63 // the delimiter symbol must not be a white space
64 if( std::isspace(fDelimiter) ){
65 std::exception error;
66 *fLog << err;
67 *fLog << "In Source: "<< __FILE__ <<" in line: "<< __LINE__ <<" ";
68 *fLog << "in function: "<< __func__ <<"\n";
69 *fLog << "The delimiter symbol must not be a white space character!\n";
70 throw error;
71 }
72
73 // the comment symbol must not be a white space
74 if( std::isspace(fComment) ){
75 std::exception error;
76 *fLog << err;
77 *fLog << "In Source: "<< __FILE__ <<" in line: "<< __LINE__ <<" ";
78 *fLog << "in function: "<< __func__ <<"\n";
79 *fLog << "The comment symbol must not be a white space character!\n";
80 throw error;
81 }
82
83 // make sure the data Matrix fM is wiped out before new data is read.
84 clear();
85
86 std::ifstream dsv_input_file( path_to_text_file, std::ifstream::in);
87
88 if( !dsv_input_file.is_open() ){
89
90 // a file which can not be opened must not pass silent!
91 *fLog << err;
92 *fLog << "In file: "<< __FILE__ <<" in line: "<< __LINE__ <<" ";
93 *fLog << "in function: "<< __func__ <<"\n";
94 *fLog << "The file: "<< path_to_text_file <<" could no be opened!\n";
95 std::exception error;
96 throw error;
97 }else{
98 // the file does exist and is now parsed
99
100 // only here the filename is set to ensure it is related to the actual
101 // file being parsed.
102 fFileName = path_to_text_file;
103
104 // we set the line counter to 0 because we read a new file.
105 fLineNumber = 0;
106
107 //as long as there are lines in the file:
108 std::string line;
109 while ( getline(dsv_input_file, line ) ){
110
111 fLineNumber++;
112
113 // check if the line can be ignored
114 if( !is_comment(line) && !is_empty_or_has_only_white_spaces(line)){
115
116 std::stringstream line_stream(line);
117 std::string token;
118
119 // create an empty row to be filled with the data chunks of
120 // a text file line
121 std::vector< double > row;
122
123 //as long as there are tokens in a line:
124 while( getline(line_stream, token, fDelimiter)){
125
126 // remove tailing and leading whitespaces
127 token = remove_leading_white_spaces(token);
128 token = remove_tailing_white_spaces(token);
129
130 // parse the text chunk to a floating number and push it
131 // back the data row
132 row.push_back(pedantic_strtod(token));
133 }
134
135 // Now that a whole text file line was parsed into a data row,
136 // the row is pushed back into the data matrix.
137 fM.push_back( row );
138 }
139 }
140 }
141
142 dsv_input_file.close();
143}
144//------------------------------------------------------------------------------
145double MMatrix::pedantic_strtod(std::string text)const{
146 // a pedantic string to float converter
147
148 // since std::strtod will return 0.0 in case the text string is empty we
149 // check for this in advance.
150 if(text.empty() ){
151 std::exception error;
152 *fLog << err;
153 *fLog << "In Source: "<< __FILE__ <<" in line: "<< __LINE__ <<" ";
154 *fLog << "in function: "<< __func__ <<"\n";
155 *fLog << "In file: "<< fFileName <<" in line: "<<fLineNumber<<"\n";
156 *fLog << "The given text to be converted to a flot is empty! \n";
157 throw error;
158 }
159
160 // Ok the text string is not empty and might store a valid floating number.
161
162 // This pointer to character is used to verify if std::strtod has parsed
163 // the string to its end.
164 char * e;
165 double FloatingNumber = std::strtod(text.c_str(), &e);
166
167 // when std::strtod parsed until the last character in the input string,
168 // e is pointing to an empty string.
169 // Otherwise e is pointing to the remaining string.
170 // Example:
171 // OK : '65.456456' -> e = ''
172 // BAD: '65.456456 585.46' -> e = ' 585.46'
173
174 if (*e != 0) {
175 std::exception error;
176 *fLog << err;
177 *fLog << "In Source: "<< __FILE__ <<" in line: "<< __LINE__ <<" ";
178 *fLog << "in function: "<< __func__ <<"\n";
179 *fLog << "In file: "<< fFileName <<" in line: "<<fLineNumber<<"\n";
180 *fLog << "The given text: '" << text <<"' can not be converted ";
181 *fLog << "to a floating point number!\n";
182 throw error;
183 }
184 return FloatingNumber;
185}
186//------------------------------------------------------------------------------
187void MMatrix::clear(){
188 // Not sure if this is neccessary but it shall enforce the correct erasing
189 // of the data Matrix fM e.g. before a new text file is parsed in.
190 for(unsigned int row=0; row<fM.size(); row++)
191 fM[row].clear();
192
193 fM.clear();
194}
195//------------------------------------------------------------------------------
196void MMatrix::print()const{
197 // A info text is printed to std::cout showing the data,
198 // the number of lines parsed in and the name of the text file parsed in.
199
200 std::stringstream info;
201 info << std::fixed << std::setprecision( 2 );
202 info << " ___MMatrix."<< __func__ <<"()____________________\n";
203 info << "| \n";
204 for(unsigned int row=0; row<fM.size(); row++){
205 info << "| "<< row <<" ";
206 for(unsigned int col=0; col<fM[row].size(); col++){
207 info << "[" << fM[row][col] << "] ";
208 }
209 info << "\n";
210 }
211 info << "| . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .\n";
212 info << "| file: " << fFileName << "\n";
213 info << "| lines: " << fLineNumber << "\n";
214 info << "|______________________________________________________________\n";
215
216 std::cout << info.str();
217}
218//------------------------------------------------------------------------------
219bool MMatrix::is_empty_or_has_only_white_spaces(std::string line)const{
220 // Shall return TRUE when the text line is empty or only holding white
221 // spaces and FALSE otherwise.
222
223 if(line.size() == 0){
224 return true;
225 }else{
226
227 bool there_are_only_whitespaces = true;
228
229 int i = 0;
230 while ( line[i] ){
231
232 if( !isspace(line[i]) ){
233 there_are_only_whitespaces = false;
234 }
235 i++;
236 }
237
238 return there_are_only_whitespaces;
239 }
240}
241//------------------------------------------------------------------------------
242bool MMatrix::is_comment(std::string line)const{
243 // TRUE -> the whole line is a comment
244 // FALSE -> the line is data or something else
245 // a comment line is a line of arbitrary number of white spaces followed
246 // by the fComment symbol
247
248 if( line.empty() ){
249 // an empty line is not a comment line
250 return false;
251 }else{
252 // remove leading whitespaces
253 line = remove_leading_white_spaces(line);
254 if( line.empty() ){
255 // after the white spaces have been removed the line turns out to
256 // be empty; so it is not a comment
257 return false;
258 }else if( line[0] == fComment ){
259 // this is a comment line
260 return true;
261 }else{
262 // there is some thing not comment like in this line
263 return false;
264 }
265 }
266}
267//------------------------------------------------------------------------------
268// Both string trimmers are taken from StackOverflow
269//http://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring
270std::string MMatrix::remove_leading_white_spaces(std::string &s)const{
271 // trim from start
272 s.erase(
273 s.begin(),
274 std::find_if(
275 s.begin(),
276 s.end(),
277 std::not1(std::ptr_fun<int, int>(std::isspace))
278 )
279 );
280 return s;
281}
282//------------------------------------------------------------------------------
283std::string MMatrix::remove_tailing_white_spaces(std::string &s)const{
284 // trim from end
285 s.erase(
286 std::find_if(
287 s.rbegin(),
288 s.rend(),
289 std::not1(std::ptr_fun<int, int>(std::isspace))
290 ).base(),
291 s.end()
292 );
293 return s;
294}
295//------------------------------------------------------------------------------
296Int_t MMatrix::ReadEnv(const TEnv &env, TString prefix, Bool_t print){
297
298 if (IsEnvDefined(env, prefix, "FileName", print))
299 {
300 TString temp_file_name =
301 GetEnvValue(env, prefix, "FileName", fFileName);
302
303 try{// to parse the text file
304 ReadFile(temp_file_name);
305 }
306 catch(std::exception error){
307 // Oh oh. There was some trouble when parsing the file. This must
308 // not be accepted.
309 return kERROR;
310 }
311
312 // The text file was correctly parsed
313 return kTRUE;
314 }
315
316 /*
317 *fLog << err << "In Source: "<< __FILE__ <<" in line: "<< __LINE__;
318 *fLog << " in function: "<< __func__ <<"\n";
319 *fLog << "There is no:'"<< prefix<<".FileName' in the config file. ";
320 *fLog << "The filename is crucial because there are no default values ";
321 *fLog << "to be asigned in case the input file with name filename is not ";
322 *fLog << "found." << std::endl;
323 */
324 return kFALSE;
325}
Note: See TracBrowser for help on using the repository browser.