//-----------------------------------------------------------------------------
// NastSimulator2d.cpp
//-----------------------------------------------------------------------------
//
//  Copyright (C) 1998 Technische Universitaet Muenchen, Germany
//  written by Bernhard Brueck
//
//  This file is part of Nast++
//
//-----------------------------------------------------------------------------
// CNastSimulator2d bildet die hoechste Ebene in Nast++.
// Hier werden die Objekte erzeugt, zerstoert und die Verwaltung vorgenommen.
// Um neue Module in Nast++ zu testen kann man von CNastSimulator2d eine
// eigene Klasse ableiten und die jeweiligen Funktionen ueberschreiben.
// Der Aufruf der Funktionen erfolgt nach folgendem Schema:
//
//    main
//        creatObjects
//            create...
//                parameter...
//        loop
//            calcTimeStep
//            beforeNavierStokes
//            solveNavierStokes
//            afterNavierStokes
//            writeOutput
//        destroyObjects
//
//-----------------------------------------------------------------------------
//  Bei den Parametern werden folgende Bereiche extrahiert
//    "simulator"
//    "geometrie"
//    "gitter"
//    "loeser"
//    "diff"
//    "navierstokes"
//    "ausgabe"
//-----------------------------------------------------------------------------
//  Changes:
//

#include "NastSimulator2d.h"
#include "NastDebug.h"

// Parameter
#include "NastParameterContext.h"

// Poisson-Loeser
#include "NastSolverPoisson2d.h"
#include "NastSolverPoisson2dSOR.h"

// Differenzenquotienten
#include "NastDiffQuot2d.h"
#include "NastDiffQuot2dDonorCell.h"

// NavierStokes-Loeser
#include "NastNavierStokes2d.h"
#include "NastNavierStokes2dMAC.h"
#include "NastNavierStokesParameter.h"

// Geometrie
#include "NastGeometry2d.h"
#include "NastGeometry2dPipe.h"
#include "NastGeometry2dStep.h"
#include "NastGeometry2dDrivenCavity.h"

// Ausgabe
#include "NastOutputContext.h"
#include "NastOutputContextIDL.h"

#include <string.h>

//-----------------------------------------------------------------------------
//                            Namen der Parameter
//-----------------------------------------------------------------------------

// Namen der Bereiche
static const char szSectionFluid[]         = "fluid";
static const char szSectionSimulator[]     = "simulator";
static const char szSectionGeometry[]      = "geometrie";
static const char szSectionSolver[]        = "loeser";
static const char szSectionDiffQuot[]      = "diff";
static const char szSectionNavierStokes[]  = "nastsolver";
static const char szSectionOutput[]        = "ausgabe";

// Namen der Parameter fuer die Geometrieparameter
static const char szGeomProblem[]         = "problem";
static const char szGeomProblemStufe[]    = "stufe";
static const char szGeomProblemRohr[]     = "rohr";
static const char szGeomProblemDCavity[]  = "dcavity";
static const char szGeomLength[]          = "laenge";
static const char szGeomInflow[]          = "inflow";

// Namen der Parameter fuer den Druckloeser
static const char szSolverPoissonTyp[]     = "typ";
static const char szSolverPoissonTypSOR[]  = "SOR";
static const char szSolverPoissonItermax[] = "itermax";
static const char szSolverPoissonOmega[]   = "omega";
static const char szSolverPoissonEps[]     = "eps";
static const char szSolverPoissonSchema[]  = "schema";
static const char szSolverPoissonDebug[]   = "debug";

// Namen der Parameter fuer die Differenzenquotienten
static const char szDiffQuotTyp[]      = "typ";
static const char szDiffQuotTypDCell[] = "dcell";
static const char szDiffQuotGamma[]    = "gamma";

// Namen der Parameter fuer den Navier-Stokes-Loeser
static const char szNavierStokesTyp[]      = "typ";
static const char szNavierStokesImax[]     = "imax";
static const char szNavierStokesJmax[]     = "jmax";

// Namen der Parameter fuer die Fluideigenschaften
static const char szFluidReynolds[] = "reynolds";
static const char szFluidGx[]       = "gx";
static const char szFluidGy[]       = "gy";

