source: trunk/Mars/mfileio/MMatrix.cc@ 18078

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