#!/usr/bin/env python
#-------------------------------------------------------------------------------
#   This file is part of the Code_Saturne Solver.
#
#   Copyright (C) 2009-2010  EDF
#
#   Code_Saturne is free software; you can redistribute it and/or modify it
#   under the terms of the GNU General Public License as published by the
#   Free Software Foundation; either version 2 of the License,
#   or (at your option) any later version.
#
#   Code_Saturne is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty
#   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   You should have received a copy of the GNU General Public Licence
#   along with the Code_Saturne Preprocessor; if not, write to the
#   Free Software Foundation, Inc.,
#   51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
#-------------------------------------------------------------------------------

#===============================================================================
# Batch options for different queuing systems
#===============================================================================
#
# Batch options for LSF (example: CCRT's platine)
# =====================
#
#BSUB -n 2
#BSUB -W 00:05
#BSUB -o genova_pump_teso.%J
#BSUB -e genova_pump_tese.%J
#BSUB -J genova_pump_tes
#
#  -n : number of processors
#  -W : walltime as hh:mm
#  -o : output file name
#  -e : error file name
#  -J : job name
#
#-------------------------------------------------------------------------------
#
# Batch options for PBS or Torque (example: Clamart2 cluster)
# ===============================
#
#PBS -l nodes=4:ppn=2
#PBS -l walltime=1:00:00
#PBS -l mem=320mb
#
#PBS -j eo
#PBS -N genova_pump_tes
#
#  nodes    : number of nodes
#  ppn      : number of process per node
#  walltime : wall clock time (hh:mm:ss)
#  mem      : memory
#
#WARNING: when coupling with SYRTHES, 1 processor will be reserved for each
#         instance of SYRTHES. The Kernel will be executed on the remaining
#         processors, so make sure to reserve a sufficiently high number
#         of processors.
#
#-------------------------------------------------------------------------------
#
# Batch options for Sun Grid Engine (example: University of Manchester MACE)
# =================================
#
# set the name of the job
##$ -N genova_pump_tes
#
# request between 2 and 4 slots
##$ -pe mpich 2-4
#
# Execute the job from the current working directory
# Job output will appear in this directory
##$ -cwd
#   can use -o dirname to redirect stdout
#   can use -e dirname to redirect stderr

#  Export these environment variables
##$ -v MPI_HOME

#set -x
#
#-------------------------------------------------------------------------------
#
# Batch options for IBM LoadLeveler (example: IBM cluster under AIX)
# =================================
#
#@ shell = /bin/sh
#
#@ job_name = genova_pump_tes
#
#@ job_type = parallel
#@ cpus = 128
#@ node_usage = not_shared
#
#@ network.MPI = csss,shared,US
#@ bulkxfer = yes
#
#@ wall_clock_limit = 00:20:00
#@ account_no = z001
#
#@ output = $(job_name).$(schedd_host).$(jobid).out
#@ error  = $(job_name).$(schedd_host).$(jobid).err
#@ notification = never
#
#@ queue
# suggested environment settings:
#  export MP_EAGER_LIMIT=65536
#  export MP_SHARED_MEMORY=yes
#  export MEMORY_AFFINITY=MCM
#  export MP_TASK_AFFINITY=MCM
#
#===============================================================================
# Import required Python modules
#===============================================================================
#
import datetime
import os
import os.path
import sys

# Trick so that one doesn't have to set the PYTHONPATH variable
sys.path.insert(0, '/opt/cs-2.0-rc2/lib/python2.4/site-packages/ncs')

import cs_config
import cs_check_consistency

from cs_exec_environment import *
from cs_case_domain import *
from cs_case import *

#===============================================================================
# User variables
#
# Variables set to 'None' will be determined automatically
#===============================================================================

casedir = '/home/james/saturne/genovaspump/GENOVA_PUMP_TEST/UNSTEADY_1'

# Meshes should be defined as a list, for example:
#   MESHES = ['part1.des', 'part2.unv']

# In case of badly oriented cells, the Preprocessor will try to
# reorient cells if REORIENT is set to True.

MESHES = None
REORIENT = False

# To join meshes with the Preprocessor, the JOIN variable should contain
# the Preprocessor command line arguments for joining, for example:
#   JOIN = '-j --color 3 4 6'
# Otherwise, set JOIN = None.

# Periodicity is an extension of joining, and works in a similar
# fashion; for example (with 2 periodic directions):
#   PERIODICITY = --perio --trans 10 0 0 --perio --trans 0 1 0
# Otherwise, set PERIODICITY to None.

# A variable may be defined over several lines, using the \ character,
# for example:
#   PERIODICITY="--perio --trans -10.2 0 0 --color 2                 \
#                --perio --rota --angle 90 --dir 0 0 1 --invpt 0 0 0 \
#                        --color 3 4

