#!/usr/bin/perl -w
#---------------------------------------------------------------------------
#@COPYRIGHT :
#             Copyright 1996, John G. Sled, 
#             McConnell Brain Imaging Centre,
#             Montreal Neurological Institute, McGill University.
#             Permission to use, copy, modify, and distribute this
#             software and its documentation for any purpose and without
#             fee is hereby granted, provided that the above copyright
#             notice appear in all copies.  The author and McGill University
#             make no representations about the suitability of this
#             software for any purpose.  It is provided "as is" without
#             express or implied warranty.
#----------------------------------------------------------------------------
#$RCSfile: nu_evaluate.in,v $
#$Revision: 1.2 $
#$Author: bert $
#$Date: 2003/05/29 17:14:24 $
#$State: Exp $
#---------------------------------------------------------------------------
# ------------------------------ MNI Header ----------------------------------
#@NAME       : NUevaluate
#@INPUT      : 
#@OUTPUT     : 
#@RETURNS    : 
#@DESCRIPTION: correct a volume for intensity non-uniformity artifacts
#@              using supplied (.imp) field
#@METHOD     : 
#@GLOBALS    : 
#@CALLS      : 
#@CREATED    : August 7, 1996      J.G.Sled  
#@MODIFIED   : 
#  $Id: nu_evaluate.in,v 1.2 2003/05/29 17:14:24 bert Exp $
#-----------------------------------------------------------------------------

use MNI::Startup qw(nocputimes);
use MNI::Spawn;
use MNI::FileUtilities qw(check_output_dirs);
use MNI::PathUtilities qw(split_path); ;
use MNI::MincUtilities qw(:history volume_minmax);
use Getopt::Tabular;


# Start main program ------------------------------------------------
&Initialize;

# evaluate field throughout volume
@mask_option = (defined $user_mask_volume) ?  qw(-mask $user_mask_volume) : ();

if($shrink_factor == 1) {
   Spawn(['evaluate_field', @mask_option, '-like', $input_volume,
          $mapping_name, $field_volume]);
}
else {
   &Spawn(['make_template', '-quiet', '-shrink', $shrink_factor, 
        $input_volume, "$TmpDir/template.mnc"]);
   &Spawn(['evaluate_field', @mask_option, '-like', "$TmpDir/template.mnc",
          $mapping_name, "$TmpDir/field_volume.mnc"]);
   &Spawn(['mincresample', '-trilinear', '-like', $input_volume,
          "$TmpDir/field_volume.mnc", $field_volume]);
}

# put lower bound on field intensity if necessary
($volmin) = &volume_minmax($field_volume);
if($volmin < $field_floor) {
   &Spawn(['mincmath', '-clamp', '-const2', $field_floor, 1.79769e+308,
          $field_volume, "$field_volume.temp"]); 
   &Spawn(['mv', "$field_volume.temp", $field_volume]);
}

# correct volume
&Spawn(['mincmath', '-copy_header', '-zero', '-div', $input_volume, $field_volume,
         $output_volume]);
&CreateHistory($input_volume,$output_volume,$mapping_name,
             localtime(time) . ">>> $0 @ARGV");

$Compress && &Spawn(['gzip', '-f', $output_volume]);

#  End of Main Program
#-----------------------------------------------------------------------------

# ------------------------------ MNI Header ----------------------------------
#@NAME       : &CreateHistory
#@INPUT      : $_[0]  name source volume
#              $_[1]  name of output volume to get history 
#              $_[2]  name of imp file containing mapping history 
#              $_[3]  string to append to history
#@OUTPUT     : 
#@RETURNS    : 
#@DESCRIPTION: 
#@METHOD     : 
#@GLOBALS    : 
#@CALLS      : get_history, put_history
#@CREATED    : 
#@MODIFIED   : 
#-----------------------------------------------------------------------------
sub CreateHistory
{
   my ($input, $output, $imp, $str) = @_;
   my (@imp_history) = ();

   # find history string in .imp file
   open(IMP, $imp) || die "Cannot open .imp file: $imp\n";
   if(<IMP> =~ /MNI Field File/i) {
      while(<IMP>) {
         if($_ =~ /^%/) {  # take first line after header that starts with a %
            $imp_history = (substr($_,1));
            last;
         }
      }
   }
   else {
      warn("Mapping file $imp does not conform\nto MNI field file format."
           ."  History information of output\nvolume will be incomplete.\n");
   }

   my (@history);
   @history  = &get_history($input);
   push(@history, ($imp_history, $str));
   &put_history($output, @history);
}


