Creating IO helper classes for writing/reading mesh data. Modifying visit plugin to use new IO capabilities. Adding unit test for IO capabilities

This commit is contained in:
Mark Berrill 2014-09-09 14:42:13 -04:00
parent 1e1e2f94e8
commit de2dfae79f
22 changed files with 1487 additions and 233 deletions

View File

@ -55,7 +55,7 @@ ENDIF()
# Add some directories to include
INCLUDE_DIRECTORIES( ${LBPM_INSTALL_DIR}/include )
INCLUDE_DIRECTORIES( "${LBPM_INSTALL_DIR}/include" )
# Set doxygen info
@ -89,6 +89,7 @@ IF ( NOT ONLY_BUILD_DOCS )
CONFIGURE_CUDA()
CONFIGURE_MIC()
CONFIGURE_LBPM()
CONFIGURE_TIMER()
CONFIGURE_LINE_COVERAGE()
ENDIF()
@ -101,6 +102,7 @@ SET( LBPM_LIBS lbpm-wia )
IF ( NOT ONLY_BUILD_DOCS )
BEGIN_PACKAGE_CONFIG( lbpm-wia )
ADD_PACKAGE_SUBDIRECTORY( common )
ADD_PACKAGE_SUBDIRECTORY( IO )
IF ( USE_CUDA )
ADD_PACKAGE_SUBDIRECTORY( gpu )
ELSE()

159
IO/Mesh.cpp Normal file
View File

@ -0,0 +1,159 @@
#include "Mesh.h"
#include "common/Utilities.h"
#include <limits>
namespace IO {
inline Point nullPoint()
{
Point tmp;
tmp.x = std::numeric_limits<double>::quiet_NaN();
tmp.y = std::numeric_limits<double>::quiet_NaN();
tmp.z = std::numeric_limits<double>::quiet_NaN();
return tmp;
}
/****************************************************
* Mesh *
****************************************************/
Mesh::Mesh( )
{
}
Mesh::~Mesh( )
{
}
/****************************************************
* PointList *
****************************************************/
PointList::PointList( )
{
}
PointList::PointList( size_t N )
{
Point tmp = nullPoint();
points.resize(N,tmp);
}
PointList::~PointList( )
{
}
/****************************************************
* TriList *
****************************************************/
TriList::TriList( )
{
}
TriList::TriList( size_t N_tri )
{
Point tmp = nullPoint();
A.resize(N_tri,tmp);
B.resize(N_tri,tmp);
C.resize(N_tri,tmp);
}
TriList::TriList( const TriMesh& mesh )
{
Point tmp = nullPoint();
A.resize(mesh.A.size(),tmp);
B.resize(mesh.B.size(),tmp);
C.resize(mesh.C.size(),tmp);
const std::vector<Point>& P = mesh.vertices->points;
for (size_t i=0; i<A.size(); i++)
A[i] = P[mesh.A[i]];
for (size_t i=0; i<B.size(); i++)
B[i] = P[mesh.B[i]];
for (size_t i=0; i<C.size(); i++)
C[i] = P[mesh.C[i]];
}
TriList::~TriList( )
{
}
/****************************************************
* TriMesh *
****************************************************/
TriMesh::TriMesh( )
{
}
TriMesh::TriMesh( size_t N_tri, size_t N_point )
{
vertices.reset( new PointList(N_point) );
A.resize(N_tri,-1);
B.resize(N_tri,-1);
C.resize(N_tri,-1);
}
TriMesh::TriMesh( size_t N_tri, std::shared_ptr<PointList> points )
{
vertices = points;
A.resize(N_tri,-1);
B.resize(N_tri,-1);
C.resize(N_tri,-1);
}
TriMesh::TriMesh( const TriList& mesh )
{
// For simlicity we will just create a mesh with ~3x the verticies for now
ASSERT(mesh.A.size()==mesh.B.size()&&mesh.A.size()==mesh.C.size());
A.resize(mesh.A.size());
B.resize(mesh.B.size());
C.resize(mesh.C.size());
vertices.reset( new PointList(3*mesh.A.size()) );
for (size_t i=0; i<A.size(); i++) {
A[i] = 3*i+0;
B[i] = 3*i+1;
C[i] = 3*i+2;
vertices->points[A[i]] = mesh.A[i];
vertices->points[B[i]] = mesh.B[i];
vertices->points[C[i]] = mesh.C[i];
}
}
TriMesh::~TriMesh( )
{
vertices.reset();
A.clear();
B.clear();
C.clear();
}
/****************************************************
* Converters *
****************************************************/
std::shared_ptr<PointList> getPointList( std::shared_ptr<Mesh> mesh )
{
return std::dynamic_pointer_cast<PointList>(mesh);
}
std::shared_ptr<TriMesh> getTriMesh( std::shared_ptr<Mesh> mesh )
{
std::shared_ptr<TriMesh> mesh2;
if ( std::dynamic_pointer_cast<TriMesh>(mesh) != NULL ) {
mesh2 = std::dynamic_pointer_cast<TriMesh>(mesh);
} else if ( std::dynamic_pointer_cast<TriList>(mesh) != NULL ) {
std::shared_ptr<TriList> trilist = std::dynamic_pointer_cast<TriList>(mesh);
ASSERT(trilist!=NULL);
mesh2.reset( new TriMesh(*trilist) );
}
return mesh2;
}
std::shared_ptr<TriList> getTriList( std::shared_ptr<Mesh> mesh )
{
std::shared_ptr<TriList> mesh2;
if ( std::dynamic_pointer_cast<TriList>(mesh) != NULL ) {
mesh2 = std::dynamic_pointer_cast<TriList>(mesh);
} else if ( std::dynamic_pointer_cast<TriMesh>(mesh) != NULL ) {
std::shared_ptr<TriMesh> trimesh = std::dynamic_pointer_cast<TriMesh>(mesh);
ASSERT(trimesh!=NULL);
mesh2.reset( new TriList(*trimesh) );
}
return mesh2;
}
} // IO namespace

116
IO/Mesh.h Normal file
View File

@ -0,0 +1,116 @@
#ifndef MESH_INC
#define MESH_INC
#include <iostream>
#include <string.h>
#include <memory>
#include <vector>
#include "common/PointList.h"
namespace IO {
/*! \class Mesh
\brief A base class for meshes
*/
class Mesh
{
public:
//! Destructor
virtual ~Mesh();
protected:
//! Empty constructor
Mesh();
Mesh(const Mesh&);
Mesh& operator=(const Mesh&);
};
/*! \class PointList
\brief A class used to hold a list of verticies
*/
class PointList: public Mesh
{
public:
//! Empty constructor
PointList();
//! Constructor for N points
PointList( size_t N );
//! Destructor
virtual ~PointList();
public:
std::vector<Point> points; //!< List of points vertex
};
/*! \class TriMesh
\brief A class used to hold a list of trianges specified by their vertex number and list of coordiantes
*/
class TriList;
class TriMesh: public Mesh
{
public:
//! TriMesh constructor
TriMesh();
//! Constructor for Nt triangles and Np points
TriMesh( size_t N_tri, size_t N_point );
//! Constructor for Nt triangles and the given points
TriMesh( size_t N_tri, std::shared_ptr<PointList> points );
//! Constructor from TriList
TriMesh( const TriList& );
//! Destructor
virtual ~TriMesh();
public:
std::shared_ptr<PointList> vertices; //!< List of verticies
std::vector<int> A; //!< First vertex
std::vector<int> B; //!< Second vertex
std::vector<int> C; //!< Third vertex
};
/*! \class TriList
\brief A class used to hold a list of triangles specified by their vertex coordinates
*/
class TriList: public Mesh
{
public:
//! Empty constructor
TriList();
//! Constructor for N triangles
TriList( size_t N_tri );
//! Constructor from TriMesh
TriList( const TriMesh& );
//! Destructor
virtual ~TriList();
public:
std::vector<Point> A; //!< First vertex
std::vector<Point> B; //!< Second vertex
std::vector<Point> C; //!< Third vertex
};
/*! \class MeshDataStruct
\brief A class used to hold database info for saving a mesh
*/
struct MeshDataStruct {
std::string meshName;
std::shared_ptr<Mesh> mesh;
//std::vector<std::string> dataName;
//std::vector<int> dataType;
//std::vector<double*> data;
};
//! Convert the mesh to a TriMesh (will return NULL if this is invalid)
std::shared_ptr<PointList> getPointList( std::shared_ptr<Mesh> mesh );
std::shared_ptr<TriMesh> getTriMesh( std::shared_ptr<Mesh> mesh );
std::shared_ptr<TriList> getTriList( std::shared_ptr<Mesh> mesh );
} // IO namespace
#endif

293
IO/MeshDatabase.cpp Normal file
View File

