#!/usr/bin/env python2.7
# -*- coding: UTF-8 -*-
#
# Copyright (C) 2010 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.

"""
Supersonic flow over a cylinder.  Note the spatial domain includes only the
fore flow for the bow shock.  To save time, the time steps is not set to be
enough for convergence.  You can further increase the steps.

The arrangement hbnt can be run by simply executing ./go run for serial or 
./go run --npart=n for parallel.
"""

from solvcon.kerpak import euler

def hbnt_base(casename=None, meshname=None, 
    gamma=None, density=None, pressure=None, M=None,
    psteps=None, ssteps=None, profile_only=False, **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 cese
    # 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.EulerWall, {},),
        'farfield': (bctregy.EulerInlet, fpb,),
        'outflow': (bctregy.CeseNonrefl, {},),
    }
    # set up case.
    basedir = os.path.abspath(os.path.join(os.getcwd(), 'result'))
    cse = euler.EulerCase(basedir=basedir, rootdir=env.projdir,
        basefn=casename, meshfn=os.path.join(env.find_scdata_mesh(), meshname),
        bcmap=bcmap, **kw)
    # anchors for solvers.
    cse.runhooks.append(anchor.RuntimeStatAnchor)
    cse.runhooks.append(anchor.MarchStatAnchor)
    cse.runhooks.append(anchor.TpoolStatAnchor)
    # informative.
    cse.runhooks.append(hook.BlockInfoHook)
    if not profile_only:
        cse.runhooks.append(hook.ProgressHook,
            psteps=psteps, linewidth=ssteps/psteps,
        )
        cse.runhooks.append(cese.CflHook, fullstop=False, psteps=ssteps,
            cflmax=10.0, linewidth=ssteps/psteps,
        )
        cse.runhooks.append(cese.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(euler.UniformIAnchor, **fpi)
    # post processing.
    if not profile_only:
        cse.runhooks.append(euler.EulerOAnchor)
        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

@euler.EulerCase.register_arrangement
def hbnt(casename, **kw):
    """
    The true arrangement which specifies necessary parameters for execution.
    For parallel execution of domain decomposition, batch is default to
    'Localhost'.
    """
    kw.setdefault('batch', 'Localhost')
    return hbnt_base(casename=casename, meshname='hyperblunt_t100mm.neu.gz',
        gamma=1.4, density=1.0, pressure=1.0, M=3.0, rkillfn='',
        diffname='tau', tauname='scale', taumin=0.0, tauscale=4.0,
        time_increment=7.e-3, steps_run=200, ssteps=50, psteps=1, **kw)

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