# ------------------------------ MNI Header ----------------------------------
#@NAME       : &SetupArgTables
#@INPUT      : none
#@OUTPUT     : none
#@RETURNS    : References to the two option tables:
#                @pref_args
#                @protocol_args
#@DESCRIPTION: Defines the tables of command line (and config file) 
#              options that we pass to ParseArgs.
#@METHOD     : 
#@GLOBALS    : makes references to many globals (almost all of 'em in fact)
#              even though most of them won't have been defined when
#              this is called
#@CALLS      : 
#@CREATED    : 
#@MODIFIED   : 
#-----------------------------------------------------------------------------
sub SetupArgTables
{
   my (@pref_args, @protocol_args);

   sub print_version
   {
      print "Program $ProgramName, built from:\n$LongVersion\n";
      exit;
   }
   # Preferences -- these shouldn't affect the results

   @pref_args = 
      (["General Options", "section"],
       ["-verbose|-quiet", "boolean", 0, \$Verbose, 
	"be noisy [default; opposite is -quiet]" ],
       ["-execute|-noexecute", "boolean", 0, \$Execute, 
	"actually execute planned commands [default]"],
       ["-clobber|-noclobber", "boolean", 0, \$Clobber,
	"overwrite output files [default: -noclobber]"],
       ["-compress|-nocompress", "boolean", 0, \$Compress,
	"compress output files [default: -nocompress]"],
       ["-tmpdir", "string", 1, \$TmpDir,
	"temporary working directory"],
       ["-keeptmp|-nokeeptmp", "boolean", 0, \$KeepTmp,
	"don't delete temporary files [default: -nokeeptmp]"],
       ["-notify", "string", 1, \$Notify,
	"set the user to notify (send email to) on failure " .
	"[default: \$USER, i.e. you]"],
       ["-nonotify", "const", 0, \$Notify,
	"disable email notification"],
       ["-version", "call", undef, \&print_version,
        "print version and quit"]);

   # Protocol (data-specific) options 

   @protocol_args = 
      (["General Options","section"],
       ["-mapping", "string", 1, \$mapping_name, 
        "specify an intensity mapping", "<nu_field.imp>"],
       ["-mask", "volume", 1, \$user_mask_volume,
	"specify region for processing.  (Not recommended)", "<mask.mnc>"],
       ["-floor", "float", 1, \$field_floor, 
        "lower bound for field intensities to avoid numerical problems. "
        ."(Default 0.1)","<value>"],
       ["-shrink", "integer", 1, \$shrink_factor, 
        "specify a smaller workspace; the"
        ." sampling in each dimension is reduced to that of the finest"
        ." sampling divided by factor or the current sampling which ever"
        ." is less. (suggest 2 or 3)", "<factor>"]); 
   
   (\@pref_args, \@protocol_args);
}

# ------------------------------ MNI Header ----------------------------------
#@NAME       : &SetHelp
#@INPUT      : none
#@OUTPUT     : none
#@RETURNS    : nothing
#@DESCRIPTION: Sets the $Help and $Usage globals, and registers them
#              with ParseArgs so that user gets useful error and help
#              messages.
#@METHOD     : 
#@GLOBALS    : $Help, $Usage
#@CALLS      : 
#@CREATED    : 
#@MODIFIED   : 
#-----------------------------------------------------------------------------
sub SetHelp
{
   $Version = '1.10';
   $LongVersion = 'Package MNI N3, version 1.10, compiled by nicks@minerva (x86_64-unknown-linux-gnu) on 2010-02-20 at 17:32:37';

   $Usage = <<USAGE;
$ProgramName, version $Version

Usage: $ProgramName [-help] [options] input_volume.mnc output_volume.mnc
USAGE

   $Help = <<HELP;

$ProgramName is a script that applies an intensity mapping to a volume. 

HELP

   Getopt::Tabular::SetHelp ($Help, $Usage);
}