// Namen der Parameter fuer den Simulator
static const char szSimulatorTimeStep[] = "tdelta";
static const char szSimulatorTimeEnd[] = "tend";
static const char szSimulatorTimeTau[] = "tau";

// Namen der Parameter fuer die Ausgabe
static const char szOutputTyp[]   = "typ";
static const char szOutputTypIDL[]= "IDL";
static const char szOutputStart[] = "start";
static const char szOutputDelta[] = "delta";
static const char szOutputFile[]  = "file";


static const int nMaxLineLength = 1024;	// Max. Laenge einer Eingabezeile
//-----------------------------------------------------------------------------
//                    Konstruktor + Destruktor
//-----------------------------------------------------------------------------

//  Defaultconstr.
CNastSimulator2d::CNastSimulator2d( const CNastParameterContext *parameter)
    :m_pGeom(0),
     m_pSolverPoisson(0),
     m_pDiffQuot(0),
     m_pNavierStokes(0),
     m_pOutputContext(0),
     m_pParameter(parameter),
     m_timeStep(0),	
     m_timeEnd(0),		
     m_timeTau(0),
     m_outStart(0),
     m_outDelta(0)
{}

//  Destruktor
CNastSimulator2d::~CNastSimulator2d()
{
    destroyObjects();

    // Test ob destroyObjects() auch keine Objekte
    // uebriggelassen hat.

    NAST_ASSERT( m_pSolverPoisson == 0 );
    NAST_ASSERT( m_pDiffQuot      == 0 );
    NAST_ASSERT( m_pNavierStokes  == 0 );
    NAST_ASSERT( m_pOutputContext == 0 );
}


//-------------------------------------------------------------------------
//    Objekte erzeugen
//-------------------------------------------------------------------------

void 
CNastSimulator2d::createObjects()
{
    NAST_ASSERT_VALID( this );

    m_pGeom          = createGeometry();
    m_pSolverPoisson = createSolverPoisson();
    m_pDiffQuot      = createDiffQuot();
    m_pNavierStokes  = createNavierStokes();
    m_pOutputContext = createOutputContext();
}


//-------------------------------------------------------------------------
//  die Geometriebeschreibung erzeugen
//-------------------------------------------------------------------------
//  Parameter fuer die Geometrie:
//     benoetigt  problem     [stufe, rohr, dcavity]
//     benoetigt  laenge.x    Ausdehnung der Geometrie in x-Richtung
//     benoetigt  laenge.y    Ausdehnung der Geometrie in y-Richtung
//     optional   inflow      Einstroemgeschwindigkeit
//

CNastGeometry2d*
CNastSimulator2d::createGeometry()
{
    NAST_ASSERT_VALID( this );

    CNastGeometry2d *pNew = 0;

    //  falls es sich um eine der einfachen Geometrien
    //  handelt, dann muss das Problem angegeben sein
    //  und die Groesse der Geometrie
    char szProblem[nMaxLineLength] = "";

    // Parameter fur die Geometrie holen
    CNastParameterContext *pCont = parameterGeometry();
    pCont->getParameter( szProblem, szGeomProblem );

    CNastDebug::dumpContextLogfile() << "Geometriebeschreibung\n";
    CNastDebug::dumpContextLogfile() << "\tProblem : " << szProblem << "\n";

    // handelt es sich um eine der einfachen Geometrien ?
    if( strcmp( szProblem,  szGeomProblemStufe   ) == 0 ||
        strcmp( szProblem,  szGeomProblemRohr    ) == 0 ||
        strcmp( szProblem,  szGeomProblemDCavity ) == 0 )
    {
        double inflow = 1;
        double sizeX = 0;	// Ausdehnung der Geometrie in x-Richtung
        double sizeY = 0;	// Ausdehnung der Geometrie in y-Richtung

        // Ausdehnung holen
        CNastParameterContext *pContLen = pCont->section(szGeomLength);

        pContLen->getParameter( sizeX, "x" ); 
        pContLen->getParameter( sizeY, "y" ); 

        delete pContLen;
        pContLen = 0;

        CNastDebug::dumpContextLogfile() << "\tsizeX : " << sizeX << "\n";
        CNastDebug::dumpContextLogfile() << "\tsizeY : " << sizeY << "\n";

        // optionale Einstroemgeschwindigkeit
        pCont->getParameter( inflow, szGeomInflow, CNastParameterContext::optional );
        CNastDebug::dumpContextLogfile() << "inflow : " << szProblem << "\n";

        // und die jeweilige Geometrie erzeugen
        const CNastBox2d box( 0, 0, sizeX, sizeY );
        if( strcmp( szProblem, szGeomProblemStufe ) == 0 )
        {
            pNew = new CNastGeometry2dStep( box, inflow );
        }

        if( strcmp( szProblem, szGeomProblemDCavity ) == 0 )
        {
            pNew = new CNastGeometry2dDrivenCavity( box, inflow );
        }
    }

    delete pCont;
    pCont = 0;

    // andere Geometrien sind noch nicht implementiert
    NAST_ASSERT( pNew );
    return pNew;
}


