#! /usr/bin/perl

# ---------------------------------------------------------------------------------
# name: sendsg.pl
# author: Marc Egger
# Date of last modification: 13.04.2007
# ---------------------------------------------------------------------------------
# DESC:
# 
# TO DO:
# 
# ---------------------------------------------------------------------------------

use Getopt::Std;
use Socket qw(:DEFAULT :crlf);
use IO::Handle;

$debug = 0;

# Global Definitons
our ($opt_h, $opt_v, $opt_m, $opt_n, $opt_t);
our $version = '1.0';

my $host ='spinglass.informatik.uni-koeln.de';
my $port ='11200';

our $meta_name;
our $meta_type;
our $email;

getopts('hvm:t:n:') || usage();
usage() unless argsok();
usage() if $opt_h;

create_connection();
$SIG{CHLD}= 'IGNORE';
my $child=fork();
die unless defined($child);

if ($child) {
  #the parent is the one who reads the answers from the socket
  read_socket();

} else { 
  #child is the one who writes to the socket. 
  write_socket();
  #wait;
  exit;
}
#exit;

#-----------------------------------------------------------------------------------------------------
sub submit_jobs {
	
  select(SERVER);
  print "beginmeta\n";
  print "beginheader\n";
  print "setparam name $meta_name\n";
  print "setparam output $meta_type\n";
  print "endheader\n";
 NEXTJOB: foreach $filename (@ARGV){
    open (FH, $filename) or die "cant open file: $! \n";
    undef($job_type); undef($job_size); undef($job_name);undef(@data);
    while (<FH>) {
      #spaces
      next if $_ =~ /^\s*$/;
      #comments
      next if $_ =~ /^#/;
      #set type
      if (/^\s*type:\s+(\w+)/) {
	$job_type = $1;
	next;
      }
      #set size
      if (/^\s*size:\s+(\d+)/) {
	$job_size = $1;
	next;	 
      } 
      #set name
      if (/^\s*name:\s+/) {
	$job_name = $';
	chomp ($job_name);
	next;
      }

      #at this point, every metainformation has to be defined
      if ((!defined($job_size) || !defined($job_type))) {
	$joberror++;
	warn "ERROR: job $filename has an invalid format.\n";
	close (FH);
	next NEXTJOB;
      }
      push(@data, $_); #push first data line
      last; # all metadata has been read properly. Now we can read data
    }
    
    push(@data, <FH>);
    
    close(FH);
    $job_name = $job_name || $filename;
    
    print "beginjob\n";
    print "beginheader\n";
    print "setparam type $job_type\n";
    print "setparam size $job_size\n";
    print "setparam name $job_name\n";
    print "endheader\n";
    print "begindata\n";
    print "@data";
    print "enddata\n";
    print "endjob\n";
    print STDOUT "OK:      job \'$job_name'\ submitted.\n" if $verbose;
  }
  print "endmeta\n";
  print "exit\n\n";
  print STDOUT "WARNING: $joberror job(s) could not be submitted due to errors in your input data.\n" if $joberror;
}

# function checks if the email-address was given in the configfile
#-----------------------------------------------------------------------------------------------------
sub readconfig {

  (-f "$ENV{HOME}/.sendsgrc") && do "$ENV{HOME}/.sendsgrc";
}