@ -0,0 +1,293 @@
#include "IO/MeshDatabase.h"
#include "common/Utilities.h"
#include <vector>
#include <map>
#include <set>
#include <ProfilerApp.h>
namespace IO {
// Remove preceeding/trailing whitespace
inline std::string deblank( const std::string& str )
{
size_t i1 = str.size();
size_t i2 = 0;
for (size_t i=0; i<str.size(); i++) {
if ( str[i]!=' ' && str[i]>=32 ) {
i1 = std::min(i1,i);
i2 = std::max(i2,i);
}
}
return str.substr(i1,i2-i1+1);
}
// MeshDatabase::MeshDatabase
MeshDatabase::MeshDatabase()
{
}
MeshDatabase::~MeshDatabase()
{
}
MeshDatabase::MeshDatabase(const MeshDatabase& rhs)
{
name = rhs.name;
type = rhs.type;
format = rhs.format;
domains = rhs.domains;
file = rhs.file;
variables = rhs.variables;
}
MeshDatabase& MeshDatabase::operator=(const MeshDatabase& rhs)
{
this->name = rhs.name;
this->type = rhs.type;
this->format = rhs.format;
this->domains = rhs.domains;
this->file = rhs.file;
this->variables = rhs.variables;
}
// Pack/Unpack the MeshDatabase to/from buffer
static size_t MeshDatabaseSize( const MeshDatabase& data )
{
size_t bytes = 2;
bytes += data.name.size()+1;
bytes += sizeof(int);
for (size_t i=0; i<data.domains.size(); i++)
bytes += data.domains[i].size()+1;
bytes += sizeof(int);
for (size_t i=0; i<data.file.size(); i++)
bytes += data.file[i].size()+1;
bytes += sizeof(int);
for (size_t i=0; i<data.variables.size(); i++)
bytes += data.variables[i].size()+1;
return bytes;
}
static void pack( const MeshDatabase& data, char *buffer )
{
buffer[0] = static_cast<char>(data.type);
buffer[1] = data.format;
size_t pos = 2;
memcpy(&buffer[pos],data.name.c_str(),data.name.size()+1);
pos += data.name.size()+1;
*reinterpret_cast<int*>(&buffer[pos]) = data.domains.size();
pos += sizeof(int);
for (size_t i=0; i<data.domains.size(); i++) {
memcpy(&buffer[pos],data.domains[i].c_str(),data.domains[i].size()+1);
pos += data.domains[i].size()+1;
}
*reinterpret_cast<int*>(&buffer[pos]) = data.file.size();
pos += sizeof(int);
for (size_t i=0; i<data.file.size(); i++) {
memcpy(&buffer[pos],data.file[i].c_str(),data.file[i].size()+1);
pos += data.file[i].size()+1;
}
*reinterpret_cast<int*>(&buffer[pos]) = data.variables.size();
pos += sizeof(int);
for (size_t i=0; i<data.variables.size(); i++) {
memcpy(&buffer[pos],data.variables[i].c_str(),data.variables[i].size()+1);
pos += data.variables[i].size()+1;
}
}
static MeshDatabase unpack( const char *buffer )
{
MeshDatabase data;
data.type = static_cast<MeshType>(buffer[0]);
data.format = buffer[1];
size_t pos = 2;
data.name = std::string(&buffer[pos]);
pos += data.name.size()+1;
int N_domains = *reinterpret_cast<const int*>(&buffer[pos]);
pos += sizeof(int);
data.domains.resize(N_domains);
for (size_t i=0; i<data.domains.size(); i++) {
data.domains[i] = std::string(&buffer[pos]);
pos += data.domains[i].size()+1;
}
int N_file = *reinterpret_cast<const int*>(&buffer[pos]);
pos += sizeof(int);
data.file.resize(N_file);
for (size_t i=0; i<data.file.size(); i++) {
data.file[i] = std::string(&buffer[pos]);
pos += data.file[i].size()+1;
}
int N_variables = *reinterpret_cast<const int*>(&buffer[pos]);
pos += sizeof(int);
data.variables.resize(N_variables);
for (size_t i=0; i<data.variables.size(); i++) {
data.variables[i] = std::string(&buffer[pos]);
pos += data.variables[i].size()+1;
}
return data;
}
// Gather the mesh databases from all processors
std::vector<MeshDatabase> gatherAll( const std::vector<MeshDatabase>& meshes, MPI_Comm comm )
{
PROFILE_START("gatherAll");
int rank = -1;
int size = 0;
MPI_Comm_rank( MPI_COMM_WORLD, &rank );
MPI_Comm_size( MPI_COMM_WORLD, &size );
// First pack the mesh data to local buffers
size_t localsize = 0;
for (size_t i=0; i<meshes.size(); i++)
localsize += MeshDatabaseSize(meshes[i]);
char *localbuf = new char[localsize];
size_t pos = 0;
for (size_t i=0; i<meshes.size(); i++) {
pack( meshes[i], &localbuf[pos] );
pos += MeshDatabaseSize(meshes[i]);
}
// Get the number of bytes each processor will be sending/recieving
int sendsize = static_cast<int>(localsize);
int *recvsize = new int[size];
MPI_Allgather(&sendsize,1,MPI_INT,recvsize,1,MPI_INT,comm);
size_t globalsize = recvsize[0];
int *disp = new int[size];
disp[0] = 0;
for (size_t i=1; i<size; i++) {
disp[i] = disp[i-1] + recvsize[i];
globalsize += recvsize[i];
}
// Send/recv the global data
char *globalbuf = new char[globalsize];
MPI_Allgatherv(localbuf,sendsize,MPI_CHAR,globalbuf,recvsize,disp,MPI_CHAR,comm);
// Unpack the data
std::map<std::string,MeshDatabase> data;
pos = 0;
while ( pos < globalsize ) {
MeshDatabase tmp = unpack(&globalbuf[pos]);
pos += MeshDatabaseSize(tmp);
std::map<std::string,MeshDatabase>::iterator it = data.find(tmp.name);
if ( it==data.end() ) {
data[tmp.name] = tmp;
} else {
for (size_t i=0; i<tmp.domains.size(); i++)
it->second.domains.push_back(tmp.domains[i]);
for (size_t i=0; i<tmp.domains.size(); i++)
it->second.file.push_back(tmp.file[i]);
for (size_t i=0; i<tmp.variables.size(); i++)
it->second.variables.push_back(tmp.variables[i]);
}
}
for (std::map<std::string,MeshDatabase>::iterator it=data.begin(); it!=data.end(); ++it) {
// Get the unique variables
std::set<std::string> data2(it->second.variables.begin(),it->second.variables.end());
it->second.variables = std::vector<std::string>(data2.begin(),data2.end());
}
// Free temporary memory
delete [] localbuf;
delete [] recvsize;
delete [] disp;
delete [] globalbuf;
// Return the results
std::vector<MeshDatabase> data2(data.size());
size_t i=0;
for (std::map<std::string,MeshDatabase>::iterator it=data.begin(); it!=data.end(); ++it, ++i)
data2[i] = it->second;
PROFILE_STOP("gatherAll");
return data2;
}
//! Write the mesh databases to a file
void write( const std::vector<MeshDatabase>& meshes, const std::string& filename )
{
PROFILE_START("write");
FILE *fid = fopen(filename.c_str(),"wb");
for (size_t i=0; i<meshes.size(); i++) {
fprintf(fid,"%s\n",meshes[i].name.c_str());
fprintf(fid," format: %i\n",static_cast<int>(meshes[i].format));
fprintf(fid," type: %i\n",static_cast<int>(meshes[i].type));
fprintf(fid," domains: ");
for (size_t j=0; j<meshes[i].domains.size(); j++) {
fprintf(fid,"%s; ",meshes[i].domains[j].c_str());
}
fprintf(fid,"\n");
fprintf(fid," file: ");
for (size_t j=0; j<meshes[i].file.size(); j++) {
fprintf(fid,"%s; ",meshes[i].file[j].c_str());
}
fprintf(fid,"\n");
fprintf(fid," variables: ");
for (size_t j=0; j<meshes[i].variables.size(); j++) {
fprintf(fid,"%s; ",meshes[i].variables[j].c_str());
}
fprintf(fid,"\n");
}
fclose(fid);
PROFILE_STOP("write");
}
// Helper function to split a line into the sub variables
static inline std::vector<std::string> splitList( const char *line )
{
std::vector<std::string> list;
size_t i1 = 0;
size_t i2 = 0;
while ( 1 ) {
if ( line[i2]==';' || line[i2]<32 ) {
std::string tmp(&line[i1],i2-i1);
tmp = deblank(tmp);
if ( !tmp.empty() )
list.push_back(tmp);
i1 = i2+1;
}
if ( line[i2]==0 )
break;
i2++;
}
return list;
}
//! Read the mesh databases from a file
std::vector<MeshDatabase> read( const std::string& filename )
{
std::vector<MeshDatabase> meshes;
PROFILE_START("read");
FILE *fid = fopen(filename.c_str(),"rb");
if ( fid==NULL )
ERROR("Error opening file");
char *line = new char[0x100000];
while ( std::fgets(line,0x100000,fid) != NULL ) {
if ( line[0]<32 ) {
// Empty line
continue;
} else if ( line[0] != ' ' ) {
meshes.resize(meshes.size()+1);
std::string name(line);
name.resize(name.size()-1);
meshes.back().name = name;
} else if ( strncmp(line," format:",10)==0 ) {
meshes.back().format = static_cast<unsigned char>(atoi(&line[10]));
} else if ( strncmp(line," type:",8)==0 ) {
meshes.back().type = static_cast<MeshType>(atoi(&line[8]));
} else if ( strncmp(line," domains:",11)==0 ) {
meshes.back().domains = splitList(&line[11]);
} else if ( strncmp(line," file:",8)==0 ) {
meshes.back().file = splitList(&line[8]);
} else if ( strncmp(line," variables:",13)==0 ) {
meshes.back().variables = splitList(&line[13]);
} else {
ERROR("Error reading line");
}
}
fclose(fid);
delete [] line;
PROFILE_STOP("read");
return meshes;
}
} // IO namespace

52
IO/MeshDatabase.h Normal file
View File

@ -0,0 +1,52 @@
#ifndef MeshDatabase_INC
#define MeshDatabase_INC
#include <iostream>
#include <string.h>
#include <memory>
#include <vector>
#ifdef USE_MPI
#include "mpi.h"
#else
typedef int MPI_Comm;
#endif
namespace IO {
//! Enum to identify mesh type
enum class MeshType : char { PointMesh=1, SurfaceMesh=2, VolumeMesh=3 };
//! Structure to hold the info about the meshes
struct MeshDatabase {
std::string name; //!< Name of the mesh
MeshType type; //!< Mesh type
unsigned char format; //!< Data format
std::vector<std::string> domains; //!< List of the domains
std::vector<std::string> file; //!< File containing the mesh data for the given domain
std::vector<std::string> variables; //!< List of the variables
public:
MeshDatabase();
~MeshDatabase();
MeshDatabase(const MeshDatabase&);
MeshDatabase& operator=(const MeshDatabase&);
};
//! Gather the mesh databases from all processors
std::vector<MeshDatabase> gatherAll( const std::vector<MeshDatabase>& meshes, MPI_Comm comm );
//! Write the mesh databases to a file
void write( const std::vector<MeshDatabase>& meshes, const std::string& filename );
//! Read the mesh databases from a file
std::vector<MeshDatabase> read( const std::string& filename );
} // IO namespace
#endif