//-------------------------------------------------------------------------
//  den Loeser fuer die Druckgleichgen erzeugen
//-------------------------------------------------------------------------
//  Parameter fuer den Loeser
//    typ  [SOR]
//   Parameter fuer den SOR-Loeser:
//    itermax 
//    omega
//    eps
//
CNastSolverPoisson2d* 
CNastSimulator2d::createSolverPoisson()
{
    NAST_ASSERT_VALID( this );

    // Parametercontext holen
    CNastParameterContext *pCont = parameterSolverPoisson();

    CNastSolverPoisson2d *pNew = 0;
    
    // welcher Loeser soll verwendet werden ?
    char szTyp[nMaxLineLength];
    pCont->getParameter( szTyp, szSolverPoissonTyp );

    CNastDebug::dumpContextLogfile() << "Poissonloeser\n";
    CNastDebug::dumpContextLogfile() << "\tTyp     : " << szTyp << "\n";

    if( strcmp( szTyp, szSolverPoissonTypSOR ) == 0)	// SOR-Loeser ?
    {
        CNastParameterContext *pContSOR = pCont->section("SOR");

        int    itermax  = 0;
        double omega    = 0;
        double eps      = 0;
        int    nSchema  = 0;
        int    nDebug   = 0;

        // Parameter fuer den SOR-Loeser holen
        pContSOR->getParameter( itermax, szSolverPoissonItermax );
        pContSOR->getParameter( omega,   szSolverPoissonOmega   );
        pContSOR->getParameter( eps,     szSolverPoissonEps     );
        pContSOR->getParameter( nSchema, szSolverPoissonSchema,
        			CNastParameterContext::optional );
        pContSOR->getParameter( nDebug, szSolverPoissonDebug,
        			CNastParameterContext::optional );

        CNastDebug::dumpContextLogfile() << "\titermax : " << itermax << "\n";
        CNastDebug::dumpContextLogfile() << "\tomega   : " << omega   << "\n";
        CNastDebug::dumpContextLogfile() << "\teps     : " << eps     << "\n";
        CNastDebug::dumpContextLogfile() << "\tSchema  : " << nSchema << "\n";
        CNastDebug::dumpContextLogfile() << "\tDebug   : " << nDebug  << "\n";

        // auf Wertebereich testen
        if( itermax <= 0 )
            NAST_FATAL_ERROR("SOR.itermax muss positiv sein");

        if( omega <= 0 )
            NAST_FATAL_ERROR("omega muss positiv sein");

        if( omega >= 2 )
            NAST_FATAL_ERROR("omega zu gross");

        if( eps <= 0 )
            NAST_FATAL_ERROR("eps muss positiv sein");

        // den Loser erzeugen
        pNew = new CNastSolverPoisson2dSOR( itermax, eps, omega, nSchema != 0, nDebug );
        delete pCont;
        pCont = 0;
    }
    else
    {
        NAST_FATAL_ERROR("unbakannter Loeser angegeben");
    }

    delete pCont;
    pCont = 0;

    NAST_ASSERT( pNew );
    return pNew;
}

//-------------------------------------------------------------------------
//  die Differenzenquotienten erzeugen
//-------------------------------------------------------------------------
//  Parameter fuer die Differenzenquotienten
//    typ  [dcell]
//  Parameter fue DonorCell (dcell)
//    gamma  Faktor fuer Upwinding

