diff --git a/AMDiS/src/DOFAdmin.cc b/AMDiS/src/DOFAdmin.cc index 6b6ec752bdae3c8d7f9869b29877a8b1404ce4c3..e92bb6060deb51dba4a68b6324252a27bc1c360d 100755 --- a/AMDiS/src/DOFAdmin.cc +++ b/AMDiS/src/DOFAdmin.cc @@ -32,6 +32,9 @@ namespace AMDiS { init(); } + DOFAdmin::~DOFAdmin() + {} + void DOFAdmin::init() { firstHole = 0; @@ -336,10 +339,6 @@ namespace AMDiS { nr0DOF[i] = v; } - DOFAdmin::~DOFAdmin() - { - } - int DOFAdmin::calcMemoryUsage() { return sizeof(DOFAdmin); diff --git a/AMDiS/src/DOFVector.hh b/AMDiS/src/DOFVector.hh index 8fd6c54acdbd6535b29f5c33be2a26ade9ae01c3..89a176ed8cdf4ab18caaf5049089ebb7b89765fa 100644 --- a/AMDiS/src/DOFVector.hh +++ b/AMDiS/src/DOFVector.hh @@ -74,7 +74,6 @@ namespace AMDiS { if (feSpace && feSpace->getAdmin()) { (feSpace->getAdmin())->addDOFIndexed(this); } - this->boundaryManager = NEW BoundaryManager(f); } diff --git a/AMDiS/src/FiniteElemSpace.cc b/AMDiS/src/FiniteElemSpace.cc index b3fc47da9a81ad2e83619761d123197efd83dc3f..03d596890aa68471c7dd8332d1fd6dc2cd1a5705 100644 --- a/AMDiS/src/FiniteElemSpace.cc +++ b/AMDiS/src/FiniteElemSpace.cc @@ -11,7 +11,8 @@ namespace AMDiS { FiniteElemSpace::FiniteElemSpace(DOFAdmin* admin_, const BasisFunction* bas_fcts_, - Mesh* aMesh, const std::string& aString) + Mesh* aMesh, + const std::string& aString) : name(aString), admin(admin_), basFcts(bas_fcts_), @@ -47,12 +48,10 @@ namespace AMDiS { } FiniteElemSpace::FiniteElemSpace() - { - } + {} FiniteElemSpace::~FiniteElemSpace() - { - } + {} FiniteElemSpace& FiniteElemSpace::operator=(const FiniteElemSpace& feSpace) { diff --git a/AMDiS/src/FiniteElemSpace.h b/AMDiS/src/FiniteElemSpace.h index 7cf8c56c7e27bd38da1e70fd06b87ad564c1fa99..59982e0ef475a524514d726ff56e35ca28e22363 100644 --- a/AMDiS/src/FiniteElemSpace.h +++ b/AMDiS/src/FiniteElemSpace.h @@ -71,37 +71,32 @@ namespace AMDiS { Mesh *mesh, const std::string& name_ = ""); - /** \brief - * destructor - */ + /// Destructor. ~FiniteElemSpace(); FiniteElemSpace& operator=(const FiniteElemSpace& feSpace); - /** \brief - * Returns \ref name - */ + /// Returns \ref name. inline std::string getName() const { return name; } - /** \brief - * Returns \ref admin - */ + /// Returns \ref admin. inline DOFAdmin* getAdmin() const { return admin; } - /** \brief - * Returns \ref basFcts - */ + /// Set a new DOF admin. + inline void setAdmin(DOFAdmin* a) { + admin = a; + } + + /// Returns \ref basFcts inline const BasisFunction* getBasisFcts() const { return basFcts; } - /** \brief - * Returns \ref mesh - */ + /// Returns \ref mesh inline Mesh* getMesh() const { return mesh; } diff --git a/AMDiS/src/Serializer.h b/AMDiS/src/Serializer.h index 0ccdb08fdbb7b4a6263de7bc91d92e4c34276035..49840bec49095211544fb80de53e7558a1ee01fa 100644 --- a/AMDiS/src/Serializer.h +++ b/AMDiS/src/Serializer.h @@ -41,15 +41,15 @@ namespace AMDiS { problem_(problem), tsModulo_(1), timestepNumber_(-1) - { + { GET_PARAMETER(0, problem_->getName() + "->output->serialization filename", &name_); GET_PARAMETER(0, problem_->getName() + "->output->write every i-th timestep", "%d", &tsModulo_); TEST_EXIT(name_ != "")("no filename\n"); - }; + } - virtual ~Serializer() {}; + virtual ~Serializer() {} virtual void writeFiles(AdaptInfo *adaptInfo, bool force, @@ -73,13 +73,13 @@ namespace AMDiS { out.close(); MSG("problem serialized to %s \n", name_.c_str()); - }; + } - void writeDelayedFiles() {}; + void writeDelayedFiles() {} bool isWritingDelayed() { return false; - }; + } protected: /** \brief @@ -108,28 +108,27 @@ namespace AMDiS { public: static void serializeInt(std::ostream &out, int* ptrInt) { out.write(reinterpret_cast<const char*>(ptrInt), sizeof(int)); - }; + } static void serializeDouble(std::ostream &out, double* ptrInt) { out.write(reinterpret_cast<const char*>(ptrInt), sizeof(double)); - }; + } static void serializeBool(std::ostream &out, bool* ptrBool) { out.write(reinterpret_cast<const char*>(ptrBool), sizeof(bool)); } - static void deserializeInt(std::istream &in, int* ptrInt) { in.read(reinterpret_cast<char*>(ptrInt), sizeof(int)); - }; + } static void deserializeDouble(std::istream &in, double* ptrInt) { in.read(reinterpret_cast<char*>(ptrInt), sizeof(double)); - }; + } static void deserializeBool(std::istream &in, bool* ptrBool) { in.read(reinterpret_cast<char*>(ptrBool), sizeof(bool)); - }; + } }; } diff --git a/AMDiS/src/SolutionDataStorage.h b/AMDiS/src/SolutionDataStorage.h index 48c1fb640293302326aaa306f9f05ea94a9f1d8c..8fab0084754b82c8f83d4cbff9727b0bd02adca2 100644 --- a/AMDiS/src/SolutionDataStorage.h +++ b/AMDiS/src/SolutionDataStorage.h @@ -2,6 +2,7 @@ #define AMDIS_SOLUTION_DATA_STORAGE_H #include <iostream> +#include <fstream> #include <vector> #include <map> #include "DOFVector.h" @@ -23,107 +24,320 @@ namespace AMDiS { }; - class DataContainer - { - public: - }; + /** \brief + * Class to store solution data for one timestep. + * + * Within this class, the solution data for one timestep is stored. The + * type of the solution data is the typename of the class, i.e., either + * DOFVector or SystemVector. The class is resonsible for serialization + * and deserialization of the solution. + * + * The class is used only from class \ref SolutionDataStorage, and must + * not be used by the user in other context. + */ template<typename T> - class SolutionDataStorage + class SolutionData { public: + + /** \brief + * The constructor requires already the data. So no empty data class + * can be created. + */ + SolutionData(T* sol, + typename SolutionHelper<T>::type fes, + double ts, + int i) + : solution(sol), + feSpace(fes), + timestamp(ts), + id(i), + serialized(false), + filename("") + {} + /** \brief - * + * The destructor either deletes the data files or deletes the pointers + * to the data. */ - SolutionDataStorage(std::string name); + ~SolutionData() + { + if (!serialized) { + DELETE solution; + deleteFeSpace(feSpace); + } + } + + /// Serialize the data to a file. + void serialize(std::string fn) + { + std::ofstream out(fn.c_str()); + serializeFeSpace(out, feSpace); + solution->serialize(out); + out.close(); + + serialized = true; + filename = fn; + + DELETE solution; + deleteFeSpace(feSpace); + } + + /// Deserialize the data from file. + void deserialize() + { + std::string feName = ""; + int dim = 0; + int degree = 0; + + std::ifstream in(filename.c_str()); + deserializeFeSpace(in, feSpace); + solution = new T("", feSpace, 0); + solution->deserialize(in); + in.close(); + + serialized = false; + filename = ""; + } /** \brief + * Returns the data. In the case the data was serialized to the disk, + * it will be first deserialized from the corresponding file. + */ + void getData(T** ptrSolution, double *ptrTimestamp) + { + if (serialized) { + deserialize(); + } + + *ptrSolution = solution; + *ptrTimestamp = timestamp; + } + + /// Returns \ref serialized. + bool isSerialized() { + return serialized; + } + + protected: + /// Serialize a fe space to a file. + void serializeFeSpace(std::ofstream &out, FiniteElemSpace* fe) + { + // Write the mesh to file. + out << fe->getMesh()->getName() << "\n"; + + int dim = fe->getMesh()->getDim(); + out.write(reinterpret_cast<const char*>(&dim), sizeof(int)); + + fe->getMesh()->serialize(out); + + // Then, write all other fe space data to file. + dim = fe->getBasisFcts()->getDim(); + int degree = fe->getBasisFcts()->getDegree(); + out << ((fe->getName() != "") ? fe->getName() : "noname") << "\n"; + out.write(reinterpret_cast<const char*>(&dim), sizeof(int)); + out.write(reinterpret_cast<const char*>(°ree), sizeof(int)); + } + + /** \brief + * Serialize a vector of fe spaces to a file. * + * Takes special care about multiple fe space pointers, pointing to the + * same fe space. In this case, only the first fe space is serialized + * completely. */ - ~SolutionDataStorage(); + void serializeFeSpace(std::ofstream &out, std::vector<FiniteElemSpace*>& fe) + { + int size = fe.size(); + out.write(reinterpret_cast<const char*>(&size), sizeof(int)); + + for (int i = 0; i < size; i++) { + // Check, if the pointer points to an fe space serialized before. + int found = -1; + for (int j = 0; j < i; j++) { + if (fe[j] == fe[i]) { + found = j; + break; + } + } + + out.write(reinterpret_cast<const char*>(&found), sizeof(int)); + // Only in case this fe space was not serialized before, write it to the file. + if (found == -1) { + serializeFeSpace(out, fe[i]); + } + } + } + void deserializeFeSpace(std::ifstream &in, FiniteElemSpace** fe) + { + std::string name = ""; + int dim = 0; + int degree = 0; + + in >> name; + in.get(); + in.read(reinterpret_cast<char*>(&dim), sizeof(int)); + Mesh *mesh = new Mesh(name, dim); + mesh->deserialize(in); + + in >> name; + in.get(); + in.read(reinterpret_cast<char*>(&dim), sizeof(int)); + in.read(reinterpret_cast<char*>(°ree), sizeof(int)); + + *fe = FiniteElemSpace::provideFESpace(NULL, + Lagrange::getLagrange(dim, degree), + mesh, + name); + (*fe)->setAdmin(const_cast<DOFAdmin*>(&(mesh->getDOFAdmin(0)))); + } + + void deserializeFeSpace(std::ifstream &in, std::vector<FiniteElemSpace*>& fe) + { + int size; + in.read(reinterpret_cast<char*>(&size), sizeof(int)); + + fe.resize(size); + for (int i = 0; i < size; i++) { + int found; + in.read(reinterpret_cast<char*>(&found), sizeof(int)); + if (found == -1) { + deserializeFeSpace(in, &(fe[i])); + } else { + fe[i] = fe[found]; + } + } + } + + /// Remove one fe space from memory. + void deleteFeSpace(FiniteElemSpace* fe) + { + if (fe) { + DELETE fe->getMesh(); + DELETE fe; + fe = NULL; + } + } + + /// Remove a vector of fe spaces from memory. + void deleteFeSpace(std::vector<FiniteElemSpace*>& fe) + { + // Stores all pointers to fe spaces, that were deleted. This should + // avoid double deletion of pointer. + std::map<FiniteElemSpace*, bool> deletedFeSpaces; + + for (int i = 0; i < static_cast<int>(fe.size()); i++) { + if (deletedFeSpaces.find(fe[i]) == deletedFeSpaces.end()) { + deleteFeSpace(fe[i]); + deletedFeSpaces[fe[i]] = true; + } + } + + fe.clear(); + } + + public: /** \brief - * Set one fix FE Space. All solutions are defined only on the given FE Space. + * Here, all the solutions (i.e. either DOFVectors or SystemVectors) + * are stored. */ - void setFixFESpace(typename SolutionHelper<T>::type feSpace); + T* solution; /** \brief - * + * Stores to every solution its FE Space. If \ref fixedFESpace is set + * to true, only one entry exists. This is than the FE Space for all + * solutions. */ - void push(T *solution, - double timestamp); + typename SolutionHelper<T>::type feSpace; /** \brief - * + * Stores to every solutions the timestamp at which the solution was + * created in the adaption loop. + */ + double timestamp; + + /** \brief + * If true, the solution data is serialied to disk and the pointers + * are not valid. + */ + bool serialized; + + /// If solution data is serialied, here the corresponding filename is stored. + std::string filename; + + int id; + }; + + + + /** \brief + * Storage for solution datas with optimization process. + * + * This class may be used to store solutions within an optimization process. + * Within the forward step, solutions are stored within this data storage, and + * are then used within the backward step. The storage supports serialization + * and deserialization of solutions (and the corresponding fe spaces) to save + * memory. + * + * The template typename must be the type of the solution data to be stored, i.e, + * either DOFVector<double> or SystemVector. + */ + template<typename T> + class SolutionDataStorage + { + public: + /** \brief + * Constructor. The parameter is a string that will be used to search for + * parameters of the storage within the init file. */ - bool pop(T **solution, - double *timestep); + SolutionDataStorage(std::string name); /** \brief - * Deletes all pointers and empties all internal vectors. + * Destructor. Deletes all stored solutions and deletes all serialized files. */ + ~SolutionDataStorage(); + + /// Add a solution and its timestamp to the storage. + void push(T *solution, double timestamp); + + /// Get solution data from storage. Returns true, if solution data is valid. + bool pop(T **solution, double *timestep); + + /// Delete all pointers and empties all internal vectors. void clear(); - /** \brief - * Returns for a given solution number the corresponding fe Space. If the + * Return for a given solution number the corresponding fe Space. If the * the fe Space is fixed, the fe Space for all solutions is stored at * position 0. */ typename SolutionHelper<T>::type getFeSpace(int i = 0) { - return feSpaces[i]; + return solutions[i]->feSpace; } - /** \brief - * - */ + /// Returns \ref poped. bool isPoped() { return poped; } - /** \brief - * - */ + /// Add a new container to the storage. void addContainer(std::string name); - /** \brief - * - */ + /// Add value to a container. void push(std::string name, WorldVector<double> value); - /** \brief - * - */ + /// Get value from a container. void pop(std::string name, WorldVector<double> &value); - /** \brief - * - */ + /// Reset, , a container/ void reset(std::string name); - /** \brief - * - */ + /// Clear, i.e. delete all values, a container. void clear(std::string name); protected: - /** \brief - * Deletes the fe space and all it content, i.e., also the dof admin, - * mesh, etc. - */ - void deleteFeSpace(FiniteElemSpace* feSpace); - - /** \brief - * Deletes a list of fe spaces. - */ - void deleteFeSpace(std::vector<FiniteElemSpace*> feSpaces) { - for (int i = 0; i < static_cast<int>(feSpaces.size()); i++) { - deleteFeSpace(feSpaces[i]); - } - - feSpaces.clear(); - } - /** \brief * */ @@ -161,30 +375,6 @@ namespace AMDiS { */ std::string writeDirectory; - /** \brief - * If true, all solutions are defined only on one FE Space. - */ - bool fixedFESpace; - - /** \brief - * Here, all the solutions (i.e. either DOFVectors or SystemVectors) - * are stored. - */ - std::vector<T*> solutions; - - /** \brief - * Stores to every solution its FE Space. If \ref fixedFESpace is set - * to true, only one entry exists. This is than the FE Space for all - * solutions. - */ - std::vector< typename SolutionHelper<T>::type > feSpaces; - - /** \brief - * Stores to every solutions the timestamp at which the solution was - * created in the adaption loop. - */ - std::vector<double> timestamps; - /** \brief * Position of the latest valid solution. */ @@ -200,6 +390,12 @@ namespace AMDiS { */ int memoryUsage; + /** \brief + * Storage for the solutions, i.e., the DOFVector, the FESpace and the + * corresponding timestep. + */ + std::vector<SolutionData<T>* > solutions; + /** \brief * */ @@ -209,6 +405,8 @@ namespace AMDiS { * */ std::map<std::string, int> containersPos; + + int idcounter; }; } diff --git a/AMDiS/src/SolutionDataStorage.hh b/AMDiS/src/SolutionDataStorage.hh index 4e108a41f2994b6ee954a2d62bef71a4480eeaee..42afe93e08ea288c72f4734a2b99b1431bb69867 100644 --- a/AMDiS/src/SolutionDataStorage.hh +++ b/AMDiS/src/SolutionDataStorage.hh @@ -1,3 +1,6 @@ +#include <iostream> +#include <sstream> + namespace AMDiS { template<typename T> @@ -5,14 +8,12 @@ namespace AMDiS { : maxMemoryUsage(100), useDisk(true), writeDirectory(""), - fixedFESpace(false), lastPos(-1), poped(false), - memoryUsage(0) + memoryUsage(0), + idcounter(0) { - solutions.empty(); - feSpaces.empty(); - timestamps.empty(); + solutions.clear(); int tmp = 0; GET_PARAMETER(0, name + "->memory usage", "%d", &maxMemoryUsage); @@ -27,29 +28,12 @@ namespace AMDiS { clear(); } - template<typename T> - void SolutionDataStorage<T>::setFixFESpace(typename SolutionHelper<T>::type feSpace) - { - FUNCNAME("SolutionDataStorage::setFixFESpace()"); - - TEST_EXIT(solutions.size() == 0)("Cannot set FE Space, if solutions already stored!\n"); - - fixedFESpace = true; - feSpaces.push_back(feSpace); - - addMemoryUsage(feSpace); - } - template<typename T> void SolutionDataStorage<T>::push(T *solution, double timestamp) { FUNCNAME("SolutionDataStorage<T>::push()"); - if (fixedFESpace) { - ERROR_EXIT("Not yet\n"); - } - // If pop was the last operation, cleanup and reset the data storage. if (poped) { clear(); @@ -58,23 +42,46 @@ namespace AMDiS { std::vector<FiniteElemSpace*> feSpace(solution->getFESpaces().size()); for (int i = 0; i < feSpace.size(); i++) { - feSpace[i] = NEW FiniteElemSpace(); - *(feSpace[i]) = *(solution->getFESpace(i)); - memoryUsage += feSpace[i]->calcMemoryUsage(); + + int found = -1; + for (int j = 0; j < i; j++) { + if (solution->getFESpace(j) == solution->getFESpace(i)) { + found = j; + break; + } + } + + if (found == -1) { + feSpace[i] = NEW FiniteElemSpace(); + *(feSpace[i]) = *(solution->getFESpace(i)); + memoryUsage += feSpace[i]->calcMemoryUsage(); + } else { + feSpace[i] = feSpace[found]; + } } - - feSpaces.push_back(feSpace); - + SystemVector *vec = NEW SystemVector("tmp", feSpace, solution->getFESpaces().size()); vec->createNewDOFVectors("tmp"); vec->setCoarsenOperation(COARSE_INTERPOL); vec->interpol(solution, 1.0); memoryUsage += vec->calcMemoryUsage(); - solutions.push_back(vec); - timestamps.push_back(timestamp); + solutions.push_back(new SolutionData<T>(vec, feSpace, timestamp, idcounter++)); lastPos++; + + /* + + if (memoryUsage / (1024 * 1024) > maxMemoryUsage) { + for (int i = 0; i < solutions.size() - 1; i++) { + if (solutions[i]->isSerialized() == false) { + std::ostringstream oss; + oss << writeDirectory << "/solutiondata_" << i << ".ser"; + solutions[i]->serialize(oss.str()); + } + } + } + */ } template<typename T> @@ -85,8 +92,7 @@ namespace AMDiS { return false; } - *solution = solutions[lastPos]; - *timestamp = timestamps[lastPos]; + solutions[lastPos]->getData(solution, timestamp); lastPos--; poped = true; @@ -101,29 +107,12 @@ namespace AMDiS { DELETE solutions[i]; } - if (!fixedFESpace) { - for (int i = 0; i < static_cast<int>(feSpaces.size()); i++) { - deleteFeSpace(feSpaces[i]); - } - } - solutions.clear(); - feSpaces.clear(); - timestamps.clear(); lastPos = -1; memoryUsage = 0; } - template<typename T> - void SolutionDataStorage<T>::deleteFeSpace(FiniteElemSpace *feSpace) - { - if (feSpace) { - DELETE feSpace->getMesh(); - DELETE feSpace; - } - } - template<typename T> void SolutionDataStorage<T>::addContainer(std::string name) {