Added HDF5 to VTF conversion utility + assosiacted fixes in HDF5 output. This now works for linear/stationary problems and nonlinear/time-dependent problems. But not yet for fully-coupled mixed methods.

git-svn-id: http://svn.sintef.no/trondheim/IFEM/trunk@1007 e10b68d5-8a6e-419e-a041-bce267b0401d
This commit is contained in:
kmo 2011-05-22 11:25:42 +00:00 committed by Knut Morten Okstad
parent 8459da8f23
commit dcd55dc7de
14 changed files with 492 additions and 219 deletions

View File

@ -282,7 +282,6 @@ int main (int argc, char** argv)
const double epsT = 1.0e-6; const double epsT = 1.0e-6;
if (dtDump <= 0.0) dtDump = params.stopTime + 1.0; if (dtDump <= 0.0) dtDump = params.stopTime + 1.0;
if (format < 0) dtSave = params.stopTime + 1.0;
double nextDump = params.time.t + dtDump; double nextDump = params.time.t + dtDump;
double nextSave = params.time.t + dtSave; double nextSave = params.time.t + dtSave;
@ -302,7 +301,7 @@ int main (int argc, char** argv)
std::cout <<"\nWriting HDF5 file "<< infile <<".hdf5"<< std::endl; std::cout <<"\nWriting HDF5 file "<< infile <<".hdf5"<< std::endl;
writer = new DataExporter(true); writer = new DataExporter(true);
writer->registerField("u","solution",DataExporter::SIM, skip2nd ? 0 : -1); writer->registerField("u","displacement",DataExporter::SIM, skip2nd ? 0 : -1);
writer->setFieldValue("u",model,(void*)&simulator.getSolution()); writer->setFieldValue("u",model,(void*)&simulator.getSolution());
writer->registerWriter(new HDF5Writer(infile)); writer->registerWriter(new HDF5Writer(infile));
writer->registerWriter(new XMLWriter(infile)); writer->registerWriter(new XMLWriter(infile));
@ -337,8 +336,9 @@ int main (int argc, char** argv)
if (params.time.t + epsT*params.time.dt > nextSave) if (params.time.t + epsT*params.time.dt > nextSave)
{ {
// Save solution variables to VTF for visualization // Save solution variables to VTF for visualization
if (!simulator.saveStep(++iStep,params.time.t,n,skip2nd)) if (format >= 0)
return 6; if (!simulator.saveStep(++iStep,params.time.t,n,skip2nd))
return 6;
// Save solution variables to HDF5 // Save solution variables to HDF5
if (writer) if (writer)

138
Apps/HDF5toVTF/HDF5toVTF.C Normal file
View File

@ -0,0 +1,138 @@
// $Id$
//==============================================================================
//!
//! \file HDF5toVTF.C
//!
//! \date Apr 08 2011
//!
//! \author Arne Morten Kvarving / SINTEF
//!
//! \brief Convert a HDF5 results database to VTF for visualisation.
//!
//==============================================================================
#include "SIM1D.h"
#include "SIM2D.h"
#include "SIM3D.h"
#include "HDF5Writer.h"
#include "XMLWriter.h"
#include "StringUtils.h"
#include <sstream>
#include <stdlib.h>
#include <string.h>
typedef std::map< std::string,std::vector<XMLWriter::Entry> > ProcessList;
int main (int argc, char** argv)
{
int format = 0;
int n[3] = { 5, 5, 5 };
int dims = 3;
char* infile = 0;
char* vtffile = 0;
for (int i = 1; i < argc; i++)
if (!strcmp(argv[i],"-vtf") && i < argc-1)
format = atoi(argv[++i]);
else if (!strcmp(argv[i],"-nviz") && i < argc-1)
n[0] = n[1] = n[2] = atoi(argv[++i]);
else if (!strcmp(argv[i],"-1D"))
dims = 1;
else if (!strcmp(argv[i],"-2D"))
dims = 2;
else if (!infile)
infile = argv[i];
else if (!vtffile)
vtffile = argv[i];
else
std::cerr <<" ** Unknown option ignored: "<< argv[i] << std::endl;
if (!infile) {
std::cout <<"usage: "<< argv[0]
<<" <inputfile> [<vtffile>] [-nviz <nviz>] [-1D|-2D]"<< std::endl;
return 0;
}
else if (!vtffile)
vtffile = infile;
std::cout <<"\n >>> IFEM HDF5 to VTF converter <<<"
<<"\n ==================================\n"
<<"\nInput file: "<< infile
<<"\nOutput file: "<< vtffile
<<"\nNumber of visualization points: "
<< n[0] <<" "<< n[1] << " " << n[2] << std::endl;
HDF5Writer hdf(strtok(infile,"."),true);
XMLWriter xml(infile);
xml.readInfo();
int levels = xml.getLastTimeLevel();
if (levels > 0) SIMinput::msgLevel = 1;
std::cout <<"Reading "<< infile <<": Time levels = "<< levels << std::endl;
const std::vector<XMLWriter::Entry>& entry = xml.getEntries();
std::vector<XMLWriter::Entry>::const_iterator it;
ProcessList processlist;
for (it = entry.begin(); it != entry.end(); ++it)
processlist[it->patchfile].push_back(*it);
ProcessList::const_iterator pit = processlist.begin();
for (int j = 1; pit != processlist.end(); ++pit, ++j)
{
SIMbase* sim;
if (dims == 1)
sim = new SIM1D;
else if (dims == 2)
sim = new SIM2D;
else
sim = new SIM3D;
std::stringstream dummy;
dummy << "PATCHFILE " << pit->first;
sim->parse(const_cast<char*>(dummy.str().c_str()),dummy);
std::stringstream dummy2;
std::string foo(pit->first);
dummy2 << "NODEFILE " << replaceAll(foo,".g2",".gno");
sim->parse(const_cast<char*>(dummy2.str().c_str()),dummy2);
if (!sim->preprocess(std::vector<int>(),false))
return 1;
bool ok = true;
if (processlist.size() > 1) {
std::string temp(strtok(vtffile,"."));
std::stringstream str;
str <<"-"<< j;
temp.append(str.str());
ok = sim->writeGlv(temp.c_str(),n,format);
}
else
ok = sim->writeGlv(vtffile,n,format);
int block = 0;
for (int i = 0; i <= levels && ok; ++i) {
int k = 20;
if (levels > 0) std::cout <<"\nTime level "<< i << std::endl;
for (it = pit->second.begin(); it != pit->second.end() && ok; ++it) {
Vector vec;
std::cout <<"Reading \""<< it->name <<"\""<< std::endl;
ok = hdf.readField(i,it->name,vec,sim,it->components);
if (it->description == "displacement")
ok &= sim->writeGlvS(vec,n,i+1,block,i,1,NULL,10,it->components);
else if (it->components < 2)
ok &= sim->writeGlvS(vec,n,i+1,block,i,2,it->name.c_str(),k++,1);
else
ok &= sim->writeGlvV(vec,it->name.c_str(),n,i+1,block);
}
if (ok)
ok = sim->writeGlvStep(i+1,i);
}
delete sim;
if (!ok) return 2;
}
return 0;
}

View File

@ -129,12 +129,11 @@ IF(NOT WIN32)
ENDIF(NOT WIN32) ENDIF(NOT WIN32)
# Make the IFEM library # Make the IFEM library
FILE(GLOB_RECURSE IFEM_SRCS ${PROJECT_SOURCE_DIR}/src/*.[Cf] FILE(GLOB_RECURSE IFEM_SRCS ${PROJECT_SOURCE_DIR}/src/*.[Cf]
${PROJECT_SOURCE_DIR}/3rdparty/*.C) ${PROJECT_SOURCE_DIR}/3rdparty/*.C)
ADD_LIBRARY(IFEM ${IFEM_SRCS}) ADD_LIBRARY(IFEM ${IFEM_SRCS})
# Make the Apps # Make some Apps
FILE(GLOB_RECURSE Poisson_SRCS ${PROJECT_SOURCE_DIR}/Apps/Poisson/*.C) FILE(GLOB_RECURSE Poisson_SRCS ${PROJECT_SOURCE_DIR}/Apps/Poisson/*.C)
ADD_EXECUTABLE(Poisson ${Poisson_SRCS}) ADD_EXECUTABLE(Poisson ${Poisson_SRCS})
TARGET_LINK_LIBRARIES(Poisson IFEM ${DEPLIBS}) TARGET_LINK_LIBRARIES(Poisson IFEM ${DEPLIBS})
@ -145,7 +144,13 @@ FILE(GLOB_RECURSE LinEl_SRCS
ADD_EXECUTABLE(LinEl ${LinEl_SRCS}) ADD_EXECUTABLE(LinEl ${LinEl_SRCS})
TARGET_LINK_LIBRARIES(LinEl IFEM ${DEPLIBS}) TARGET_LINK_LIBRARIES(LinEl IFEM ${DEPLIBS})
# Tests IF(HDF5_LIBRARIES AND VTFWRITER_LIBRARIES)
FILE(GLOB_RECURSE HDF2VTF_SRCS ${PROJECT_SOURCE_DIR}/Apps/HDF5toVTF/*.C)
ADD_EXECUTABLE(HDF5toVTF ${HDF2VTF_SRCS})
TARGET_LINK_LIBRARIES(HDF5toVTF IFEM ${DEPLIBS})
ENDIF(HDF5_LIBRARIES AND VTFWRITER_LIBRARIES)
# Regression tests
FILE(GLOB_RECURSE LINEL_TESTFILES "${PROJECT_SOURCE_DIR}/Apps/LinearElasticity/Test/*.reg") FILE(GLOB_RECURSE LINEL_TESTFILES "${PROJECT_SOURCE_DIR}/Apps/LinearElasticity/Test/*.reg")
FOREACH(TESTFILE ${LINEL_TESTFILES}) FOREACH(TESTFILE ${LINEL_TESTFILES})
ADD_TEST(${TESTFILE} ${PROJECT_SOURCE_DIR}/test/regtest.sh "${CMAKE_BINARY_DIR}/${EXECUTABLE_OUTPUT_PATH}/LinEl" "${TESTFILE}") ADD_TEST(${TESTFILE} ${PROJECT_SOURCE_DIR}/test/regtest.sh "${CMAKE_BINARY_DIR}/${EXECUTABLE_OUTPUT_PATH}/LinEl" "${TESTFILE}")

30
HOWTO
View File

@ -1,17 +1,17 @@
Dette må gjøres for å kompilere denne versjonen: Dette må gjøres for å kompilere denne versjonen:
sudo apt-get install libboost-dev
sudo apt-get install libblas-dev sudo apt-get install libblas-dev
sudo apt-get install liblapack-dev sudo apt-get install liblapack-dev
sudo apt-get install libarpack2-dev sudo apt-get install libarpack2-dev
sudo apt-get install libsuperlu3-dev sudo apt-get install libsuperlu3-dev
sudo apt-get install libboost-dev
sudo apt-get install libpetsc3.0.0-dev sudo apt-get install libpetsc3.0.0-dev
Installer GoToolsCore og GoTrivariate fra GoTools-svn. Installer GoToolsCore og GoTrivariate fra GoTools-svn.
Gjør så cmake ., make og sudo make install i disse katalogene Gjør så cmake ., make og sudo make install i disse katalogene
CMake og out-of-tree builds: CMake og out-of-tree builds:
CMake støtter debug og release-builds samtidig vi det som kalles CMake støtter debug og release-builds samtidig via det som kalles
out-of-tree builds. In-tree builds av App'ene forventer at har byggefilene out-of-tree builds. In-tree builds av App'ene forventer at har byggefilene
i en underkatalog med samme navn som bygge-typen. Feks for å bygge Debug i en underkatalog med samme navn som bygge-typen. Feks for å bygge Debug
gjør vi: gjør vi:
@ -20,26 +20,28 @@ mkdir Debug
cd Debug cd Debug
cmake .. -DCMAKE_BUILD_TYPE:STRING=Debug cmake .. -DCMAKE_BUILD_TYPE:STRING=Debug
På samme måte kan vi lage en release-katalog. På samme måte kan vi lage en release-katalog.
Merk: Hvis du har en CMakeCache.txt i root når du prøver dette, vil Merk: Hvis du har en CMakeCache.txt i root når du prøver dette, vil
det ikke fungere. det ikke fungere.
Flagg av interesse: Flagg av interesse:
Per default lenker vi mot et minimum av bibliotek. Det betyr ingen Per default lenker vi mot et minimum av bibliotek. Det betyr ingen
PETSc, ingen SuperLU, ingen VTFWriter og ingen SAMG. Disse kan slås på PETSc og ingen SAMG. Disse kan slås på med opsjoner:
med opsjoner:
-DENABLE_SUPERLU:BOOL=1, -DENABLE_PETSC:BOOL=1, -DENABLE_VTFWRITER:BOOL=1 -DENABLE_PETSC:BOOL=1 og -DENABLE_SAMG:BOOL=1.
og -DENABLE_SAMG:BOOL=1.
Vi bygger kun libIFEM og Apps/Poisson. For å kompilere mot parallel Petsc bruker du -DENABLE_PARALLEL_PETSC:BOOL=1
Stokes og FiniteDefElasticity har egen CMakeLists.txt. Disse er
satt opp til å bruke in-tree kopi av libIFEM per default, men sjekker Ved å spesifisere -DDISABLE_SUPERLU:BOOL=1 kan du slå av SuperLU ligningsløseren.
system hvis den ikke finner in-tree. Du kan tvinge system med Ved å spesifisere -DENABLE_SUPERLU_MT:BOOL=1 kan du aktivere multi-threaded SuperLU
-DFORCE_SYSTEM_IFEM:BOOL=1. Merk at in-tree sjekkes både for <root>/<type> og istedet for den serielle versjonen.
i <root>.
Ved å spesifisere -DDISABLE_HDF5:BOOL=1 kan du slå av HDF5-støtten. Ved å spesifisere -DDISABLE_HDF5:BOOL=1 kan du slå av HDF5-støtten.
For å kompilere mot parallel Petsc bruker du -DENABLE_PARALLEL_PETSC:BOOL=1 Vi bygger kun libIFEM, Apps/Poisson og Apps/LinearElasticity.
Stokes og FiniteDefElasticity har egne CMakeLists.txt. Disse
er satt opp til å bruke in-tree kopi av libIFEM per default,
men sjekker system hvis den ikke finner in-tree.
Du kan tvinge system med -DFORCE_SYSTEM_IFEM:BOOL=1.
Merk at in-tree sjekkes både for <root>/<type> og i <root>.

View File

@ -484,10 +484,10 @@ bool ASMbase::injectNodeVec (const Vector& nodeVec, Vector& globRes,
{ {
if (nndof == 0) nndof = nf; if (nndof == 0) nndof = nf;
if (nodeVec.size() < MLGN.size()*nndof) if (nodeVec.size() != MLGN.size()*nndof)
{ {
std::cerr <<" *** ASMbase::injectNodeVec:: Invalid patch vector, size = " std::cerr <<" *** ASMbase::injectNodeVec:: Invalid patch vector, size = "
<< nodeVec.size() <<" < "<< MLGN.size()*nndof << std::endl; << nodeVec.size() <<" != "<< MLGN.size()*nndof << std::endl;
return false; return false;
} }

View File

@ -1036,17 +1036,19 @@ bool SIMbase::writeGlvV (const Vector& vec, const char* fieldName,
bool SIMbase::writeGlvS (const Vector& psol, const int* nViz, bool SIMbase::writeGlvS (const Vector& psol, const int* nViz,
int iStep, int& nBlock, double time, int iStep, int& nBlock, double time,
bool psolOnly, const char* vecName) char psolOnly, const char* pvecName,
int idBlock, int psolComps)
{ {
if (psol.empty()) if (psol.empty())
return true; return true;
else if (!myVtf) else if (!myVtf)
return false; return false;
if (!psolOnly) if (!psolOnly && myProblem)
myProblem->initResultPoints(time); myProblem->initResultPoints(time);
Matrix field; Matrix field;
Vector lovec;
size_t i, j; size_t i, j;
int geomID = 0; int geomID = 0;
const size_t pMAX = 6; const size_t pMAX = 6;
@ -1070,11 +1072,14 @@ bool SIMbase::writeGlvS (const Vector& psol, const int* nViz,
// 1. Evaluate primary solution variables // 1. Evaluate primary solution variables
myModel[i]->extractNodeVec(psol,myProblem->getSolution()); Vector& locvec = myProblem ? myProblem->getSolution() : lovec;
if (!myModel[i]->evalSolution(field,myProblem->getSolution(),nViz)) myModel[i]->extractNodeVec(psol,locvec,psolComps);
if (!myModel[i]->evalSolution(field,locvec,nViz))
return false; return false;
if (!myVtf->writeVres(field,++nBlock,++geomID,nVcomp)) if (psolOnly > 1)
geomID++;
else if (!myVtf->writeVres(field,++nBlock,++geomID,nVcomp))
return false; return false;
else else
vID[0].push_back(nBlock); vID[0].push_back(nBlock);
@ -1085,7 +1090,7 @@ bool SIMbase::writeGlvS (const Vector& psol, const int* nViz,
else else
dID[j].push_back(nBlock); dID[j].push_back(nBlock);
if (psolOnly) continue; // skip secondary solution if (psolOnly || !myProblem) continue; // skip secondary solution
// 2. Direct evaluation of secondary solution variables // 2. Direct evaluation of secondary solution variables
@ -1154,22 +1159,32 @@ bool SIMbase::writeGlvS (const Vector& psol, const int* nViz,
// Write result block identifications // Write result block identifications
bool ok = true; bool ok = true;
int idBlock = 10; if (!vID[0].empty())
if (vecName) if (pvecName)
ok = myVtf->writeVblk(vID[0],vecName,idBlock,iStep); ok = myVtf->writeVblk(vID[0],pvecName,idBlock,iStep);
else else
ok = myVtf->writeDblk(vID[0],"Solution",idBlock,iStep); ok = myVtf->writeDblk(vID[0],"Solution",idBlock,iStep);
if (!ok) return false;
if (scalarEq && !psolOnly) if (ok && !vID[1].empty())
if (!myVtf->writeVblk(vID[1],"Flux",idBlock+1,iStep)) ok = myVtf->writeVblk(vID[1],"Flux",idBlock+1,iStep);
return false;
for (j = 0; j < pMAX && !dID[j].empty(); j++) std::string pname;
if (!myVtf->writeSblk(dID[j],myProblem->getField1Name(j),++idBlock,iStep)) if (!myProblem)
return false; {
pname = pvecName ? pvecName : "Solution";
if (psolOnly < 2) pname += "_w";
}
if (psolOnly) return true; for (j = 0; j < pMAX && !dID[j].empty() && ok; j++)
{
if (myProblem)
pname = myProblem->getField1Name(j);
else if (psolOnly < 2)
(*pname.rbegin()) ++;
ok = myVtf->writeSblk(dID[j],pname.c_str(),++idBlock,iStep);
}
if (psolOnly || !myProblem || !ok) return ok;
size_t nf = myProblem->getNoFields(2); size_t nf = myProblem->getNoFields(2);
for (i = j = 0; i < nf && !sID[j].empty(); i++, j++) for (i = j = 0; i < nf && !sID[j].empty(); i++, j++)

View File

@ -296,15 +296,18 @@ public:
//! \param nBlock Running result block counter //! \param nBlock Running result block counter
//! \param[in] time Load/time step parameter //! \param[in] time Load/time step parameter
//! \param[in] psolOnly If \e true, skip secondary solution field evaluation //! \param[in] psolOnly If \e true, skip secondary solution field evaluation
//! \param[in] vecName Optional name of the primary vector field solution //! \param[in] pvecName Optional name of the primary vector field solution
//! \param[in] idBlock Starting value of result block numbering
//! \param[in] psolComps Optional number of primary solution components
//! //!
//! \details The primary vector field solution is written as a deformation //! \details The primary vector field solution is written as a deformation
//! plot if \a vecName is NULL. Otherwise, it is written as a named vector //! plot if \a pvecName is NULL. Otherwise, it is written as a named vector
//! field. If an analytical solution is provided, the exact secondary solution //! field. If an analytical solution is provided, the exact secondary solution
//! fields are written to the VTF-file as well. //! fields are written to the VTF-file as well.
virtual bool writeGlvS(const Vector& psol, const int* nViz, int iStep, virtual bool writeGlvS(const Vector& psol, const int* nViz, int iStep,
int& nBlock, double time = 0.0, bool psolOnly = false, int& nBlock, double time = 0.0, char psolOnly = 0,
const char* vecName = 0); const char* pvecName = 0, int idBlock = 10,
int psolComps = 0);
//! \brief Writes a mode shape and associated eigenvalue to the VTF-file. //! \brief Writes a mode shape and associated eigenvalue to the VTF-file.
//! \details The eigenvalue is used as a label on the step state info //! \details The eigenvalue is used as a label on the step state info

View File

@ -3,15 +3,26 @@
#include "DataExporter.h" #include "DataExporter.h"
#include <iostream> #include <iostream>
#include <algorithm> #include <algorithm>
#ifdef PARALLEL_PETSC
#include <mpi.h>
#endif
DataExporter::DataExporter(bool dynWrts) : deleteWriters(dynWrts), m_level(-1) DataWriter::DataWriter (const std::string& name) : m_name(name)
{ {
#ifdef PARALLEL_PETSC
MPI_Comm_size(MPI_COMM_WORLD,&m_size);
MPI_Comm_rank(MPI_COMM_WORLD,&m_rank);
#else
m_size = 1;
m_rank = 0;
#endif
} }
DataExporter::~DataExporter()
DataExporter::~DataExporter ()
{ {
if (deleteWriters) if (m_delete)
for (size_t i = 0; i < m_writers.size(); i++) for (size_t i = 0; i < m_writers.size(); i++)
delete m_writers[i]; delete m_writers[i];
} }
@ -40,6 +51,7 @@ bool DataExporter::registerWriter(DataWriter* writer)
return true; return true;
} }
bool DataExporter::setFieldValue(const std::string& name, bool DataExporter::setFieldValue(const std::string& name,
void* data, void* data2) void* data, void* data2)
{ {
@ -52,10 +64,11 @@ bool DataExporter::setFieldValue(const std::string& name,
return true; return true;
} }
bool DataExporter::dumpTimeLevel() bool DataExporter::dumpTimeLevel()
{ {
if (m_level == -1) if (m_level == -1)
m_level = getWritersTimeLevel()+1; m_level = this->getWritersTimeLevel()+1;
std::map<std::string,FileEntry>::iterator it; std::map<std::string,FileEntry>::iterator it;
std::vector<DataWriter*>::iterator it2; std::vector<DataWriter*>::iterator it2;
@ -72,7 +85,7 @@ bool DataExporter::dumpTimeLevel()
(*it2)->writeSIM(m_level,*it); (*it2)->writeSIM(m_level,*it);
break; break;
default: default:
std::cout <<"DataExporter: Invalid field type registered, skipping" std::cerr <<"DataExporter: Invalid field type registered, skipping"
<< std::endl; << std::endl;
break; break;
} }
@ -84,52 +97,59 @@ bool DataExporter::dumpTimeLevel()
return true; return true;
} }
bool DataExporter::loadTimeLevel(int level, DataWriter* input)
{
if (!input && m_writers.empty())
return false;
if (!input)
input = m_writers.front();
if (level == -1)
level = m_level = input->getLastTimeLevel();
if (level == -1)
return false;
bool DataExporter::loadTimeLevel (int level, DataWriter* input)
{
if (!input)
if (m_writers.empty())
return false;
else
input = m_writers.front();
if (level == -1)
if ((m_level = input->getLastTimeLevel()) < 0)
return false;
else
level = m_level;
bool ok = true;
input->openFile(level); input->openFile(level);
std::map<std::string,FileEntry>::iterator it; std::map<std::string,FileEntry>::iterator it;
for (it = m_entry.begin(); it != m_entry.end(); ++it) for (it = m_entry.begin(); it != m_entry.end() && ok; ++it)
{
if (!it->second.data) if (!it->second.data)
return false; ok = false;
switch (it->second.field) else switch (it->second.field)
{ {
case VECTOR: case VECTOR:
input->readVector(level,*it); ok = input->readVector(level,*it);
break; break;
case SIM: case SIM:
input->readSIM(level,*it); ok = input->readSIM(level,*it);
break; break;
default: default:
std::cout << "DataExporter::loadTimeLevel: Invalid field type " ok = false;
<< "registered, skipping" << std::endl; std::cerr <<" *** DataExporter: Invalid field type registered "
<< it->second.field << std::endl;
break; break;
} }
}
input->closeFile(level); input->closeFile(level);
m_level++; m_level++;
return true; return ok;
} }
int DataExporter::getTimeLevel()
int DataExporter::getTimeLevel ()
{ {
if (m_level == -1) if (m_level == -1)
m_level = getWritersTimeLevel(); m_level = this->getWritersTimeLevel();
return m_level; return m_level;
} }
int DataExporter::getWritersTimeLevel()
int DataExporter::getWritersTimeLevel () const
{ {
std::vector<int> levels; std::vector<int> levels;
std::vector<DataWriter*>::const_iterator it2; std::vector<DataWriter*>::const_iterator it2;

View File

@ -9,51 +9,55 @@
class DataWriter; class DataWriter;
class DataExporter { class DataExporter
public: {
enum FieldType { public:
VECTOR, enum FieldType {
SIM VECTOR,
}; SIM
};
struct FileEntry { struct FileEntry {
std::string description; std::string description;
FieldType field; FieldType field;
int size; int size;
void* data; void* data;
void* data2; void* data2;
}; };
DataExporter(bool dynamicWriters = false); //! \brief Default constructor.
virtual ~DataExporter(); //! \param[in] dynWriters If \e true, delete the writers on destruction.
DataExporter(bool dynWriters = false) : m_delete(dynWriters), m_level(-1) {}
//! \brief The desctructor deletes the writers if \a dynWriters was \e true.
~DataExporter();
//! \brief Registers an entry for storage. //! \brief Registers an entry for storage.
//! param[in] name Name of entry //! param[in] name Name of entry
//! param[in] description Description of entry //! param[in] description Description of entry
//! param[in] Type of entry //! param[in] field Type of entry
//! param[in] size set to number of entries in an array, //! param[in] size Number of entries in an array,
// the time level to use for SIM //! the time level to use for SIM
bool registerField(const std::string& name, bool registerField(const std::string& name,
const std::string& description, const std::string& description,
FieldType field, size_t size=0); FieldType field, size_t size=0);
bool registerWriter(DataWriter* writer); bool registerWriter(DataWriter* writer);
bool setFieldValue(const std::string& name, void* data, void* data2=NULL); bool setFieldValue(const std::string& name, void* data, void* data2=NULL);
bool dumpTimeLevel(); bool dumpTimeLevel();
//! \brief Loads last time level with first registered writer by default. //! \brief Loads last time level with first registered writer by default.
bool loadTimeLevel(int level=-1, DataWriter* input=NULL); bool loadTimeLevel(int level=-1, DataWriter* input=NULL);
int getTimeLevel(); int getTimeLevel();
protected: protected:
int getWritersTimeLevel(); int getWritersTimeLevel() const;
std::map<std::string,FileEntry> m_entry; std::map<std::string,FileEntry> m_entry;
std::vector<DataWriter*> m_writers; std::vector<DataWriter*> m_writers;
bool deleteWriters; bool m_delete;
int m_level; int m_level;
}; };
@ -62,7 +66,7 @@ typedef std::pair<std::string,DataExporter::FileEntry> DataEntry;
class DataWriter class DataWriter
{ {
protected: protected:
DataWriter() {} DataWriter(const std::string& name);
public: public:
virtual ~DataWriter() {} virtual ~DataWriter() {}
@ -73,7 +77,13 @@ public:
virtual void closeFile(int level) = 0; virtual void closeFile(int level) = 0;
virtual void writeVector(int level, const DataEntry& entry) = 0; virtual void writeVector(int level, const DataEntry& entry) = 0;
virtual void readVector(int level, const DataEntry& entry) = 0; virtual bool readVector(int level, const DataEntry& entry) = 0;
virtual void writeSIM(int level, const DataEntry& entry) = 0; virtual void writeSIM(int level, const DataEntry& entry) = 0;
virtual void readSIM(int level, const DataEntry& entry) = 0; virtual bool readSIM(int level, const DataEntry& entry) = 0;
protected:
std::string m_name; //!< File name
int m_size; //!< Number of MPI nodes (processors)
int m_rank; //!< MPI rank (processor ID)
}; };

View File

@ -4,7 +4,6 @@
#include "SIMbase.h" #include "SIMbase.h"
#include "IntegrandBase.h" #include "IntegrandBase.h"
#include <sstream> #include <sstream>
#include <numeric>
#include <sys/stat.h> #include <sys/stat.h>
#ifdef HAS_HDF5 #ifdef HAS_HDF5
@ -16,30 +15,23 @@
#endif #endif
HDF5Writer::HDF5Writer (const std::string& name) : m_hdf5(name+".hdf5") HDF5Writer::HDF5Writer (const std::string& name, bool append)
: DataWriter(name+".hdf5")
{ {
#ifdef HAS_HDF5 #ifdef HAS_HDF5
struct stat temp; struct stat temp;
// file already exists - open and find the next group // file already exists - open and find the next group
if (stat(m_hdf5.c_str(),&temp) == 0) if (append && stat(m_name.c_str(),&temp) == 0)
m_flag = H5F_ACC_RDWR; m_flag = H5F_ACC_RDWR;
else else
m_flag = H5F_ACC_TRUNC; m_flag = H5F_ACC_TRUNC;
#endif #endif
#ifdef PARALLEL_PETSC
MPI_Comm_rank(MPI_COMM_WORLD,&m_rank);
MPI_Comm_size(MPI_COMM_WORLD,&m_size);
#else
m_rank = 0;
#endif
} }
HDF5Writer::~HDF5Writer()
{
}
int HDF5Writer::getLastTimeLevel() int HDF5Writer::getLastTimeLevel()
{ {
int result = 0;
#ifdef HAS_HDF5 #ifdef HAS_HDF5
if (m_flag == H5F_ACC_TRUNC) if (m_flag == H5F_ACC_TRUNC)
return -1; return -1;
@ -47,12 +39,11 @@ int HDF5Writer::getLastTimeLevel()
hid_t acc_tpl = H5P_DEFAULT; hid_t acc_tpl = H5P_DEFAULT;
#ifdef PARALLEL_PETSC #ifdef PARALLEL_PETSC
MPI_Info info = MPI_INFO_NULL; MPI_Info info = MPI_INFO_NULL;
acc_tpl = H5Pcreate (H5P_FILE_ACCESS); acc_tpl = H5Pcreate(H5P_FILE_ACCESS);
H5Pset_fapl_mpio(acc_tpl, MPI_COMM_WORLD, info); H5Pset_fapl_mpio(acc_tpl, MPI_COMM_WORLD, info);
#endif #endif
m_file = H5Fopen(m_hdf5.c_str(),m_flag,acc_tpl); m_file = H5Fopen(m_name.c_str(),m_flag,acc_tpl);
int result=0;
while (1) { while (1) {
std::stringstream str; std::stringstream str;
str << '/' << result; str << '/' << result;
@ -61,11 +52,8 @@ int HDF5Writer::getLastTimeLevel()
result++; result++;
} }
H5Fclose(m_file); H5Fclose(m_file);
return result-1;
#else
return -1;
#endif #endif
return result-1;
} }
void HDF5Writer::openFile(int level) void HDF5Writer::openFile(int level)
@ -78,9 +66,9 @@ void HDF5Writer::openFile(int level)
H5Pset_fapl_mpio(acc_tpl, MPI_COMM_WORLD, info); H5Pset_fapl_mpio(acc_tpl, MPI_COMM_WORLD, info);
#endif #endif
if (m_flag == H5F_ACC_TRUNC) if (m_flag == H5F_ACC_TRUNC)
m_file = H5Fcreate(m_hdf5.c_str(),m_flag,H5P_DEFAULT,acc_tpl); m_file = H5Fcreate(m_name.c_str(),m_flag,H5P_DEFAULT,acc_tpl);
else else
m_file = H5Fopen(m_hdf5.c_str(),m_flag,acc_tpl); m_file = H5Fopen(m_name.c_str(),m_flag,acc_tpl);
std::stringstream str; std::stringstream str;
str << '/' << level; str << '/' << level;
@ -153,9 +141,10 @@ void HDF5Writer::writeArray(int group, const std::string& name,
#endif #endif
} }
void HDF5Writer::readVector(int level, const DataEntry& entry) bool HDF5Writer::readVector(int level, const DataEntry& entry)
{ {
// readArray(level,entry.first,entry.second.size,entry.second.data); // readArray(level,entry.first,entry.second.size,entry.second.data);
return true;
} }
void HDF5Writer::writeVector(int level, const DataEntry& entry) void HDF5Writer::writeVector(int level, const DataEntry& entry)
@ -163,14 +152,15 @@ void HDF5Writer::writeVector(int level, const DataEntry& entry)
writeArray(level,entry.first,entry.second.size,entry.second.data); writeArray(level,entry.first,entry.second.size,entry.second.data);
} }
void HDF5Writer::readSIM(int level, const DataEntry& entry) bool HDF5Writer::readSIM(int level, const DataEntry& entry)
{ {
bool ok = true;
#ifdef HAS_HDF5 #ifdef HAS_HDF5
SIMbase* sim = static_cast<SIMbase*>(entry.second.data); SIMbase* sim = static_cast<SIMbase*>(entry.second.data);
Vector* sol = static_cast<Vector*>(entry.second.data2); Vector* sol = static_cast<Vector*>(entry.second.data2);
if (!sol) return; if (!sol) return false;
for (int i = 0; i < sim->getNoPatches(); ++i) { for (int i = 0; i < sim->getNoPatches() && ok; ++i) {
std::stringstream str; std::stringstream str;
str << level; str << level;
str << '/'; str << '/';
@ -180,12 +170,42 @@ void HDF5Writer::readSIM(int level, const DataEntry& entry)
if (loc > 0) { if (loc > 0) {
double* tmp = NULL; int siz = 0; double* tmp = NULL; int siz = 0;
readArray(group2,entry.first,siz,tmp); readArray(group2,entry.first,siz,tmp);
sim->injectPatchSolution(*sol,Vector(tmp,siz),loc-1,entry.second.size); ok = sim->injectPatchSolution(*sol,Vector(tmp,siz),
loc-1,entry.second.size);
delete[] tmp; delete[] tmp;
} }
H5Gclose(group2); H5Gclose(group2);
} }
#endif #endif
return ok;
}
bool HDF5Writer::readField(int level, const std::string& name,
Vector& vec, SIMbase* sim, int components)
{
bool ok = true;
openFile(level);
#ifdef HAS_HDF5
vec.resize(sim->getNoNodes()*components);
for (int i = 0; i < sim->getNoPatches() && ok; ++i) {
std::stringstream str;
str << level;
str << '/';
str << i+1;
hid_t group2 = H5Gopen2(m_file,str.str().c_str(),H5P_DEFAULT);
int loc = sim->getLocalPatchIndex(i+1);
if (loc > 0) {
double* tmp = NULL; int siz = 0;
readArray(group2,name,siz,tmp);
ok = sim->injectPatchSolution(vec,Vector(tmp,siz),
loc-1,components);
delete[] tmp;
}
H5Gclose(group2);
}
#endif
closeFile(level);
return ok;
} }
void HDF5Writer::writeSIM(int level, const DataEntry& entry) void HDF5Writer::writeSIM(int level, const DataEntry& entry)
@ -208,17 +228,29 @@ void HDF5Writer::writeSIM(int level, const DataEntry& entry)
group2 = H5Gcreate2(m_file,str.str().c_str(),0,H5P_DEFAULT,H5P_DEFAULT); group2 = H5Gcreate2(m_file,str.str().c_str(),0,H5P_DEFAULT,H5P_DEFAULT);
int loc = sim->getLocalPatchIndex(i+1); int loc = sim->getLocalPatchIndex(i+1);
if (loc > 0) // we own the patch if (loc > 0) // we own the patch
{
sim->extractPatchSolution(*sol,loc-1); sim->extractPatchSolution(*sol,loc-1);
if (entry.second.size == -1) { Vector& psol = const_cast<Integrand*>(prob)->getSolution();
Matrix field; writeArray(group2,entry.first,psol.size(),psol.ptr());
if (loc > 0) // TODO: For mixed methods we need to output each primary field
sim->evalSecondarySolution(field,loc-1); // TODO: The above is sufficient for simulation restarts.
for (size_t j = 0; j < prob->getNoFields(2); ++j) // TODO: For mixed methods we need to output each primary field
writeArray(group2,prob->getField2Name(j),field.cols(), // TODO: separately in addition, with reference to correct spline basis.
field.getRow(j+1).ptr()); if (entry.second.size == -1) {
Matrix field;
sim->evalSecondarySolution(field,loc-1);
for (size_t j = 0; j < prob->getNoFields(2); ++j)
writeArray(group2,prob->getField2Name(j),field.cols(),
field.getRow(j+1).ptr());
}
}
else // must write empty dummy records for the other patches
{
double dummy;
writeArray(group2,entry.first,0,&dummy);
for (size_t j = 0; j < prob->getNoFields(2); ++j)
writeArray(group2,prob->getField2Name(j),0,&dummy);
} }
Vector& psol = const_cast<Integrand*>(prob)->getSolution();
writeArray(group2, entry.first, loc > 0 ? psol.size() : 0, psol.ptr());
H5Gclose(group2); H5Gclose(group2);
} }
#endif #endif
@ -226,15 +258,15 @@ void HDF5Writer::writeSIM(int level, const DataEntry& entry)
bool HDF5Writer::checkGroupExistence(int parent, const char* path) bool HDF5Writer::checkGroupExistence(int parent, const char* path)
{ {
bool result = false;
#ifdef HAS_HDF5 #ifdef HAS_HDF5
// turn off errors to avoid cout spew // turn off errors to avoid cout spew
herr_t (*old_func)(void*); herr_t (*old_func)(void*);
void* old_client_data; void* old_client_data;
H5Eget_auto(&old_func,&old_client_data); H5Eget_auto(&old_func,&old_client_data);
H5Eset_auto(NULL,NULL); H5Eset_auto(NULL,NULL);
bool result =H5Gget_objinfo((hid_t)parent,path,0,NULL) == 0; result = H5Gget_objinfo((hid_t)parent,path,0,NULL) == 0;
H5Eset_auto(old_func,old_client_data); H5Eset_auto(old_func,old_client_data);
return result;
#endif #endif
return false; return result;
} }

View File

@ -3,35 +3,37 @@
#pragma once #pragma once
#include "DataExporter.h" #include "DataExporter.h"
#include "MatVec.h"
class SIMbase;
class HDF5Writer : public DataWriter { class HDF5Writer : public DataWriter
public: {
public:
HDF5Writer(const std::string& name, bool append = false);
virtual ~HDF5Writer() {}
HDF5Writer(const std::string& name); virtual int getLastTimeLevel();
virtual ~HDF5Writer();
int getLastTimeLevel(); virtual void openFile(int level);
virtual void closeFile(int level);
void openFile(int level); virtual void writeVector(int level, const DataEntry& entry);
void closeFile(int level); virtual bool readVector(int level, const DataEntry& entry);
virtual void writeSIM(int level, const DataEntry& entry);
virtual bool readSIM(int level, const DataEntry& entry);
void writeVector(int level, const DataEntry& entry); bool readField(int level, const std::string& name,
void readVector(int level, const DataEntry& entry); Vector& vec, SIMbase* sim, int components);
void writeSIM(int level, const DataEntry& entry);
void readSIM(int level, const DataEntry& entry);
protected: protected:
void writeArray(int group, const std::string& name, void writeArray(int group, const std::string& name,
int len, void* data); int len, void* data);
void readArray(int group, const std::string& name, void readArray(int group, const std::string& name,
int& len, double*& data); int& len, double*& data);
bool checkGroupExistence(int parent, const char* group); bool checkGroupExistence(int parent, const char* group);
std::string m_hdf5; int m_file;
int m_file; unsigned int m_flag;
unsigned int m_flag;
int m_rank; // MPI rank
int m_size; // number of MPI nodes
}; };

View File

@ -23,10 +23,10 @@
namespace utl namespace utl
{ {
//! \brief Parses a character string into an integer or an integer range. //! \brief Parses a character string into an integer or an integer range.
//! \param values The integer value(s) is(are) appended to this vector //! \param values The integer value(s) is/are appended to this vector
//! \param argv Character string with integer data //! \param[in] argv Character string with integer data
//! //!
//! \details An integer range is recognised through the syntax <i>:<j>. //! \details An integer range is recognised through the syntax \a i:j.
void parseIntegers(std::vector<int>& values, const char* argv); void parseIntegers(std::vector<int>& values, const char* argv);
//! \brief Reads one line, ignoring comment lines and leading blanks. //! \brief Reads one line, ignoring comment lines and leading blanks.

View File

@ -3,31 +3,23 @@
#include "XMLWriter.h" #include "XMLWriter.h"
#include "SIMbase.h" #include "SIMbase.h"
#include "IntegrandBase.h" #include "IntegrandBase.h"
#include "StringUtils.h"
#ifdef PARALLEL_PETSC #include "tinyxml.h"
#include <mpi.h> #include <fstream>
#endif #include <cstdio>
XMLWriter::XMLWriter(const std::string& name) : m_xml(name+".xml") XMLWriter::XMLWriter(const std::string& name) : DataWriter(name+".xml")
{ {
m_doc = NULL; m_doc = NULL;
#ifdef PARALLEL_PETSC m_node = NULL;
MPI_Comm_rank(MPI_COMM_WORLD,&m_rank);
MPI_Comm_size(MPI_COMM_WORLD,&m_size);
#else
m_rank = 0;
#endif
} }
XMLWriter::~XMLWriter()
{
}
int XMLWriter::getLastTimeLevel() int XMLWriter::getLastTimeLevel()
{ {
int result=-1; int result=-1;
TiXmlDocument doc(m_xml.c_str()); TiXmlDocument doc(m_name.c_str());
doc.LoadFile(); doc.LoadFile();
TiXmlHandle handle(&doc); TiXmlHandle handle(&doc);
TiXmlElement* levels = handle.FirstChild("info"). TiXmlElement* levels = handle.FirstChild("info").
@ -38,10 +30,12 @@ int XMLWriter::getLastTimeLevel()
return result; return result;
} }
void XMLWriter::openFile(int level) void XMLWriter::openFile(int level)
{ {
if (m_rank != 0) if (m_rank != 0)
return; return;
m_doc = new TiXmlDocument; m_doc = new TiXmlDocument;
TiXmlElement element("info"); TiXmlElement element("info");
m_node = m_doc->InsertEndChild(element); m_node = m_doc->InsertEndChild(element);
@ -59,13 +53,37 @@ void XMLWriter::closeFile(int level)
TiXmlText value(temp); TiXmlText value(temp);
pNewNode->InsertEndChild(value); pNewNode->InsertEndChild(value);
m_doc->SaveFile(m_xml); m_doc->SaveFile(m_name);
delete m_doc; delete m_doc;
m_doc = NULL; m_doc = NULL;
} }
void XMLWriter::readVector(int level, const DataEntry& entry)
void XMLWriter::readInfo()
{ {
TiXmlDocument doc(m_name);
doc.LoadFile();
TiXmlHandle handle(&doc);
TiXmlElement* elem = handle.FirstChild("info").
FirstChild("entry").ToElement();
while (elem) {
if (strcasecmp(elem->Attribute("type"),"field") == 0) {
Entry entry;
entry.name = elem->Attribute("name");
entry.description = elem->Attribute("description");
entry.patches = atoi(elem->Attribute("patches"));
entry.components = atoi(elem->Attribute("components"));
entry.patchfile = elem->Attribute("patchfile");
m_entry.push_back(entry);
}
elem = elem->NextSiblingElement("entry");
}
}
bool XMLWriter::readVector(int level, const DataEntry& entry)
{
return true;
} }
void XMLWriter::writeVector(int level, const DataEntry& entry) void XMLWriter::writeVector(int level, const DataEntry& entry)
@ -81,8 +99,10 @@ void XMLWriter::writeVector(int level, const DataEntry& entry)
m_node->InsertEndChild(element); m_node->InsertEndChild(element);
} }
void XMLWriter::readSIM(int level, const DataEntry& entry)
bool XMLWriter::readSIM(int level, const DataEntry& entry)
{ {
return true;
} }
void XMLWriter::writeSIM(int level, const DataEntry& entry) void XMLWriter::writeSIM(int level, const DataEntry& entry)
@ -90,25 +110,38 @@ void XMLWriter::writeSIM(int level, const DataEntry& entry)
if (m_rank != 0) if (m_rank != 0)
return; return;
// Assume that all fields use the same basis as the geometry.
// TODO: Not true for mixed methods, fix later...
std::string g2file(m_name);
std::ofstream os(replaceAll(g2file,".xml",".g2").c_str());
static_cast<SIMbase*>(entry.second.data)->dumpGeometry(os);
int nPatch = static_cast<SIMbase*>(entry.second.data)->getNoPatches(); int nPatch = static_cast<SIMbase*>(entry.second.data)->getNoPatches();
const Integrand* prb = static_cast<SIMbase*>(entry.second.data)->getProblem(); const Integrand* prb = static_cast<SIMbase*>(entry.second.data)->getProblem();
// primary solution // primary solution
addField(entry.first,entry.second.description,"field",nPatch); addField(entry.first,entry.second.description,"field",g2file,
prb->getNoFields(1),nPatch);
// secondary solutions // secondary solutions
if (entry.second.size == -1) if (entry.second.size == -1)
for (size_t j = 0; j < prb->getNoFields(2); j++) for (size_t j = 0; j < prb->getNoFields(2); j++)
addField(prb->getField2Name(j),"secondary","field",nPatch); addField(prb->getField2Name(j),"secondary","field",g2file,1,nPatch);
} }
void XMLWriter::addField(const std::string& name, const std::string& description,
const std::string& type, int patches) void XMLWriter::addField (const std::string& name,
const std::string& description,
const std::string& type,
const std::string& patchfile,
int components, int patches)
{ {
TiXmlElement element("entry"); TiXmlElement element("entry");
element.SetAttribute("name",name.c_str()); element.SetAttribute("name",name.c_str());
element.SetAttribute("description",description.c_str()); element.SetAttribute("description",description.c_str());
element.SetAttribute("type",type.c_str()); element.SetAttribute("type",type.c_str());
element.SetAttribute("patches",patches); element.SetAttribute("patches",patches);
element.SetAttribute("components",components);
element.SetAttribute("patchfile",patchfile.c_str());
m_node->InsertEndChild(element); m_node->InsertEndChild(element);
} }

View File

@ -3,32 +3,45 @@
#pragma once #pragma once
#include "DataExporter.h" #include "DataExporter.h"
#include "tinyxml.h"
class TiXmlDocument;
class TiXmlNode;
class XMLWriter : public DataWriter { class XMLWriter : public DataWriter
public: {
XMLWriter(const std::string& name); public:
virtual ~XMLWriter(); struct Entry {
std::string name;
std::string description;
std::string patchfile;
int patches;
int components;
};
int getLastTimeLevel(); XMLWriter(const std::string& name);
virtual ~XMLWriter() {}
void openFile(int level); virtual int getLastTimeLevel();
void closeFile(int level);
void writeVector(int level, const DataEntry& entry); void readInfo();
void readVector(int level, const DataEntry& entry); const std::vector<Entry>& getEntries() const { return m_entry; }
void writeSIM(int level, const DataEntry& entry);
void readSIM(int level, const DataEntry& entry);
protected: virtual void openFile(int level);
void addField(const std::string& name, const std::string& description, virtual void closeFile(int level);
const std::string& type, int patches);
std::string m_xml;
int m_rank; // MPI rank virtual void writeVector(int level, const DataEntry& entry);
int m_size; // number of MPI nodes virtual bool readVector(int level, const DataEntry& entry);
virtual void writeSIM(int level, const DataEntry& entry);
virtual bool readSIM(int level, const DataEntry& entry);
TiXmlDocument* m_doc; protected:
TiXmlNode* m_node; void addField(const std::string& name, const std::string& description,
const std::string& type, const std::string& patchfile,
int components, int patches);
std::vector<Entry> m_entry;
TiXmlDocument* m_doc;
TiXmlNode* m_node;
}; };