CNastDiffQuot2d*
CNastSimulator2d::createDiffQuot()
{
    NAST_ASSERT_VALID( this );

    // Parametercontext holen
    CNastParameterContext *pCont = parameterDiffQuot();
    CNastDiffQuot2d *pNew = 0;

    // welcher Differenzenquot. soll verwendet werden ?
    char szTyp[nMaxLineLength];
    pCont->getParameter( szTyp, szDiffQuotTyp );

    CNastDebug::dumpContextLogfile() << "Differenzenqotienten: \n";
    CNastDebug::dumpContextLogfile() << "\tTyp  : " << szTyp << "\n";

    if( strcmp( szTyp, szDiffQuotTypDCell ) == 0)	// Donor-Cell ?
    {
        CNastParameterContext *pContDCell = pCont->section(szDiffQuotTypDCell);
        double gamma = 0;
        pContDCell->getParameter( gamma, szDiffQuotGamma );
        CNastDebug::dumpContextLogfile() << "\tgamma: " << gamma << "\n";
        
        delete pContDCell;
        pContDCell = 0;

        if( gamma < 0)
            NAST_FATAL_ERROR( "gamma darf nicht negativ sein");

        if( gamma >  1)
            NAST_FATAL_ERROR( "gamma darf nicht groesser als eins sein");

        pNew = new CNastDiffQuot2dDonorCell( gamma );
    }
    else
    {
        NAST_FATAL_ERROR("unbekannter typ bei den Diffrerenzenquotienten");
    }
        

    delete pCont;
    pCont = 0;

    NAST_ASSERT( pNew );
    return pNew;
}


//-------------------------------------------------------------------------
//  den Loser fuer die Navier-Stokes-Gleichungen erzeugen
//-------------------------------------------------------------------------
//  Parameter fuer den Navier-Stokes Loeser
//  
//

CNastNavierStokes2d*
CNastSimulator2d::createNavierStokes()
{
    NAST_ASSERT_VALID( this );

    // Parametercontext holen
    const CNastParameterContext *pContNavierStokes = parameterNavierStokes();
    const CNastParameterContext *pContFluid        = parameterFluid();
    CNastNavierStokes2d *pNew = 0;

    // Anzahl der Zellen
    int nSizeI = 0;
    int nSizeJ = 0;

    pContNavierStokes->getParameter( nSizeI, szNavierStokesImax );
    pContNavierStokes->getParameter( nSizeJ, szNavierStokesJmax );

    // welcher Differenzenquot. soll verwendet werden ?
    char szTyp[nMaxLineLength];
    pContNavierStokes->getParameter( szTyp, szNavierStokesTyp );

    // Volumenkraefte (optional)
    double gx     = 0;
    double gy     = 0;
    double reynolds = 0;

    pContFluid->getParameter( gx, 
        		      szFluidGx, 
        		      CNastParameterContext::optional);
    
    pContFluid->getParameter( gy, 
        		      szFluidGy, 
        		      CNastParameterContext::optional);
    
    pContFluid->getParameter( reynolds, 
        		      szFluidReynolds);
    
    CNastNavierStokesParameter para( gx, gy, reynolds );
    
    CNastDebug::dumpContextLogfile() << "Navier-Stokes Loeser: \n";
    CNastDebug::dumpContextLogfile() << "\tTyp  : " << szTyp  << "\n";
    CNastDebug::dumpContextLogfile() << "\tsizeI: " << nSizeI << "\n";
    CNastDebug::dumpContextLogfile() << "\tsizeJ: " << nSizeJ << "\n";

    CNastDebug::dumpContextLogfile() << "Fluid: \n";
    CNastDebug::dumpContextLogfile() << "\tgx        : " << gx     << "\n";
    CNastDebug::dumpContextLogfile() << "\tgy        : " << gy     << "\n";
    CNastDebug::dumpContextLogfile() << "\treynolds  : " << gy     << "\n";

    if( strcmp( szTyp, "mac" ) == 0)	// MAC ?
    {
        pNew = new CNastNavierStokes2dMAC( *(getSolverPoisson()),
        				   *(getDiffQuot()),
        				   *(getGeometry()),
        				   para,
        				   nSizeI,
        				   nSizeJ );
    }
    else
    {
        NAST_FATAL_ERROR("unbekannter Typ bei den Navier-Stokes-Loeser angegeben");
    }
        
    NAST_ASSERT( pNew );
    return pNew;
    
}

