#!/usr/bin/env python
#-------------------------------------------------------------------------------
#   This file is part of the Code_Saturne Solver.
#
#   Copyright (C) 2009-2011  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
#-------------------------------------------------------------------------------
#
#===============================================================================
# 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, '/usr/local/lib/python2.7/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 = 'CASEDIRNAME'

# 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

# 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__':

    # Set environment modules if present

    set_modules()

    # Values in case and associated domain set from global variables

    d = domain(meshes = MESHES,
               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:
        d.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
                            pset_size = 1)                # 32 or 64 on IBM BG/P
    else:
        sd = None

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

    case = case(casedir,
                d,
                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)