# See the user documentation or run 'cs_preprocess --help' for details.

JOIN = None
PERIODICITY = None

# Additional files.

# If thermochemistry applies, the name of the thermochemistry data file
# may be specified through THERMOCHEMISTRY_DATA. For example:
#   THERMOCHEMISTRY_DATA='dp_FCP'
# If meteorological profiles are used, the name of the meteo data file
# may be specified through METEO_DATA. For example:
#   METEO_DATA='meteo'

# Additional input files found in the DATA subdirectory may be defined in
# the USER_INPUT_FILES list. Similarly, additional output files to
# retrieve can be defined in USER_OUTPUT_FILES, for example:
#   USER_OUTPOUT_FILES = ['plot1.dat', 'plot2.dump']

# By default, the corresponding values are set to None.

THERMOCHEMISTRY_DATA = None
METEO_DATA = None
USER_INPUT_FILES = None
USER_OUTPUT_FILES = None

# Number of MPI processes associated with the whole calculation (auto if none).

N_PROCS = None
N_PROCS_MIN = 1
N_PROCS_MAX = None

# Partition options (if separate run from resolution)

# PARTITION_LIST defines the partitionings that will be built
# if EXEC_SOLVER is set to False and EXEC_PARTITION to True (see below).
# For example, PARTITION_LIST = (128, 256) will produce files
# 'domain_number_128' and 'domain_number_256' in RESU/PARTITION_OUTPUT.

# PARTITION_OPTS may contain other partitioner options, for example
#   PARTITION_OPTS = '--scotch --no-perio'; by default, it is set to None.

PARTITION_LIST = None
PARTITION_OPTS = None

# Solver options

# when the GUI is used, the PARAMETERS variable should contain the name
# of the XML parameters file, which should always be placed in the
# DATA subdirectory (for example, PARAMETERS = 'case1.xml').

# CHECK_ARGS allows activation of elementary mesh quality tests, as
# well as basic linear algebra operations micro-benchmarks, and
# may thus take the following values:
#   '-q' (or '--quality') for mesh quality criteria and gradient tests for
# a known function (sin(x+2y+3z)).
#   '--benchmark' or '--benchmark --mpitrace' for basic linear algebra
# operation benchmarks.

# CUT_WARPED_FACES used to cut the faces whose warp angle is larger than a
# given tolerance (in degrees), for example: CUT_WARPED_FACES = '--cwf 0.01'
# Otherwise, it is set to None.

# OUTPUT_ARGS allows setting the command-line argument for redirection of
# the output, for example: OUTPUT_ARGS = '--logp 1'.
# Otherwise, it is set to None.

PARAMETERS = None
CUT_WARPED_FACES = None
CHECK_ARGS = None
OUTPUT_ARGS = None

# Optional list of hosts (if not using a batch system).

HOSTS_LIST = None

# Calculation stages to execute.
# If EXEC_SOLVER is set to False, the Preprocessor's preprocessor_output file
# is copied in RESU, and the Partitioner's output is copied in a
# PARTITION_OUTPUT directory in RESU. Note also that when partitioning
# with no solver execution, the number of processors required is not known
# in advance, so the PARTITION_LIST variable above must also be defined.

EXEC_PREPROCESS = True
EXEC_PARTITION = True
EXEC_SOLVER = True

# The user may choose to use a mesh in the old .tlc or .slc format instead
# of a preprocessed mesh by setting SOLCOM = True.
# Note that this is deprecated, and incompatible with parallel execution.

SOLCOM = False

# Adaptation (not operational yet)

HOMARD_PREFIX = None

# CS_TMP_PREFIX variable allows the user to specify in which temporary
# directory the calculation will run. If set to None, a default directory
# will be used (architecture dependent). If a value is specified,
# the temporary directory will be of the form:
#  <CS_TMP_PREFIX>/tmp_Saturne/<STUDY>.<CASE>.<DATE>

CS_TMP_PREFIX = None

# VALGRIND enables running of the solver through Valgrind if this
# memory-checking tool is available. In this case, it should
# contain the corresponding command-line arguments, such as:
#   VALGRIND='valgrind --tool=memcheck'
# Otherwise, it should be set to None.

VALGRIND = None

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

def def_exec_prefix():
    """
    Define execution directory prefix.
    """

    if CS_TMP_PREFIX != None:
        return os.path.join(CS_TMP_PREFIX, "tmp_Saturne")

    exec_prefix = None

    # Preferential base working directories

    if sys.platform == 'win32' or sys.platform == 'win64':
        user = os.getenv('USERNAME')
    else:
        user = os.getenv('USER')

        exec_prefix_prefs = [os.getenv('SCRATCHDIR'),
                             os.path.join('/scratch', user),
                             os.path.join('/local00/users', user),
                             os.path.join('/local01/users', user)]

    if os.getenv('TMPDIR') != '/tmp':
        exec_prefix_prefs.append(os.getenv('TMPDIR'))

    exec_prefix_prefs.append(os.getenv('HOME'))

    for prefix in exec_prefix_prefs:
        if prefix != None and os.path.isdir(prefix):
            exec_prefix = os.path.join(prefix, 'tmp_Saturne')
            break

    return exec_prefix

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

