#!/usr/bin/env perl
# Plotrdf.  This script reads "Moldy" output files and extracts RDF information
# skipping page breaks.
#
#  Usage: plotrdf [-a] [-gp|-xg] [-ps|-eps] [-np] [-m REGEXP] moldy-output-file ...
#      -a         Take average of multiple RDF blocks
#      -gp        Write a script and invoke GNUPLOT to plot data
#      -xg        Write a script and invoke GRACE to plot data
#      -ps        Invoke GNUPLOT or GRACE to plot data and write as a PostScript file
#      -eps       Invoke GNUPLOT or GRACE to plot data and write as an encapsulated 
#                 PostScript (EPS) file
#      -np        Do not plot data, write a GNUPLOT or GRACE script
#      -m REGEXP  output/plot only columns which match the (perl) regular 
#                 expression REGEXP. (no '//' needed)    
# Output format is in columns with different components laid out
# across the page "r rdf1 rdf2 rdf3 ..."
#
# If the -g flag is given the dara is output to a file and GNUPLOT commands to
# plot it are sent to the standard output instead.
#
# Multiple RDF blocks in one or multiple files are processed and output
# sequentially except if +-a" flag is given, whereupon they are averaged.
#
# Columns may be selected by matching with a PERL regular expression
# (sans //) given as the argument to the "-m" option.
#

sub rdfout  {
    my ($rdflist, $binw, $plotfd, $scale) = @_;
    my ($nrdf, $r);
    $r = 0.5*$binw;

    select((select($plotfd), $| = 1)[0]);

    printf $plotfd ("#%7s","r");
    foreach $hdr ( keys %$rdflist ) {
	printf $plotfd (" %8s",$hdr);
	$hdrx = $hdr;
    }
    $nrdf=$#{$$rdflist{(keys %$rdflist)[0]}}+1;

    printf $plotfd ("\n");
    for( $j=0; $j < $nrdf ; $j++) {
	printf $plotfd ("%8.3f", $r);
	foreach $hdr ( keys %$rdflist ) {
	    printf $plotfd (" %8.3f",$scale*$$rdflist{$hdr}[$j]);
	}
	printf $plotfd ("\n");
	$r += $binw;
    }
}

sub usage {
   printf STDERR "Usage: [-a] [-gp|-xg] [-ps|-eps] [-np] [-m REGEXP] moldy-output-file ...\n";
   printf STDERR "    -a         Take average of multiple RDF blocks\n";
   printf STDERR "    -gp        Write a script and invoke GNUPLOT to plot data\n";
   printf STDERR "    -xg        Write a script and invoke GRACE to plot data\n";
   printf STDERR "    -ps        Invoke GNUPLOT or GRACE to plot data and write as a PostScript file\n";
   printf STDERR "    -eps       Invoke GNUPLOT or GRACE to plot data and write as an encapsulated PostScript (EPS) file\n";
   printf STDERR "    -np        Do not plot data, write a GNUPLOT or GRACE script\n";
   printf STDERR "    -m REGEXP  output/plot only columns which match the (perl) regular expression REGEXP. (no '//' needed)\n";
die;
}

sub pfout {
    my($hdrlist, $plotfile, $psflag, $title) = @_;
    gpout(@_) if $gpflag > 0;
    graceout(@_) if $grflag > 0;

}

sub gpout {
    my($hdrlist, $plotfile, $psflag, $title) = @_;
    my($i, $ncols);
    $ncols = $#$hdrlist;
    $filenum  = 0 if( $filenum == "") ;
    $onefile = !( $plotfile =~ /\.data(\d+)$/);
    $filenum = $1 if (! $onefile);

    $| = 1;

    if( $psflag == 1){
      print   "set terminal postscript landscape color solid\n";
      printf   "set output \"%s.ps\"\n", $plotfile;
    }
    if( $psflag == 2){
      print   "set terminal postscript eps color solid\n";
      printf   "set output \"%s.eps\"\n", $plotfile;
    }
    print   "set data style lines\n";
    print   "set title \"",$title,"\"\n";
    print   "set xlabel \"r(A)\"\n";
    print   "set ylabel \"g(r)\"\n";
#    print   "set yrange  [0:5]\n";
    print   "re" if( $nofirst );
    print   "plot ";
    foreach $i (0..$ncols) {
      if( $onefile ) {
	print   "\"$plotfile\" using 1:",$i+2," title \"$$hdrlist[$i]\"" ;
      } else {
	print   "\"$plotfile\" using 1:",$i+2," title \"$$hdrlist[$i] (set $filenum)\"" ;
      }
      print   ", " if ($i < $ncols);
    }
    print   "\npause -1\n";
    if ( ! $nofirst ) {$nofirst=1};
}

