#include #include #include #include #include "Arh3Writer.h" #include "Mesh.h" #include "MeshStructure.h" #include "Traverse.h" #include "DOFVector.h" #include "../Arh3Reader.h" #include #include #include #include #ifdef HAVE_COMPRESSION #include #include #endif namespace AMDiS { namespace io { using namespace std; namespace Arh3Writer { namespace detail { void write(string filename, DOFVector* vec0, DOFVector* vec1, DOFVector* vec2, bool writeParallel, Cpsformat cps, string dataformat, bool writeMacro) { vector*> vecs(0); if (vec0 != NULL) vecs.push_back(vec0); if (vec1 != NULL) vecs.push_back(vec1); if (vec2 != NULL) vecs.push_back(vec2); write(filename, NULL, vecs, writeParallel, cps, dataformat, writeMacro); } void updateAnimationFile(AdaptInfo *adaptInfo, std::vector* arhAnimationFrames, bool createSubDir, int indexLength, int indexDecimals, std::string animationFilename) { FUNCNAME("updateAnimationFile()"); arhAnimationFrames->push_back(adaptInfo->getTime()); boost::iostreams::filtering_ostream file; { ofstream swapfile(animationFilename.c_str(), ios::out | ios::trunc | ios::binary); TEST_EXIT(swapfile.is_open()) ("Cannot open file %s for writing!\n", animationFilename.c_str()); swapfile.close(); } file.push(boost::iostreams::file_descriptor_sink(animationFilename, ios::trunc | ios::binary)); #ifdef HAVE_PARALLEL_DOMAIN_AMDIS string typeId = "tparh"; #else string typeId = "tarh"; #endif string baseDir = createSubDir ? "./data/" : "./"; uint32_t baseDirLen = baseDir.length(); int major = AMDiS::io::Arh3Reader::TARH_MAJOR; int minor = AMDiS::io::Arh3Reader::TARH_MINOR; typeId += '_' + boost::lexical_cast(major) + '.' + boost::lexical_cast(minor); if (typeId.length() <= 16) { // 16 is the Id size string rest(16 - typeId.length(), ' '); typeId.append(rest); } uint32_t indexLength_ = indexLength; uint32_t indexDecimals_ = indexDecimals; file.write(typeId.c_str(), 16); file.write(reinterpret_cast(&baseDirLen), 4); file.write(baseDir.c_str(), baseDirLen); file.write(reinterpret_cast(&indexLength_), 4); file.write(reinterpret_cast(&indexDecimals_), 4); for (size_t i = 0; i < arhAnimationFrames->size(); i++) file.write(reinterpret_cast(&arhAnimationFrames[i]), 8); } #ifdef HAVE_PARALLEL_DOMAIN_AMDIS void writeParallelFile(string filename, Mesh* mesh, bool createSubDir, bool writeMacro) { ofstream file; file.open(filename.c_str(), ios::out | ios::binary | ios::trunc); string typeId = "parh", macroFilename = "", perFilename = ""; string baseDir = createSubDir ? "./data/" : "./"; string macroData = "", periodicData = ""; uint32_t baseDirLen = baseDir.length(); Parameters::get(mesh->getName() + "->macro file name", macroFilename); Parameters::get(mesh->getName() + "->periodic file", perFilename); int major = AMDiS::io::Arh3Reader::PARH_MAJOR; int minor = AMDiS::io::Arh3Reader::PARH_MINOR; uint32_t nFiles = MPI::COMM_WORLD.Get_size(); uint32_t macroFile_nl = 0; map partitionMap = Parallel::MeshDistributor::globalMeshDistributor->getPartitionMap(); uint32_t nMacros = partitionMap.size(); typeId += '_' + boost::lexical_cast(major) + '.' + boost::lexical_cast(minor); if (typeId.length() <= 16) { // 16 is the Id size string rest(16 - typeId.length(), ' '); typeId.append(rest); } else ERROR_EXIT("Should not happen.\n"); file.write(typeId.c_str(), 16); file.write(reinterpret_cast(&baseDirLen), 4); file.write(baseDir.c_str(), baseDirLen); file.write(reinterpret_cast(&nFiles), 4); if (writeMacro && macroFilename.length()) { macroFile_nl = 13; readFileToString(macroFilename, macroData); if (perFilename.length()) { macroFile_nl = 27; readFileToString(perFilename, periodicData); } } file.write(reinterpret_cast(¯oFile_nl), 4); file.write(reinterpret_cast(&nMacros), 4); map::const_iterator it = partitionMap.begin(); uint32_t rank = 0; for (;it != partitionMap.end(); it++) { rank = it->second; file.write(reinterpret_cast(&rank), 4); } // write macro and periodic file if (writeMacro && macroFilename.length()) { file.seekp(0, ios_base::end); long macroPos = file.tellp(), perPos = 0; file.write(macroData.c_str(), macroData.length()); if (perFilename.length()) { perPos = file.tellp(); file.write(periodicData.c_str(), periodicData.length()); } // update macroFile_nl int offset = 16 + //typeId 4 + //baseDirLen baseDirLen + //baseDir 4 + //nFiles 4; //macroFile_nl file.seekp(offset); file << "this:" << macroPos; if (perFilename.length()) file << ";this:" << perPos; } } #endif void write(string filename, Mesh* mesh, vector*> vecs, bool writeParallel, Cpsformat cps, string dataformat, bool writeMacro) { FUNCNAME("Arh3Writer::detail::write()"); map::const_iterator it = dataformatMap.find(dataformat); TEST_EXIT(it != dataformatMap.end())("Wrong data format.\n"); std::set meshset; std::set nameset; if (mesh) meshset.insert(mesh); for (size_t i = 0; i < vecs.size(); i++) { TEST_EXIT(vecs[i] != NULL)("Vecs[%i] is NULL. Please check.\n", i); meshset.insert(vecs[i]->getFeSpace()->getMesh()); nameset.insert(vecs[i]->getName()); } if (meshset.size() == 0) { WARNING("There is nothing to be writen.\n"); return; } TEST_EXIT(nameset.size() == vecs.size()) ("DOFVectors in vecs cannot have idential name. Please check.\n"); bool multiMesh = meshset.size() > 1; //if mesh exists, the meshes in vecs should be the same. if (mesh) { for (size_t i = 0; i < vecs.size(); i++) TEST_EXIT(mesh == vecs[i]->getFeSpace()->getMesh()) ("The mesh of DOFVector %i in vecs is not equal to the second parameter.\n", i); writeAux(filename, mesh, vecs, writeParallel, cps, dataformat, writeMacro); } else { if (!multiMesh) writeAux(filename, vecs[0]->getFeSpace()->getMesh(), vecs, writeParallel, cps, dataformat, writeMacro); else { vector visited(vecs.size(), false); vector*> splitedVecs(0); Mesh* tmpMesh = NULL; for(size_t i = 0; i < vecs.size(); i++) { if(!visited[i]) { splitedVecs.clear(); splitedVecs.push_back(vecs[i]); visited[i] = true; tmpMesh = vecs[i]->getFeSpace()->getMesh(); for(size_t j = i + 1; j < vecs.size(); j++) if(vecs[j]->getFeSpace()->getMesh() == tmpMesh) { splitedVecs.push_back(vecs[j]); visited[j] = true; } } string newfilename = filename; if(filename.length() > 4 && filename.substr(filename.length()- 4, filename.length()) == ".arh") newfilename = filename.substr(0, filename.length() - 4) + "." + tmpMesh->getName() + filename.substr(filename.length()-4 , filename.length()); else newfilename = filename + "." + tmpMesh->getName() + ".arh"; writeAux(newfilename, splitedVecs[0]->getFeSpace()->getMesh(), splitedVecs, writeParallel, cps, dataformat, writeMacro); } } } } int writeHeader(ofstream& file, Mesh *mesh, vector*> vecs, map >& feSpaces, Cpsformat cps, string dataformat) { FUNCNAME("Arh3Writer::detail::writeHeader()"); // int nbits = boost::lexical_cast(dataformat.substr(2, 2)); TEST_EXIT(file.is_open())("the file is not open. should not happen.\n"); map AFEDfileName; uint32_t valueNamesLen = 0, fileNamesLen = 0; for (size_t i = 0; i < vecs.size(); i++) valueNamesLen += vecs[i]->getName().length(); map >::iterator feSpaceIt; for (feSpaceIt = feSpaces.begin(); feSpaceIt != feSpaces.end(); feSpaceIt++) AFEDfileName.insert(make_pair(feSpaceIt->first, string())); uint32_t nValueVectors = vecs.size(); uint32_t nFeSpaces = feSpaces.size(); uint32_t nMacroElements = mesh->getNumberOfMacros(); uint32_t nMacro = 0; TraverseStack st; ElInfo *el = st.traverseFirst(mesh, 0, Mesh::CALL_EL_LEVEL); while (el) { nMacro++; el = st.traverseNext(el); } uint32_t dow = mesh->getGeo(WORLD); uint32_t dim = mesh->getDim(); uint32_t headerLen = 34 + //fixed part of header nMacroElements * 12 + 12 + //macroElemnts table fileNamesLen + //feSpaces table nFeSpaces * 20 + //feSpaces table valueNamesLen + //value vector table nValueVectors * 12 + //also value vector table 4; //macroFile_nl string typeId = "sarh"; #ifndef HAVE_COMPRESSION cps = NONE; #endif uint8_t *major = const_cast(&(AMDiS::io::Arh3Reader::MAJOR)); uint8_t *minor = const_cast(&(AMDiS::io::Arh3Reader::MINOR)); int cpsflag = static_cast(cps); uint32_t minus1 = -1; //fixed header file.write(typeId.c_str(), 4); file.write(reinterpret_cast(major), 1); file.write(reinterpret_cast(minor), 1); file.write(reinterpret_cast(&headerLen), 4); file.write(reinterpret_cast(&dow), 4); file.write(reinterpret_cast(&dim), 4); file.write(reinterpret_cast(&nFeSpaces), 4); file.write(reinterpret_cast(&nValueVectors), 4); file.write(reinterpret_cast(&nMacroElements), 4); file.write(reinterpret_cast(&cpsflag), 4); //macro table deque::const_iterator macroIter = mesh->firstMacroElement(); while(macroIter != mesh->endOfMacroElements()) { uint32_t macroIndex = (*macroIter)->getIndex(); file.write(reinterpret_cast(¯oIndex), 4); file.write(reinterpret_cast(&minus1), 4); file.write(reinterpret_cast(&minus1), 4); macroIter++; } file.write(reinterpret_cast(&minus1), 4); file.write(reinterpret_cast(&minus1), 4); file.write(reinterpret_cast(&minus1), 4); vector feSpaceNumOfVecs(vecs.size()); uint32_t posDOFs = 0, nameStrLen = 0; string nameStr(""); size_t i = 0; //feSpace table for(feSpaceIt = feSpaces.begin(); feSpaceIt != feSpaces.end(); feSpaceIt++, i++) { nameStr = AFEDfileName[feSpaceIt->first]; nameStrLen = nameStr.length(); file.write(reinterpret_cast(&nameStrLen), 4); file.write(nameStr.c_str(), nameStrLen); DimVec* nDOF = feSpaceIt->first->getBasisFcts()->getNumberOfDofs(); // for(int j = 1; j < nDOF->getSize(); j++) { posDOFs = (*nDOF)[j]; file.write(reinterpret_cast(&posDOFs), 4); } for(int j = nDOF->getSize(); j < 4 ; j++) { posDOFs = 0; file.write(reinterpret_cast(&posDOFs), 4); } posDOFs = (*nDOF)[0]; file.write(reinterpret_cast(&posDOFs), 4); // for(size_t j = 0; j < feSpaceIt->second.size(); j++) feSpaceNumOfVecs[feSpaceIt->second[j]] = i; } //vector table for(i = 0; i < vecs.size(); i++) { nameStr = vecs[i]->getName(); nameStrLen = nameStr.length(); file.write(reinterpret_cast(&nameStrLen), 4); file.write(nameStr.c_str(), nameStrLen); file.write(reinterpret_cast(&feSpaceNumOfVecs[i]), 4); file.write(dataformat.c_str(), 4); } uint32_t macroFile_nl = 0; file.write(reinterpret_cast(¯oFile_nl), 4); return headerLen; } void writeAux(string filename, Mesh *mesh, vector*> vecs, bool writeParallel, Cpsformat cps, string dataformat, bool writeMacro) { FUNCNAME("Arh3Writer::detail::writeAux()"); TEST_EXIT(mesh)("empty mesh.\n"); //initialization ofstream file; file.open(filename.c_str(), ios::out | ios::binary | ios::trunc); map > sortedFeSpaces; map >::iterator feSpaceIt; vector > macroSize; // (uncompressed size, compressed size) DegreeOfFreedom globalDof; size_t i = 0, j = 0; for(i = 0; i < vecs.size(); i++) { sortedFeSpaces[vecs[i]->getFeSpace()].push_back(i); } vector > visited(sortedFeSpaces.size()); pair::iterator,bool> ret; //file header information int headerLen = writeHeader(file, mesh, vecs, sortedFeSpaces, cps, dataformat); //macro elements information MeshStructure elementStructure; vector > values(vecs.size()); int32_t macroElIndex = -1; TraverseStack stack; ElInfo *elInfo = stack.traverseFirst(mesh, -1, Mesh::CALL_EVERY_EL_PREORDER); while (elInfo) { if (elInfo->getLevel() == 0) { if (macroElIndex != -1) { elementStructure.commit(); macroSize.push_back(writeMacroElement(file, elementStructure, values, sortedFeSpaces, cps, dataformat)); } elementStructure.clear(); macroElIndex = elInfo->getElement()->getIndex(); for (j = 0; j < vecs.size(); j++) values[j].clear(); for (j = 0; j < sortedFeSpaces.size(); j++) visited[j].clear(); } elementStructure.insertElement(elInfo->getElement()->isLeaf()); if (elInfo->getElement()->isLeaf()) { int valuePos = 0; for(feSpaceIt = sortedFeSpaces.begin(), i = 0; feSpaceIt != sortedFeSpaces.end(); feSpaceIt++, i++) { DOFAdmin* admin = feSpaceIt->first->getAdmin(); TEST_EXIT(admin)("the DOFAdmin of DOFVector is null, this should not happen.\n"); int n0, nd, nd0; if ((nd = admin->getNumberOfDofs(VERTEX))) { int vertices = mesh->getGeo(VERTEX); nd0 = admin->getNumberOfPreDofs(VERTEX); n0 = mesh->getNode(VERTEX); // for (int n = 0; n < vertices; n++) for(int d = 0; d < nd; d++) { globalDof = elInfo->getElement()->getDof(n0 + n, nd0 + d); ret = visited[i].insert(globalDof); if(ret.second) { for(j = 0 ; j < feSpaceIt->second.size(); j++) { values[valuePos + j].push_back((*vecs[feSpaceIt->second[j]])[globalDof]); } } } } if (mesh->getDim() > 1) { if ((nd = admin->getNumberOfDofs(EDGE))) { int edges = mesh->getGeo(EDGE); nd0 = admin->getNumberOfPreDofs(EDGE); n0 = mesh->getNode(EDGE); for (int n = 0; n < edges; n++) for(int d = 0; d < nd; d++) { globalDof = elInfo->getElement()->getDof(n0 + n, nd0 + d); ret = visited[i].insert(globalDof); if(ret.second) { for(j = 0 ; j < feSpaceIt->second.size(); j++) { values[valuePos + j].push_back((*vecs[feSpaceIt->second[j]])[globalDof]); } } } } } if (mesh->getDim() == 3) { if ((nd = admin->getNumberOfDofs(FACE))) { int faces = mesh->getGeo(FACE); nd0 = admin->getNumberOfPreDofs(FACE); n0 = mesh->getNode(FACE); for (int n = 0; n < faces; n++) for(int d = 0; d < nd; d++) { globalDof = elInfo->getElement()->getDof(n0 + n, nd0 + d); ret = visited[i].insert(globalDof); if(ret.second) { for(j = 0 ; j < feSpaceIt->second.size(); j++) { values[valuePos + j].push_back((*vecs[feSpaceIt->second[j]])[globalDof]); } } } } } if ((nd = admin->getNumberOfDofs(CENTER))) { nd0 = admin->getNumberOfPreDofs(CENTER); n0 = mesh->getNode(CENTER); for(int d = 0; d < nd; d++) { globalDof = elInfo->getElement()->getDof(n0, nd0 + d); ret = visited[i].insert(globalDof); if(ret.second) { for(j = 0 ; j < feSpaceIt->second.size(); j++) { values[valuePos + j].push_back((*vecs[feSpaceIt->second[j]])[globalDof]); } } } } valuePos += feSpaceIt->second.size(); }//feSpace loop }//isLeaf elInfo = stack.traverseNext(elInfo); } // And write the last macro element to file. TEST_EXIT_DBG(macroElIndex != -1)("Should not happen!\n"); elementStructure.commit(); macroSize.push_back(writeMacroElement(file, elementStructure, values, sortedFeSpaces, cps, dataformat)); TEST_EXIT(macroSize.size() == (unsigned)mesh->getNumberOfMacros())("Should not happen.\n"); //reset the macro positions in file setMacrosPos(file, headerLen, macroSize); if (writeMacro) setMacroFile(file, headerLen, mesh); file.close(); MSG("ARH file written to: %s\n", filename.c_str()); } void setMacrosPos(ofstream& file, int headerLen, vector >& macroSize) { file.seekp(34); long pos = 0; int startPos = headerLen; for(size_t i = 0; i < macroSize.size(); i++) { pos = file.tellp(); file.seekp(pos + 4); file.write(reinterpret_cast(&startPos), 4); file.write(reinterpret_cast(¯oSize[i].first), 4); startPos += macroSize[i].second; } pos = file.tellp(); file.seekp(pos + 4); file.write(reinterpret_cast(&startPos), 4); } void setMacroFile(std::ofstream& file, int headerLen, Mesh* mesh) { string macroFilename = "", perFilename = ""; string macroData = "", periodicData = ""; Parameters::get(mesh->getName() + "->macro file name", macroFilename); Parameters::get(mesh->getName() + "->periodic file", perFilename); if (!macroFilename.length()) { WARNING("macro file not found.\n"); return; } // write macro file to the end readFileToString(macroFilename, macroData); file.seekp(0, ios_base::end); long macroPos = file.tellp(), perPos = 0; file.write(macroData.c_str(), macroData.length()); // write periodic file to the end if (perFilename.length()) { readFileToString(perFilename, periodicData); perPos = file.tellp(); file.write(periodicData.c_str(), periodicData.length()); } // update macroFile_nl uint32_t macroFile_nl = perFilename.length() ? 27 : 13; file.seekp(headerLen - 4); file.write(reinterpret_cast(¯oFile_nl), 4); file << "this:" << macroPos; if (perFilename.length()) file << ";this:" << perPos; // update headerLen headerLen += macroFile_nl; file.seekp(6); file.write(reinterpret_cast(&headerLen), 4); } void readFileToString(std::string filename, std::string& data) { ifstream file(filename.c_str()); file.seekg(0, std::ios::end); data.reserve(file.tellg()); file.seekg(0, std::ios::beg); data.assign((istreambuf_iterator(file)), istreambuf_iterator()); } pair writeMacroElement(ofstream &file, MeshStructure &code, vector >& values, map >& feSpaces, Cpsformat cps, string dataformat) { stringstream dataStream(ios::out | ios::in | ios::binary); uint32_t nStructureCodes = code.getCode().size(); dataStream.write(reinterpret_cast(&nStructureCodes), 4); uint32_t codeSize = code.getNumElements(); dataStream.write(reinterpret_cast(&codeSize), 4); dataStream.write(reinterpret_cast(&(const_cast&>(code.getCode())[0])), 8 * nStructureCodes); if (values.size() > 0) { int moreSize = 0, valuePos = 0; map >::iterator it; for(it = feSpaces.begin(); it != feSpaces.end(); it++) { uint32_t nValuesPerVector = values[valuePos].size(); dataStream.write(reinterpret_cast(&nValuesPerVector), 4); moreSize += 4; for (size_t i = 0; i < it->second.size(); i++) moreSize += writeValues(dataStream, dataformat, values[valuePos + i]); valuePos += it->second.size(); } } stringstream tmp(ios::out | ios::in | ios::binary); boost::iostreams::filtering_streambuf in; #ifdef HAVE_COMPRESSION switch(cps) { case ZLIB: in.push(boost::iostreams::zlib_compressor()); break; case BZIP2: in.push(boost::iostreams::bzip2_compressor()); break; case NONE: break; default: MSG("NOT correct compression flag.\n"); } #endif in.push(dataStream); boost::iostreams::copy(in, tmp); file << tmp.rdbuf(); return make_pair(dataStream.str().length(), tmp.str().length()); } template int writeValues(stringstream& file, vector& values) { size_t size = values.size(); T* data = new T[size]; for (size_t i = 0; i < size; i++) data[i] = static_cast(values[i]); file.write(reinterpret_cast(&data[0]), sizeof(T) * size); delete [] data; return sizeof(T) * size; } int writeValues(stringstream& file, string dataformat, vector& values) { FUNCNAME("Arh3Writer::detail::writeValues()"); int newsize = 0; std::map::const_iterator it = dataformatMap.find(dataformat); TEST_EXIT(it != dataformatMap.end())("Wrong data format.\n"); switch(it->second) { case SI08: newsize = writeValues(file, values); break; case SI16: newsize = writeValues(file, values); break; case SI32: newsize = writeValues(file, values); break; case SI64: newsize = writeValues(file, values); break; case UI08: newsize = writeValues(file, values); break; case UI16: newsize = writeValues(file, values); break; case UI32: newsize = writeValues(file, values); break; case UI64: newsize = writeValues(file, values); break; case SF32: newsize = writeValues(file, values); break; case SF64: newsize = writeValues(file, values); break; default: ERROR_EXIT("Wrong data format.\n"); } return newsize; } }//end namespace detail } // end namespace Arh3Writer } } // end namespace io, AMDiS