if __name__ == '__main__':

    # Values in case and associated domain set from global variables

    d1 = domain(meshes = 'entreeetroue_gros_rot_expe.des',
               reorient = REORIENT,
               join = JOIN,
               periodicity = PERIODICITY,
               partition_list = PARTITION_LIST,
               partition_opts = PARTITION_OPTS,
               param = PARAMETERS,
               solcom = SOLCOM,
               cut_warped_faces = CUT_WARPED_FACES,
               mode_args = CHECK_ARGS,
               logging_args = OUTPUT_ARGS,
               thermochemistry_data = THERMOCHEMISTRY_DATA,
               meteo_data = METEO_DATA,
               user_input_files = USER_INPUT_FILES,
               user_output_files = USER_OUTPUT_FILES,
               n_procs = N_PROCS,
               n_procs_min = N_PROCS_MIN,
               n_procs_max = N_PROCS_MAX)

    d2 = domain(meshes = 'diffuseur_gros_rot.des',
               reorient = REORIENT,
               join = JOIN,
               periodicity = PERIODICITY,
               partition_list = PARTITION_LIST,
               partition_opts = PARTITION_OPTS,
               param = PARAMETERS,
               solcom = SOLCOM,
               cut_warped_faces = CUT_WARPED_FACES,
               mode_args = CHECK_ARGS,
               logging_args = OUTPUT_ARGS,
               thermochemistry_data = THERMOCHEMISTRY_DATA,
               meteo_data = METEO_DATA,
               user_input_files = USER_INPUT_FILES,
               user_output_files = USER_OUTPUT_FILES,
               n_procs = N_PROCS,
               n_procs_min = N_PROCS_MIN,
               n_procs_max = N_PROCS_MAX)

    if VALGRIND != None:
        d1.valgrind = VALGRIND
        d2.valgrind = VALGRIND

    # Possible SYRTHES coupling

    if os.path.isdir(os.path.join(casedir, 'DATA_SYR')):
        sd = syrthes_domain(syrthes_env = 'syrthes.env',  # SYRTHES paths file
                            echo_comm = None,             # coupling verbosity
                            coupling_mode = 'MPI',        # 'MPI' or 'sockets'
                            coupled_app_ids = 1)          # coupled app. ids
    else:
        sd = None

    # Now handle case for the corresponding calculation domain(s).

    case = case(casedir,
                [d1,d2],
                sd,
                results_by_suffix = True,
                exec_preprocess = EXEC_PREPROCESS,
                exec_partition = EXEC_PARTITION,
                exec_solver = EXEC_SOLVER)

    # Select suffix (define if only running the solver or saving results)

    suffix = None

    # Force MPI environment if mpi_environment != None

    mpi_env = None

    # Syntax is as follows:
    #
    # mpi_env = mpi_environment()
    #
    # Some fields may need to be modified in case of incorrect defaults
    # (due to the wide variety of MPI implementations and build options,
    # the default configuration may not give correct values in some cases).

    # mpi_env.bindir = path to mpi binaries
    # mpi_env.mpiexec = mpiexec, mpirun, or equivalent command
    # mpi_env.mpiexec_args = option to pass arguments (usually None, or -args)
    # mpi_env.mpiexec_exe = option to define executable (usually None, of -exe)
    # mpi_env.mpiexec_n = option to define number of ranks (e.g. ' -n ', ' -np ')
    # mpi_env.gen_hostsfile = shell command to generate hostsfile if required
    # mpi_env.del_hostsfile = shell command to delete hostsfile if required
    # mpi_env.mpiboot = command to start environment (e.g. mpdboot, lamboot)
    # mpi_env.mpihalt = command to halt environment (e.g. mpdallexit, lamhalt)
    # mpi_env.mpmd = MPI_MPMD_mpiexec (mpiexec colon-separated syntax), or
    #                MPI_MPMD_configfile (mpiexec -configfile syntax), or
    #                MPI_MPMD_script, or
    #                MPI_MPMD_execve

    # Execute script

    case.run(n_procs=None,
             hosts_list=HOSTS_LIST,
             mpi_environment=mpi_env,
             exec_prefix=def_exec_prefix(),
             suffix=suffix,
             prepare_data=True,
             run_solver=True,
             save_results=True)