//-------------------------------------------------------------------------
//  Den Ausgabecontext erzeugen
//-------------------------------------------------------------------------
CNastOutputContext*
CNastSimulator2d::createOutputContext()
{
    NAST_ASSERT_VALID( this );

    // Parametercontext fuer die Ausgabe holen
    const CNastParameterContext *pCont = parameterOutputContext();
    CNastOutputContext *pNew = 0;
    
    // Zeitpunkt und Schrittweite holen
    pCont->getParameter( m_outStart,
        		 szOutputStart,
        		 CNastParameterContext::optional);
    
    pCont->getParameter( m_outDelta,
        		 szOutputDelta,
        		 CNastParameterContext::optional);
    
    // welcher Ausgabecontext soll verwendet werden ?
    char szTyp[nMaxLineLength];
    pCont->getParameter( szTyp, szOutputTyp );

    CNastDebug::dumpContextLogfile() << "Ausgabe: \n";
    CNastDebug::dumpContextLogfile() << "\tTyp  : " << szTyp  << "\n";

    if( strcmp( szTyp, szOutputTypIDL ) == 0)	// IDL ?
    {
        char szFileName[nMaxLineLength];
        pCont->getParameter( szFileName,  szOutputFile );

        CNastDebug::dumpContextLogfile() << "\tDatei: " << szFileName << "\n";

        pNew = new CNastOutputContextIDL( szFileName );
    }
    else
    {
        NAST_FATAL_ERROR("unbekannter Typ bei der Ausgabe");
    }
        

    NAST_ASSERT( pNew );
    return pNew;

}

//-------------------------------------------------------------------------
//  Objekte wieder zerstoeren
//-------------------------------------------------------------------------

void 
CNastSimulator2d::destroyObjects()
{
    NAST_ASSERT_VALID( this );

    if( m_pNavierStokes)  destroyNastNavierStokes();
    if( m_pGeom)          destroyGeometry();
    if( m_pSolverPoisson) destroySolverPoisson();
    if( m_pDiffQuot)      destroyDiffQuot();
    if( m_pOutputContext) destroyOutputContext();
}

void
CNastSimulator2d::destroyGeometry()
{
    NAST_ASSERT_VALID( this );
    NAST_ASSERT( m_pGeom );    

    delete m_pGeom;
    m_pGeom = 0;
}

void 
CNastSimulator2d::destroySolverPoisson()
{
    NAST_ASSERT_VALID( this );
    NAST_ASSERT( m_pSolverPoisson );

    delete m_pSolverPoisson;
    m_pSolverPoisson = 0;
}

void 
CNastSimulator2d::destroyDiffQuot()
{
    NAST_ASSERT_VALID( this );
    NAST_ASSERT( m_pDiffQuot );

    delete m_pDiffQuot;
    m_pDiffQuot = 0;
}

void
CNastSimulator2d::destroyNastNavierStokes()
{
    NAST_ASSERT_VALID( this );
    NAST_ASSERT( m_pNavierStokes );

    delete m_pNavierStokes;
    m_pNavierStokes = 0;
}

void 
CNastSimulator2d::destroyOutputContext()
{
    NAST_ASSERT_VALID( this );
    NAST_ASSERT( m_pOutputContext );

    delete m_pOutputContext;
    m_pOutputContext = 0;
}

//-------------------------------------------------------------------------
//  Parameter erfragen
//-------------------------------------------------------------------------

// physikalische Parameter des Fluids 
CNastParameterContext*
CNastSimulator2d::parameterFluid()
{
    NAST_ASSERT_VALID( this );
    return m_pParameter->section( szSectionFluid );
}


// Parameter fuer CNastParamterSimulator ..
CNastParameterContext*
CNastSimulator2d::parameterSimulator()
{
    NAST_ASSERT_VALID( this );
    return m_pParameter->section( szSectionSimulator );
}


