#!/usr/bin/env python2.7
# -*- coding: UTF-8 -*-
#
# Copyright (C) 2010-2011 Yung-Yu Chen <yyc@solvcon.net>.
#
# This program 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.
#
# This program 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 License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

"""
Distributed parallelization of CUDA with supersonic flow over a cylinder.
Solver has CUDA enabled.  Note the spatial domain includes only the fore flow
for the bow shock.  You can further increase the steps.

The arrangement blnt can be run by simply executing ./go run.
"""

from solvcon.batch import Torque
from solvcon.kerpak import gasdyn

class Tester(Torque):
    BASH_HOME_SOURCE = ['.bashrc_path', '.bashrc_acct']
    def create_worker(self, *args, **kw):
        return self.create_worker_ssh(*args, **kw)
    @property
    def str_path(self):
        import os
        sep = ':'
        ppaths = []
        for path in os.environ.get('PYTHONPATH', '').split(sep):
            ppaths.append(os.path.abspath(path))
        ret = [super(Tester, self).str_path]
        if ppaths:
            ret.append('export PYTHONPATH=%s'%sep.join(ppaths+['$PYTHONPATH']))
        ret.append('export')
        ret.append('python2.6 -c "from solvcon.conf import env; print env.scu"')
        return '\n'.join(ret)

def par_base(casename=None, meshname=None,
    gamma=None, density=None, pressure=None, M=None,
    psteps=None, ssteps=None, **kw
):
    """
    Fundamental configuration of the simulation and return the case object.

    @return: the created Case object.
    @rtype: solvcon.case.BlockCase
    """
    import os
    from numpy import sqrt
    from solvcon.conf import env
    from solvcon.boundcond import bctregy
    from solvcon.solver import ALMOST_ZERO
    from solvcon import hook, anchor
    from solvcon.kerpak import cuse
    # set flow properties (fp).
    fpb = {
        'gamma': gamma, 'rho': density, 'v2': 0.0, 'v3': 0.0, 'p': pressure,
    }
    fpb['v1'] = M*sqrt(gamma*fpb['p']/fpb['rho'])
    fpi = fpb.copy()
    # set up BCs.
    bcmap = {
        'cylinder': (bctregy.GasdynWall, {},),
        'farfield': (bctregy.GasdynInlet, fpb,),
        'outflow': (bctregy.CuseNonrefl, {},),
    }
    # set up case.
    basedir = os.path.abspath(os.getcwd())
    if os.path.basename(basedir) != 'result':   # for submitted job.
        basedir = os.path.join(os.getcwd(), 'result')
    cse = gasdyn.GasdynCase(basedir=basedir, rootdir=env.projdir,
        basefn=casename, meshfn=os.path.join(env.find_scdata_mesh(), meshname),
        bcmap=bcmap, **kw)
    # anchors for solvers.
    for key in 'Runtime', 'March', 'Tpool':
        cse.runhooks.append(getattr(anchor, key+'StatAnchor'))
    # informative.
    cse.runhooks.append(hook.BlockInfoHook)
    cse.runhooks.append(hook.ProgressHook,
        psteps=psteps, linewidth=ssteps/psteps)
    cse.runhooks.append(cuse.CflHook, fullstop=False, psteps=ssteps,
        cflmax=10.0, linewidth=ssteps/psteps)
    cse.runhooks.append(cuse.ConvergeHook, psteps=ssteps)
    cse.runhooks.append(hook.SplitMarker)
    cse.runhooks.append(hook.GroupMarker)
    # initializer.
    cse.runhooks.append(anchor.FillAnchor, keys=('soln',), value=ALMOST_ZERO)
    cse.runhooks.append(anchor.FillAnchor, keys=('dsoln',), value=0)
    cse.runhooks.append(gasdyn.UniformIAnchor, **fpi)
    # post processing.
    cse.runhooks.append(gasdyn.GasdynOAnchor, rsteps=ssteps)
    cse.runhooks.append(hook.PMarchSave, anames=[
        ('soln', False, -4),
        ('rho', True, 0),
        ('p', True, 0),
        ('T', True, 0),
        ('ke', True, 0),
        ('M', True, 0),
        ('sch', True, 0),
        ('v', True, 0.5),
    ], fpdtype='float64', psteps=ssteps)
    return cse

def par_skel(casename, **kw):
    return par_base(casename=casename, meshname='hyperblunt_t100mm.neu.gz',
        gamma=1.4, density=1.0, pressure=1.0, rkillfn='', ncuth=128,
        steps_run=2000, ssteps=500, psteps=10, **kw)

@gasdyn.GasdynCase.register_arrangement
def par(casename, **kw):
    return par_skel(casename=casename, M=3.0, time_increment=9.e-3, **kw)

@gasdyn.GasdynCase.register_arrangement
def par_m5(casename, **kw):
    return par_skel(casename=casename, M=5.0, time_increment=6.e-3,
        taumin=0.5, **kw)

@gasdyn.GasdynCase.register_arrangement
def par_m10(casename, **kw):
    return par_skel(casename=casename, M=5.0, time_increment=3.e-3,
        taumin=1.0, **kw)

@gasdyn.GasdynCase.register_arrangement
def par_m20(casename, **kw):
    return par_skel(casename=casename, M=20.0, time_increment=1.6e-3,
        taumin=1.0, **kw)

if __name__ == '__main__':
    import solvcon
    solvcon.go()
