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