103
IO/Reader.cpp Normal file
View File

@ -0,0 +1,103 @@
#include "IO/Reader.h"
#include "IO/MeshDatabase.h"
#include "common/Utilities.h"
#include <ProfilerApp.h>
#include <iostream>
#include <string.h>
#include <memory>
#include <vector>
// List the timesteps in the given directors (dumps.LBPM)
std::vector<std::string> IO::readTimesteps( const std::string& filename )
{
PROFILE_START("readTimesteps");
FILE *fid= fopen(filename.c_str(),"rb");
if ( fid==NULL )
ERROR("Error opening file");
std::vector<std::string> timesteps;
char buf[1000];
while (fgets(buf,sizeof(buf),fid) != NULL) {
std::string line(buf);
line.resize(line.size()-1);
if ( line.empty() )
continue;
timesteps.push_back(line);
}
fclose(fid);
PROFILE_STOP("readTimesteps");
return timesteps;
}
// Read the list of variables for the given timestep
std::vector<IO::MeshDatabase> IO::getMeshList( const std::string& path, const std::string& timestep )
{
std::string filename = path + "/" + timestep + "/LBM.summary";
return IO::read( filename );
}
// Read the given mesh domain
std::shared_ptr<IO::Mesh> IO::getMesh( const std::string& path, const std::string& timestep,
const IO::MeshDatabase& meshDatabase, int domain )
{
PROFILE_START("getMesh");
std::shared_ptr<IO::Mesh> mesh;
if ( meshDatabase.format==1 ) {
// Old format (binary doubles)
std::string filename = path + "/" + timestep + "/" + meshDatabase.file[domain];
FILE *fid = fopen(filename.c_str(),"rb");
INSIST(fid!=NULL,"Error opening file");
fseek( fid, 0, SEEK_END );
size_t bytes = ftell(fid);
size_t N_max = bytes/sizeof(double)+1000;
double *data = new double[N_max];
fseek(fid,0,SEEK_SET);
size_t count = fread(data,sizeof(double),N_max,fid);
fclose(fid);
if ( count%3 != 0 )
ERROR("Error reading file");
if ( meshDatabase.type==IO::MeshType::PointMesh ) {
size_t N = count/3;
std::shared_ptr<PointList> pointlist( new PointList(N) );
std::vector<Point>& P = pointlist->points;
for (size_t i=0; i<N; i++) {
P[i].x = data[3*i+0];
P[i].y = data[3*i+1];
P[i].z = data[3*i+2];
}
mesh = pointlist;
} else if ( meshDatabase.type==IO::MeshType::SurfaceMesh ) {
if ( count%9 != 0 )
ERROR("Error reading file (2)");
size_t N_tri = count/9;
std::shared_ptr<TriList> trilist( new TriList(N_tri) );
std::vector<Point>& A = trilist->A;
std::vector<Point>& B = trilist->B;
std::vector<Point>& C = trilist->C;
for (size_t i=0; i<N_tri; i++) {
A[i].x = data[9*i+0];
A[i].y = data[9*i+1];
A[i].z = data[9*i+2];
B[i].x = data[9*i+3];
B[i].y = data[9*i+4];
B[i].z = data[9*i+5];
C[i].x = data[9*i+6];
C[i].y = data[9*i+7];
C[i].z = data[9*i+8];
}
mesh = trilist;
} else {
ERROR("Unknown mesh type");
}
delete [] data;
} else {
ERROR("Unknown format");
}
PROFILE_STOP("getMesh");
return mesh;
}

31
IO/Reader.h Normal file
View File

@ -0,0 +1,31 @@
#ifndef READER_INC
#define READER_INC
#include <iostream>
#include <string.h>
#include <memory>
#include <vector>
#include "IO/Mesh.h"
#include "IO/MeshDatabase.h"
namespace IO {
//! List the timesteps in the given directors (dumps.LBPM)
std::vector<std::string> readTimesteps( const std::string& filename );
//! Read the list of variables for the given timestep
std::vector<IO::MeshDatabase> getMeshList( const std::string& path, const std::string& timestep );
//! Read the given mesh domain
std::shared_ptr<IO::Mesh> getMesh( const std::string& path, const std::string& timestep,
const MeshDatabase& mesh, int domain );
} // IO namespace
#endif

108
IO/Writer.cpp Normal file
View File

@ -0,0 +1,108 @@
#include "IO/Writer.h"
#include "IO/MeshDatabase.h"
#include "common/Utilities.h"
#include "mpi.h"
#include <sys/stat.h>
#include <algorithm>
#include <vector>
#include <set>
static bool global_summary_created = false;
// Write the mesh data in the original format
static std::vector<IO::MeshDatabase> writeMeshesOrigFormat( const std::vector<IO::MeshDataStruct>& meshData, const char* path )
{
int rank = -1;
MPI_Comm_rank( MPI_COMM_WORLD, &rank );
std::vector<IO::MeshDatabase> meshes_written;
for (size_t i=0; i<meshData.size(); i++) {
char domain[100], filename[100], fullpath[200];
sprintf(domain,"%05i",rank);
sprintf(filename,"%s.%05i",meshData[i].meshName.c_str(),rank);
sprintf(fullpath,"%s/%s",path,filename);
FILE *fid = fopen(fullpath,"wb");
std::shared_ptr<IO::Mesh> mesh = meshData[i].mesh;
IO::MeshDatabase mesh_entry;
mesh_entry.name = meshData[i].meshName;
mesh_entry.format = 1;
mesh_entry.domains.push_back(domain);
mesh_entry.file.push_back(filename);
if ( std::dynamic_pointer_cast<IO::PointList>(mesh)!=NULL ) {
// List of points
mesh_entry.type = IO::MeshType::PointMesh;
std::shared_ptr<IO::PointList> pointlist = std::dynamic_pointer_cast<IO::PointList>(mesh);
const std::vector<Point>& P = pointlist->points;
for (size_t i=0; i<P.size(); i++) {
double x[3];
x[0] = P[i].x; x[1] = P[i].y; x[2] = P[i].z;
fwrite(x,sizeof(double),3,fid);
}
} else if ( std::dynamic_pointer_cast<IO::TriList>(mesh)!=NULL || std::dynamic_pointer_cast<IO::TriMesh>(mesh)!=NULL ) {
// Triangle mesh
mesh_entry.type = IO::MeshType::SurfaceMesh;
std::shared_ptr<IO::TriList> trilist = IO::getTriList(mesh);
const std::vector<Point>& A = trilist->A;
const std::vector<Point>& B = trilist->B;
const std::vector<Point>& C = trilist->C;
for (size_t i=0; i<A.size(); i++) {
double tri[9];
tri[0] = A[i].x; tri[1] = A[i].y; tri[2] = A[i].z;
tri[3] = B[i].x; tri[4] = B[i].y; tri[5] = B[i].z;
tri[6] = C[i].x; tri[7] = C[i].y; tri[8] = C[i].z;
fwrite(tri,sizeof(double),9,fid);
}
} else {
ERROR("Unknown mesh");
}
fclose(fid);
meshes_written.push_back(mesh_entry);
}
return meshes_written;
}
// Write the mesh data
void IO::writeData( int timestep, const std::vector<IO::MeshDataStruct>& meshData )
{
const int format = 1;
int rank = -1;
int size = 0;
MPI_Comm_rank( MPI_COMM_WORLD, &rank );
MPI_Comm_size( MPI_COMM_WORLD, &size );
// Create the output directory
char path[100];
sprintf(path,"vis%03i",timestep);
if ( rank == 0 )
mkdir(path,S_IRWXU|S_IRGRP);
// Write the mesh files
std::vector<IO::MeshDatabase> meshes_written;
if ( format == 1 ) {
// Write the original triangle format
meshes_written = writeMeshesOrigFormat( meshData, path );
} else {
ERROR("Unknown format");
}
// Gather a complete list of files on rank 0
meshes_written = gatherAll(meshes_written,MPI_COMM_WORLD);
// Write the summary files
if ( rank == 0 ) {
// Write the summary file for the current timestep
char filename[200];
sprintf(filename,"%s/LBM.summary",path);
write(meshes_written,filename);
// Add the timestep to the global summary file
FILE *fid = NULL;
if ( !global_summary_created ) {
fid = fopen("summary.LBM","wb");
global_summary_created = true;
} else {
fid = fopen("summary.LBM","ab");
}
fprintf(fid,"%s\n",path);
fclose(fid);
}
}

21
IO/Writer.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef WRITER_INC
#define WRITER_INC
#include <iostream>
#include <string.h>
#include <memory>
#include <vector>
#include "IO/Mesh.h"
#include "IO/MeshDatabase.h"
namespace IO {
void writeData( int timestep, const std::vector<IO::MeshDataStruct>& meshData );
} // IO namespace
#endif

View File