#-----------------------------------------------------------------------------------------------------
sub argsok {

  # Optional Arguments
  $opt_v and $verbose = 1;
  readconfig();
  $meta_type = $opt_t || $meta_type || 'long';

  # Mandatory Arguments
  $meta_name = $opt_n;
  return 0 unless $meta_name;

  # the email-adress has to be defined either in the configfile or per argument
  $email = $opt_m || $email;
  return 0 unless $email;
	
  # we need the path
  return 0 if ($#ARGV == -1);	#AENDERN
	
  #everything is ok if we get here
  return 1;
}

#-----------------------------------------------------------------------------------------------------
sub usage {

  print << "EOF";
sendsg, send meta jobs to the spin glass server. $version

   Copyright (C) 2007 by Institut fuer Informatik, Koeln.
   written by Marc Egger.

Usage: sendsg [OPTIONS] -m email\@adress -n your_metajobname FILE ...

   -h                   show summary of options
   -t [long|short]      configure how much detail you want to see in the 
                        server output (Default: long)
                        short reports the ground state characteristics only
   -m [email]           email-address the results will be sent to
   -v			verbose mode
   -n [meta jobname]	set the name of the meta job. e.g. foobar

   FILE ...             list of files with spin glass input data. The accepted
                        format can be found either in the man page or
			on www.informatik.uni-koeln.de/spinglass

EXAMPLE:
   sendsg -v -m foo\@bar.com -n gauss100 ~/gauss100/*

if you place a file named .sendsgrc in your home directory, whicht contains following line:
   \$email="your\@address";
you won't need the -m flag when you are sending jobs to the server
   
Report bugs to <spinglass-adm\@informatik.uni-koeln.de>. 
For further information, visit www.informatik.uni-koeln.de/spinglass
EOF
	
	exit 0;
}

#-----------------------------------------------------------------------------------------------------
sub create_connection {

  # create socket-connection
  my $protocol = getprotobyname('tcp');
  $host = inet_aton($host) or die "$host: unknown host";
  my $dest_addr = sockaddr_in($port,$host);
  # create socket
  socket(SERVER, AF_INET, SOCK_STREAM, $protocol) or die "socket() failed: $!";
  # Connection to host!
  connect(SERVER,$dest_addr) or die "connect() failed: $!";
  # Set autoflush ->1;
  select((select(SERVER), $| = 1)[0]); 
}

#-----------------------------------------------------------------------------------------------------
sub write_socket {

  select(SERVER);
  print "hello\n";
  print "auth $email\n";
  submit_jobs();
}

#-----------------------------------------------------------------------------------------------------
sub read_socket {

  while (<SERVER>) {
    print "$_" if $debug;
    if ($_=~ /^(5\d+)/) {
      chomp($_);
      print "ERROR $1:$'";
      $error++;
    }
  }
  $n = $#ARGV+1;
  if ($error) {
    print "\nERROR: sending produced $error errors.\n";
  } else {
    print "\nOK: meta job \'$meta_name\' containing $n job(s) successfully submitted.\n";
  }
}

# Start sendsg documentation

=head1 NAME

sendsg.pl - send spin glass meta jobs to the spin glass server system.

=head1 SYNOPSIS

sendsg [OPTIONS] -m email@adress -n your_metajobname FILE ...

=head1 DESCRIPTION

With this client you can send spin glass samples to the spin glass
server for the computation of exact ground states. In contrast to the
mail-based server system that we have offered until now, you are not
forced any more to send your jobs one after the other. Instead, you
can now bundle your jobs to so called 'meta jobs'. A meta job contains
a number of single files. Within a meta job, each single
instance/sample has to be contained in a single file. Each file
contains a spin-glass sample in a particular format.

I<sendsg> awaits at least 3 parameters. First of all, you state the
email-address to which the results should be sent back. You can skip
the C<-m> option if you place a file named .sendsgrc in your home
directory containing a line with your email address, followed by an
empty line:

   $email="your@address";

Secondly, you specify the name of the meta job. Finally, you specify
which job files belong to the meta job. In the easiest case you simply
state the name of the directory in which the job files are stored -
followed by a slash and an asterisk, e.g. C</home/yourname/foo/*>

=head1 FORMAT INPUTDATA

The server input format is the same as for the old email-based
server. The first line contains the type specification. The second
determines the length scale of the lattice. The third line contains a
user-defined job name. if you want to name the jobs-files like the
filename, you can simply skip the C<name: > command in line 3.

The subsequent lines contain the couplings in
the format spin_i spin_j coupling(spin_i,spin_j). We count the spins
from 1 to N^2 or N^3, depending on the type. The spins are labeled
linearly row after row within one layer, and layer after layer, as you
can see here:



        |     |     |
      -(1)---(2)---(3)--
        |     |     |
      -(4)---(5)---(6)--
        |     |     |
      -(7)---(8)---(9)--
        |     |     |
 
Parameters have to be specified in the way <PARAMETER> : <VALUE>. 
Available are:

   1. type: You can choose between 
            * pm:    two dimensional Edwards Anderson (EA) spin glass 
                     with +/-1 distribution and periodic boundary conditions.

            * gauss: two dimensional EA spin glass with arbitrary continuous 
                     distributions and periodic boundary conditions. 
                     Please use the fixed point format (e.g., 0.9876 is right, while 9.876e-01 is wrong.)
            
            * pm3:   three dimensional Edwards Anderson spin glass 
                     with +/-1 distribution and periodic boundary conditions.
            
            * gauss3: three dimensional Edwards Anderson spin glass with 
                      arbitrary continuous distribution and periodic boundary conditions.
            
            * sk:     Sherrington-Kirkpatrick spin-glass model with arbitrary distribution 
                      for the couplings. 
                      This model is computed by an exact branch-and-bound code 
                      using semidefinite programming. 
                      It has been provided to us by the group of Prof. Dr. Franz Rendl in Klagenfurt. 

   2. size: determines the linear size of the grid, i.e. size = L for an LxLxL grid. 
            In case of the sk model it is the total number of spins.
   
   3. name of the sample. The value can be any line of characters (including blanks)

These four lines can appear in any order. Blanc lines anywhere are ignored. 
You can include comment lines into your mail. 
These comment lines have to start with the following characters: #

A legal input looks like this:

	type: gauss
	size: 3
	name: 3x3 system as a test for this nice service
	
	1 2 -1.089460678023
	2 3 0.526296171959
	3 1 1.492510060258
	4 5 0.542925533731
	5 6 0.440804946137
	6 4 -0.555618772831
	7 8 0.400843564493
	8 9 0.005781770273
	9 7 -0.283108779696
	1 4 -1.428048251086
	2 5 0.063139021975
	3 6 1.529559080159
	4 7 -1.669458764103
	5 8 0.193231695455
	6 9 1.291781128584
	7 1 0.604670335948
	8 2 0.890948261885
	9 3 -0.822280541834



=head1 OPTIONS

=over 4

=item -h

show summary of options
   
=item -t [long|short]

configure how much detail you want to see in the server output (Default: long)
short reports the ground state characteristics only

=item -m [email]

email address the results will be sent to

=item -v

verbose mode
   
=item -n [meta job name]

set the name of the meta job. e.g. foobar

=item FILE ...

list of files with spin glass input data

=back 4

=head1 EXAMPLE
   
sendsg -v -m foo@bar.com -n gauss100 ~/gauss100/*

=head1 AUTHOR

Written by Marc Egger.

=head1 BUGS

Report bugs to <spinglass-adm@informatik.uni-koeln.de>. 
For further information, visit www.informatik.uni-koeln.de/spinglass.

=head1 COPYRIGHT

Copyright (C) 2007 by Institut fuer Informatik, Koeln.

=cut