// Parameter um ein Geometrieobjekt zu erzeugen
CNastParameterContext* 
CNastSimulator2d::parameterGeometry()
{
    NAST_ASSERT_VALID( this );
    return m_pParameter->section( szSectionGeometry );
}


// Parameter um ein Gleichungsloeserobjekt zu erzeugen
CNastParameterContext* 
CNastSimulator2d::parameterSolverPoisson()
{
    NAST_ASSERT_VALID( this );
    return m_pParameter->section( szSectionSolver );
}


// Parameter um die Differenzenquotienten zu erzeugen
CNastParameterContext* 
CNastSimulator2d::parameterDiffQuot()
{
    NAST_ASSERT_VALID( this );
    return m_pParameter->section( szSectionDiffQuot );
}


// Parameter um den Navier-Stokes-Loser zu erzeugen
CNastParameterContext* 
CNastSimulator2d::parameterNavierStokes()
{
    NAST_ASSERT_VALID( this );
    return m_pParameter->section( szSectionNavierStokes );
}


// Parameter um den Ausgabecontext zu erzeugen
CNastParameterContext* 
CNastSimulator2d::parameterOutputContext()
{
    NAST_ASSERT_VALID( this );
    return m_pParameter->section( szSectionOutput );
}

//-------------------------------------------------------------------------
//    Hauptschleife
//-------------------------------------------------------------------------

//  komplette Simulation (incl, Obj. erzeugen und freigeben)
void 
CNastSimulator2d::main()
{
    NAST_ASSERT_VALID( this );

    // Objekte erzeugen
    createObjects();
    
    // die Membervariablen fuer die Zeitsteuerung belegen
    const CNastParameterContext *pCont = parameterSimulator();
    pCont->getParameter( m_timeStep, szSimulatorTimeStep );
    pCont->getParameter( m_timeEnd,  szSimulatorTimeEnd  );
    pCont->getParameter( m_timeTau,  szSimulatorTimeTau  );

    // dann in die Hauptschleife gehen
    loop();

    // un die Objekte wieder zerstoeren
    destroyObjects();
}


// die Hauptzeitschleife
void 
CNastSimulator2d::loop()
{
    NAST_ASSERT_VALID( this );

    double t = 0;
    while( t < m_timeEnd )
    {
        // Zeitschritt berechenen
        const double dt = calcTimeStep();

        // Zeit weitersetzen und neue Loesung berechnen
        t += dt;

        CNastDebug::dumpContextLogfile() << "t:" << t;
        CNastDebug::dumpContextLogfile() << " dt:" << dt;

        getNavierStokes()->solve( t );

        // Ausgabe 
        if( m_outDelta && t >  m_outStart )	// Startzeitunkt schon vorbei ?
        {
            int time0 = (int)((t - m_outStart     ) /  m_outDelta);
            int time1 = (int)((t - m_outStart + dt) /  m_outDelta);

            if( time0 != time1 )
        	getOutputContext()->out( getNavierStokes()->grid() );
        }
    }
}


static double nastmin( double a, double b)
{
    if( a > b ) return b;
    return a;
}

//  die Schrittweite bestimmen um zum naechsten Zeitpunkt zu gelangen
double 
CNastSimulator2d::calcTimeStep()
{
    NAST_ASSERT_VALID( this );

    // Es gibt drei Stellen, die auf die Schrittweite Einfluss nehmen
    //  1. der Loeser fuer die Navier-Stokes-Gleichungen
    //  2. die Geometrie (z.B. bei bewegen Geometrien )
    //  3. die gewuenschte Schrittweite
    // Bei der Geometrie und bei den Navier-Stokes-Loeser wird
    // noch der Sicherheitsfaktor tau beruecksichtigt und dann
    // das Minimum der drei Werte verwendet
    
    const double dt_nav  = getNavierStokes()->maxTimeStep();
    const double dt_geom = getGeometry()->maxTimeStep();
    
     // Als Ergebnis wird dann das Minimum
    return nastmin( m_timeStep, m_timeTau * nastmin( dt_nav,  dt_geom ));
}


//  Dummy, der vor dem Navier-Stokes-Loeser aufgerufen wird
void 
CNastSimulator2d::beforeNavierStokes()
{
    NAST_ASSERT_VALID( this );
}