@ -33,15 +33,24 @@ ENDIF()
# Install plugin
MACRO( VISIT_PLUGIN SRC_DIR TARGET )
FILE( MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${SRC_DIR}" )
CONFIGURE_FILE( "${CMAKE_CURRENT_SOURCE_DIR}/${SRC_DIR}/${TARGET}.xml" "${CMAKE_CURRENT_BINARY_DIR}/${SRC_DIR}/${TARGET}.xml" )
FILE( GLOB ConfigFiles RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/${SRC_DIR}"
"${CMAKE_CURRENT_SOURCE_DIR}/${SRC_DIR}/*.C" "${CMAKE_CURRENT_SOURCE_DIR}/${SRC_DIR}/*.h" )
ADD_CUSTOM_TARGET(copy-${SRC_DIR})
FOREACH( ConfigFile ${ConfigFiles} )
ADD_CUSTOM_COMMAND(TARGET copy-${SRC_DIR} PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/${SRC_DIR}/${ConfigFile}" "${CMAKE_CURRENT_BINARY_DIR}/${SRC_DIR}/${ConfigFile}"
)
ENDFOREACH()
ADD_CUSTOM_TARGET(
${SRC_DIR}
${CMAKE_COMMAND} -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/${SRC_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/${SRC_DIR}"
COMMAND ${VISIT_XML_CMAKE} ${TARGET}.xml
COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} .
COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS} .
COMMAND make
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${SRC_DIR}"
SOURCES ${SRC_DIR}
DEPENDS lbpm-wia copy-${SRC_DIR}
)
ENDMACRO()

View File

@ -1,14 +1,14 @@
MACRO ( CONFIGURE_LINE_COVERAGE )
MACRO( CONFIGURE_LINE_COVERAGE )
SET ( COVERAGE_LIBS )
IF ( ENABLE_GCOV )
ADD_DEFINITIONS ( -fprofile-arcs -ftest-coverage )
SET ( COVERAGE_LIBS -lgcov -fprofile-arcs )
ENDIF ()
ENDMACRO ()
ENDMACRO()
# Macro to configure CUDA
MACRO ( CONFIGURE_CUDA )
MACRO( CONFIGURE_CUDA )
CHECK_ENABLE_FLAG( USE_CUDA 0 )
IF( USE_CUDA )
SET( CUDA_FLAGS ${CUDA_NVCC_FLAGS} )
@ -41,14 +41,14 @@ ENDMACRO()
# Macro to configure MIC
MACRO ( CONFIGURE_MIC )
MACRO( CONFIGURE_MIC )
CHECK_ENABLE_FLAG( USE_MIC 0 )
ADD_DEFINITIONS ( "-D USE_MIC" )
ENDMACRO()
# Macro to find and configure the MPI libraries
MACRO ( CONFIGURE_MPI )
MACRO( CONFIGURE_MPI )
# Determine if we want to use MPI
CHECK_ENABLE_FLAG(USE_MPI 1 )
IF ( USE_MPI )
@ -122,12 +122,64 @@ MACRO ( CONFIGURE_MPI )
ENDMACRO ()
# Macro to find and configure timer
MACRO( CONFIGURE_TIMER )
# Determine if we want to use the timer utility
CHECK_ENABLE_FLAG( USE_TIMER 0 )
IF ( USE_TIMER )
# Check if we specified the timer directory
IF ( TIMER_DIRECTORY )
VERIFY_PATH ( ${TIMER_DIRECTORY} )
VERIFY_PATH ( ${TIMER_DIRECTORY}/include )
VERIFY_PATH ( ${TIMER_DIRECTORY}/lib )
SET( TIMER_INCLUDE ${TIMER_DIRECTORY}/include )
FIND_LIBRARY( TIMER_LIBS NAMES timerutility PATHS ${TIMER_DIRECTORY}/lib NO_DEFAULT_PATH )
SET( TIMER_CXXFLAGS "-DUSE_TIMER -I${TIMER_DIRECTORY}/include" )
SET( TIMER_LDFLAGS -L${TIMER_DIRECTORY}/lib )
SET( TIMER_LDLIBS -ltimerutility )
ELSE()
MESSAGE( FATAL_ERROR "Default search for TIMER is not yet supported. Use -D TIMER_DIRECTORY=" )
SET( TIMER_CXXFLAGS )
SET( TIMER_LDFLAGS )
SET( TIMER_LDLIBS )
ENDIF()
INCLUDE_DIRECTORIES( ${TIMER_INCLUDE} )
ADD_DEFINITIONS( "-D USE_TIMER" )
MESSAGE( "Using timer utility" )
MESSAGE( " TIMER_LIBRARIES = ${TIMER_LIBS}" )
ELSE()
FILE(WRITE "${LBPM_INSTALL_DIR}/include/null_timer/ProfilerApp.h" "#define PROFILE_START(...) do {} while(0)\n" )
FILE(APPEND "${LBPM_INSTALL_DIR}/include/null_timer/ProfilerApp.h" "#define PROFILE_STOP(...) do {} while(0)\n" )
FILE(APPEND "${LBPM_INSTALL_DIR}/include/null_timer/ProfilerApp.h" "#define PROFILE_START2(...) do {} while(0)\n" )
FILE(APPEND "${LBPM_INSTALL_DIR}/include/null_timer/ProfilerApp.h" "#define PROFILE_STOP2(...) do {} while(0)\n" )
FILE(APPEND "${LBPM_INSTALL_DIR}/include/null_timer/ProfilerApp.h" "#define PROFILE_SCOPED(...) do {} while(0)\n" )
FILE(APPEND "${LBPM_INSTALL_DIR}/include/null_timer/ProfilerApp.h" "#define PROFILE_SYNCRONIZE() do {} while(0)\n" )
FILE(APPEND "${LBPM_INSTALL_DIR}/include/null_timer/ProfilerApp.h" "#define PROFILE_SAVE(...) do {} while(0)\n" )
FILE(APPEND "${LBPM_INSTALL_DIR}/include/null_timer/ProfilerApp.h" "#define PROFILE_STORE_TRACE(X) do {} while(0)\n" )
FILE(APPEND "${LBPM_INSTALL_DIR}/include/null_timer/ProfilerApp.h" "#define PROFILE_ENABLE(...) do {} while(0)\n" )
FILE(APPEND "${LBPM_INSTALL_DIR}/include/null_timer/ProfilerApp.h" "#define PROFILE_DISABLE() do {} while(0)\n" )
FILE(APPEND "${LBPM_INSTALL_DIR}/include/null_timer/ProfilerApp.h" "#define PROFILE_ENABLE_TRACE() do {} while(0)\n" )
FILE(APPEND "${LBPM_INSTALL_DIR}/include/null_timer/ProfilerApp.h" "#define PROFILE_DISABLE_TRACE() do {} while(0)\n" )
FILE(APPEND "${LBPM_INSTALL_DIR}/include/null_timer/ProfilerApp.h" "#define PROFILE_ENABLE_MEMORY() do {} while(0)\n" )
FILE(APPEND "${LBPM_INSTALL_DIR}/include/null_timer/ProfilerApp.h" "#define PROFILE_DISABLE_MEMORY() do {} while(0)\n" )
INCLUDE_DIRECTORIES( "${LBPM_INSTALL_DIR}/include/null_timer" )
MESSAGE( "Disabling timer utility" )
ENDIF()
ENDMACRO()
# Macro to configure system-specific libraries and flags
MACRO ( CONFIGURE_SYSTEM )
MACRO( CONFIGURE_SYSTEM )
# First check/set the compile mode
IF( NOT CMAKE_BUILD_TYPE )
MESSAGE(FATAL_ERROR "CMAKE_BUILD_TYPE is not set")
ENDIF()
# Disable gxx debug flags if we are building the visit plugin
# This is necessary to prvent segfaults caused by inconsistent object sizes
# caused by std::vector<std::string> in the avtMeshMetaData class
IF ( USE_VISIT )
SET( DISABLE_GXX_DEBUG 1 )
ENDIF()
# Remove extra library links
# Get the compiler
SET_COMPILER ()

View File

@ -252,6 +252,7 @@ MACRO( ADD_LBPM_EXE_DEP EXE )
# Add the libraries
TARGET_LINK_LIBRARIES( ${EXE} ${LBPM_LIBS} )
# Add external libraries
TARGET_LINK_LIBRARIES( ${EXE} ${TIMER_LIBS} )
TARGET_LINK_LIBRARIES( ${EXE} ${EXTERNAL_LIBS} )
IF ( USE_MPI )
TARGET_LINK_LIBRARIES( ${EXE} ${MPI_LINK_FLAGS} ${MPI_LIBRARIES} )
@ -497,6 +498,7 @@ MACRO( ADD_DISTCLEAN )
example
common
visit
IO
)
ADD_CUSTOM_TARGET (distclean @echo cleaning for source distribution)
IF (UNIX)

View File

@ -1,10 +1,14 @@
#ifndef PointList_INC
#define PointList_INC
#include <math.h>
struct Point {
Point() : x(0.0), y(0.0), z(0.0) {}
Point(double xv,double yv,double zv) : x(xv), y(yv), z(zv) {}
Point(const Point& rhs): x(rhs.x), y(rhs.y), z(rhs.z) {}
Point& operator=(const Point& rhs) { this->x=rhs.x; this->y=rhs.y; this->z=rhs.z; }
~Point() {}
double x,y,z;
};
@ -179,3 +183,6 @@ template <class T> DTMutableList<T> IncreaseSize(const DTList<T> &A,size_t addLe
}
#endif

View File

@ -5,7 +5,6 @@ INSTALL_LBPM_EXE( TestBubble )
CONFIGURE_FILE( ${CMAKE_CURRENT_SOURCE_DIR}/cylindertest ${CMAKE_CURRENT_BINARY_DIR}/cylindertest COPYONLY )
# Add the tests
ADD_LBPM_TEST( pmmc_cylinder )
ADD_LBPM_TEST( TestBubble )
@ -13,12 +12,15 @@ ADD_LBPM_TEST( TestCylinderAreas )
ADD_LBPM_TEST( TestSphereCurvature )
ADD_LBPM_TEST_1_2_4( testCommunication )
ADD_LBPM_TEST_1_2_4( testUtilities )
ADD_LBPM_TEST( TestWriter )
# Sample test that will run with 1, 2, and 4 processors, failing with 4 or more procs
ADD_LBPM_TEST_1_2_4( hello_world )
SET_TESTS_PROPERTIES( hello_world PROPERTIES ENVIRONMENT "MPICH_RDMA_ENABLED_CUDA=0")
SET_TESTS_PROPERTIES( hello_world_2procs PROPERTIES ENVIRONMENT "MPICH_RDMA_ENABLED_CUDA=0")
SET_TESTS_PROPERTIES( hello_world_4procs PROPERTIES ENVIRONMENT "MPICH_RDMA_ENABLED_CUDA=0")
IF ( USE_MPI )
SET_TESTS_PROPERTIES( hello_world_2procs PROPERTIES ENVIRONMENT "MPICH_RDMA_ENABLED_CUDA=0")
SET_TESTS_PROPERTIES( hello_world_4procs PROPERTIES ENVIRONMENT "MPICH_RDMA_ENABLED_CUDA=0")
ENDIF()
# Add CPU/GPU specific test

