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:
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
45
Apps/Common/SIMconfigure.h
Normal file
45
Apps/Common/SIMconfigure.h
Normal 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
|
||||
Reference in New Issue
Block a user