//  Uebergang auf die Werte zum naechsten Zeitpunkt
void 
CNastSimulator2d::solveNavierStokes()
{
    NAST_ASSERT_VALID( this );
}

//  Dummy, der nach dem Navier-Stokes-Loeser aufgerufen wird
void 
CNastSimulator2d::afterNavierStokes()
{
    NAST_ASSERT_VALID( this );
}


//  Daten ausgeben
void 
CNastSimulator2d::writeOutput()
{
    NAST_ASSERT_VALID( this );
}

//-------------------------------------------------------------------------
//    Zugriff auf die Objekte
//-------------------------------------------------------------------------

CNastGeometry2d*
CNastSimulator2d::getGeometry()
{
    NAST_ASSERT_VALID( this );
    NAST_ASSERT( m_pGeom );
    return m_pGeom;
}


CNastSolverPoisson2d*
CNastSimulator2d::getSolverPoisson()
{
    NAST_ASSERT_VALID( this );
    NAST_ASSERT( m_pSolverPoisson );
    return m_pSolverPoisson;
}

CNastDiffQuot2d*
CNastSimulator2d::getDiffQuot()
{
    NAST_ASSERT_VALID( this );
    NAST_ASSERT( m_pDiffQuot );
    return m_pDiffQuot;
}

CNastNavierStokes2d*
CNastSimulator2d::getNavierStokes()
{
    NAST_ASSERT_VALID( this );
    NAST_ASSERT( m_pNavierStokes );
    return m_pNavierStokes;
}

CNastOutputContext*
CNastSimulator2d::getOutputContext()
{
    NAST_ASSERT_VALID( this );
    NAST_ASSERT( m_pOutputContext );
    return m_pOutputContext;
}

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

void 
CNastSimulator2d::debugDump( CNastDumpContext &dumpContext ) const
{
    CNastObject::debugDump( dumpContext );
    dumpContext << "CNastSimulator2d" << "\n";
    
    if( m_pGeom )          
        dumpContext << "\tGeometrie       : vorhanden \n";
    else
        dumpContext << "\tGeometrie       : nicht vorhanden \n";

    if( m_pSolverPoisson ) 
        dumpContext << "\tPoissonloeser   : vorhanden \n";
    else
        dumpContext << "\tPoissonloeser   : nicht vorhanden \n";

    if( m_pDiffQuot )      
        dumpContext << "\tDifferenzenqot. : vorhanden \n";
    else
        dumpContext << "\tDifferenzenqot. : nicht vorhanden \n";

    if( m_pNavierStokes )  
        dumpContext << "\tNav.Stok.loeser : vorhanden \n";
    else
        dumpContext << "\tNav.Stok.loeser : nicht vorhanden \n";

    if( m_pOutputContext ) 
        dumpContext << "\tAusgabecontext  : vorhanden \n";
    else
        dumpContext << "\tAusgabecontext  : nicht vorhanden \n";

    dumpContext << "m_timeStep = " << m_timeStep << "\n";
    dumpContext << "m_timeEnd  = " << m_timeEnd  << "\n";	
    dumpContext << "m_timeTau  = " << m_timeTau  << "\n";
    dumpContext << "m_outStart = " << m_outStart << "\n";
    dumpContext << "m_outDelta = " << m_outDelta << "\n";
}

void 
CNastSimulator2d::assertValid() const
{
    // zuerst einmal AssertValid der Basisklasse aufrufen
    CNastObject::assertValid(); 

    // die Zeiger auf die Objekte muessen entweder 0 enthalten
    // oder auf gueltige Objekte zeigen.

    if( m_pGeom )          NAST_ASSERT_VALID( m_pGeom );
    if( m_pSolverPoisson ) NAST_ASSERT_VALID( m_pSolverPoisson );
    if( m_pDiffQuot )      NAST_ASSERT_VALID( m_pDiffQuot );
    if( m_pNavierStokes )  NAST_ASSERT_VALID( m_pNavierStokes );
    if( m_pOutputContext ) NAST_ASSERT_VALID( m_pOutputContext );

    NAST_ASSERT_VALID( m_pParameter );
}