View File

@ -13,8 +13,12 @@
#include "D3Q7.h"
#include "Color.h"
#include "Communication.h"
#include "IO/Mesh.h"
#include "IO/Writer.h"
#include "ProfilerApp.h"
#define CBUB
#define USE_NEW_WRITER
using namespace std;
@ -101,6 +105,8 @@ int main(int argc, char **argv)
MPI_Init(&argc,&argv);
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
MPI_Comm_size(MPI_COMM_WORLD,&nprocs);
Utilities::setAbortBehavior(true,true,false);
PROFILE_ENABLE(0);
// parallel domain size (# of sub-domains)
int nprocx,nprocy,nprocz;
int iproc,jproc,kproc;
@ -2089,11 +2095,17 @@ int main(int argc, char **argv)
Gwn_global(0),Gwn_global(1),Gwn_global(2),Gwn_global(3),Gwn_global(4),Gwn_global(5)); // orientation of wn interface
}
FILE *WN_TRIS;
sprintf(LocalRankFilename,"%s%s","wn-tris.",LocalRankString);
WN_TRIS = fopen(LocalRankFilename,"wb");
#ifdef USE_NEW_WRITER
std::shared_ptr<IO::TriList> mesh( new IO::TriList() );
mesh->A.reserve(8*ncubes);
mesh->B.reserve(8*ncubes);
mesh->C.reserve(8*ncubes);
#else
FILE *WN_TRIS;
sprintf(LocalRankFilename,"%s%s","wn-tris.",LocalRankString);
WN_TRIS = fopen(LocalRankFilename,"wb");
#endif
for (c=0;c<ncubes;c++){
// Get cube from the list
i = cubeList(0,c);
@ -2131,20 +2143,33 @@ int main(int argc, char **argv)
A = C;
C = P;
}
//fprintf(WN_TRIS,"%f %f %f %f %f %f %f %f %f \n",A.x,A.y,A.z,B.x,B.y,B.z,C.x,C.y,C.z);
fwrite(&A.x,sizeof(A.x),1,WN_TRIS);
fwrite(&A.y,sizeof(A.y),1,WN_TRIS);
fwrite(&A.z,sizeof(A.z),1,WN_TRIS);
fwrite(&B.x,sizeof(B.x),1,WN_TRIS);
fwrite(&B.y,sizeof(B.y),1,WN_TRIS);
fwrite(&B.z,sizeof(B.z),1,WN_TRIS);
fwrite(&C.x,sizeof(C.x),1,WN_TRIS);
fwrite(&C.y,sizeof(C.y),1,WN_TRIS);
fwrite(&C.z,sizeof(C.z),1,WN_TRIS);
#ifdef USE_NEW_WRITER
mesh->A.push_back(A);
mesh->B.push_back(B);
mesh->C.push_back(C);
#else
//fprintf(WN_TRIS,"%f %f %f %f %f %f %f %f %f \n",A.x,A.y,A.z,B.x,B.y,B.z,C.x,C.y,C.z);
fwrite(&A.x,sizeof(A.x),1,WN_TRIS);
fwrite(&A.y,sizeof(A.y),1,WN_TRIS);
fwrite(&A.z,sizeof(A.z),1,WN_TRIS);
fwrite(&B.x,sizeof(B.x),1,WN_TRIS);
fwrite(&B.y,sizeof(B.y),1,WN_TRIS);
fwrite(&B.z,sizeof(B.z),1,WN_TRIS);
fwrite(&C.x,sizeof(C.x),1,WN_TRIS);
fwrite(&C.y,sizeof(C.y),1,WN_TRIS);
fwrite(&C.z,sizeof(C.z),1,WN_TRIS);
#endif
}
}
fclose(WN_TRIS);
#ifdef USE_NEW_WRITER
std::vector<IO::MeshDataStruct> meshData(1);
meshData[0].meshName = "wn-tris";
meshData[0].mesh = mesh;
IO::writeData( bubbleCount, meshData );
#else
fclose(WN_TRIS);
#endif
}
//************************************************************************/
DeviceBarrier();
@ -2184,7 +2209,7 @@ int main(int argc, char **argv)
fwrite(DensityValues,8,2*N,PHASE);
fclose(PHASE);
*/ //************************************************************************/
PROFILE_SAVE("TestBubble");
return 0;
// ****************************************************

176
tests/TestWriter.cpp Normal file
View File

@ -0,0 +1,176 @@
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <exception>
#include <stdexcept>
#include <fstream>
#include <mpi.h>
#include <memory>
#include "common/UnitTest.h"
#include "common/Utilities.h"
#include "IO/MeshDatabase.h"
#include "IO/Reader.h"
#include "IO/Writer.h"
inline bool approx_equal( const Point& A, const Point& B )
{
double tol = 1e-8*(A.x*A.x+A.y*A.y+A.z*A.z);
return fabs(A.x-B.x)<=tol && fabs(A.y-B.y)<=tol && fabs(A.z-B.z)<=tol;
}
int main(int argc, char **argv)
{
int rank,nprocs;
MPI_Init(&argc,&argv);
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
MPI_Comm_size(MPI_COMM_WORLD,&nprocs);
Utilities::setAbortBehavior(true,true,false);
Utilities::setErrorHandlers();
UnitTest ut;
// Create some points
const int N_points = 8;
const int N_tri = 12;
double x[8] = { 0, 1, 0, 1, 0, 1, 0, 1 };
double y[8] = { 0, 0, 1, 1, 0, 0, 1, 1 };
double z[8] = { 0, 0, 0, 0, 1, 1, 1, 1 };
int tri[N_tri][3] = {
{0,1,3}, {0,3,2}, {4,5,7}, {4,7,6}, // z faces
{0,1,4}, {1,4,5}, {2,3,6}, {3,6,7}, // y faces
{0,2,4}, {2,4,6}, {1,3,5}, {3,5,7} // x faces
};
// Create the meshes
std::shared_ptr<IO::PointList> set1( new IO::PointList(N_points) );
for (int i=0; i<N_points; i++) {
set1->points[i].x = x[i];
set1->points[i].y = y[i];
set1->points[i].z = z[i];
}
std::shared_ptr<IO::TriMesh> trimesh( new IO::TriMesh(N_tri,set1) );
for (int i=0; i<N_tri; i++) {
trimesh->A[i] = tri[i][0];
trimesh->B[i] = tri[i][1];
trimesh->C[i] = tri[i][2];
}
std::shared_ptr<IO::TriList> trilist( new IO::TriList(*trimesh) );
for (int i=0; i<N_tri; i++) {
Point A(x[tri[i][0]],y[tri[i][0]],z[tri[i][0]]);
Point B(x[tri[i][1]],y[tri[i][1]],z[tri[i][1]]);
Point C(x[tri[i][2]],y[tri[i][2]],z[tri[i][2]]);
if ( !approx_equal(trilist->A[i],A) || !approx_equal(trilist->B[i],B) || !approx_equal(trilist->C[i],C) )
{
printf("Failed to create trilist\n");
return -1;
}
}
// Write the data
std::vector<IO::MeshDataStruct> meshData(3);
meshData[0].meshName = "pointmesh";
meshData[0].mesh = set1;
meshData[1].meshName = "trimesh";
meshData[1].mesh = trimesh;
meshData[2].meshName = "trilist";
meshData[2].mesh = trilist;
IO::writeData( 0, meshData );
IO::writeData( 3, meshData );
MPI_Barrier(MPI_COMM_WORLD);
// Get a list of the timesteps
std::vector<std::string> timesteps = IO::readTimesteps("summary.LBM");
if ( timesteps.size()==2 )
ut.passes("Corrent number of timesteps");
else
ut.failure("Incorrent number of timesteps");
// Check the mesh lists
for (size_t i=0; i<timesteps.size(); i++) {
// Load the list of meshes and check its size
std::vector<IO::MeshDatabase> list = IO::getMeshList(".",timesteps[i]);
if ( list.size()==meshData.size() )
ut.passes("Corrent number of meshes found");
else
ut.failure("Incorrent number of meshes found");
// Check the number of domains for each mesh
bool pass = true;
for (size_t j=0; j<list.size(); j++)
pass = pass && list[j].domains.size()==nprocs;
if ( pass ) {
ut.passes("Corrent number of domains for mesh");
} else {
ut.failure("Incorrent number of domains for mesh");
continue;
}
// For each domain, load the mesh and check its data
for (size_t j=0; j<list.size(); j++) {
for (size_t k=0; k<list[i].domains.size(); k++) {
std::shared_ptr<IO::Mesh> mesh = IO::getMesh(".",timesteps[i],list[j],k);
if ( mesh==NULL ) {
printf("Failed to load %s\n",meshData[i].meshName.c_str());
pass = false;
break;
}
if ( meshData[j].meshName=="pointmesh" ) {
// Check the pointmesh
std::shared_ptr<IO::PointList> pmesh = IO::getPointList(mesh);
if ( pmesh==NULL ) {
pass = false;
break;
}
if ( pmesh->points.size()!=N_points ) {
pass = false;
break;
}
}
if ( meshData[j].meshName=="trimesh" || meshData[j].meshName=="trilist" ) {
// Check the trimesh/trilist
std::shared_ptr<IO::TriMesh> mesh1 = IO::getTriMesh(mesh);
std::shared_ptr<IO::TriList> mesh2 = IO::getTriList(mesh);
if ( mesh1==NULL || mesh2==NULL ) {
pass = false;
break;
}
if ( mesh1->A.size()!=N_tri || mesh1->B.size()!=N_tri || mesh1->C.size()!=N_tri ||
mesh2->A.size()!=N_tri || mesh2->B.size()!=N_tri || mesh2->C.size()!=N_tri )
{
pass = false;
break;
}
const std::vector<Point>& P1 = mesh1->vertices->points;
const std::vector<int>& A1 = mesh1->A;
const std::vector<int>& B1 = mesh1->B;
const std::vector<int>& C1 = mesh1->C;
const std::vector<Point>& A2 = mesh2->A;
const std::vector<Point>& B2 = mesh2->B;
const std::vector<Point>& C2 = mesh2->C;
const std::vector<Point>& A = trilist->A;
const std::vector<Point>& B = trilist->B;
const std::vector<Point>& C = trilist->C;
for (size_t i=0; i<N_tri; i++) {
if ( !approx_equal(P1[A1[i]],A[i]) || !approx_equal(P1[B1[i]],B[i]) || !approx_equal(P1[C1[i]],C[i]) )
pass = false;
if ( !approx_equal(A2[i],A[i]) || !approx_equal(B2[i],B[i]) || !approx_equal(C2[i],C[i]) )
pass = false;
}
}
}
}
if ( pass ) {
ut.passes("Meshes loaded correctly");
} else {
ut.failure("Meshes did not load correctly");
continue;
}
}
// Finished
ut.report();
int N_errors = ut.NumFailGlobal();
MPI_Barrier(MPI_COMM_WORLD);
MPI_Finalize();
return N_errors;
}

