#! perl -w

=head1 NAME

cfx5adapt - Run the ANSYS CFX Mesh Adaption standalone

=cut

#!/bin/sh
#==============================================================================
# @(#) $Id$
#------------------------------------------------------------------------------
##
## Name:
##
## cfx5adapt
##
## Purpose:
##
## Run the ANSYS CFX Mesh Adaption capability as a standalone process.
##
## This command is provided for advanced users only.  It takes a
## results file as output by the ANSYS CFX Solver, runs the Mesh Adaption
## process on it, and outputs a definition file which can be passed
## back to the cfx5solve command.  It is intended for use where the
## Mesh Adaption and the solution processes cannot be run on the same
## host.
##
## Synopsis:
#S
#S cfx5adapt [-res <file>] [-name <def-name>] [-help] [-database <database>]
#S
## []  denotes an optional argument. 
## |   separates mutually exclusive arguments. 
## ... following an argument indicates that it may be repeated.
## <>  denotes that substitution of a suitable value is required. All other
##     arguments are keywords, some of which have a short form.
##
## Arguments:
##
#A -db <database>
#A -database <database>
#U -adapt-db <database>
#U -refiner-db <database>
##     Specify a CFX-Build 5 database for use with the "adaption to
##     geometry" feature.
##
#A -help
#A -h
##     Print this message.
##
#A -name <name>
##     Choose a name for the ANSYS CFX Solver Input File created by this
##     process, and for the temporary directory used.  If this switch
##     is not specified, the same process as used by the cfx5solve
##     command will be used to choose a unique name.
##
#A -save
##     Do not delete any temporary files after the run. Normally the standard
##     temporary files created by the ANSYS CFX Solver are deleted automatically
##     after each run.
##
#A -verbose
#A -v
##     Specifying this option may result in additional output being sent to 
##     the Unix "standard output" file (normally the screen).
#U ****************************************************************************
#U *                                                                          *
#U *     The following features are supported only within CFX and are not     *
#U *     shown by the -help option when the command is run elsewhere.         *
#U *                                                                          *
#U ****************************************************************************
#U
#U Unsupported Features:        
#U
#U Arguments:
#U
#U -core
#U     Allow core dumps.
#U
#U -debug
#U     Run components compiled with debugging options.
#U
#------------------------------------------------------------------------------

# get the standard ANSYS CFX library directory
BEGIN {
  if ($0 =~ m!^([a-z]:)?[\\/]!i) {
    # it's an absolute path, use it as-is
    (my $nd=$0) =~ s!(perllib[\\/])?[^\\/]*$!!i;
    unshift @INC, "$nd/perllib";
  } else {
    # wrap this in an eval, and if it fails, pray ... for example,
    # this can fail on Windows if we're running off a share.
    eval {
      require FindBin;
      FindBin->import();
      unshift @INC, "$FindBin::Bin/perllib";
      push @INC, $FindBin::Bin;
    };
    warn $@ if $@;
  }
  if (defined $ENV{CFX_LOCAL_PERLLIB}) {
     unshift @INC, $ENV{CFX_LOCAL_PERLLIB};
  }

}

use CFX5::Init;
CFX5::Init::init();

use vars qw($CVSVersion);
sub BEGIN {
  $CVSVersion='@(#) $Id$\n';
}

use strict;

use CFX5::Output qw(:all);
use CFX5::Config qw(%Config export_conf query_conf append_to_libpath);
use CFX5::PrintConfig;

use CFX5::CmdLine qw(:util parse_cmdline);

use CFX5::PathManip qw(join_file split_file fullpath basename dirname);
use CFX5::FileTests;
#use CFX5::System qw(assert_can_window);
#use CFX5::FileStat;

use CFX5::ExitRoutines qw(:tidyup);

#use CFX5::FrameServ;

use CFX5::Commands qw(do_cmd parse_rv);

#use CFX5::Job;

#use CFX5::CCLI qw(export_parser_conf);

use CFX5::PDB;
use CFX5::WorkDir;

#
# read the configuration
#
CFX5::Config::read_config();

