1 /*
2  * ngspice-analysis.c
3  *
4  * Authors:
5  *  Marc Lorber <Lorber.Marc@wanadoo.fr>
6  *  Bernhard Schuster <bernhard@ahoi.io>
7  *  Guido Trentalancia <guido@trentalancia.com>
8  *
9  * Web page: https://ahoi.io/project/oregano
10  *
11  * Copyright (C) 2009-2012  Marc Lorber
12  * Copyright (C) 2014       Bernhard Schuster
13  * Copyright (C) 2017       Guido Trentalancia
14  *
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License as
17  * published by the Free Software Foundation; either version 2 of the
18  * License, or (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23  * General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public
26  * License along with this program; if not, write to the
27  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
28  * Boston, MA 02110-1301, USA.
29  */
30 
31 #include <glib.h>
32 #include <sys/types.h>
33 #include <sys/wait.h>
34 #include <ctype.h>
35 #include <stdlib.h>
36 #include <glib/gi18n.h>
37 
38 #include "ngspice.h"
39 #include "netlist-helper.h"
40 #include "dialogs.h"
41 #include "engine-internal.h"
42 #include "ngspice-analysis.h"
43 #include "../tools/thread-pipe.h"
44 #include "../tools/cancel-info.h"
45 
46 #define SP_TITLE "oregano\n"
47 #define CPU_TIME "CPU time since last call:"
48 
49 #define TAGS_COUNT (sizeof(analysis_tags) / sizeof(struct analysis_tag))
50 #include "debug.h"
51 #define IS_THIS_ITEM(str, item) (!strncmp (str, item, strlen (item)))
52 #ifdef DEBUG_THIS
53 #undef DEBUG_THIS
54 #endif
55 #define DEBUG_THIS 1
56 
57 /**
58  * \brief extract the resulting variables from ngspice output
59  *
60  * In ngspice a number can terminate only with a space,
61  * while in spice3 a number can also terminate with a
62  * comma.
63  *
64  * In the Fourier analysis the name of the output ends
65  * with a colon.
66  *
67  * Tested function.
68  *
69  * @returns a GArray filled up doubles
70  */
get_variables(const gchar * str,gint * count)71 gchar **get_variables (const gchar *str, gint *count)
72 {
73 	g_return_val_if_fail (str, NULL);
74 
75 	gchar **out;
76 	static gchar *tmp[100];
77 	const gchar *start, *end;
78 	gint i = 0;
79 
80 	start = str;
81 	while (isspace (*start))
82 		start++;
83 	end = start;
84 	while (*end != '\0') {
85 		if (isspace (*end) || *end == ',' || *end == ':') {
86 			// number ended, designate as such and replace the string
87 			tmp[i] = g_strndup (start, (gsize)(end - start));
88 			i++;
89 			start = end;
90 			while (isspace (*start) || *start == ',' || *start == ':')
91 				start++;
92 			end = start;
93 		} else {
94 			end++;
95 		}
96 	}
97 	if (end > start) {
98 		tmp[i] = g_strndup (start, (gsize)(end - start));
99 		i++;
100 	}
101 
102 	if (i == 0) {
103 		g_warning ("NO COLUMNS FOUND\n");
104 		return NULL;
105 	}
106 
107 	// append an extra NUL slot to allow using g_strfreev
108 	out = g_new0 (gchar *, i + 1);
109 	(*count) = i;
110 	memcpy (out, tmp, sizeof(gchar *) * i);
111 	out[i] = NULL;
112 	return out;
113 }
114 
115 /**
116  * @resources: caller frees
117  */
parse_dc_analysis(NgspiceAnalysisResources * resources)118 static ThreadPipe *parse_dc_analysis (NgspiceAnalysisResources *resources)
119 {
120 	ThreadPipe *pipe = resources->pipe;
121 	gchar **buf = &resources->buf;
122 	const SimSettings* const sim_settings = resources->sim_settings;
123 	GList **analysis = resources->analysis;
124 	guint *num_analysis = resources->num_analysis;
125 
126 	static SimulationData *sdata;
127 	static Analysis *data;
128 	gsize size;
129 	gboolean found = FALSE;
130 	gchar **variables;
131 	gint i, n = 0, index = 0;
132 	gdouble val[10];
133 	gdouble np1;
134 
135 	NG_DEBUG ("DC: result str\n>>>\n%s\n<<<", *buf);
136 
137 	data = g_new0 (Analysis, 1);
138 	sdata = SIM_DATA (data);
139 	sdata->type = ANALYSIS_TYPE_DC_TRANSFER;
140 	sdata->functions = NULL;
141 
142 	np1 = 1.;
143 	ANALYSIS (sdata)->dc.start = sim_settings_get_dc_start (sim_settings);
144 	ANALYSIS (sdata)->dc.stop = sim_settings_get_dc_stop (sim_settings);
145 	ANALYSIS (sdata)->dc.step = sim_settings_get_dc_step (sim_settings);
146 
147 	np1 = (ANALYSIS (sdata)->dc.stop - ANALYSIS (sdata)->dc.start) / ANALYSIS (sdata)->dc.step;
148 	ANALYSIS (sdata)->dc.sim_length = np1;
149 
150 	pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
151 	pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
152 
153 	// Calculates the number of variables
154 	variables = get_variables (*buf, &n);
155 	if (!variables)
156 		return pipe;
157 
158 	n = n - 1;
159 	sdata->var_names = (char **)g_new0 (gpointer, n);
160 	sdata->var_units = (char **)g_new0 (gpointer, n);
161 	sdata->var_names[0] = g_strdup ("Voltage sweep");
162 	sdata->var_units[0] = g_strdup (_ ("voltage"));
163 	sdata->var_names[1] = g_strdup (variables[2]);
164 	sdata->var_units[1] = g_strdup (_ ("voltage"));
165 
166 	sdata->n_variables = 2;
167 	sdata->got_points = 0;
168 	sdata->got_var = 0;
169 	sdata->data = (GArray **)g_new0 (gpointer, 2);
170 
171 	pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
172 
173 	for (i = 0; i < 2; i++)
174 		sdata->data[i] = g_array_new (TRUE, TRUE, sizeof(double));
175 
176 	sdata->min_data = g_new (double, n);
177 	sdata->max_data = g_new (double, n);
178 
179 	// Read the data
180 	for (i = 0; i < 2; i++) {
181 		sdata->min_data[i] = G_MAXDOUBLE;
182 		sdata->max_data[i] = -G_MAXDOUBLE;
183 	}
184 	found = FALSE;
185 	while (((pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size)) != 0) && !found) {
186 		if (strlen (*buf) <= 2) {
187 			pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
188 			pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
189 			pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
190 		}
191 		variables = get_variables (*buf, &i);
192 		if (!variables)
193 			return pipe;
194 		index = atoi (variables[0]);
195 		for (i = 0; i < n; i++) {
196 			val[i] = g_ascii_strtod (variables[i + 1], NULL);
197 			sdata->data[i] = g_array_append_val (sdata->data[i], val[i]);
198 			if (val[i] < sdata->min_data[i])
199 				sdata->min_data[i] = val[i];
200 			if (val[i] > sdata->max_data[i])
201 				sdata->max_data[i] = val[i];
202 		}
203 		sdata->got_points++;
204 		sdata->got_var = 2;
205 		if (index >= ANALYSIS (sdata)->dc.sim_length)
206 			found = TRUE;
207 	}
208 
209 	*analysis = g_list_append (*analysis, sdata);
210 	(*num_analysis)++;
211 
212 	return pipe;
213 }
214 
215 /**
216  * @resources: caller frees
217  */
parse_ac_analysis(NgspiceAnalysisResources * resources)218 static ThreadPipe *parse_ac_analysis (NgspiceAnalysisResources *resources)
219 {
220 	ThreadPipe *pipe = resources->pipe;
221 	gboolean is_vanilla = resources->is_vanilla;
222 	gchar *scale, **variables, **buf = &resources->buf;
223 	const SimSettings* const sim_settings = resources->sim_settings;
224 	GList **analysis = resources->analysis;
225 	guint *num_analysis = resources->num_analysis;
226 	static SimulationData *sdata;
227 	static Analysis *data;
228 	gsize size;
229 	gboolean found = FALSE;
230 	gint i, n = 0, index = 0;
231 	gdouble fstart, fstop, val[10];
232 
233 	NG_DEBUG ("AC: result str\n>>>\n%s\n<<<", *buf);
234 
235 	data = g_new0 (Analysis, 1);
236 	sdata = SIM_DATA (data);
237 	sdata->type = ANALYSIS_TYPE_AC;
238 	sdata->functions = NULL;
239 
240 	ANALYSIS (sdata)->ac.sim_length = 1.;
241 
242 	ANALYSIS (sdata)->ac.start = fstart = sim_settings_get_ac_start (sim_settings);
243 	ANALYSIS (sdata)->ac.stop = fstop = sim_settings_get_ac_stop (sim_settings);
244 
245         scale = sim_settings_get_ac_type (sim_settings);
246         if (!g_ascii_strcasecmp (scale, "LIN")) {
247                 ANALYSIS (sdata)->ac.sim_length = (double) sim_settings_get_ac_npoints (sim_settings);
248         } else if (!g_ascii_strcasecmp (scale, "DEC")) {
249                 ANALYSIS (sdata)->ac.sim_length = (double) sim_settings_get_ac_npoints (sim_settings) * log10 (fstop / fstart);
250         } else if (!g_ascii_strcasecmp (scale, "OCT")) {
251                 ANALYSIS (sdata)->ac.sim_length = (double) sim_settings_get_ac_npoints (sim_settings) * log10 (fstop / fstart) / log10 (2);
252         }
253 
254 	pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
255 	pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
256 
257 	// Calculates the number of variables
258 	variables = get_variables (*buf, &n);
259 	if (!variables)
260 		return pipe;
261 
262 	n = n - 1;
263 	sdata->var_names = (char **)g_new0 (gpointer, n);
264 	sdata->var_units = (char **)g_new0 (gpointer, n);
265 	sdata->var_names[0] = g_strdup ("Frequency");
266 	sdata->var_units[0] = g_strdup (_ ("frequency"));
267 	sdata->var_names[1] = g_strdup (variables[2]);
268 	sdata->var_units[1] = g_strdup (_ ("voltage"));
269 
270 	sdata->n_variables = 2;
271 	sdata->got_points = 0;
272 	sdata->got_var = 0;
273 	sdata->data = (GArray **)g_new0 (gpointer, 2);
274 
275 	pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
276 
277 	for (i = 0; i < 2; i++)
278 		sdata->data[i] = g_array_new (TRUE, TRUE, sizeof(double));
279 
280 	sdata->min_data = g_new (double, n);
281 	sdata->max_data = g_new (double, n);
282 
283 	// Read the data
284 	for (i = 0; i < 2; i++) {
285 		sdata->min_data[i] = G_MAXDOUBLE;
286 		sdata->max_data[i] = -G_MAXDOUBLE;
287 	}
288 	found = FALSE;
289 	while (((pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size)) != 0) && !found) {
290 		if (strlen (*buf) <= 2) {
291 			pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
292 			pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
293 			pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
294 		}
295 
296 		variables = get_variables (*buf, &i);
297 		if (!variables)
298 			return pipe;
299 
300 		index = atoi (variables[0]);
301 		for (i = 0; i < n; i++) {
302 			if (i == 0)
303 				val[i] = g_ascii_strtod (variables[i + 1], NULL);
304 			if (is_vanilla && i > 0)
305 				val[i] = g_ascii_strtod (variables[i + 2], NULL);
306 			else
307 				val[i] = g_ascii_strtod (variables[i + 1], NULL);
308 			sdata->data[i] = g_array_append_val (sdata->data[i], val[i]);
309 			if (val[i] < sdata->min_data[i])
310 				sdata->min_data[i] = val[i];
311 			if (val[i] > sdata->max_data[i])
312 				sdata->max_data[i] = val[i];
313 		}
314 		sdata->got_points++;
315 		sdata->got_var = 2;
316 		if (index >= ANALYSIS (sdata)->ac.sim_length - 1)
317 			found = TRUE;
318 	}
319 
320 	*analysis = g_list_append (*analysis, sdata);
321 	(*num_analysis)++;
322 
323 	return pipe;
324 }
325 
326 /**
327  * Structure that helps parsing the output of ngspice.
328  *
329  * @name: The name (handled like an ID) of the column.
330  * @unit: The physical unit. it can have one of the following values:
331  * "none", "time", "voltage", "current", "unknown"
332  * @data: The data.
333  * @min: The min value of the data.
334  * @max: The max value of the data.
335  */
336 typedef struct {
337 	GString *name;
338 	GString *unit;
339 	GArray *data;
340 	gdouble min;
341 	gdouble max;
342 } NgspiceColumn;
343 
344 /**
345  * Structure that helps parsing the output of ngspice.
346  *
347  * @ngspice_columns: The columns.
348  * @current_variables: New columns are appended to the end
349  * of the columns array. Because the index- and time-column
350  * are displayed repeatedly with every 3 new columns, there
351  * is needed an information how to interpret the incoming
352  * data to append it to the right columns. The current_variables
353  * array maps the position of the input data in the file
354  * to the position of the related column position in the table.
355  */
356 typedef struct {
357 	GPtrArray *ngspice_columns;
358 	GArray *current_variables;
359 } NgspiceTable;
360 
361 /**
362  * Allocates memory.
363  *
364  * @name: The name (ID) of the new column
365  * @predicted_size: The predicted end size of the new column.
366  */
ngspice_column_new(const gchar * name,guint predicted_size)367 static NgspiceColumn *ngspice_column_new(const gchar *name, guint predicted_size) {
368 	NgspiceColumn *ret_val = malloc(sizeof(NgspiceColumn));
369 
370 	ret_val->name = g_string_new(name);
371 
372 	if (g_str_has_prefix(name, "Index"))
373 		ret_val->unit = g_string_new("none");
374 	else if (g_str_has_prefix(name, "time"))
375 		ret_val->unit = g_string_new("time");
376 	else if (g_str_has_prefix(name, "V") || g_str_has_prefix(name, "v"))
377 		ret_val->unit = g_string_new("voltage");
378 	else if (g_str_has_suffix(name, "#branch"))
379 		ret_val->unit = g_string_new("current");
380 	else
381 		ret_val->unit = g_string_new("unknown");
382 
383 	ret_val->data = g_array_sized_new(TRUE, TRUE, sizeof(gdouble), predicted_size);
384 	ret_val->min = G_MAXDOUBLE;
385 	ret_val->max = -G_MAXDOUBLE;
386 
387 	return ret_val;
388 }
389 
390 /**
391  * Frees memory.
392  */
ngspice_column_destroy(gpointer ptr)393 static void ngspice_column_destroy(gpointer ptr) {
394 	NgspiceColumn *column = (NgspiceColumn *)ptr;
395 	if (column == NULL)
396 		return;
397 	if (column->name != NULL)
398 		g_string_free(column->name, TRUE);
399 	if (column->unit != NULL)
400 		g_string_free(column->unit, TRUE);
401 	g_free(column);
402 }
403 
404 /**
405  * Allocates memory.
406  */
ngspice_table_new()407 static NgspiceTable *ngspice_table_new() {
408 	NgspiceTable *ret_val = malloc(sizeof(NgspiceTable));
409 	ret_val->ngspice_columns = g_ptr_array_new_with_free_func(ngspice_column_destroy);
410 	ret_val->current_variables = g_array_new(TRUE, TRUE, sizeof(guint));
411 	return ret_val;
412 }
413 
414 /**
415  * Frees the memory.
416  */
ngspice_table_destroy(NgspiceTable * ngspice_table)417 static void ngspice_table_destroy(NgspiceTable *ngspice_table) {
418 
419 	if (ngspice_table->ngspice_columns != NULL) {
420 		guint len = ngspice_table->ngspice_columns->len;
421 
422 		for (int i = 0; i < len; i++) {
423 			NgspiceColumn *column = ngspice_table->ngspice_columns->pdata[i];
424 			if (column != NULL)
425 				g_array_free(column->data, TRUE);
426 		}
427 
428 		g_ptr_array_free(ngspice_table->ngspice_columns, TRUE);
429 	}
430 
431 	if (ngspice_table->current_variables != NULL)
432 		g_array_free(ngspice_table->current_variables, TRUE);
433 
434 	g_free(ngspice_table);
435 }
436 
437 /**
438  * Converts "x...x#branch" to "I(x...x)".
439  *
440  * Let "x...x" be the name of a part in the ngspice netlist,
441  * then the current variable (current, that flows through
442  * that part) of that part is named
443  * "x...x#branch" in ngspice. To shorten the name and make
444  * it prettier, the name will be displayed as "I(x...x)"
445  * in Oregano (analogous to V(node_nr)).
446  */
convert_variable_name(gchar ** variable)447 static void convert_variable_name(gchar **variable) {
448 	gchar **splitted = g_regex_split_simple("\\#branch", *variable, 0, 0);
449 	g_free(*variable);
450 	*variable = g_strdup_printf("I(%s)", *splitted);
451 	g_strfreev(splitted);
452 }
453 
454 /**
455  * Creates and appends new columns to the table, if there are new variables.
456  * The referenced columns are now the newly added columns.
457  *
458  * @predicted_size: The predicted end size of the new columns. It is assumed
459  * that the new columns will have the same size.
460  */
ngspice_table_new_columns(NgspiceTable * ngspice_table,gchar ** variables,guint predicted_size)461 static void ngspice_table_new_columns(NgspiceTable *ngspice_table, gchar **variables, guint predicted_size) {
462 	if (ngspice_table->ngspice_columns->len > 0) {
463 		NgspiceColumn *column = (NgspiceColumn *)ngspice_table->ngspice_columns->pdata[0];
464 		predicted_size = column->data->len;
465 	}
466 
467 	g_array_free(ngspice_table->current_variables, TRUE);
468 	ngspice_table->current_variables = g_array_new(TRUE, TRUE, sizeof(guint));
469 
470 	for (gchar **variable = variables; *variable != NULL && **variable != '\n' && **variable != 0; variable++) {
471 		if (g_str_has_suffix(*variable, "#branch"))
472 			convert_variable_name(variable);
473 		int i;
474 		for (i = 0; i < ngspice_table->ngspice_columns->len; i++) {
475 			if (!strcmp(*variable, ((NgspiceColumn *)ngspice_table->ngspice_columns->pdata[i])->name->str))
476 				break;
477 		}
478 		if (i == ngspice_table->ngspice_columns->len) {
479 			NgspiceColumn *new_column = ngspice_column_new(*variable, predicted_size);
480 			g_ptr_array_add(ngspice_table->ngspice_columns, new_column);
481 		}
482 		g_array_append_val(ngspice_table->current_variables, i);
483 	}
484 }
485 
486 /**
487  * Appends a split line to the end of the current referenced columns.
488  */
ngspice_table_add_data(NgspiceTable * ngspice_table,gchar ** data)489 static void ngspice_table_add_data(NgspiceTable *ngspice_table, gchar **data) {
490 	g_return_if_fail(data != NULL);
491 	g_return_if_fail(*data != NULL);
492 	if (**data == 0)
493 		return;
494 	g_return_if_fail(ngspice_table != NULL);
495 
496 	guint64 index = g_ascii_strtoull(*data, NULL, 10);
497 	for (int i = 0; data[i] != NULL && data[i][0] != 0 && data[i][0] != '\n' && i < ngspice_table->current_variables->len; i++) {
498 		guint column_index = g_array_index(ngspice_table->current_variables, guint, i);
499 		NgspiceColumn *column = (NgspiceColumn*)(ngspice_table->ngspice_columns->pdata[column_index]);
500 		if (column->data->len > index) {
501 			continue;//assert equal
502 		}
503 		gdouble new_content = g_ascii_strtod(data[i], NULL);
504 		g_array_append_val(column->data, new_content);
505 		if (new_content < column->min)
506 			column->min = new_content;
507 		if (new_content > column->max)
508 			column->max = new_content;
509 	}
510 }
511 
512 /**
513  * Counts the number of different guints. If a certain
514  * guint occurs more than once, it is counted as one.
515  */
get_real_len(GArray * array_guint)516 static guint get_real_len(GArray *array_guint) {
517 	guint ret_val = 0;
518 	for (guint i = 0; i < array_guint->len; i++) {
519 		ret_val++;
520 		for (guint j = 0; j < i; j++) {
521 			if (g_array_index(array_guint, guint, i) == g_array_index(array_guint, guint, j)) {
522 				ret_val--;
523 				break;
524 			}
525 		}
526 	}
527 
528 	return ret_val;
529 }
530 
531 /**
532  * Returns the index that is currently parsed.
533  *
534  * The first referenced column is the string-index column,
535  * the second referenced column is the time. The index and
536  * the time column can already be filled up by earlier
537  * iterations, so the length of the third referenced column
538  * represents the index that is currently parsed.
539  */
get_current_index(NgspiceTable * ngspice_table)540 static guint get_current_index(NgspiceTable *ngspice_table) {
541 	guint column_nr = g_array_index(ngspice_table->current_variables, guint, 2);
542 	NgspiceColumn *column = g_ptr_array_index(ngspice_table->ngspice_columns, column_nr);
543 	return column->data->len;
544 }
545 
546 typedef struct {
547 	NgspiceTable *table;
548 	ThreadPipe *pipe;
549 	gboolean is_cancel;
550 } ParseTransientAnalysisReturnResources;
551 
552 /**
553  * @resources: caller frees
554  */
parse_transient_analysis_resources(NgspiceAnalysisResources * resources)555 static ParseTransientAnalysisReturnResources parse_transient_analysis_resources (NgspiceAnalysisResources *resources)
556 {
557 	gchar **buf = &resources->buf;
558 	const SimSettings *sim_settings = resources->sim_settings;
559 	guint *num_analysis = resources->num_analysis;
560 	ProgressResources *progress_reader = resources->progress_reader;
561 	guint64 no_of_data_rows = resources->no_of_data_rows_transient;
562 	guint no_of_variables = resources->no_of_variables;
563 
564 
565 	enum STATE {
566 		NGSPICE_ANALYSIS_STATE_READ_DATA,
567 		NGSPICE_ANALYSIS_STATE_DATA_SMALL_BLOCK_END,
568 		NGSPICE_ANALYSIS_STATE_DATA_LARGE_BLOCK_END,
569 		NGSPICE_ANALYSIS_STATE_DATA_END,
570 		NGSPICE_ANALYSIS_STATE_READ_VARIABLES_NEW,
571 		NGSPICE_ANALYSIS_STATE_READ_VARIABLES_OLD
572 	};
573 
574 	g_mutex_lock(&progress_reader->progress_mutex);
575 	progress_reader->progress = 0;
576 	progress_reader->time = g_get_monotonic_time();
577 	g_mutex_unlock(&progress_reader->progress_mutex);
578 
579 	gsize size;
580 
581 	NgspiceTable *ngspice_table = ngspice_table_new();
582 
583 	ParseTransientAnalysisReturnResources ret_val;
584 	ret_val.table = ngspice_table;
585 	ret_val.pipe = resources->pipe;
586 	ret_val.is_cancel = TRUE;
587 
588 	enum STATE state = NGSPICE_ANALYSIS_STATE_DATA_LARGE_BLOCK_END;
589 
590 	guint i = 0;
591 
592 	do {
593 		if (i % 50 == 0 && cancel_info_is_cancel(resources->cancel_info))
594 			return ret_val;
595 
596 		switch (state) {
597 			case NGSPICE_ANALYSIS_STATE_READ_VARIABLES_NEW:
598 			{
599 				gchar **splitted_line = g_regex_split_simple(" +", *buf, 0, 0);
600 
601 				ngspice_table_new_columns(ngspice_table, splitted_line, no_of_data_rows);
602 
603 				g_strfreev(splitted_line);
604 
605 				state = NGSPICE_ANALYSIS_STATE_READ_VARIABLES_OLD;
606 				break;
607 			}
608 			case NGSPICE_ANALYSIS_STATE_READ_DATA:
609 			{
610 				gchar **splitted_line = g_regex_split_simple("\\t+|-{2,}", *buf, 0, 0);
611 
612 				ngspice_table_add_data(ngspice_table, splitted_line);
613 
614 				g_strfreev(splitted_line);
615 
616 				if ((ret_val.pipe = thread_pipe_pop(ret_val.pipe, (gpointer *)buf, &size)) == NULL)
617 					return ret_val;
618 
619 				switch (*buf[0]) {
620 				case '\f':{
621 					// estimate progress begin
622 					guint len_of_current_variables = get_real_len(ngspice_table->current_variables) - 2;
623 					guint len_of_current_columns = ngspice_table->ngspice_columns->len - 2;
624 					guint count_of_variables_already_finished = len_of_current_columns - len_of_current_variables;
625 					g_mutex_lock(&progress_reader->progress_mutex);
626 					progress_reader->progress = (double)count_of_variables_already_finished / (double)no_of_variables +
627 							(double)len_of_current_variables / (double)no_of_variables *
628 							(double)get_current_index(ngspice_table) / (double)no_of_data_rows;
629 					progress_reader->time = g_get_monotonic_time();
630 					g_mutex_unlock(&progress_reader->progress_mutex);
631 					// estimate progress end
632 
633 					state = NGSPICE_ANALYSIS_STATE_DATA_SMALL_BLOCK_END;
634 					break;}
635 				case '\n':
636 					state = NGSPICE_ANALYSIS_STATE_DATA_END;
637 					break;
638 				}
639 				break;
640 			}
641 			case NGSPICE_ANALYSIS_STATE_READ_VARIABLES_OLD:
642 			{
643 				if ((ret_val.pipe = thread_pipe_pop(ret_val.pipe, (gpointer *)buf, &size)) == NULL)
644 					return ret_val;
645 
646 				if (*buf[0] != '-')
647 					state = NGSPICE_ANALYSIS_STATE_READ_DATA;
648 				break;
649 			}
650 			case NGSPICE_ANALYSIS_STATE_DATA_SMALL_BLOCK_END:
651 			{
652 				if ((ret_val.pipe = thread_pipe_pop(ret_val.pipe, (gpointer *)buf, &size)) == NULL)
653 					return ret_val;
654 
655 				switch (*buf[0]) {
656 				case 'I':
657 					state = NGSPICE_ANALYSIS_STATE_READ_VARIABLES_OLD;
658 					break;
659 				case ' ':
660 					state = NGSPICE_ANALYSIS_STATE_DATA_LARGE_BLOCK_END;
661 					break;
662 				}
663 				break;
664 			}
665 			case NGSPICE_ANALYSIS_STATE_DATA_LARGE_BLOCK_END:
666 			{
667 				if ((ret_val.pipe = thread_pipe_pop(ret_val.pipe, (gpointer *)buf, &size)) == NULL)
668 					return ret_val;
669 
670 				if (*buf[0] == 'I')
671 					state = NGSPICE_ANALYSIS_STATE_READ_VARIABLES_NEW;
672 				break;
673 			}
674 			case NGSPICE_ANALYSIS_STATE_DATA_END:
675 				break;
676 		}
677 	} while (state != NGSPICE_ANALYSIS_STATE_DATA_END);
678 
679 	ret_val.is_cancel = FALSE;
680 
681 	SimulationData *sdata = SIM_DATA (g_new0 (Analysis, 1));
682 	sdata->type = ANALYSIS_TYPE_TRANSIENT;
683 	sdata->functions = NULL;
684 
685 	gint nodes_nb = ngspice_table->ngspice_columns->len - 2;
686 
687 	ANALYSIS (sdata)->transient.sim_length =
688 	    sim_settings_get_trans_stop (sim_settings) - sim_settings_get_trans_start (sim_settings);
689 	ANALYSIS (sdata)->transient.step_size = sim_settings_get_trans_step (sim_settings);
690 
691 	sdata->var_names = g_new0 (gchar *, nodes_nb + 1);
692 	sdata->var_units = g_new0 (gchar *, nodes_nb + 1);
693 	sdata->data = g_new0 (GArray *, nodes_nb + 1);
694 	sdata->min_data = g_new (gdouble, nodes_nb + 1);
695 	sdata->max_data = g_new (gdouble, nodes_nb + 1);
696 
697 	for (int i = 0; i < nodes_nb + 1; i++) {
698 		NgspiceColumn *column = ngspice_table->ngspice_columns->pdata[i+1];
699 		sdata->var_names[i] = g_strdup(column->name->str);
700 		sdata->var_units[i] = g_strdup(column->unit->str);
701 		sdata->data[i] = column->data;
702 		sdata->min_data[i] = column->min;
703 		sdata->max_data[i] = column->max;
704 
705 		ngspice_table->ngspice_columns->pdata[i+1] = NULL;
706 	}
707 	sdata->n_variables = nodes_nb + 1;
708 	NgspiceColumn *column = ngspice_table->ngspice_columns->pdata[0];
709 	sdata->got_points = column->data->len;
710 	sdata->got_var = nodes_nb + 1;
711 
712 	(*num_analysis)++;
713 	*resources->analysis = g_list_append (*resources->analysis, sdata);
714 
715 	return ret_val;
716 }
717 
parse_transient_analysis(NgspiceAnalysisResources * resources)718 static ThreadPipe *parse_transient_analysis (NgspiceAnalysisResources *resources) {
719 	ParseTransientAnalysisReturnResources ret_res = parse_transient_analysis_resources(resources);
720 
721 	ngspice_table_destroy(ret_res.table);
722 
723 	if (ret_res.is_cancel && ret_res.pipe) {
724 		thread_pipe_set_read_eof(ret_res.pipe);
725 		ret_res.pipe = NULL;
726 	}
727 
728 	return ret_res.pipe;
729 }
730 
731 /**
732  * @resources: caller frees
733  */
parse_fourier_analysis(NgspiceAnalysisResources * resources)734 static ThreadPipe *parse_fourier_analysis (NgspiceAnalysisResources *resources)
735 {
736 	ThreadPipe *pipe = resources->pipe;
737 	gchar **buf = &resources->buf;
738 	const SimSettings *sim_settings = resources->sim_settings;
739 	GList **analysis = resources->analysis;
740 	guint *num_analysis = resources->num_analysis;
741 
742 	static SimulationData *sdata;
743 	static Analysis *data;
744 	gsize size;
745 	gchar **variables;
746 	gint i, n = 0, j, k;
747 	gdouble val[3];
748 	gchar **node_ids;
749 	gchar *vout;
750 
751 	NG_DEBUG ("FOURIER: result str\n>>>\n%s\n<<<", *buf);
752 
753 	data = g_new0 (Analysis, 1);
754 	sdata = SIM_DATA (data);
755 	sdata->type = ANALYSIS_TYPE_FOURIER;
756 	sdata->functions = NULL;
757 
758 	g_strchug (*buf);
759 	ANALYSIS (sdata)->fourier.freq = sim_settings_get_fourier_frequency (sim_settings);
760 
761 	vout = sim_settings_get_fourier_vout (sim_settings);
762 	node_ids = g_strsplit (vout, " ", 0);
763 	for (i = 0; node_ids[i] != NULL; i++) {
764 	}
765 	g_strfreev (node_ids);
766 	g_free (vout);
767 	ANALYSIS (sdata)->fourier.nb_var = i + 1;
768 	n = ANALYSIS (sdata)->fourier.nb_var;
769 	sdata->n_variables = n;
770 
771 	sdata->var_names = (char **)g_new0 (gpointer, n);
772 	sdata->var_units = (char **)g_new0 (gpointer, n);
773 	sdata->var_names[0] = g_strdup ("Frequency");
774 	sdata->var_units[0] = g_strdup (_ ("frequency"));
775 
776 	sdata->got_points = 0;
777 	sdata->got_var = 0;
778 
779 	sdata->data = (GArray **)g_new0 (gpointer, n);
780 	for (i = 0; i < n; i++)
781 		sdata->data[i] = g_array_new (TRUE, TRUE, sizeof(double));
782 
783 	sdata->min_data = g_new (double, n);
784 	sdata->max_data = g_new (double, n);
785 
786 	for (i = 0; i < n; i++) {
787 		sdata->min_data[i] = G_MAXDOUBLE;
788 		sdata->max_data[i] = -G_MAXDOUBLE;
789 	}
790 
791 	// For each output voltage (plus the frequency for the x-axis),
792 	// scan its data set
793 	for (k = 1; k < n; k++) {
794 		variables = get_variables (*buf, &i);
795 		if (!variables)
796 			return pipe;
797 
798 		// Skip data set header (4 lines)
799 		for (i = 0; i < 4; i++)
800 			pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
801 
802 		sdata->var_names[k] = g_strdup_printf ("mag(%s)", variables[3]);
803 		sdata->var_units[k] = g_strdup (_ ("voltage"));
804 
805 		// Scan data set for 10 harmonics
806 		for (j = 0; j < 10; j++) {
807 			pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
808 			if (!pipe)
809 				return pipe;
810 
811 			sscanf (*buf, "\t%d\t%lf\t%lf\t%lf", &i, &val[0], &val[1], &val[2]);
812 			if (k == 1) {
813 				sdata->data[0] = g_array_append_val (sdata->data[0], val[0]);
814 				if (val[0] < sdata->min_data[0])
815 					sdata->min_data[0] = val[0];
816 				if (val[0] > sdata->max_data[0])
817 					sdata->max_data[0] = val[0];
818 				sdata->data[1] = g_array_append_val (sdata->data[1], val[1]);
819 				if (val[1] < sdata->min_data[1])
820 					sdata->min_data[1] = val[1];
821 				if (val[1] > sdata->max_data[1])
822 					sdata->max_data[1] = val[1];
823 				sdata->got_points = sdata->got_points + 2;
824 			} else {
825 				sdata->data[k] = g_array_append_val (sdata->data[k], val[1]);
826 				if (val[1] < sdata->min_data[k])
827 					sdata->min_data[k] = val[1];
828 				if (val[1] > sdata->max_data[k])
829 					sdata->max_data[k] = val[1];
830 				sdata->got_points++;
831 			}
832 		}
833 		pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
834 		if (!pipe)
835 			return pipe;
836 
837 		pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
838 		if (!pipe)
839 			return pipe;
840 
841 	}
842 
843 	sdata->got_var = n;
844 
845 	*analysis = g_list_append (*analysis, sdata);
846 	(*num_analysis)++;
847 
848 	return pipe;
849 }
850 
851 /**
852  * @resources: caller frees
853  */
parse_noise_analysis(NgspiceAnalysisResources * resources)854 static ThreadPipe *parse_noise_analysis (NgspiceAnalysisResources *resources)
855 {
856 	ThreadPipe *pipe = resources->pipe;
857 	gboolean is_vanilla = resources->is_vanilla;
858 	gchar *scale, **variables, **buf = &resources->buf;
859 	const SimSettings* const sim_settings = resources->sim_settings;
860 	GList **analysis = resources->analysis;
861 	guint *num_analysis = resources->num_analysis;
862 	static SimulationData *sdata;
863 	static Analysis *data;
864 	gsize size;
865 	gboolean found = FALSE;
866 	gint i, n = 0, index = 0;
867 	gdouble fstart, fstop, val[10];
868 
869 	NG_DEBUG ("NOISE: result str\n>>>\n%s\n<<<", *buf);
870 
871 	data = g_new0 (Analysis, 1);
872 	sdata = SIM_DATA (data);
873 	sdata->type = ANALYSIS_TYPE_NOISE;
874 	sdata->functions = NULL;
875 
876 	ANALYSIS (sdata)->noise.sim_length = 1.;
877 
878 	ANALYSIS (sdata)->noise.start = fstart = sim_settings_get_noise_start (sim_settings);
879 	ANALYSIS (sdata)->noise.stop = fstop = sim_settings_get_noise_stop (sim_settings);
880 
881 	scale = sim_settings_get_noise_type (sim_settings);
882 	if (!g_ascii_strcasecmp (scale, "LIN")) {
883 		ANALYSIS (sdata)->noise.sim_length = (double) sim_settings_get_noise_npoints (sim_settings);
884 	} else if (!g_ascii_strcasecmp (scale, "DEC")) {
885 		ANALYSIS (sdata)->noise.sim_length = (double) sim_settings_get_noise_npoints (sim_settings) * log10 (fstop / fstart);
886 	} else if (!g_ascii_strcasecmp (scale, "OCT")) {
887 		ANALYSIS (sdata)->noise.sim_length = (double) sim_settings_get_noise_npoints (sim_settings) * log10 (fstop / fstart) / log10 (2);
888 	}
889 
890 	pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
891 	pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
892 
893 	// Calculates the number of variables
894 	variables = get_variables (*buf, &n);
895 	if (!variables)
896 		return pipe;
897 
898 	n = n - 1;
899 	sdata->var_names = (char **)g_new0 (gpointer, 3);
900 	sdata->var_units = (char **)g_new0 (gpointer, 3);
901 	sdata->var_names[0] = g_strdup ("Frequency");
902 	sdata->var_units[0] = g_strdup (_ ("frequency"));
903 	sdata->var_names[1] = g_strdup ("Input Noise Spectrum");
904 	sdata->var_units[1] = g_strdup (_ ("psd"));
905 	sdata->var_names[2] = g_strdup ("Output Noise Spectrum");
906 	sdata->var_units[2] = g_strdup (_ ("psd"));
907 
908 	sdata->n_variables = 3;
909 	sdata->got_points = 0;
910 	sdata->got_var = 0;
911 	sdata->data = (GArray **)g_new0 (gpointer, 3);
912 
913 	pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
914 
915 	for (i = 0; i < 3; i++)
916 		sdata->data[i] = g_array_new (TRUE, TRUE, sizeof(double));
917 
918 	sdata->min_data = g_new (double, 3);
919 	sdata->max_data = g_new (double, 3);
920 
921 	// Read the data
922 	for (i = 0; i < 3; i++) {
923 		sdata->min_data[i] = G_MAXDOUBLE;
924 		sdata->max_data[i] = -G_MAXDOUBLE;
925 	}
926 	found = FALSE;
927 	while (!found && ((pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size)) != 0)) {
928 		if (strlen (*buf) <= 2) {
929 			pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
930 			pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
931 			pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
932 		}
933 
934 		variables = get_variables (*buf, &i);
935 		if (!variables)
936 			return pipe;
937 
938 		index = atoi (variables[0]);
939 		for (i = 0; i < 3; i++) {
940 			val[i] = g_ascii_strtod (variables[i + 1], NULL);
941 			sdata->data[i] = g_array_append_val (sdata->data[i], val[i]);
942 			if (val[i] < sdata->min_data[i])
943 				sdata->min_data[i] = val[i];
944 			if (val[i] > sdata->max_data[i])
945 				sdata->max_data[i] = val[i];
946 		}
947 		sdata->got_points++;
948 
949 		if (index >= ANALYSIS (sdata)->noise.sim_length - 1)
950 			found = TRUE;
951 	}
952 
953 	// Spice 3f5 is affected by a sort of bug and prints extra data
954 	if (is_vanilla) {
955 		while (((pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size)) != 0)) {
956 			if (strlen (*buf) < 2)
957 				break;
958 		}
959 	}
960 
961 	sdata->got_var = 3;
962 
963 	*analysis = g_list_append (*analysis, sdata);
964 	(*num_analysis)++;
965 
966 	return pipe;
967 }
968 
969 /**
970  * Stores all the data coming through the given pipe to the given file.
971  * This is needed because in case of failure, ngspice prints additional
972  * error information to stdout.
973  *
974  * Maybe the user wants to analyze the ngspice output by external software.
975  */
ngspice_save(const gchar * path_to_file,ThreadPipe * pipe,CancelInfo * cancel_info)976 void ngspice_save (const gchar *path_to_file, ThreadPipe *pipe, CancelInfo *cancel_info)
977 {
978 	FILE *file = fopen(path_to_file, "w");
979 	gpointer buf = NULL;
980 	gsize size;
981 
982 	for (int i = 0; (pipe = thread_pipe_pop(pipe, &buf, &size)) != NULL; i++) {
983 		if (size != 0)
984 			fwrite(buf, 1, size, file);
985 		/**
986 		 * cancel_info uses mutex operations, so it shouldn't be
987 		 * called to often.
988 		 */
989 		if (i % 50 == 0 && cancel_info_is_cancel(cancel_info))
990 			break;
991 	}
992 	fclose(file);
993 	if (pipe != NULL)
994 		thread_pipe_set_read_eof(pipe);
995 }
996 
get_analysis_type(gchar * buf_in,AnalysisType * type_out)997 static gboolean get_analysis_type(gchar *buf_in, AnalysisType *type_out) {
998 
999 	int i = 0;
1000 	gchar *analysis_name = oregano_engine_get_analysis_name_by_type(i);
1001 	while (analysis_name) {
1002 		if (g_str_has_prefix (buf_in, analysis_name)) {
1003 			*type_out = i;
1004 			g_free(analysis_name);
1005 			return TRUE;
1006 		}
1007 		g_free(analysis_name);
1008 
1009 		i++;
1010 		analysis_name = oregano_engine_get_analysis_name_by_type(i);
1011 	}
1012 	return FALSE;
1013 }
1014 
parse_no_of_data_rows(gchar * line)1015 static guint64 parse_no_of_data_rows(gchar *line) {
1016 	gchar **splitted = g_regex_split_simple("No\\. of Data Rows \\: \\D*(\\d+)\\n", line, 0, 0);
1017 	guint64 no_of_data_rows = g_ascii_strtoull(splitted[1], NULL, 10);
1018 	g_strfreev(splitted);
1019 
1020 	return no_of_data_rows;
1021 }
1022 
parse_no_of_variables(ThreadPipe * pipe,gchar ** buf)1023 static guint parse_no_of_variables(ThreadPipe *pipe, gchar **buf) {
1024 	gsize size;
1025 
1026 	for (int i = 0; i < 5; i++)
1027 		pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
1028 
1029 	guint no_of_variables = 0;
1030 	while (**buf != '\n') {
1031 		no_of_variables++;
1032 		pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
1033 	}
1034 
1035 	return no_of_variables;
1036 }
1037 
1038 /**
1039  * @resources: caller frees
1040  */
ngspice_analysis(NgspiceAnalysisResources * resources)1041 void ngspice_analysis (NgspiceAnalysisResources *resources)
1042 {
1043 	ThreadPipe *pipe = resources->pipe;
1044 	const SimSettings *sim_settings = resources->sim_settings;
1045 	AnalysisTypeShared *current = resources->current;
1046 	gboolean is_vanilla = resources->is_vanilla;
1047 	gchar **buf = &resources->buf;
1048 	gsize size;
1049 	gboolean end_of_output;
1050 	gboolean transient_enabled = sim_settings_get_trans (sim_settings);
1051 	gboolean fourier_enabled = sim_settings_get_fourier (sim_settings);
1052 	gboolean dc_enabled = sim_settings_get_dc (sim_settings);
1053 	gboolean ac_enabled = sim_settings_get_ac (sim_settings);
1054 	gboolean noise_enabled = sim_settings_get_noise (sim_settings);
1055 
1056 	if (thread_pipe_pop(pipe, (gpointer *)buf, &size) == NULL)
1057 		return;
1058 
1059 	if (!is_vanilla) {
1060 		// Get the number of AC Analysis data rows
1061 		while (ac_enabled && !g_str_has_prefix (*buf, "No. of Data Rows : ")) {
1062 			if (thread_pipe_pop(pipe, (gpointer *)buf, &size) == NULL)
1063 				return;
1064 		}
1065 		if (ac_enabled && g_str_has_prefix(*buf, "No. of Data Rows : "))
1066 			resources->no_of_data_rows_ac = parse_no_of_data_rows(*buf);
1067 
1068 		if (ac_enabled && thread_pipe_pop(pipe, (gpointer *)buf, &size) == NULL)
1069 			return;
1070 
1071 		// Get the number of DC Analysis data rows
1072 		while (dc_enabled && !g_str_has_prefix (*buf, "No. of Data Rows : ")) {
1073 			if (thread_pipe_pop(pipe, (gpointer *)buf, &size) == NULL)
1074 				return;
1075 		}
1076 		if (dc_enabled && g_str_has_prefix(*buf, "No. of Data Rows : "))
1077 			resources->no_of_data_rows_dc = parse_no_of_data_rows(*buf);
1078 
1079 		if (dc_enabled && thread_pipe_pop(pipe, (gpointer *)buf, &size) == NULL)
1080 			return;
1081 
1082 		// Get the number of Operating Point Analysis data rows
1083 		while (!g_str_has_prefix (*buf, "No. of Data Rows : ")) {
1084 			if (thread_pipe_pop(pipe, (gpointer *)buf, &size) == NULL)
1085 				return;
1086 		}
1087 		if (g_str_has_prefix(*buf, "No. of Data Rows : "))
1088 			resources->no_of_data_rows_op = parse_no_of_data_rows(*buf);
1089 
1090 		if (thread_pipe_pop(pipe, (gpointer *)buf, &size) == NULL)
1091 			return;
1092 
1093 		// Get the number of Transient Analysis variables
1094 		while (transient_enabled && !g_str_has_prefix (*buf, "Initial Transient Solution")) {
1095 			if (thread_pipe_pop(pipe, (gpointer *)buf, &size) == NULL)
1096 				return;
1097 		}
1098 		if (transient_enabled && g_str_has_prefix(*buf, "Initial Transient Solution"))
1099 			resources->no_of_variables = parse_no_of_variables(pipe, buf);
1100 
1101 		if (transient_enabled && thread_pipe_pop(pipe, (gpointer *)buf, &size) == NULL)
1102 			return;
1103 
1104 		// Get the number of Transient Analysis data rows
1105 		while (transient_enabled && !g_str_has_prefix (*buf, "No. of Data Rows : ")) {
1106 			if (thread_pipe_pop(pipe, (gpointer *)buf, &size) == NULL)
1107 				return;
1108 		}
1109 		if (transient_enabled && g_str_has_prefix(*buf, "No. of Data Rows : "))
1110 			resources->no_of_data_rows_transient = parse_no_of_data_rows(*buf);
1111 
1112 		if (transient_enabled && thread_pipe_pop(pipe, (gpointer *)buf, &size) == NULL)
1113 			return;
1114 
1115 		// Get the number of Noise Analysis data rows
1116 		while (noise_enabled && !g_str_has_prefix (*buf, "No. of Data Rows : ")) {
1117 			if (thread_pipe_pop(pipe, (gpointer *)buf, &size) == NULL)
1118 				return;
1119 		}
1120 		if (noise_enabled && g_str_has_prefix(*buf, "No. of Data Rows : "))
1121 			resources->no_of_data_rows_noise = parse_no_of_data_rows(*buf);
1122 	} else {
1123 		while (!g_str_has_prefix (*buf, "Operating point information:")) {
1124 			if (thread_pipe_pop(pipe, (gpointer *)buf, &size) == NULL)
1125 				return;
1126 		}
1127 	}
1128 
1129 	while (!g_str_has_suffix (*buf, SP_TITLE)) {
1130 		if (thread_pipe_pop(pipe, (gpointer *)buf, &size) == NULL)
1131 			return;
1132 	}
1133 
1134 	end_of_output = FALSE;
1135 	for (int i = 0; transient_enabled || fourier_enabled || dc_enabled || ac_enabled || noise_enabled; i++) {
1136 
1137 		AnalysisType analysis_type = ANALYSIS_TYPE_NONE;
1138 
1139 		do {
1140 			pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
1141 			g_strstrip (*buf);
1142 			if (!g_ascii_strncasecmp (*buf, "CPU time", 8))
1143 				end_of_output = TRUE;
1144 			NG_DEBUG ("%d buf = %s", i, *buf);
1145 		} while (pipe != NULL && !end_of_output && (*buf[0] == '*' || *buf[0] == '\0'));
1146 
1147 		// The simulation has finished: no more analysis to parse
1148 		if (end_of_output)
1149 			break;
1150 
1151 		if (!get_analysis_type(*buf, &analysis_type) && i == 0) {
1152 			oregano_warning ("No analysis found");
1153 			break;
1154 		}
1155 
1156 		gboolean unexpected_analysis_found = FALSE;
1157 
1158 		g_mutex_lock(&current->mutex);
1159 		current->type = analysis_type;
1160 		g_mutex_unlock(&current->mutex);
1161 
1162 		switch (analysis_type) {
1163 		case ANALYSIS_TYPE_TRANSIENT:
1164 			pipe = parse_transient_analysis (resources);
1165 			transient_enabled = FALSE;
1166 			break;
1167 		case ANALYSIS_TYPE_FOURIER:
1168 			pipe = parse_fourier_analysis (resources);
1169 			fourier_enabled = FALSE;
1170 			break;
1171 		case ANALYSIS_TYPE_DC_TRANSFER:
1172 			pipe = parse_dc_analysis (resources);
1173 			dc_enabled = FALSE;
1174 			break;
1175 		case ANALYSIS_TYPE_AC:
1176 			pipe = parse_ac_analysis (resources);
1177 			ac_enabled = FALSE;
1178 			break;
1179 		case ANALYSIS_TYPE_NOISE:
1180 			pipe = parse_noise_analysis (resources);
1181 			noise_enabled = FALSE;
1182 			break;
1183 		default:
1184 			oregano_warning ("Unexpected analysis found");
1185 			unexpected_analysis_found = TRUE;
1186 			break;
1187 		}
1188 
1189 		g_mutex_lock(&current->mutex);
1190 		current->type = ANALYSIS_TYPE_NONE;
1191 		g_mutex_unlock(&current->mutex);
1192 
1193 		if (unexpected_analysis_found || pipe == NULL)
1194 			break;
1195 	}
1196 
1197 	if (pipe != NULL)
1198 		thread_pipe_set_read_eof(pipe);
1199 
1200 	resources->pipe = NULL;
1201 }
1202