View File

@ -18,6 +18,8 @@
//#define CBUB
//#define WRITE_SURFACES
#define USE_EXP_CONTACT_ANGLE
#define USE_NEW_WRITER
using namespace std;
@ -2430,28 +2432,47 @@ int main(int argc, char **argv)
WriteCheckpoint(LocalRestartFile, cDen, cDistEven, cDistOdd, N);
#ifdef WRITE_SURFACES
sprintf(tmpstr,"vis%03d",logcount);
if (rank==0){
mkdir(tmpstr,0777);
}
MPI_Barrier(MPI_COMM_WORLD);
FILE *WN_TRIS;
sprintf(LocalRankFilename,"%s/%s%s",tmpstr,"wn-tris.",LocalRankString);
WN_TRIS = fopen(LocalRankFilename,"wb");
FILE *NS_TRIS;
sprintf(LocalRankFilename,"%s/%s%s",tmpstr,"ns-tris.",LocalRankString);
NS_TRIS = fopen(LocalRankFilename,"wb");
#ifdef USE_NEW_WRITER
std::shared_ptr<TriList> wn_mesh( new TriList() );
wn_mesh->A.reserve(8*ncubes);
wn_mesh->B.reserve(8*ncubes);
wn_mesh->C.reserve(8*ncubes);
std::shared_ptr<TriList> ns_mesh( new TriList() );
ns_mesh->A.reserve(8*ncubes);
ns_mesh->B.reserve(8*ncubes);
ns_mesh->C.reserve(8*ncubes);
std::shared_ptr<TriList> ws_mesh( new TriList() );
ws_mesh->A.reserve(8*ncubes);
ws_mesh->B.reserve(8*ncubes);
ws_mesh->C.reserve(8*ncubes);
std::shared_ptr<TriList> wns_mesh( new TriList() );
wns_mesh->A.reserve(8*ncubes);
wns_mesh->B.reserve(8*ncubes);
wns_mesh->C.reserve(8*ncubes);
#else
sprintf(tmpstr,"vis%03d",logcount);
if (rank==0){
mkdir(tmpstr,0777);
}
MPI_Barrier(MPI_COMM_WORLD);
FILE *WS_TRIS;
sprintf(LocalRankFilename,"%s/%s%s",tmpstr,"ws-tris.",LocalRankString);
WS_TRIS = fopen(LocalRankFilename,"wb");
FILE *WN_TRIS;
sprintf(LocalRankFilename,"%s/%s%s",tmpstr,"wn-tris.",LocalRankString);
WN_TRIS = fopen(LocalRankFilename,"wb");
FILE *WNS_PTS;
sprintf(LocalRankFilename,"%s/%s%s",tmpstr,"wns-crv.",LocalRankString);
WNS_PTS = fopen(LocalRankFilename,"wb");
FILE *NS_TRIS;
sprintf(LocalRankFilename,"%s/%s%s",tmpstr,"ns-tris.",LocalRankString);
NS_TRIS = fopen(LocalRankFilename,"wb");
FILE *WS_TRIS;
sprintf(LocalRankFilename,"%s/%s%s",tmpstr,"ws-tris.",LocalRankString);
WS_TRIS = fopen(LocalRankFilename,"wb");
FILE *WNS_PTS;
sprintf(LocalRankFilename,"%s/%s%s",tmpstr,"wns-crv.",LocalRankString);
WNS_PTS = fopen(LocalRankFilename,"wb");
#endif
for (c=0;c<ncubes;c++){
// Get cube from the list
@ -2500,16 +2521,22 @@ int main(int argc, char **argv)
C.x += 1.0*iproc*(Nx-2);
C.y += 1.0*jproc*(Nx-2);
C.z += 1.0*kproc*(Nx-2);
// write the triangle
fwrite(&A.x,sizeof(A.x),1,WN_TRIS);
fwrite(&A.y,sizeof(A.y),1,WN_TRIS);
fwrite(&A.z,sizeof(A.z),1,WN_TRIS);
fwrite(&B.x,sizeof(B.x),1,WN_TRIS);
fwrite(&B.y,sizeof(B.y),1,WN_TRIS);
fwrite(&B.z,sizeof(B.z),1,WN_TRIS);
fwrite(&C.x,sizeof(C.x),1,WN_TRIS);
fwrite(&C.y,sizeof(C.y),1,WN_TRIS);
fwrite(&C.z,sizeof(C.z),1,WN_TRIS);
#ifdef USE_NEW_WRITER
wn_mesh->A.push_back(A);
wn_mesh->B.push_back(B);
wn_mesh->C.push_back(C);
#else
// write the triangle
fwrite(&A.x,sizeof(A.x),1,WN_TRIS);
fwrite(&A.y,sizeof(A.y),1,WN_TRIS);
fwrite(&A.z,sizeof(A.z),1,WN_TRIS);
fwrite(&B.x,sizeof(B.x),1,WN_TRIS);
fwrite(&B.y,sizeof(B.y),1,WN_TRIS);
fwrite(&B.z,sizeof(B.z),1,WN_TRIS);
fwrite(&C.x,sizeof(C.x),1,WN_TRIS);
fwrite(&C.y,sizeof(C.y),1,WN_TRIS);
fwrite(&C.z,sizeof(C.z),1,WN_TRIS);
#endif
}
for (int r=0;r<n_ws_tris;r++){
A = ws_pts(ws_tris(0,r));
@ -2525,16 +2552,22 @@ int main(int argc, char **argv)
C.x += 1.0*iproc*(Nx-2);
C.y += 1.0*jproc*(Nx-2);
C.z += 1.0*kproc*(Nx-2);
// write the triangle
fwrite(&A.x,sizeof(A.x),1,WS_TRIS);
fwrite(&A.y,sizeof(A.y),1,WS_TRIS);
fwrite(&A.z,sizeof(A.z),1,WS_TRIS);
fwrite(&B.x,sizeof(B.x),1,WS_TRIS);
fwrite(&B.y,sizeof(B.y),1,WS_TRIS);
fwrite(&B.z,sizeof(B.z),1,WS_TRIS);
fwrite(&C.x,sizeof(C.x),1,WS_TRIS);
fwrite(&C.y,sizeof(C.y),1,WS_TRIS);
fwrite(&C.z,sizeof(C.z),1,WS_TRIS);
#ifdef USE_NEW_WRITER
ws_mesh->A.push_back(A);
ws_mesh->B.push_back(B);
ws_mesh->C.push_back(C);
#else
// write the triangle
fwrite(&A.x,sizeof(A.x),1,WS_TRIS);
fwrite(&A.y,sizeof(A.y),1,WS_TRIS);
fwrite(&A.z,sizeof(A.z),1,WS_TRIS);
fwrite(&B.x,sizeof(B.x),1,WS_TRIS);
fwrite(&B.y,sizeof(B.y),1,WS_TRIS);
fwrite(&B.z,sizeof(B.z),1,WS_TRIS);
fwrite(&C.x,sizeof(C.x),1,WS_TRIS);
fwrite(&C.y,sizeof(C.y),1,WS_TRIS);
fwrite(&C.z,sizeof(C.z),1,WS_TRIS);
#endif
}
for (int r=0;r<n_ns_tris;r++){
A = ns_pts(ns_tris(0,r));
@ -2550,16 +2583,22 @@ int main(int argc, char **argv)
C.x += 1.0*iproc*(Nx-2);
C.y += 1.0*jproc*(Nx-2);
C.z += 1.0*kproc*(Nx-2);
// write the triangle
fwrite(&A.x,sizeof(A.x),1,NS_TRIS);
fwrite(&A.y,sizeof(A.y),1,NS_TRIS);
fwrite(&A.z,sizeof(A.z),1,NS_TRIS);
fwrite(&B.x,sizeof(B.x),1,NS_TRIS);
fwrite(&B.y,sizeof(B.y),1,NS_TRIS);
fwrite(&B.z,sizeof(B.z),1,NS_TRIS);
fwrite(&C.x,sizeof(C.x),1,NS_TRIS);
fwrite(&C.y,sizeof(C.y),1,NS_TRIS);
fwrite(&C.z,sizeof(C.z),1,NS_TRIS);
#ifdef USE_NEW_WRITER
ns_mesh->A.push_back(A);
ns_mesh->B.push_back(B);
ns_mesh->C.push_back(C);
#else
// write the triangle
fwrite(&A.x,sizeof(A.x),1,NS_TRIS);
fwrite(&A.y,sizeof(A.y),1,NS_TRIS);
fwrite(&A.z,sizeof(A.z),1,NS_TRIS);
fwrite(&B.x,sizeof(B.x),1,NS_TRIS);
fwrite(&B.y,sizeof(B.y),1,NS_TRIS);
fwrite(&B.z,sizeof(B.z),1,NS_TRIS);
fwrite(&C.x,sizeof(C.x),1,NS_TRIS);
fwrite(&C.y,sizeof(C.y),1,NS_TRIS);
fwrite(&C.z,sizeof(C.z),1,NS_TRIS);
#endif
}
for (int p=0; p < n_nws_pts; p++){
P = nws_pts(p);
@ -2569,10 +2608,23 @@ int main(int argc, char **argv)
fwrite(&P.z,sizeof(P.z),1,WNS_PTS);
}
}
fclose(WN_TRIS);
fclose(NS_TRIS);
fclose(WS_TRIS);
fclose(WNS_PTS);
#ifdef USE_NEW_WRITER
std::vector<MeshDataStruct> meshData(4);
meshData[0].meshName = "wn-tris";
meshData[0].mesh = wn_mesh;
meshData[1].meshName = "ws-tris";
meshData[1].mesh = ws_mesh;
meshData[2].meshName = "ns-tris";
meshData[2].mesh = ns_mesh;
meshData[3].meshName = "wns-tris";
meshData[3].mesh = wns_mesh;
writeData( logcount, meshData );
#else
fclose(WN_TRIS);
fclose(NS_TRIS);
fclose(WS_TRIS);
fclose(WNS_PTS);
#endif
logcount++;
#endif
}

