Added: New solver template for stationary problems, SIMSolverStat.

This class only contains the output handling and no time-stepping.
The SIMSolver and SIMSolverAdap templates then inherit SIMSolverStat,
adding time-stepping/restart and adaptive functionality, respectively.
This makes it clear that SIMSolverAdap is not for time-dependent problems.
Also moved the ConfigureSIM template to a separate header file.
This commit is contained in:
Knut Morten Okstad
2017-04-25 00:48:29 +02:00
parent 49d2000ee9
commit 5aa904a82d
5 changed files with 248 additions and 172 deletions

View File

@@ -16,7 +16,7 @@
#include "SIMadmin.h"
#include "SIMdependency.h"
#include "SIMSolver.h"
#include "SIMconfigure.h"
#include "IFEM.h"
#include "Utilities.h"
#include "MatVec.h"

View File

@@ -23,173 +23,25 @@
/*!
\brief Struct for configuring a given simulator.
\details Your SIM needs to specialize this for its type.
\brief Template class for stationary simulator drivers.
\details This template can be instantiated over any type implementing the
ISolver interface. It provides data output to HDF5 and VTF.
*/
template<class T>
struct SolverConfigurator
{
//! \brief Configures a simulator.
//! \param sim The simulator to configure
//! \param props The setup properties for the simulator
//! \param infile The input file to parse
int setup(T& sim, const typename T::SetupProps& props, char* infile);
};
//! \brief Configuration template
template<class T>
int ConfigureSIM(T& t, char* infile,
const typename T::SetupProps& p = typename T::SetupProps())
{
SolverConfigurator<T> setup;
return setup.setup(t, p, infile);
}
/*!
\brief Template class for simulator drivers.
\details This template can be instanciated over any type implementing the
ISolver interface. It provides a time stepping loop with data output.
*/
template<class T1> class SIMSolver : public SIMadmin
template<class T1> class SIMSolverStat : public SIMadmin
{
public:
//! \brief The constructor initializes the reference to the actual solver.
SIMSolver(T1& s1) : SIMadmin("Time integration driver"), S1(s1)
SIMSolverStat(T1& s1, const char* head = nullptr) : SIMadmin(head), S1(s1)
{
saveDivergedSol = false;
exporter = nullptr;
}
//! \brief The destructor deletes the results data exporter object.
virtual ~SIMSolver() { delete exporter; }
virtual ~SIMSolverStat() { delete exporter; }
//! \brief Returns a const reference to the time stepping information.
const TimeStep& getTimePrm() const { return tp; }
//! \brief Advances the time step one step forward.
bool advanceStep() { return tp.increment() && S1.advanceStep(tp); }
//! \brief Solves the problem up to the final time.
virtual int solveProblem(char* infile, const char* heading = nullptr,
bool saveInit = true)
{
// Save FE model to VTF and HDF5 for visualization
// Optionally save the initial configuration also
int geoBlk = 0, nBlock = 0;
if (!this->saveState(geoBlk,nBlock,true,infile,saveInit))
return 2;
this->printHeading(heading);
// Solve for each time step up to final time
for (int iStep = 1; this->advanceStep(); iStep++)
if (!S1.solveStep(tp))
return saveDivergedSol && !S1.saveStep(tp,nBlock) ? 4 : 3;
else if (!this->saveState(geoBlk,nBlock))
return 4;
else
IFEM::pollControllerFifo();
return 0;
}
//! \brief Serialize internal state for restarting purposes.
//! \param data Container for serialized data
bool serialize(DataExporter::SerializeData& data)
{
return tp.serialize(data) && S1.serialize(data);
}
//! \brief Set internal state from a serialized state.
//! \param[in] data Container for serialized data
bool deSerialize(const DataExporter::SerializeData& data)
{
return tp.deSerialize(data) && S1.deSerialize(data);
}
protected:
//! \brief Parses a data section from an input stream.
virtual bool parse(char* keyw, std::istream& is) { return tp.parse(keyw,is); }
//! \brief Parses a data section from an XML element.
virtual bool parse(const TiXmlElement* elem)
{
if (strcasecmp(elem->Value(),"postprocessing"))
return tp.parse(elem);
const TiXmlElement* child = elem->FirstChildElement();
for (; child; child = child->NextSiblingElement())
if (!strncasecmp(child->Value(),"savediverg",10))
saveDivergedSol = true;
return true;
}
//! \brief Writes an application-specific heading, if provided
void printHeading(const char* heading)
{
if (heading)
{
std::string myHeading(heading);
size_t n = myHeading.find_last_of('\n');
if (n+1 < myHeading.size()) n = myHeading.size()-n;
IFEM::cout <<"\n\n"<< myHeading <<"\n";
for (size_t i = 0; i < n && i < myHeading.size(); i++) IFEM::cout <<'=';
IFEM::cout << std::endl;
}
}
//! \brief Saves geometry and results to VTF and HDF5 for current time step.
bool saveState(int& geoBlk, int& nBlock, bool newMesh = false,
char* infile = nullptr, bool saveRes = true)
{
if (newMesh && !S1.saveModel(infile,geoBlk,nBlock))
return false;
if (saveRes && !S1.saveStep(tp,nBlock))
return false;
if (saveRes && exporter) {
DataExporter::SerializeData data;
if (exporter->dumpForRestart(&tp) && this->serialize(data))
return exporter->dumpTimeLevel(&tp,newMesh,&data);
else // no restart dump, or serialization failure
return exporter->dumpTimeLevel(&tp,newMesh);
}
return true;
}
public:
//! \brief Handles application restarts by reading a serialized solver state.
//! \param[in] restartFile File to read restart state from
//! \param[in] restartStep Index of the time step to read restart state for
//! \return One-based time step index of the restart state read.
//! If zero, no restart specified. If negative, read failure.
int restart(const std::string& restartFile, int restartStep)
{
if (restartFile.empty()) return 0;
DataExporter::SerializeData data;
HDF5Writer hdf(restartFile,adm,true);
if ((restartStep = hdf.readRestartData(data,restartStep)) >= 0)
{
IFEM::cout <<"\n === Restarting from a serialized state ==="
<<"\n file = "<< restartFile
<<"\n step = "<< restartStep << std::endl;
if (this->deSerialize(data))
return restartStep+1;
else
restartStep = -2;
}
std::cerr <<" *** SIMSolver: Failed to read restart data."<< std::endl;
return restartStep;
}
//! \brief Nothing to read for this template.
virtual bool read(const char*) { return true; }
//! \brief Handles application data output.
//! \param[in] hdf5file The file to save to
@@ -211,14 +63,192 @@ public:
}
}
protected:
//! \brief Writes an application-specific heading, if provided
void printHeading(const char* heading)
{
if (heading)
{
std::string myHeading(heading);
size_t n = myHeading.find_last_of('\n');
if (n+1 < myHeading.size()) n = myHeading.size()-n;
IFEM::cout <<"\n\n"<< myHeading <<"\n";
for (size_t i = 0; i < n && i < myHeading.size(); i++) IFEM::cout <<'=';
IFEM::cout << std::endl;
}
}
public:
//! \brief Solves the stationary problem.
virtual int solveProblem(char* infile, const char* heading = nullptr,
bool = false)
{
// Save FE model to VTF for visualization
int geoBlk = 0, nBlock = 0;
if (!S1.saveModel(infile,geoBlk,nBlock))
return 1;
this->printHeading(heading);
// Solve the stationary problem
TimeStep dummy;
if (!S1.solveStep(dummy))
return 2;
// Save the results
if (!S1.saveStep(dummy,nBlock))
return 4;
if (exporter && !exporter->dumpTimeLevel())
return 5;
return 0;
}
protected:
T1& S1; //!< The actual solver
DataExporter* exporter; //!< Administrator for result output to HDF5 file
};
/*!
\brief Template class for transient simulator drivers.
\details This template can be instantiated over any type implementing the
ISolver interface. It provides a time stepping loop and restart in addition.
*/
template<class T1> class SIMSolver : public SIMSolverStat<T1>
{
public:
//! \brief The constructor initializes the reference to the actual solver.
SIMSolver(T1& s1) : SIMSolverStat<T1>(s1,"Time integration driver")
{
saveDivergedSol = false;
}
//! \brief Empty destructor.
virtual ~SIMSolver() {}
//! \brief Reads solver data from the specified input file.
virtual bool read(const char* file) { return this->SIMadmin::read(file); }
//! \brief Returns a const reference to the time stepping information.
const TimeStep& getTimePrm() const { return tp; }
//! \brief Advances the time step one step forward.
bool advanceStep() { return tp.increment() && this->S1.advanceStep(tp); }
//! \brief Solves the problem up to the final time.
virtual int solveProblem(char* infile, const char* heading = nullptr,
bool saveInit = true)
{
// Save FE model to VTF and HDF5 for visualization
// Optionally save the initial configuration also
int geoBlk = 0, nBlock = 0;
if (!this->saveState(geoBlk,nBlock,true,infile,saveInit))
return 2;
this->printHeading(heading);
// Solve for each time step up to final time
for (int iStep = 1; this->advanceStep(); iStep++)
if (!this->S1.solveStep(tp))
return saveDivergedSol && !this->S1.saveStep(tp,nBlock) ? 4 : 3;
else if (!this->saveState(geoBlk,nBlock))
return 4;
else
IFEM::pollControllerFifo();
return 0;
}
//! \brief Serialize internal state for restarting purposes.
//! \param data Container for serialized data
bool serialize(DataExporter::SerializeData& data)
{
return tp.serialize(data) && this->S1.serialize(data);
}
//! \brief Set internal state from a serialized state.
//! \param[in] data Container for serialized data
bool deSerialize(const DataExporter::SerializeData& data)
{
return tp.deSerialize(data) && this->S1.deSerialize(data);
}
protected:
//! \brief Parses a data section from an input stream.
virtual bool parse(char* keyw, std::istream& is) { return tp.parse(keyw,is); }
//! \brief Parses a data section from an XML element.
virtual bool parse(const TiXmlElement* elem)
{
if (strcasecmp(elem->Value(),"postprocessing"))
return tp.parse(elem);
const TiXmlElement* child = elem->FirstChildElement();
for (; child; child = child->NextSiblingElement())
if (!strncasecmp(child->Value(),"savediverg",10))
saveDivergedSol = true;
return true;
}
//! \brief Saves geometry and results to VTF and HDF5 for current time step.
bool saveState(int& geoBlk, int& nBlock, bool newMesh = false,
char* infile = nullptr, bool saveRes = true)
{
if (newMesh && !this->S1.saveModel(infile,geoBlk,nBlock))
return false;
if (saveRes && !this->S1.saveStep(tp,nBlock))
return false;
if (saveRes && SIMSolverStat<T1>::exporter) {
DataExporter::SerializeData data;
if (SIMSolverStat<T1>::exporter->dumpForRestart(&tp) &&
this->serialize(data))
return SIMSolverStat<T1>::exporter->dumpTimeLevel(&tp,newMesh,&data);
else // no restart dump, or serialization failure
return SIMSolverStat<T1>::exporter->dumpTimeLevel(&tp,newMesh);
}
return true;
}
public:
//! \brief Handles application restarts by reading a serialized solver state.
//! \param[in] restartFile File to read restart state from
//! \param[in] restartStep Index of the time step to read restart state for
//! \return One-based time step index of the restart state read.
//! If zero, no restart specified. If negative, read failure.
int restart(const std::string& restartFile, int restartStep)
{
if (restartFile.empty()) return 0;
DataExporter::SerializeData data;
HDF5Writer hdf(restartFile,SIMadmin::adm,true);
if ((restartStep = hdf.readRestartData(data,restartStep)) >= 0)
{
IFEM::cout <<"\n === Restarting from a serialized state ==="
<<"\n file = "<< restartFile
<<"\n step = "<< restartStep << std::endl;
if (this->deSerialize(data))
return restartStep+1;
else
restartStep = -2;
}
std::cerr <<" *** SIMSolver: Failed to read restart data."<< std::endl;
return restartStep;
}
private:
bool saveDivergedSol; //!< If \e true, save also the diverged solution to VTF
protected:
TimeStep tp; //!< Time stepping information
T1& S1; //!< The actual solver
DataExporter* exporter; //!< Administrator for result output to HDF5 file
};
#endif

