//----------------------------------------------------------------------------- // 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 //----------------------------------------------------------------------------- // 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 ); }