#include "IO/Writer.h" #include "IO/MeshDatabase.h" #include "IO/IOHelpers.h" #include "IO/silo.h" #include "common/MPI_Helpers.h" #include "common/Utilities.h" #include "shared_ptr.h" #include #include #include #include enum class Format { OLD, NEW, SILO, UNKNOWN }; /**************************************************** * Initialize the writer * ****************************************************/ static std::string global_IO_path; static Format global_IO_format = Format::UNKNOWN; void IO::initialize( const std::string& path, const std::string& format, bool append ) { if ( path.empty() ) global_IO_path = "."; else global_IO_path = path; if ( format == "old" ) global_IO_format = Format::OLD; else if ( format == "new" ) global_IO_format = Format::NEW; else if ( format == "silo" ) global_IO_format = Format::SILO; else ERROR("Unknown format"); int rank = comm_rank(MPI_COMM_WORLD); if ( !append && rank==0 ) { mkdir(path.c_str(),S_IRWXU|S_IRGRP); std::string filename; if ( global_IO_format==Format::OLD || global_IO_format==Format::NEW ) filename = global_IO_path + "/summary.LBM"; else if ( global_IO_format==Format::SILO ) filename = global_IO_path + "/LBM.visit"; else ERROR("Unknown format"); auto fid = fopen(filename.c_str(),"wb"); fclose(fid); } } // Write the mesh data in the original format static std::vector writeMeshesOrigFormat( const std::vector& meshData, const std::string& path ) { int rank = MPI_WORLD_RANK(); std::vector meshes_written; for (size_t i=0; i mesh = meshData[i].mesh; IO::MeshDatabase mesh_entry; mesh_entry.name = meshData[i].meshName; mesh_entry.type = meshType(*mesh); mesh_entry.meshClass = meshData[i].mesh->className(); mesh_entry.format = 1; IO::DatabaseEntry domain; domain.name = domainname; domain.file = filename; domain.offset = 0; mesh_entry.domains.push_back(domain); if ( !meshData[i].vars.empty() ) { printf("Warning: variables are not supported with this format\n"); //for (size_t j=0; jname ); } const std::string meshClass = mesh->className(); if ( meshClass=="PointList" ) { // List of points std::shared_ptr pointlist = std::dynamic_pointer_cast(mesh); const std::vector& P = pointlist->points; for (size_t i=0; i trilist = IO::getTriList(mesh); const std::vector& A = trilist->A; const std::vector& B = trilist->B; const std::vector& C = trilist->C; for (size_t i=0; iclassName(); database.format = format; // Write the mesh IO::DatabaseEntry domain; domain.name = domainname; domain.file = filename; domain.offset = -1; database.domains.push_back(domain); // Write the variables for (size_t i=0; iname; info.type = mesh.vars[i]->type; info.dim = mesh.vars[i]->dim; database.variables.push_back(info); // Add domain variable info IO::DatabaseEntry variable; variable.name = mesh.vars[i]->name; variable.file = filename; variable.offset = -1; std::pair key(domain.name,mesh.vars[i]->name); database.variable_data.insert( std::pair,IO::DatabaseEntry>(key,variable) ); } return database; } // Write a mesh (and variables) to a file static IO::MeshDatabase write_domain( FILE *fid, const std::string& filename, const IO::MeshDataStruct& mesh, int format ) { const int level = 0; int rank = MPI_WORLD_RANK(); // Create the MeshDatabase IO::MeshDatabase database = getDatabase( filename, mesh, format ); // Write the mesh IO::DatabaseEntry& domain = database.domains[0]; domain.offset = ftell(fid); std::pair data = mesh.mesh->pack(level); fprintf(fid,"Mesh: %s-%05i: %lu\n",mesh.meshName.c_str(),rank,data.first); fwrite(data.second,1,data.first,fid); fprintf(fid,"\n"); delete [] (char*) data.second; // Write the variables for (size_t i=0; i key(domain.name,mesh.vars[i]->name); IO::DatabaseEntry& variable = database.variable_data[key]; variable.offset = ftell(fid); int dim = mesh.vars[i]->dim; int type = static_cast(mesh.vars[i]->type); size_t N = mesh.vars[i]->data.length(); if ( type == static_cast(IO::VariableType::NullVariable) ) { ERROR("Variable type not set"); } size_t N_mesh = mesh.mesh->numberPointsVar(mesh.vars[i]->type); ASSERT(N==dim*N_mesh); fprintf(fid,"Var: %s-%05i-%s: %i, %i, %lu, %lu, double\n", database.name.c_str(), rank, variable.name.c_str(), dim, type, N_mesh, N*sizeof(double) ); fwrite(mesh.vars[i]->data.data(),sizeof(double),N,fid); fprintf(fid,"\n"); } return database; } #ifdef USE_SILO // Write a PointList mesh (and variables) to a file template static void writeSiloPointMesh( DBfile *fid, const IO::PointList& mesh, const std::string& meshname ) { const auto& points = mesh.getPoints(); std::vector x(points.size()), y(points.size()), z(points.size()); for (size_t i=0; i( fid, meshname, 3, points.size(), coords ); } static void writeSiloPointList( DBfile *fid, const IO::MeshDataStruct& meshData, IO::MeshDatabase database ) { const IO::PointList& mesh = dynamic_cast( *meshData.mesh ); const std::string meshname = database.domains[0].name; if ( meshData.precision == IO::DataType::Double ) { writeSiloPointMesh( fid, mesh, meshname ); } else if ( meshData.precision == IO::DataType::Float ) { writeSiloPointMesh( fid, mesh, meshname ); } else { ERROR("Unsupported format"); } const auto& points = mesh.getPoints(); std::vector x(points.size()), y(points.size()), z(points.size()); for (size_t i=0; i data2( var.data.size() ); data2.copy( var.data ); silo::writePointMeshVariable( fid, meshname, var.name, data2 ); } else if ( var.precision == IO::DataType::Int ) { Array data2( var.data.size() ); data2.copy( var.data ); silo::writePointMeshVariable( fid, meshname, var.name, data2 ); } else { ERROR("Unsupported format"); } } } // Write a TriMesh mesh (and variables) to a file template static void writeSiloTriMesh( DBfile *fid, const IO::TriMesh& mesh, const std::string& meshname ) { const auto& points = mesh.vertices->getPoints(); std::vector x(points.size()), y(points.size()), z(points.size()); for (size_t i=0; i( fid, meshname, 3, 2, points.size(), coords, mesh.A.size(), tri ); } static void writeSiloTriMesh2( DBfile *fid, const IO::MeshDataStruct& meshData, const IO::TriMesh& mesh, IO::MeshDatabase database ) { const std::string meshname = database.domains[0].name; if ( meshData.precision == IO::DataType::Double ) { writeSiloTriMesh( fid, mesh, meshname ); } else if ( meshData.precision == IO::DataType::Float ) { writeSiloTriMesh( fid, mesh, meshname ); } else { ERROR("Unsupported format"); } for (size_t i=0; i( var.type ); if ( var.precision == IO::DataType::Double ) { silo::writeTriMeshVariable( fid, 3, meshname, var.name, var.data, type ); } else if ( var.precision == IO::DataType::Float ) { Array data2( var.data.size() ); data2.copy( var.data ); silo::writeTriMeshVariable( fid, 3, meshname, var.name, data2, type ); } else if ( var.precision == IO::DataType::Int ) { Array data2( var.data.size() ); data2.copy( var.data ); silo::writeTriMeshVariable( fid, 3, meshname, var.name, data2, type ); } else { ERROR("Unsupported format"); } } } static void writeSiloTriMesh( DBfile *fid, const IO::MeshDataStruct& meshData, IO::MeshDatabase database ) { const IO::TriMesh& mesh = dynamic_cast( *meshData.mesh ); writeSiloTriMesh2( fid, meshData, mesh, database ); } static void writeSiloTriList( DBfile *fid, const IO::MeshDataStruct& meshData, IO::MeshDatabase database ) { auto mesh = getTriMesh( meshData.mesh ); writeSiloTriMesh2( fid, meshData, *mesh, database ); } // Write a DomainMesh mesh (and variables) to a file static void writeSiloDomainMesh( DBfile *fid, const IO::MeshDataStruct& meshData, IO::MeshDatabase database ) { const IO::DomainMesh& mesh = dynamic_cast( *meshData.mesh ); RankInfoStruct info( mesh.rank, mesh.nprocx, mesh.nprocy, mesh.nprocz ); std::array range = { info.ix*mesh.Lx/info.nx, (info.ix+1)*mesh.Lx/info.nx, info.jy*mesh.Ly/info.ny, (info.jy+1)*mesh.Ly/info.ny, info.kz*mesh.Lz/info.nz, (info.kz+1)*mesh.Lz/info.nz }; std::array N = { mesh.nx, mesh.ny, mesh.nz }; std::array baseindex = { info.ix, info.jy, info.kz }; const std::string meshname = database.domains[0].name; silo::writeUniformMesh<3>( fid, meshname, range, N ); silo::write( fid, meshname+"_rankinfo", { mesh.rank, mesh.nprocx, mesh.nprocy, mesh.nprocz } ); for (size_t i=0; i( var.type ); if ( var.precision == IO::DataType::Double ) { silo::writeUniformMeshVariable<3>( fid, meshname, N, var.name, var.data, type ); } else if ( var.precision == IO::DataType::Float ) { Array data2( var.data.size() ); data2.copy( var.data ); silo::writeUniformMeshVariable<3>( fid, meshname, N, var.name, data2, type ); } else if ( var.precision == IO::DataType::Int ) { Array data2( var.data.size() ); data2.copy( var.data ); silo::writeUniformMeshVariable<3>( fid, meshname, N, var.name, data2, type ); } else { ERROR("Unsupported format"); } } } // Write a mesh (and variables) to a file static IO::MeshDatabase write_domain_silo( DBfile *fid, const std::string& filename, const IO::MeshDataStruct& mesh, int format ) { const int level = 0; int rank = MPI_WORLD_RANK(); // Create the MeshDatabase IO::MeshDatabase database = getDatabase( filename, mesh, format ); if ( database.meshClass=="PointList" ) { writeSiloPointList( fid, mesh, database ); } else if ( database.meshClass=="TriMesh" ) { writeSiloTriMesh( fid, mesh, database ); } else if ( database.meshClass=="TriList" ) { writeSiloTriList( fid, mesh, database ); } else if ( database.meshClass=="DomainMesh" ) { writeSiloDomainMesh( fid, mesh, database ); } else { ERROR("Unknown mesh class"); } return database; } // Write the summary file for silo std::pair getSiloMeshType( const std::string& meshClass ) { int meshType = 0; int varType = 0; if ( meshClass=="PointList" ) { meshType = DB_POINTMESH; varType = DB_POINTVAR; } else if ( meshClass=="TriMesh" ) { meshType = DB_UCDMESH; varType = DB_UCDVAR; } else if ( meshClass=="TriList" ) { meshType = DB_UCDMESH; varType = DB_UCDVAR; } else if ( meshClass=="DomainMesh" ) { meshType = DB_QUAD_RECT; varType = DB_QUADVAR; } else { ERROR("Unknown mesh class"); } return std::make_pair( meshType, varType ); } void writeSiloSummary( const std::vector& meshes_written, const std::string& filename ) { auto fid = silo::open( filename, silo::CREATE ); for ( const auto& data : meshes_written ) { auto type = getSiloMeshType( data.meshClass ); std::vector meshTypes( data.domains.size(), type.first ); std::vector varTypes( data.domains.size(), type.second ); std::vector meshNames; for ( const auto& tmp : data.domains ) meshNames.push_back( tmp.file + ":" + tmp.name ); silo::writeMultiMesh( fid, data.name, meshNames, meshTypes ); for (const auto& variable : data.variables ) { std::vector varnames; for ( const auto& tmp : data.domains ) varnames.push_back( tmp.file + ":" + variable.name ); silo::writeMultiVar( fid, variable.name, varnames, varTypes ); } } silo::close( fid ); } #endif // Write the mesh data in the new format static std::vector writeMeshesNewFormat( const std::vector& meshData, const std::string& path, int format ) { int rank = MPI_WORLD_RANK(); std::vector meshes_written; char filename[100], fullpath[200]; sprintf(filename,"%05i",rank); sprintf(fullpath,"%s/%s",path.c_str(),filename); FILE *fid = fopen(fullpath,"wb"); for (size_t i=0; i mesh = meshData[i].mesh; meshes_written.push_back( write_domain(fid,filename,meshData[i],format) ); } fclose(fid); return meshes_written; } // Write the mesh data to silo static std::vector writeMeshesSilo( const std::vector& meshData, const std::string& path, int format ) { #ifdef USE_SILO int rank = MPI_WORLD_RANK(); std::vector meshes_written; char filename[100], fullpath[200]; sprintf(filename,"%05i.silo",rank); sprintf(fullpath,"%s/%s",path.c_str(),filename); auto fid = silo::open( fullpath, silo::CREATE ); for (size_t i=0; i mesh = meshData[i].mesh; meshes_written.push_back( write_domain_silo(fid,filename,meshData[i],format) ); } silo::close( fid ); return meshes_written; #else ERROR("Application built without silo support"); return std::vector(); #endif } /**************************************************** * Write the mesh data * ****************************************************/ void IO::writeData( const std::string& subdir, const std::vector& meshData, MPI_Comm comm ) { if ( global_IO_path.empty() ) IO::initialize( ); PROFILE_START("writeData"); int rank = comm_rank(comm); // Check the meshData before writing for ( const auto& data : meshData ) { if ( !data.check() ) ERROR("Error in meshData"); } // Create the output directory std::string path = global_IO_path + "/" + subdir; if ( rank == 0 ) { mkdir(path.c_str(),S_IRWXU|S_IRGRP); } MPI_Barrier(comm); // Write the mesh files std::vector meshes_written; if ( global_IO_format == Format::OLD ) { // Write the original triangle format meshes_written = writeMeshesOrigFormat( meshData, path ); } else if ( global_IO_format == Format::NEW ) { // Write the new format (double precision) meshes_written = writeMeshesNewFormat( meshData, path, 2 ); } else if ( global_IO_format == Format::SILO ) { // Write silo meshes_written = writeMeshesSilo( meshData, path, 4 ); } else { ERROR("Unknown format"); } // Gather a complete list of files on rank 0 meshes_written = gatherAll(meshes_written,comm); // Write the summary files if ( rank == 0 ) { // Write the summary file for the current timestep char filename[200]; sprintf(filename,"%s/LBM.summary",path.c_str()); write(meshes_written,filename); // Write summary silo file if needed #ifdef USE_SILO if ( global_IO_format == Format::SILO ) { sprintf(filename,"%s/summary.silo",path.c_str()); writeSiloSummary(meshes_written,filename); } #endif // Add the timestep to the global summary file if ( global_IO_format == Format::OLD || global_IO_format == Format::NEW ) { auto filename = global_IO_path+"/summary.LBM"; FILE *fid = fopen(filename.c_str(),"ab"); fprintf(fid,"%s/\n",subdir.c_str()); fclose(fid); } else if ( global_IO_format == Format::SILO ) { auto filename = global_IO_path+"/LBM.visit"; FILE *fid = fopen(filename.c_str(),"ab"); fprintf(fid,"%s/summary.silo\n",subdir.c_str()); fclose(fid); } else { ERROR("Unknown format"); } } PROFILE_STOP("writeData"); }