View File

@ -1,12 +1,24 @@
<?xml version="1.0"?>
<Plugin name="LBM" type="database" label="LBM" version="1.0" mdspecificcode="true" dbtype="MTMD">
<Plugin name="LBM" type="database" label="LBM" version="1.0" mdspecificcode="true" dbtype="MTMD">
<FilePatterns>
*.LBM
*.LBM
</FilePatterns>
<CXXFLAGS>
-I${LBPM_INSTALL_DIR}/include
-DUSE_MPI
-I${MPI_INCLUDE}
${TIMER_CXXFLAGS}
</CXXFLAGS>
<LDFLAGS>
-L${LBPM_INSTALL_DIR}/lib
-L${CMAKE_CURRENT_BINARY_DIR}/..
${TIMER_LDFLAGS}
${MPI_LINK_FLAGS}
</LDFLAGS>
<LIBS>
-llbpm-wia
${TIMER_LDLIBS}
${MPI_LIBRARIES}
</LIBS>
</Plugin>
</Plugin>

View File

@ -45,6 +45,10 @@
#include <string>
// LBPM headers
#include "IO/Reader.h"
#include "common/Utilities.h"
// vtk headers
#include <vtkFloatArray.h>
#include <vtkRectilinearGrid.h>
@ -57,6 +61,7 @@
#include <avtDatabaseMetaData.h>
#include <vtkHelpers.h>
#include <DBOptionsAttributes.h>
#include <Expression.h>
@ -104,6 +109,8 @@ avtLBMFileFormat::avtLBMFileFormat(const char *filename)
: avtMTMDFileFormat(filename)
{
DebugStream::Stream1() << "avtLBMFileFormat::avtLBMFileFormat: " << filename << std::endl;
Utilities::setAbortBehavior(true,true,true);
Utilities::setErrorHandlers();
// Get the path to the input file
std::string file(filename);
size_t k1 = file.rfind(47);
@ -111,55 +118,9 @@ avtLBMFileFormat::avtLBMFileFormat(const char *filename)
if ( k1==std::string::npos ) { k1=0; }
if ( k2==std::string::npos ) { k2=0; }
path = file.substr(0,std::max(k1,k2));
// Load the summary file
DebugStream::Stream1() << "Loading " << filename << std::endl;
FILE *fid= fopen(filename,"r");
if ( fid==NULL ) {
DebugStream::Stream1() << "Error opening file" << std::endl;
return;
}
char buf[1000];
while (fgets(buf,sizeof(buf),fid) != NULL) {
std::string line(buf);
line.resize(line.size()-1);
if ( line.empty() )
continue;
timesteps.push_back(line);
}
fclose(fid);
// For each time step, get the list of meshes and files
meshlist.resize(timesteps.size());
for (size_t i=0; i<timesteps.size(); i++) {
std::string filename2 = path + "/" + timesteps[i] + "/LBM.summary";
FILE *fid= fopen(filename2.c_str(),"r");
if ( fid==NULL ) {
DebugStream::Stream1() << "Error opening timestep: " << filename << std::endl;
return;
}
char buf[1000];
while (fgets(buf,sizeof(buf),fid) != NULL) {
std::string file(buf);
file.resize(file.size()-1);
if ( file.empty() )
continue;
size_t k = file.rfind('.');
std::string meshname = file.substr(0,k);
if ( meshlist[i][meshname].meshname.empty() ) {
meshlist[i][meshname].meshname = meshname;
if ( meshname=="ns-tris" || meshname=="ws-tris" || meshname=="wn-tris" ) {
meshlist[i][meshname].type = AVT_SURFACE_MESH;
} else if ( meshname=="wns-crv" ) {
meshlist[i][meshname].type = AVT_POINT_MESH;
} else {
DebugStream::Stream1() << "Warning: unknown mesh type for mesh: " << meshname << std::endl;
}
}
meshlist[i][meshname].files.push_back(file);
}
fclose(fid);
}
timesteps = IO::readTimesteps(filename);
}
@ -208,7 +169,7 @@ avtLBMFileFormat::FreeUpResources(void)
if ( obj!=NULL )
obj->Delete();
}
meshcache.clear();
database.clear();
DebugStream::Stream2() << " finished" << std::endl;
}
@ -230,41 +191,34 @@ void
avtLBMFileFormat::PopulateDatabaseMetaData(avtDatabaseMetaData *md, int timeState)
{
DebugStream::Stream1() << "avtLBMFileFormat::PopulateDatabaseMetaData: " << timeState << std::endl;
// Read the mesh dabases
database = IO::getMeshList(path,timesteps[timeState]);
// Add the mesh domains to the meta data
std::map<std::string,meshdata>::iterator it;
for (it=meshlist[timeState].begin(); it!=meshlist[timeState].end(); ++it) {
std::sort(it->second.files.begin(),it->second.files.end());
std::string meshname = it->first;
avtMeshType type = it->second.type;
for (size_t i=0; i<database.size(); i++) {
DebugStream::Stream1() << " Adding " << database[i].name << std::endl;
avtMeshMetaData *mmd = new avtMeshMetaData;
mmd->name = meshname;
mmd->meshType = it->second.type;
mmd->name = database[i].name;
mmd->meshType = vtkMeshType(database[i].type);
mmd->spatialDimension = 3;
mmd->topologicalDimension = -1;
if ( mmd->meshType==AVT_SURFACE_MESH )
mmd->topologicalDimension = 2;
mmd->numBlocks = it->second.files.size();
mmd->blockNames = std::vector<std::string>(it->second.files.size());
for(size_t i=0; i<it->second.files.size(); i++) {
char tmp[100];
sprintf(tmp,"%s.%5i",meshname.c_str(),(int)i);
mmd->blockNames[i] = std::string(tmp);
}
mmd->numBlocks = database[i].domains.size();
mmd->blockNames = database[i].domains;
md->Add(mmd);
// Add expressions for the coordinates
const char *xyz[3] = {"x","y","z"};
for(int i=0; i<3; ++i) {
for(int j=0; j<3; j++) {
Expression expr;
char expdef[100], expname[100];
sprintf(expdef,"coord(<%s>)[%i]",meshname.c_str(),i);
sprintf(expname,"%s-%s",meshname.c_str(),xyz[i]);
sprintf(expdef,"coord(<%s>)[%i]",mmd->name.c_str(),j);
sprintf(expname,"%s-%s",mmd->name.c_str(),xyz[j]);
expr.SetName(expname);
expr.SetDefinition(expdef);
expr.SetType(Expression::ScalarMeshVar);
md->AddExpression(&expr);
}
}
DebugStream::Stream1() << " Finished" << std::endl;
//
// CODE TO ADD A SCALAR VARIABLE
@ -372,94 +326,50 @@ avtLBMFileFormat::PopulateDatabaseMetaData(avtDatabaseMetaData *md, int timeStat
// ****************************************************************************
vtkDataSet *
avtLBMFileFormat::GetMesh(int timestate, int domain, const char *meshname)
avtLBMFileFormat::GetMesh(int timeState, int domain, const char *meshname)
{
DebugStream::Stream1() << "avtLBMFileFormat::GetMesh - " << meshname
<< "," << timeState << "," << domain << std::endl;
TIME_TYPE start, stop, freq;
get_frequency(&freq);
get_time(&start);
// Get the filename
DebugStream::Stream1() << "avtLBMFileFormat::GetMesh: ";
std::string filename = path + "/" + timesteps[timestate] + "/" +
meshlist[timestate][std::string(meshname)].files[domain];
avtMeshType type = meshlist[timestate][std::string(meshname)].type;
DebugStream::Stream1() << filename << std::endl;
// Check if we have a cached copy of the mesh
char cache_name[1000];
sprintf(cache_name,"%i-%i-%s",timestate,domain,meshname);
sprintf(cache_name,"%i-%i-%s",timeState,domain,meshname);
if ( meshcache.find(cache_name)!=meshcache.end() )
return dynamic_cast<vtkDataSet*>(meshcache.find(cache_name)->second);
// Read the raw data
FILE *fid = fopen(filename.c_str(),"rb");
if ( fid==NULL ) {
DebugStream::Stream1() << " Error opening file" << std::endl;
return NULL;
}
fseek( fid, 0, SEEK_END );
size_t bytes = ftell(fid);
size_t N_max = bytes/sizeof(double)+1000;
double *data = new double[N_max];
fseek( fid, 0, SEEK_SET );
size_t count = fread(data,sizeof(double),N_max,fid);
fclose(fid);
if ( count%3 ) {
DebugStream::Stream1() << " Error reading data: " << count << std::endl;
delete [] data;
return NULL;
}
if ( count==0 ) {
DebugStream::Stream2() << " No points read" << std::endl;
delete [] data;
return NULL;
}
// Create the points in vtk
DebugStream::Stream2() << " Creating vtkFloatArray" << std::endl;
vtkFloatArray *coords = vtkFloatArray::New();
coords->SetNumberOfComponents(3);
coords->SetNumberOfTuples(count/3);
for (size_t i=0; i<count/3; i++)
coords->SetTuple3(i,data[3*i+0],data[3*i+1],data[3*i+2]);
delete [] data;
DebugStream::Stream2() << " Creating vtkPoints" << std::endl;
vtkPoints *points = vtkPoints::New(VTK_FLOAT);
points->SetData(coords);
points->ComputeBounds();
// Create the mesh
DebugStream::Stream2() << " Creating mesh" << std::endl;
vtkPolyData *mesh = vtkPolyData::New();
mesh->SetPoints(points);
if ( type==AVT_SURFACE_MESH ) {
size_t N_tri = count/9;
mesh->Allocate(N_tri);
for (size_t i=0; i<N_tri; i++) {
vtkIdType ids[3] = {3*i+0,3*i+1,3*i+2};
mesh->InsertNextCell(VTK_TRIANGLE,3,ids);
// Read the mesh
std::shared_ptr<IO::Mesh> mesh;
for (size_t i=0; i<database.size(); i++) {
if ( database[i].name==std::string(meshname) ) {
DebugStream::Stream1() << " calling getMesh" << std::endl;
try {
mesh = IO::getMesh(path,timesteps[timeState],database[i],domain);
} catch (const std::exception &err) {
DebugStream::Stream1() << " Caught errror calling getMesh:" << std::endl;
DebugStream::Stream1() << err.what() << std::endl;
} catch (...) {
DebugStream::Stream1() << " Caught unknown errror calling getMesh" << std::endl;
return NULL;
}
}
} else if ( type==AVT_POINT_MESH ) {
size_t N_tri = count/3;
mesh->Allocate(N_tri);
for (size_t i=0; i<N_tri; i++) {
vtkIdType ids[1] = {i};
mesh->InsertNextCell(VTK_VERTEX,1,ids);
}
} else {
DebugStream::Stream1() << " Unknown mesh type" << std::endl;
points->Delete();
coords->Delete();
}
if ( mesh==NULL ) {
DebugStream::Stream1() << " Error loading mesh" << std::endl;
return NULL;
}
mesh->BuildCells();
mesh->ComputeBounds();
// Create the mesh in vtk
vtkDataSet* vtkMesh = meshToVTK(mesh);
DebugStream::Stream2() << " mesh created:" << std::endl;
DebugStream::Stream2() << " " << mesh->GetNumberOfCells() << std::endl;
DebugStream::Stream2() << " " << mesh->GetNumberOfCells() << std::endl;
mesh->PrintSelf(DebugStream::Stream2(),vtkIndent(6));
points->Delete();
coords->Delete();
ASSERT(vtkMesh!=NULL);
DebugStream::Stream2() << " " << vtkMesh->GetNumberOfCells() << std::endl;
DebugStream::Stream2() << " " << vtkMesh->GetNumberOfCells() << std::endl;
vtkMesh->PrintSelf(DebugStream::Stream2(),vtkIndent(6));
// Cache the mesh and return
// meshcache[cache_name] = mesh;
get_time(&stop);
DebugStream::Stream2() << " Time required: " << get_diff(start,stop,freq) << std::endl;
return mesh;
return vtkMesh;
}

View File

@ -49,6 +49,7 @@
#include <vector>
#include <map>
#include "IO/MeshDatabase.h"
@ -101,12 +102,7 @@ class avtLBMFileFormat : public avtMTMDFileFormat
virtual void PopulateDatabaseMetaData(avtDatabaseMetaData *, int);
std::string path;
std::vector<std::string> timesteps;
struct meshdata {
std::string meshname;
avtMeshType type;
std::vector<std::string> files;
};
std::vector<std::map<std::string,meshdata> > meshlist;
std::vector<IO::MeshDatabase> database;
std::map<std::string,vtkObjectBase*> meshcache;
};

10
visit/testVisit.py Normal file
View File

@ -0,0 +1,10 @@
# visit -debug 1 -valgrind engine_ser -cli -s /projects/JamesClure/LBPM-WIA/visit/testVisit.py
OpenDatabase("localhost:/projects/JamesClure/build/debug/tests/summary.LBM", 0)
#AddPlot("Mesh", "pointmesh", 1, 1)
AddPlot("Mesh", "trilist", 1, 1)
DrawPlots()
#quit()

116
visit/vtkHelpers.h Normal file
View File

@ -0,0 +1,116 @@
// vtk headers
#include <vtkFloatArray.h>
#include <vtkRectilinearGrid.h>
#include <vtkStructuredGrid.h>
#include <vtkUnstructuredGrid.h>
#include <vtkPointSet.h>
#include <vtkCellType.h>
#include <vtkPolyData.h>
#include <vtkCellArray.h>
// LBPM headers
#include "IO/Mesh.h"
// Convert a point array to vtkFloatArray
inline vtkFloatArray* pointToVTK( const std::vector<Point>& points )
{
vtkFloatArray *coords = vtkFloatArray::New();
coords->SetNumberOfComponents(3);
coords->SetNumberOfTuples(points.size());
for (size_t i=0; i<points.size(); i++)
coords->SetTuple3(i,points[i].x,points[i].y,points[i].z);
return coords;
}
// Return the mesh type
inline avtMeshType vtkMeshType( IO::MeshType meshType )
{
avtMeshType vtkType = AVT_UNKNOWN_MESH;
if ( meshType==IO::MeshType::PointMesh )
vtkType = AVT_POINT_MESH;
else if ( meshType==IO::MeshType::SurfaceMesh )
vtkType = AVT_SURFACE_MESH;
else if ( meshType==IO::MeshType::VolumeMesh )
vtkType = AVT_UNSTRUCTURED_MESH;
return vtkType;
}
// Convert a PointList to vtkDataSet
inline vtkDataSet* PointListToVTK( std::shared_ptr<const IO::PointList> mesh )
{
vtkFloatArray *coords = pointToVTK(mesh->points);
vtkPoints *points = vtkPoints::New(VTK_FLOAT);
points->SetData(coords);
points->ComputeBounds();
size_t N = mesh->points.size();
vtkPolyData *vtkMesh = vtkPolyData::New();
vtkMesh->SetPoints(points);
vtkMesh->Allocate(N);
for (int i=0; i<(int)N; i++) {
vtkIdType ids[1] = {i};
vtkMesh->InsertNextCell(VTK_VERTEX,1,ids);
}
// vtkMesh->BuildCells();
vtkMesh->ComputeBounds();
points->Delete();
coords->Delete();
return vtkMesh;
}
// Convert a TriMesh to vtkDataSet
inline vtkDataSet* TriMeshToVTK( std::shared_ptr<const IO::TriMesh> mesh )
{
vtkFloatArray *coords = pointToVTK(mesh->vertices->points);
ASSERT(coords!=NULL);
vtkPoints *points = vtkPoints::New(VTK_FLOAT);
points->SetData(coords);
points->ComputeBounds();
const std::vector<int>& A = mesh->A;
const std::vector<int>& B = mesh->B;
const std::vector<int>& C = mesh->C;
size_t N_tri = A.size();
vtkPolyData *vtkMesh = vtkPolyData::New();
vtkMesh->SetPoints(points);
vtkMesh->Allocate(N_tri);
for (int i=0; i<(int)N_tri; i++) {
vtkIdType ids[3] = {A[i],B[i],C[i]};
vtkMesh->InsertNextCell(VTK_TRIANGLE,3,ids);
}
vtkMesh->BuildCells();
vtkMesh->ComputeBounds();
points->Delete();
coords->Delete();
return vtkMesh;
}
// Convert a mesh to vtkDataSet
inline vtkDataSet* meshToVTK( std::shared_ptr<IO::Mesh> mesh )
{
vtkDataSet* mesh2 = NULL;
if ( std::dynamic_pointer_cast<IO::PointList>(mesh) != NULL ) {
// We are dealing with a point mesh
DebugStream::Stream1() << " Creating point mesh" << std::endl;
std::shared_ptr<const IO::PointList> pointMesh = IO::getPointList(mesh);
mesh2 = PointListToVTK( pointMesh );
DebugStream::Stream1() << " Point mesh created" << std::endl;
} else if ( std::dynamic_pointer_cast<IO::TriMesh>(mesh) != NULL ||
std::dynamic_pointer_cast<IO::TriList>(mesh) != NULL )
{
DebugStream::Stream1() << " Creating surface mesh" << std::endl;
std::shared_ptr<const IO::TriMesh> triMesh = IO::getTriMesh(mesh);
mesh2 = TriMeshToVTK( triMesh );
DebugStream::Stream1() << " Surface mesh created" << std::endl;
} else {
DebugStream::Stream1() << " Error, unknown mesh type" << std::endl;
return NULL;
}
return mesh2;
}