use vars qw($resfile $name $fullname $db $save);

parse_cmdline
  ( \@ARGV,
    'INCLUDE_STD',
    "-adapt-db+" => '-db',
    "-database+" => '-db',
    "-db+" => \$db,
    "-fullname+" => \$fullname,
    "-name+" => sub { 
      my $prob=$_[1];
      _error("$prob is not a valid problem name")
        if (index($prob,$Config{dir_sep}) > -1);
      $name=$prob;
    },
    "-refiner-db+" => '-db',
    "-refiner-exec+" => sub { conf_execfile('CFX5_REFINER_EXEC','ANSYS CFX Mesh Refiner executable %%',@_); },
    '-res+' => \$resfile,
    '-result+' => '-res',
    '-results+' => '-res',
    "-save" => \$save,
  );

exit_if_error();

#------------------------------------------------------------------------------

unless (defined $resfile) {
  _error("You must specify a ANSYS CFX Results File to adapt");
} else {
  CFX5::FileTests::datafile($resfile, "ANSYS CFX Results File $resfile");
}

# TODO the solver script copies the database, but we don't here as
# it's quicker that way!  Should we?  Eg, if it needs to port it to a
# different platform.
if (defined $db) {
  $db=fullpath($db);
  CFX5::FileTests::datafile_w($db, "CFX-Build 5 database $db");
}

exit_if_error();

# get a run number
unless (defined $fullname) {
  $fullname=ChooseName();
}

sub ChooseName {
  unless (defined $name) {
    ($name=basename($resfile)) =~ s!(?:_\d+)?\.[^./\\]*$!!;
  }

  # break this down into a directory and a filename
  my $probdir=dirname($name);
  my $probname=basename($name);

  local *CHECKDIR;

  # start reading the directory
  unless (opendir CHECKDIR, $probdir) {
    _error("Unable to work out next problem number as the destination directory\n\t'$probdir'",
         "\ncould not be read: $!");
    return undef;
  }

  my $max=0;
  my $f;
  while (defined ($f=readdir(CHECKDIR))) {
    if ($f =~ m{\Q${probname}\E_([0-9][0-9][0-9])(\.(dir|out|res|trn|cfx|def))?$}i) {
      # it matches this problem
      $max=$1 if $1 > $max;
    }
  }

  closedir CHECKDIR;

  if ($max >= 999) {
    _error("The file number cannot exceed 999.",
           "\nPlease choose a new problem name, or work in a different directory.");
    return "xxx";
  }

  # now max is the biggest number we found for this problem, or 0 if we
  # didn't find any, just add one and zero-pad it.
  $max++;
  $max=("0"x(3-length($max))).$max;

  return fullpath($name.'_'.$max);
}

# make sure we have the settings we need
CFX5::PDB::setup_environment();

exit_if_error();

CFX5::PrintConfig::show_vars_by_verbosity();

my $output;
if ($resfile =~ m!\.(?:def|res)$!i) {
  $output="$fullname.def";
} else {
  $output="$fullname.cfx";
}
_info("Running the ANSYS CFX Mesh Refiner on $resfile, outputting to $output");

#
# create the working directory
#
my $dir=new CFX5::WorkDir("$fullname.dir");
$dir->set_basename($fullname);

# we copy this, as the refiner likes to fiddle with it, and if we link
# it the result will be a version of the def file with lots of history
# junk.
$dir->input_file_copy(res => $resfile);

$dir->creatable_file('def');
$dir->mark_output_file(def => $output);

$dir->enter();

exit_if_error();

my @args;
if (defined $db) {
  push @args, '-CAD_database', $db;
} else {
  push @args, '-dont_adapt_to_geometry';
}

my $rv=parse_rv(do_cmd($Config{CFX5_REFINER_EXEC}, @args));

$dir->leave();

# should we always output the files?
$dir->output_marked_files_done();

unless ($rv->is_success()) {
  _error("The ANSYS CFX Mesh Refiner", $rv->errstr());
}

unless ($save) {
  $dir->junk_directory();
}

exit_if_error();

exit(0);