# ------------------------------ MNI Header ----------------------------------
#@NAME       : &ValidateArgs
#@INPUT      : 
#@OUTPUT     : 
#@RETURNS    : 
#@DESCRIPTION: Checks global variables for inconsistencies caused by bad
#               combinations of arguments
#@METHOD     : 
#@GLOBALS    : 
#@CALLS      : 
#@CREATED    : 
#@MODIFIED   : 
#-----------------------------------------------------------------------------
sub ValidateArgs
{
   # check whether $output_volume can be over written
   ((-e $output_volume || -e "$output_volume.gz" ) && ! $Clobber) &&
      (die("Clobber option not given.  Cannot overwrite file:"
              ." $output_volume\n"));

   # check that appropriate files and directories exist
   (-r $input_volume) || die("Cannot read input file: $input_volume");
   (defined $user_mask_volume && !(-r $user_mask_volume)) &&
      die("Cannot read mask volume file: $user_mask_volume");
   if (defined $mapping_name) {
      !(-r $mapping_name) &&
         die("Cannot read mapping file: $mapping_name");
   }
   else {
      die("No mapping specified.  Nothing to do.");
   }
   
   ($shrink_factor < 1) &&
      die("Shrink factor must be greater than or equal to one.");

   check_output_dirs($TmpDir,$output_directory);
}

# ------------------------------ MNI Header ----------------------------------
#@NAME       : &Initialize
#@INPUT      : 
#@OUTPUT     : 
#@RETURNS    : 
#@DESCRIPTION: Sets global variables, parses command line.  Dies on
#              any error.
#@METHOD     : 
#@GLOBALS    : preferences: $Verbose, $Execute, $Clobber, $Debug, $KeepTmp
#              
#@CALLS      : &SetSpawnOptions
#              &SetupArgTables
#              &ParseArgs::Parse
#@CREATED    : 
#@MODIFIED   : 
#-----------------------------------------------------------------------------
sub Initialize
{
   my ($pref_tbl, $protocol_tbl);

   &SetHelp;
 
   # NUevaluate specific parameters
   undef $user_mask_volume;
   undef $mapping_name;
   $shrink_factor = 1;
   $field_floor  = 0.1;

   # Parse command line arguments
   ($pref_tbl, $protocol_tbl) = &SetupArgTables;
   &Getopt::Tabular::AddPatternType("volume", ".+(\\.mnc|\\.mnc\\.gz|"
                       ."\\.mnc\\.Z|\\.mnc\\.z)\$", "minc volume");
   GetOptions([@$pref_tbl, @$protocol_tbl], \@ARGV, \@reducedARGV)
         || exit 1;

   if (@reducedARGV != 2) 
   { 
      print STDERR "Leftover args: @reducedARGV\n" if @reducedARGV;
      print STDERR $Usage;
      die "Incorrect number of arguments\n";
   }
   ($input_volume, $output_volume) = @reducedARGV;

   # validate argument combinations and check filenames
   ValidateArgs;

   # expand some arguments
   ($output_directory, $basename) = split_path($output_volume, 
                                               'last', [qw(gz z Z)]);
   $field_volume = "$TmpDir/$basename" ."_field.mnc";

   # Set global variables for calling various programs
   MNI::Spawn::SetOptions (strict  => 2);
   RegisterPrograms([('mincinfo','mincmath', 'evaluate_field', 
                'make_template', 'mincresample', 'gzip', 'mv')]); 

   $verbose_option = ($Verbose) ? '-verbose' : '-quiet';
   
   AddDefaultArgs('mincmath', ['-clobber', $verbose_option]);
   AddDefaultArgs('evaluate_field', ['-clobber', $verbose_option]);
} 