sub graceout {
    my($hdrlist, $plotfile, $psflag, $title) = @_;
    my($i, $ncols, $onefile, $filenum);

    $| = 1;

    print   "\@timestamp def \"",scalar(localtime),"\"\n";
    print   "\@with g0\n";
    print   "\@title \"",$title,"\"\n";
    print   "\@xaxis label \"r(A)\"\n";
    print   "\@yaxis label \"g(r)\"\n";

    $ncols = $#$hdrlist;
    $setnum = 0 if( $setnum == "") ;
    $filenum  = 0 if( $filenum == "") ;

    print   "\@read block \"$plotfile\"\n";

    $onefile = !( $plotfile =~ /\.data(\d+)$/);
    $filenum = $1 if (! $onefile);

    foreach $i (0..$ncols ) {
      print "\@with s",$setnum,"\n";
      print "\@block xy \"1:",$i+2,"\"\n";
      if( $onefile ) {
        print "\@s",$setnum," legend \"$$hdrlist[$i]\"\n" ;
      } else {
        print "\@s",$setnum," legend \"$$hdrlist[$i] (set $filenum)\"\n" ;
      }
      $setnum++;
    }
    if( $psflag == 1){
      print   "\@hardcopy device \"PS\"\n";
      printf  "\@print to \"%s.ps\"\n\@print\n", $plotfile;
    }
    if( $psflag == 2){
      print   "\@hardcopy device \"EPS\"\n\@device \"EPS\" op \"bbox:tight\"\n";
      printf  "\@print to \"%s.eps\"\n\@print\n", $plotfile;
    }
}


$gpflag = 0;
$grflag = 0;
$plotflag = 1;
$psflag = 0;
$aflag = 0;
$plotfd=*STDOUT;
$match = ".";

use Getopt::Long;
&GetOptions("gp", "xg", "np", "ps", "eps", "a", "m=s")|| &usage();

if ($opt_gp && $opt_xg) {&usage()};
if ($opt_ps && $opt_eps) {&usage()};

$match = $opt_m if $opt_m;
$gpflag= $opt_gp if $opt_gp;
$grflag= $opt_xg if $opt_xg;
$plotflag= 0 if $opt_np;
$psflag= 1 if $opt_ps;
$psflag= 2 if $opt_eps;
$aflag = $opt_a if $opt_a;

$filebody=$ARGV[0];
if ( ($gpflag || $grflag) && $aflag ) {
    $plotfile = $filebody.".data";
    open PLOTFILE, ">$plotfile" || die "Failed to open plot file $plotfile for writing\n";
    $plotfd=*PLOTFILE;
    $| = 1;
}

if( $plotflag ) {
    if ($gpflag) {
	open STDOUT, "| gnuplot -persist" or die "Failed to open pipe to GNUPLOT process";
    } elsif ($grflag) {
	if( $psflag ) {
	    open STDOUT, "| gracebat -pipe" or die "Failed to open pipe to GRACEBAT process";
	} else {
	    open STDOUT, "| xmgrace -pipe" or die "Failed to open pipe to GRACE process";
	}
    }
}

$be = 0;
$hdr = "";
$nrdfblocks=0;
$firstblock = 1;
$iline=0;
while ( <> ) {
    #
    # Reading phase
    #
    if (/^ New run entitled "([^"]*)" started/){
     $title = $1;
     $newrun = 1;
    }
    $title = $1 if (/^ This is restart No \d+ of run "([^"]*)" started/);
    if ( /^_+$/ ... /^_+$/ ) {
	#
	# Store rdfs and column heads at end of "A-B RDF" block or and of RDFs
	#
	if ( (/^\s([^\s]+-[^\s]+) RDF$/ || /^_+$/) && $hdr ne "") {
	    if($hdr=~$match) {
		if( $aflag ) {
		    $nrdf=$#{$rdflist{$hdr}};
		    if( $firstblock == 0 && ( $#rdf != $nrdf || !exists $rdflist{$hdr})) {
			printf STDERR "Error: Multiple RDF data blocks do not match\n", $#rdf, $nrdf;
			exit 2;
		    }	
		    foreach $i (0..$#rdf) {
			$rdflist{$hdr}[$i] += $rdf[$i];
		    }
		} else {
		    $rdflist{$hdr} = [@rdf];
		}
	    }
	    @rdf = ();
	    $hdr = "";
	}
	# 
	# Record column header and binwidth
	#
	$hdr=$1 if (/^\s([^\s]+-[^\s]+) RDF$/);
	if  (/^\sRadial Distribution Functions\sBin width=([0-9.]+)$/)
	  {
	      $binw=$1 ;
	      $nrdfblocks++;
	  }
	#
	# Record data block
	#
	if ( /^[0-9.e ]+/ ) {
	    chop;
	    @line = split;
	    @rdf = (@rdf, @line);
	}
	#
	# RDF block is delimited by lined of underscores
	#
	if ( /^_+$/) {
	    if ($be == 0) {
		@rdf=();
		$be++;
	    } else {
		#
		# End of RDF block.  Print out results
		#
		$be = 0;
		$firstblock = 0;
		if( ! $aflag ) {
                   if ( $gpflag || $grflag ) {
                       $fnum++;
                       $plotfile = $filebody.".data".$fnum;
                       open PLOTFILE, ">$plotfile" || die "Failed to open plot file $plotfile for writing\n";
                       $plotfd=*PLOTFILE;
                       $| = 1;
                   }
		    rdfout(\%rdflist, $binw, $plotfd, 1.0);
		    pfout([keys %rdflist], $plotfile, $psflag, $title) if ($gpflag || $grflag);
                    close PLOTFILE
		}
		
	    }
	}
    }
}
if( $aflag ) {
    rdfout(\%rdflist, $binw, $plotfd, 1.0/$nrdfblocks);
    pfout([keys %rdflist], $plotfile, $psflag, $title) if ($gpflag || $grflag);
}
	
