#!/usr/local/bin/perl
#

use Getopt::Long;

$progname = "mt0parse";

sub usage {
	print STDERR "usage: $progname [options] .mt0-file
 - process HSPICE .measure file produced by monte-carlo analysis
Options:
    -c	    Attempt to correlate parameters that affect errors
    -s N    omit summary, dump all parameters for sweep N. **FIRST SWEEP IS '0'
    -p N    dump fet parameters in .param syntax for sweep N only.
    -D P    Include parameter P in summary output
    -E P    Parameter P indicates error if abs. value greater than threshold
    -e      print/check all 'verror*' params even if -D and -E are specified.
    -t V    Set threshold for error-detection to V, default 0.5
";
}

Getopt::Long::config('no_auto_abbrev',
                     'no_ignore_case','no_ignore_case_always');

$dump_sweepno = -1;
$dump_fetparams = -1;
$cflag = 0;
$eflag = 0;
$err_thresh = 0.5;
$no_verror = 0;
$rc = 0;
@errflags = ();
@toprint = ();

%optctl = ("s|dumpsweep=i"    => \$dump_sweepno,
	   "p|fetparams=i"    => \$dump_fetparams,
           "c|correlate!"     => \$cflag,
           "e|autoerror!"     => \$eflag,
           "t|threshold=f"     => \$err_thresh,
           "E|errflags=s@"     => \@errflags,
           "D|display=s@"     => \@toprint,
           "v|verbose!"     => \$verbose
);

if(!GetOptions(%optctl)) {
	&usage();
        exit 1;
}

if(($#errflags >= 0 || $#toprint >= 0) && !$eflag) {
	$no_verror = 1;
}
# print "errflags=$#errflags toprint=$#toprint eflag=$eflag no_verror=$no_verror\n";

if($dump_fetparams != -1) {
	$dump_sweepno = $dump_fetparams;
} else {
	$dump_fetparams = 0;
}

# get header and first line of column titles
hline: while($_ = <>) {
	$_ =~ s/^\s*//;

	next hline if($_ =~ m/DATA1/);
	next hline if($_ =~ m/.TITLE/);

	if($_ !~ m/^index/) {
		die "index expected";
	}
	@titles = split(/\s+/, $_);
	last hline;
}

# get rest of column titles
tline: while($_ = <>) {
	$_ =~ s/^\s*//;
	@f = split(/\s+/, $_);
	push(@titles, @f);

	last tline if ($_ =~ m/alter\#/);
}

#print "titles=", join(',', @titles), "\n";
$nvals = $#titles;
# printf "%d values\n", $nvals+1;

unshift(@toprint, 'index');
@errflags = ();

for($i = 0; $i <= $nvals; $i++) {
	$didx{$titles[$i]} = $i;

	if(!$no_verror) {
		if($titles[$i] =~ m/^verror/) {
			push(@toprint, $titles[$i]);
		}
		if($titles[$i] =~ m/^verror/) {
			push(@errflags, $titles[$i]);
		}
	}
}

# check that everything we're supposed to print really exists.
foreach $t (@toprint) {
	if(!defined($didx{$t})) {
		print STDERR "$progname: no parameter $t found in input.\n";
		$rc = 1;
	}
}
if($rc) {
	exit 1;
}

# initialize statistics
for($i = 0; $i <= $nvals; $i++) {
	$alltotal[$i] = 0;
	$errtotal[$i] = 0;

	$maxval[$i] = -1e12;
	$minval[$i] = 1e12;
}


$nerrors = 0;
$sweepno = 0;

# titles on output
if($dump_sweepno < 0) {
	foreach $t (@toprint) {
		printf "%10s", $t;
	}
	print "\n";
}

# process each sweep
sweep: while(!eof) {
	$nd = 0;
	@data = ();

	dline: while($_ = <>) {
		if(eof) {
			if($sweepno == $dump_sweepno) {
				dump_sweep();
			}
			last sweep;
		}
		$_ =~ s/^\s*//;
		@d = split(/\s+/, $_);
		push(@data, @d);
		$nd = $#data;
		last dline if($nd >= $nvals);
	}

	if($dump_sweepno < 0) {
		foreach $t (@toprint) {
			$v = $data[$didx{$t}];
			if(int($v) == $v) {
				printf "%9d ", $v;
			} elsif(abs($v) < 0.01) {
				printf "%9.3e ", $v;
			} else {
				printf "%9.3f ", $v;
			}
		}
		$err = 0;
		foreach $t (@errflags) {
			if(abs ($data[$didx{$t}]) > $err_thresh) {
				$err = 1;
			}
		}
		if($err) {
			print "  error";

			if($cflag) {
				for($i = 0; $i <= $nvals; $i++) {
					$errtotal[$i] += $data[$i];
				}
			}
		}
		print "\n";
	}

	if($sweepno == $dump_sweepno) {
		dump_sweep();
	}
	if($cflag) {
		for($i = 0; $i <= $nvals; $i++) {
			$alltotal[$i] += $data[$i];
		}
	}

	for($i = 0; $i <= $nvals; $i++) {
		if($minval[$i] > $data[$i]) {
			$minval[$i] = $data[$i];
		}
		if($maxval[$i] < $data[$i]) {
			$maxval[$i] = $data[$i];
		}
	}

	$sweepno++;
}


if($dump_sweepno < 0) {
	print "MIN:      ";
	foreach $t (@toprint) {
		if ($t ne 'index') {
			$v = $minval[$didx{$t}];
			if (int($v) == $v) {
				printf "%9d ", $v;
			} elsif (abs($v) < 0.01) {
				printf "%9.3e ", $v;
			} else {
				printf "%9.3f ", $v;
			}
		}
	}
	print "\n";

	print "MAX:      ";
	foreach $t (@toprint) {
		if ($t ne 'index') {
			$v = $maxval[$didx{$t}];
			if (int($v) == $v) {
				printf "%9d ", $v;
			} elsif (abs($v) < 0.01) {
				printf "%9.3e ", $v;
			} else {
				printf "%9.3f ", $v;
			}
		}
	}
	print "\n";
}

if($cflag) {
	print "param                mean/all   mean/error\n";
	for($i = 0; $i <= $nvals; $i++) {
		printf "%-20s %10.3e %10.3e\n",
			$titles[$i],
			$alltotal[$i] / $sweepno,
			($nerrors == 0) ? 0 : $errtotal[$i] / $nerrors;
	}
}

exit 0;

#############################################################################
sub dump_sweep
{
	my($i, $fetinst, $param);

	for($i = 0; $i <= $nvals; $i++) {
		if($dump_fetparams) { # fet params only in .param syntax
			if($titles[$i] =~ m/([:\w]+)@([:\w]+)/) {
				$fetinst = $1;
				$param = $2;
				if($param =~ m/:/) {
					print STDERR "WARNING: sweep parameters found for heirarchical netlist;\n";
					print STDERR "         output will not be usable for rerunning simulaton.\n";
				}
				printf ".param %s = %e\n", $param, $data[$i];
			}
		} else {
			printf "%s %e\n", $titles[$i], $data[$i];
		}
	}
}
