1 /*
2 * MBDyn (C) is a multibody analysis code.
3 * http://www.mbdyn.org
4 *
5 * Copyright (C) 1996-2017
6 *
7 * Pierangelo Masarati <masarati@aero.polimi.it>
8 * Paolo Mantegazza <mantegazza@aero.polimi.it>
9 *
10 * Dipartimento di Ingegneria Aerospaziale - Politecnico di Milano
11 * via La Masa, 34 - 20156 Milano, Italy
12 * http://www.aero.polimi.it
13 *
14 * Changing this copyright notice is forbidden.
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation (version 2 of the License).
19 *
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 */
30 /* Copyright Marco Morandini */
31
32 #include<cstdlib>
33 #include<fstream>
34 // #include<iostream>
35 // #include<sstream>
36 // #include<iosfwd>
37 #include<string>
38 #include<sstream>
39 #include<map>
40 #include<list>
41 #include<vector>
42 #include<limits>
43 #include<algorithm>
44
45 #undef yyFlexLexer
46 #define yyFlexLexer MbdynpostFlexLexer
47 #include <FlexLexer.h>
48 #undef yyFlexLexer
49
50 int output_frequency = 0;
51
52 int step = 0;
53 double current_time = 0.0;
54 double tstep = 0.;
55 int niter = 0;
56 double reserr = 0.;
57 double solerr = 0.;
58 int solconv = 0;
59
60 #include "Post.hh"
61
skipws(std::istream * file)62 void skipws(std::istream * file) {
63 typedef std::streambuf::traits_type traits_type;
64 const int eof = traits_type::eof();
65 int c;
66 bool testdelim;// = (c == ' ' || c == '\t');
67 c = file->get();
68 while (traits_type::eq_int_type(c, ' ')
69 || traits_type::eq_int_type(c, '\t') ) {
70 c = file->get();
71 }
72 testdelim = ( traits_type::eq_int_type(c, ' ')
73 || traits_type::eq_int_type(c, '\t') );
74 while (!testdelim) {
75 c = file->get();
76 testdelim = ( traits_type::eq_int_type(c, ' ' )
77 || traits_type::eq_int_type(c, '\t' )
78 || traits_type::eq_int_type(c, '\n' )
79 || traits_type::eq_int_type(c, eof )
80 );
81 }
82 if (c == '\n') {
83 file->unget();
84 //buf->sputback((char)c);
85 }
86
87
88 // std::streambuf * buf = file->rdbuf();
89 // typedef std::streambuf::traits_type traits_type;
90 // const int eof = traits_type::eof();
91 // int c = buf->sgetc();
92 // bool testdelim;// = (c == ' ' || c == '\t');
93 // while (traits_type::eq_int_type(c, ' ')
94 // || traits_type::eq_int_type(c, '\t') ) {
95 // c = buf->sbumpc();
96 // }
97 // testdelim = ( traits_type::eq_int_type(c, ' ')
98 // || traits_type::eq_int_type(c, '\t') );
99 // while (!testdelim) {
100 // c = buf->sbumpc();
101 // testdelim = ( traits_type::eq_int_type(c, ' ' )
102 // || traits_type::eq_int_type(c, '\t' )
103 // || traits_type::eq_int_type(c, '\n' )
104 // || traits_type::eq_int_type(c, eof )
105 // );
106 // }
107 // if (c == '\n') {
108 // buf->sungetc();
109 // //buf->sputback((char)c);
110 // }
111 // // while (testdelim) {
112 // // c = buf->sbumpc();
113 // // testdelim = (c == ws || c == tab);
114 // // }
115 // // //buf->sputback(c);
116 // // buf->sungetc();
117 }
118
skipline(std::istream * file)119 void skipline(std::istream * file) {
120 std::streambuf * buf = file->rdbuf();
121 // const int nl = '\n';
122 // const int eof = std::streambuf::traits_type::eof();
123 // int c = buf->sbumpc();
124 // bool testdelim = (c == '\n' || c == eof);
125 // while (!testdelim) {
126 // c = buf->sbumpc();
127 // testdelim = (c == '\n' || c == eof);
128 // }
129
130 std::streambuf::int_type eof = std::streambuf::traits_type::eof();
131 typedef std::streambuf::traits_type traits_type;
132 std::streambuf::int_type c = buf->sgetc();
133 while (!traits_type::eq_int_type(c, eof)
134 && !traits_type::eq_int_type(c, '\n')) {
135 c = buf->snextc();
136 }
137 buf->sbumpc();
138 }
139
140
141 struct OutputElement {
142 int label;
143 int num_outputs;
144 std::map<int,int> output_cols;
145 std::vector<double> outputs;
OutputElementOutputElement146 OutputElement(const int i) : label(i), num_outputs(0) {};
147 };
148
149 struct OutputFile {
150 std::string name;
151 int num_elements;
152 std::istream * file;
153 std::list<OutputElement> elements; //ordinati per posizione in output
154 std::map<int, std::list<OutputElement>::iterator> element_positions; //<position in the file, position in output>
155 //only for elements stored in std::list<OutputElement> elements
OutputFileOutputFile156 OutputFile(std::string s) : name(s), num_elements(0), file(0) {};
157 };
158
159 std::list<OutputFile> files;
160
161
ParseLog(std::istream & in,std::ostream & out)162 bool ParseLog(std::istream& in, std::ostream& out) {
163 MbdynpostFlexLexer flex(&in, &out);
164 //flex.set_debug(1);
165 int type;
166 while ((type = flex.yylex()) != EOF_TOK) {
167 //std::cerr << "tipo token " << type << " " << flex.YYText() <<
168 //std::endl << "-----------------------------" << std::endl;
169 switch (type) {
170 case OUTPUT_FREQUENCY_TOK:
171 in >> output_frequency;
172 return true;
173 break;
174 default:
175 break;
176 }
177 }
178 return false;
179 }
ParseOut(MbdynpostFlexLexer & flex,std::istream & in)180 bool ParseOut(MbdynpostFlexLexer &flex, std::istream& in) {
181 int type;
182 while ((type = flex.yylex()) != EOF_TOK) {
183 switch (type) {
184 case STEP_TOK:
185 in >> step >> current_time >> tstep >> niter >> reserr >> solerr >> solconv;
186 return true;
187 break;
188 default:
189 break;
190 }
191 }
192 return false;
193 }
194
ParseCommands(std::istream & in,std::ostream & out)195 bool ParseCommands(std::istream& in, std::ostream& out) {
196 MbdynpostFlexLexer flex(&in, &out);
197 // std::string a; in >> a;
198 // std::cerr << a << " xxxx\n";
199 //flex.set_debug(1);
200 int type;
201 do {
202 if ((type = flex.yylex()) != FILE_EXTENSION_TOK) {
203 std::cerr << "Unrecognized post_description token \""
204 << flex.YYText() << "\"\n"
205 << "Expected a file extension\n";
206 return false;
207 }
208 files.push_back(OutputFile(flex.YYText()));
209 if ((type = flex.yylex()) != DUEPUNTI_TOK) {
210 std::cerr << "Unrecognized post_description token \""
211 << flex.YYText() << "\"\n"
212 << "Expected a \":\"\n";
213 return false;
214 }
215 do {
216 if ((type = flex.yylex()) != LABEL_TOK) {
217 std::cerr << "Unrecognized post_description token \""
218 << flex.YYText() << "\"\n"
219 << "Expected an element label\n";
220 return false;
221 }
222 OutputFile &fl(*files.rbegin());
223 fl.num_elements++;
224 int i = atoi(flex.YYText());
225 fl.elements.push_back(OutputElement(i));
226 OutputElement &el(*fl.elements.rbegin());
227 if ((type = flex.yylex()) != DUEPUNTI_TOK) {
228 std::cerr << "Unrecognized post_description token \""
229 << flex.YYText() << "\"\n"
230 << "Expected a \":\"\n";
231 return false;
232 }
233 do {
234 if ((type = flex.yylex()) != LABEL_TOK) {
235 std::cerr << "Unrecognized post_description token \""
236 << flex.YYText() << "\"\n"
237 << "Expected an integer\n";
238 return false;
239 }
240 int i = atoi(flex.YYText());
241 el.output_cols[i] = el.num_outputs;
242 el.num_outputs++;
243 } while ((type = flex.yylex()) == COMMA_TOK);
244 el.outputs.resize(el.num_outputs);
245 } while (type == DUEPUNTI_TOK);
246 } while (type == DUEDUEPUNTI_TOK);
247 if ((type = flex.yylex()) != EOF_TOK) {
248 std::cerr << "Unrecognized post_description token \""
249 << flex.YYText() << "\"\n"
250 << "Expected the end of commands\n";
251 return false;
252 }
253
254 // std::cerr << "tipo token " << type << " " << flex.YYText() <<
255 // std::endl << "-----------------------------" << std::endl;
256 // switch (type) {
257 // case FILE_EXTENSION_TOK:
258 // std::cerr << "Estensione " << flex.YYText() <<
259 // " = " << flex.YYLeng() << "\n";
260 // break;
261 // case LABEL_TOK:
262 // std::cerr << "Label " << flex.YYText() <<
263 // " = " << flex.YYLeng() << "\n";
264 // break;
265 // case COLUMN_TOK:
266 // std::cerr << "Colonna " << flex.YYText() <<
267 // " = " << flex.YYLeng() << "\n";
268 // break;
269 // case COMMA_TOK:
270 // std::cerr << "Comma " << flex.YYText() <<
271 // " = " << flex.YYLeng() << "\n";
272 // break;
273 // case DUEPUNTI_TOK:
274 // std::cerr << "Duepunti " << flex.YYText() <<
275 // " = " << flex.YYLeng() << "\n";
276 // break;
277 // case DUEDUEPUNTI_TOK:
278 // std::cerr << "Dueduepunti " << flex.YYText() <<
279 // " = " << flex.YYLeng() << "\n";
280 // break;
281 // default:
282 // std::cerr << "Unrecognized post_description token \""
283 // << flex.YYText() << "\"\n";
284 // return false;
285 // break;
286 // }
287 // }
288 return true;
289 }
290
291
292
293
294 #include <argp.h>
295 const char *argp_program_version = "MbdynPost-0.1";
296 const char *argp_program_bug_address = "<marco.morandini@polimi.it>";
297 static char args_doc[] = "post_description input_file_basename";
298 static char doc[] = "MbdynPost -- another Mbdyn result parser\n"
299 "\n"
300 " MBDyn (C) is a multibody analysis code. \n"
301 " http://www.mbdyn.org\n"
302 "\n"
303 " Copyright (C) 1996-2017\n"
304 "\n"
305 " Pierangelo Masarati <masarati@aero.polimi.it>\n"
306 " Paolo Mantegazza <mantegazza@aero.polimi.it>\n"
307 "\n"
308 " Changing this copyright notice is forbidden.\n"
309 "\n"
310 " This program is free software; you can redistribute it and/or modify\n"
311 " it under the terms of the GNU General Public License as published by\n"
312 " the Free Software Foundation (version 2 of the License).\n"
313 "\n"
314 " This program is distributed in the hope that it will be useful,\n"
315 " but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
316 " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
317 " GNU General Public License for more details.\n"
318 "\n"
319 " You should have received a copy of the GNU General Public License\n"
320 " along with this program; if not, write to the Free Software\n"
321 " Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"
322 "\n"
323 "\nCopyright 2017 Marco Morandini\n"
324 "\n"
325 "\nIt is assumed that the file input_file_basename.log exists.\n"
326 "\nThe post_description argument has the following syntax:\n"
327 "\tpost_description: file_output[::file_output]*\n"
328 "\tfile output: file_suffix:el_output[:el_output]*\n"
329 "\tel_output: el_number:col_number[,col_number]*\n\n"
330 ;
331 static struct argp_option options[] = {
332 {"output", 'o', "FILEOUT", 0, "Output to FILEOUT.dat instead of standard output" },
333 {"skip", 's', "SKIP", 0, "Output every SKIP time steps" },
334 {"begin", 'b', "t0", 0, "Output from t = t0" },
335 {"end", 'e', "t1", 0, "Output up to t = t1" },
336 { 0 }
337 };
338
339 struct arguments {
340 char *args[2]; /* input file basename */
341 char *output_file;
342 int skip;
343 float t0;
344 float t1;
argumentsarguments345 arguments() : output_file(0), skip(0), t0(0.), t1(0.) {};
346 };
347
348 static error_t
parse_opt(int key,char * arg,struct argp_state * state)349 parse_opt (int key, char *arg, struct argp_state *state) {
350 /* Get the INPUT argument from `argp_parse', which we
351 know is a pointer to our arguments structure. */
352 struct arguments *argu = (arguments*)state->input;
353
354 switch (key) {
355 case 'o':
356 argu->output_file = arg;
357 break;
358
359 case 's':
360 argu->skip = atoi(arg);
361 break;
362
363 case 'b':
364 argu->t0 = atof(arg);
365 break;
366
367 case 'e':
368 argu->t1 = atof(arg);
369 break;
370
371 case ARGP_KEY_ARG:
372 if (state->arg_num >= 2) {
373 /* Too many arguments. */
374 std::cerr << "too many\n";
375 argp_usage (state);
376 }
377
378 argu->args[state->arg_num] = arg;
379 break;
380
381 case ARGP_KEY_END:
382 if (state->arg_num < 2) {
383 /* Not enough arguments. */
384 std::cerr << "too less\n";
385 argp_usage (state);
386 }
387 break;
388
389 default:
390 return ARGP_ERR_UNKNOWN;
391 }
392 return 0;
393 }
394
395 static struct argp argp_s = { options, parse_opt, args_doc, doc };
396
397 struct allocate_file : public std::unary_function<OutputFile&, std::istream *> {
398 std::string basename;
399 bool success;
allocate_fileallocate_file400 allocate_file(std::string bs) : basename(bs), success(true) {};
operatorallocate_file401 void operator()(OutputFile& it) {
402 std::string namefile(basename);
403 namefile += ".";
404 namefile += it.name;
405 it.name = namefile;
406 std::ifstream * file;
407 file = new std::ifstream(namefile.c_str());
408 if (file == 0 || !file->is_open()) {
409 file = 0;
410 std::cerr << "Unable to open result file " << namefile << "\n";
411 } else {
412 int label, first_label, num_labels;
413 *file >> label;
414 first_label = label;
415 num_labels = 0;
416 std::map<int, int> element_labels;
417 if (!file->eof()) {
418 do {
419 element_labels[label] = num_labels;
420 num_labels++;
421 std::string line;
422 std::getline(*file, line);
423 *file >> label;
424 } while (!file->eof() && (label != first_label));
425 }
426 it.num_elements = num_labels;
427 file->seekg(0, std::ios::beg);
428 for (std::list<OutputElement>::iterator ite = it.elements.begin();
429 ite != it.elements.end(); ite++) {
430 std::map<int, int>::const_iterator itep;
431 if ((itep = element_labels.find(ite->label)) != element_labels.end()) {
432 it.element_positions[itep->second] = ite;
433 } else {
434 std::cerr << "Requested output for inexistent element " << namefile
435 << ":" << ite->label << "\n";
436 success = false;
437 };
438 }
439 }
440 it.file = file;
441 }
442 };
443 struct skip_time_step : public std::unary_function<OutputFile&, void> {
444 mutable bool success;
445 mutable bool last;
skip_time_stepskip_time_step446 skip_time_step(bool l) : success(true), last(l) {};
operatorskip_time_step447 void operator()(OutputFile& it, bool last = false) const {
448 std::istream * file = it.file;
449 std::string line;
450 std::ios::pos_type pos = file->tellg();
451 for (int i=0; i < it.num_elements; i++) {
452 std::getline(*file, line);
453 }
454 if (file->eof() && !last) {
455 std::cerr << "Unexpected end of file skipping " << it.name << "; repositioning stream\n";
456 file->seekg(pos);
457 success = false;
458 }
459 }
460 };
461
462 struct read_time_step : public std::unary_function<OutputFile&, void> {
463 mutable bool success;
464 mutable bool last;
read_time_stepread_time_step465 read_time_step(bool l) : success(true), last(l) {};
operatorread_time_step466 void operator()(OutputFile& it, bool last = false) const {
467 std::istream * file = it.file;
468 std::string line;
469 int cur_element, prev_element;
470 cur_element = 0; prev_element = -1;
471 std::ios::pos_type pos = file->tellg();
472 for (std::map<int, std::list<OutputElement>::iterator>::const_iterator ite = it.element_positions.begin();
473 ite != it.element_positions.end(); ite++) {
474 cur_element = ite->first;
475 for (int i=1; i < cur_element - prev_element; i++) {
476 file->ignore(std::numeric_limits<std::streamsize>::max(),'\n');
477 //file->ignore(10000,'\n');
478 //skipline(file);
479 // std::getline(*file, line);
480 }
481 std::list<OutputElement>::iterator elit = ite->second;
482 std::map<int,int>::iterator colit;
483 int cur_col, prev_col;
484 prev_col = 0;
485 for (colit = elit->output_cols.begin(); colit != elit->output_cols.end(); colit++) {
486 cur_col = colit->first;
487 for (int i = 1; i < cur_col - prev_col; i++) {
488 skipws(file);
489 //*file >> x;
490 }
491 *file >> elit->outputs[colit->second];
492 //elit->outputs[colit->second] = x;
493 prev_col = cur_col;
494 }
495
496 file->ignore(std::numeric_limits<std::streamsize>::max(),'\n');
497 //file->ignore(10000,'\n');
498 //skipline(file);
499 // std::getline(*file, line);
500 prev_element = cur_element;
501 }
502 for (int i=1; i < it.num_elements - prev_element; i++) {
503 file->ignore(std::numeric_limits<std::streamsize>::max(),'\n');
504 //file->ignore(10000,'\n');
505 //skipline(file);
506 // std::getline(*file, line);
507 }
508 if (file->eof() && !last) {
509 //std::cerr << "Unexpected end of file reading " << it.name << "; repositioning stream\n";
510 file->seekg(pos);
511 success = false;
512 }
513 }
514 };
515
516 struct write_time_step : public std::unary_function<OutputFile&, void> {
517 mutable bool success;
518 mutable std::ostream * file;
write_time_stepwrite_time_step519 write_time_step(std::ostream * f) : success(true), file(f) {};
operatorwrite_time_step520 void operator()(OutputFile& it) const {
521 for (std::list<OutputElement>::iterator elit = it.elements.begin();
522 elit != it.elements.end(); elit++) {
523 for (int i = 0; i<elit->num_outputs; i++) {
524 *file << elit->outputs[i] << " ";
525 }
526 }
527 }
528 };
529
530 struct close_file : public std::unary_function<OutputFile&, void> {
operatorclose_file531 void operator()(OutputFile& it) const {
532 if (it.file != 0) {
533 static_cast<std::ifstream*>(it.file)->close();
534 }
535 }
536 };
537
main(int argc,char * argv[])538 int main(int argc, char *argv[]) {
539 std::cout.sync_with_stdio(false);
540 std::cerr.sync_with_stdio(false);
541 struct arguments argu;
542
543 argp_parse (&argp_s, argc, argv, 0, 0, &argu);
544 std::ostream *out;
545 std::istream *commands;
546 std::istream *in_log;
547 std::istream *in_out;
548 if (argu.output_file != 0) {
549 std::string namefile(argu.output_file);
550 namefile += ".dat";
551 std::cerr << "out: " << namefile << "\n";
552 out = new std::ofstream(namefile.c_str());
553 if (out == 0) {
554 std::cerr << "Unable to open output file " << namefile << "\n";
555 return 1;
556 }
557 } else {
558 out = &std::cout;
559 }
560 commands = new std::istringstream(argu.args[0]);
561 if (!ParseCommands(*commands, std::cerr)) {
562 return 1;
563 }
564 std::string basename(argu.args[1]);
565 std::string namefile(basename);
566 namefile += ".log";
567 in_log = new std::ifstream(namefile.c_str());
568 if (in_log == 0 || !static_cast<std::ifstream*>(in_log)->is_open()) {
569 std::cerr << "Unable to open log file " << namefile << "\n";
570 return 1;
571 }
572 namefile = basename;
573 namefile += ".out";
574 in_out = new std::ifstream(namefile.c_str());
575 if (in_out == 0 || !static_cast<std::ifstream*>(in_out)->is_open()) {
576 std::cerr << "Unable to open out file " << namefile << "\n";
577 return 1;
578 }
579
580 if (!ParseLog(*in_log, std::cerr)) {
581 return 1;
582 }
583
584 MbdynpostFlexLexer flexout(in_out, out);
585
586 bool status;
587 status = std::for_each(files.begin(), files.end(), allocate_file(basename)).success;
588 if (!ParseOut(flexout, *in_out)) {
589 return 1;
590 }
591 //da eliminare
592 do {
593 status = std::for_each(files.begin(), files.end(), read_time_step(false)).success;
594 if (status && ((argu.t1 == 0.) || (current_time <= argu.t1) ) ) {
595 if (current_time >= argu.t0) {
596 *out << current_time << " ";
597 status = std::for_each(files.begin(), files.end(), write_time_step(out)).success;
598 *out << "\n";
599 for (int i=0; i < argu.skip; i++) {
600 if (!std::for_each(files.begin(), files.end(), skip_time_step(false)).success) {
601 break;
602 }
603 }
604 for (int i=1; i < (argu.skip + 1) * output_frequency; i++) {
605 if (!ParseOut(flexout, *in_out)) {
606 break;
607 }
608 }
609 } else {
610 for (int i=1; i < output_frequency; i++) {
611 if (!ParseOut(flexout, *in_out)) {
612 break;
613 }
614 }
615 }
616 } else {
617 break;
618 }
619 } while (ParseOut(flexout, *in_out));
620 std::for_each(files.begin(), files.end(), close_file());
621 // WriteTimeData(*out, *in_out, *in_mov, argu.skip, strnode_num);
622 if (argu.output_file) {
623 static_cast<std::ofstream*>(out)->close();
624 }
625 return 0;
626 }
627
628