//-----------------------------------------------------------------------------
// NastGeometry2dStep.cpp
//-----------------------------------------------------------------------------
//
//  Copyright (C) 1998 Technische Universitaet Muenchen, Germany
//  written by Bernhard Brueck
//
//  This file is part of Nast++
//
//-----------------------------------------------------------------------------
//  Implementierung einer einfachen Geometriebeschreibung fue die Stroemung
//  ueber eine Stufe
//-----------------------------------------------------------------------------
//  Changes:
//

#include "NastGeometry2dStep.h"
#include "NastDebug.h"
#include "NastCellField2d.h"

#include <signal.h>		// Workaround fuer einen Bug in HP-Includefiles
#include <limits.h>		// DBL_MAX

#ifdef _MSC_VER
#   include <float.h>
#endif

//-----------------------------------------------------------------------------
//                    Konstruktor + Destruktor
//-----------------------------------------------------------------------------

//  Defaultconstr.
CNastGeometry2dStep::CNastGeometry2dStep(const CNastBox2d &boundingBox,
        				 double velocity )
:m_box( boundingBox ),
 m_boxStep( boundingBox.pntMin(),        // sued-west Ecke
            boundingBox.sizeX() / 4,     // Laenge der Stufe
            boundingBox.sizeY() / 2),    // Hoehe der Stufe
 m_velocity( velocity )
{}

//  Destruktor
CNastGeometry2dStep::~CNastGeometry2dStep()
{
    NAST_ASSERT_VALID( this );
}


//-----------------------------------------------------------------------------
//                    Memberfunktionen
//-----------------------------------------------------------------------------
CNastBox2d 
CNastGeometry2dStep::boundingBox() const
{
    return m_box;
}

//  setzen der Zelleigenschaften
void CNastGeometry2dStep::setCells( CNastCellField2d &cells ) const
{
    const int nSizeI = cells.sizeI();
    const int nSizeJ = cells.sizeJ();

    const double dx = cells.box().sizeX() / nSizeI;
    const double dy = cells.box().sizeY() / nSizeJ;
    const CNastVector2d vecX( dx, 0 );
    const CNastVector2d vecY( 0 , dy);
    const CNastPoint2d pnt( cells.box().minX(), 
        		    cells.box().minY() );

    for( int i = 0; i < nSizeI; i++)
        for( int j = 0;  j < nSizeJ; j++)
        {
            //  fuer jede Zelle wird eine Box erzeugt, und danach wird getestet
            //  ob sie im Gebiet liegt
            const CNastBox2d boxTest( pnt + i*vecX + j*vecY, dx, dy );
 
            if( m_boxStep.isOutside( boxTest ) && m_box.isInside( boxTest ))
        	cells.setCellType( i, j, CNastCell2d::FLUID );
            else
        	cells.setCellType( i, j, CNastCell2d::BARRIER );
        }
}


CNastBoundaryPoint2d 
CNastGeometry2dStep::boundaryPoint( const CNastPoint2d  &pnt,
        			    const CNastVector2d &vec ) const
{
    NAST_ASSERT( m_box.isInside( pnt ));     // Punkt muss innerhalb des Fluids liegen
    NAST_ASSERT( m_boxStep.isOutside( pnt ));

    NAST_ASSERT( vec == CNastVector2d( 1.0, 0.0 ) ||
        	 vec == CNastVector2d(-1.0, 0.0 ) ||
        	 vec == CNastVector2d( 0.0, 1.0 ) ||
        	 vec == CNastVector2d( 0.0,-1.0 ));
        
    CNastPoint2d  pntBorder;
    CNastVector2d vecVel = CNastVector2d(  0.0, 0.0 );;

    CNastVector2d vecNorm = -1 * vec;
    CNastBoundaryPoint2d::Condition cond = CNastBoundaryPoint2d::NOSLIP;

    if( vec.x() > 0 && vec.y() == 0 )      // Richtung Osten ?
    {
        pntBorder = CNastPoint2d( m_box.maxX(), pnt.y() );
        cond      = CNastBoundaryPoint2d::OUTFLOW;
        vecVel    = CNastVector2d(  0.5 * m_velocity, 0.0 );
        cond      = CNastBoundaryPoint2d::INFLOW;
    }
    else if( vec.x() < 0 && vec.y() == 0 ) // Richtung Westen ?
    {
        if( pnt.y() > m_boxStep.maxY() ) // ueberhalb der Stufe ?
        {
            //  hier gilt die Einstroembedingung
            pntBorder = CNastPoint2d( m_box.minX(), pnt.y() );
 	    vecVel    = CNastVector2d(  m_velocity, 0.0 );
            cond      = CNastBoundaryPoint2d::INFLOW;
        }
        else
        {
            //  hier treffen wir auf jeden Fall die Stufe
            pntBorder = CNastPoint2d( m_boxStep.maxX(), pnt.y() );
            vecVel    = CNastVector2d(  0.0, 0.0 );
        }
    }
    else if( vec.x() == 0 && vec.y() > 0 ) // Richtung Sueden ?
    {
        if( pnt.x() > m_boxStep.maxX() )   // oestlich der Stufe ?
        {
            pntBorder = CNastPoint2d( pnt.x(), m_box.minY() );
        }
        else
        {
            //  hier wird die Stufe getroffen
            pntBorder = CNastPoint2d( pnt.x(), m_boxStep.maxY() );
        }
    }
    else if( vec.x() == 0 && vec.y() < 0 ) // Richtung Norden ?
    {
        pntBorder = CNastPoint2d( pnt.x(), m_box.maxY() );
    }
    else
        NAST_ASSERT( false );

    return CNastBoundaryPoint2d( pntBorder,vecNorm, vecVel, cond);
}


bool 
CNastGeometry2dStep::isMovable() const
{
    return false;
}


void 
CNastGeometry2dStep::move( const CNastNavierStokes &solution )
{
    //  Geometrie kann nicht bewegt werden
    NAST_ASSERT( false );
}


double 
CNastGeometry2dStep::maxTimeStep() const
{
    NAST_ASSERT_VALID( this );
    return DBL_MAX;		// keine Beschraenkung
}


// ----------------------------------------------------------------------------
//                                    Debug
// ----------------------------------------------------------------------------

void 
CNastGeometry2dStep::debugDump( CNastDumpContext &dumpContext ) const
{
    CNastGeometry2d::debugDump( dumpContext );
    dumpContext << "CNastGeometry2dStep" << "\n";
    dumpContext << "\tm_velocity = " << m_velocity << "\n";
    dumpContext << "\tm_box     = " << m_box << "\n";
    dumpContext << "\tm_boxStep = " << m_boxStep << "\n";
}

void 
CNastGeometry2dStep::assertValid() const
{
    // zuerst einmal AssertValid der Basisklasse aufrufen
    CNastGeometry2d::assertValid(); 
}