View File

@@ -20,15 +20,15 @@
/*!
\brief Template class for stationary adaptive simulator drivers.
\details This template can be instanciated over any type implementing the
\details This template can be instantiated over any type implementing the
ISolver interface. It provides an adaptive loop with data output.
*/
template<class T1> class SIMSolverAdap : public SIMSolver<T1>
template<class T1> class SIMSolverAdap : public SIMSolverStat<T1>
{
public:
//! \brief The constructor forwards to the parent class constructor.
SIMSolverAdap(T1& s1) : SIMSolver<T1>(s1), aSim(s1,false)
SIMSolverAdap(T1& s1) : SIMSolverStat<T1>(s1), aSim(s1,false)
{
this->S1.setSol(&aSim.getSolution());
}
@@ -36,21 +36,22 @@ public:
//! \brief Empty destructor.
virtual ~SIMSolverAdap() {}
//! \brief Solves the problem up to the final time.
virtual int solveProblem(char* infile, const char* heading, bool = false)
//! \brief Reads solver data from the specified input file.
virtual bool read(const char* file) { return this->SIMadmin::read(file); }
//! \brief Solves the problem on a sequence of adaptively refined meshes.
virtual int solveProblem(char* infile, const char* = nullptr, bool = false)
{
if (!aSim.initAdaptor())
return 1;
this->printHeading(heading);
for (int iStep = 1; aSim.adaptMesh(iStep); iStep++)
if (!aSim.solveStep(infile,iStep))
return 1;
else if (!aSim.writeGlv(infile,iStep))
return 2;
else if (SIMSolver<T1>::exporter)
SIMSolver<T1>::exporter->dumpTimeLevel(nullptr,true);
else if (SIMSolverStat<T1>::exporter)
SIMSolverStat<T1>::exporter->dumpTimeLevel(nullptr,true);
return 0;
}
@@ -59,12 +60,12 @@ protected:
//! \brief Parses a data section from an input stream.
virtual bool parse(char* keyw, std::istream& is)
{
return this->SIMSolver<T1>::parse(keyw,is) && aSim.parse(keyw,is);
return aSim.parse(keyw,is);
}
//! \brief Parses a data section from an XML element.
virtual bool parse(const TiXmlElement* elem)
{
return this->SIMSolver<T1>::parse(elem) && aSim.parse(elem);
return aSim.parse(elem);
}
AdaptiveSIM aSim; //!< Adaptive simulation driver

View File

@@ -19,7 +19,7 @@
/*!
\brief Template class for time-slab adaptive simulator drivers.
\details This template can be instanciated over any type implementing the
\details This template can be instantiated over any type implementing the
ISolver interface. It provides a time stepping loop with data output,
with mesh refinements at fixed time intervals. The refinement is based on the
solution state a given number of increments ahead of the refinement time.

View File

@@ -0,0 +1,45 @@
// $Id$
//==============================================================================
//!
//! \file SIMconfigure.h
//!
//! \date Oct 12 2012
//!
//! \author Arne Morten Kvarving / SINTEF
//!
//! \brief SIM solver configurator.
//!
//==============================================================================
#ifndef _SIM_CONFIGURE_H_
#define _SIM_CONFIGURE_H_
/*!
\brief Struct for configuring a given simulator.
\details Your SIM needs to specialize this for its type.
*/
template<class T> struct SolverConfigurator
{
//! \brief Configures a simulator.
//! \param sim The simulator to configure
//! \param[in] props The setup properties for the simulator
//! \param[in] infile The input file to parse
int setup(T& sim, const typename T::SetupProps& props, char* infile);
};
//! \brief Configuration template.
//! \param sim The simulator to configure
//! \param[in] infile The input file to parse
//! \param[in] props The setup properties for the simulator
template<class T>
int ConfigureSIM(T& sim, char* infile,
const typename T::SetupProps& props = typename T::SetupProps())
{
SolverConfigurator<T> setup;
return setup.setup(sim,props,infile);
}
#endif