Skip to content
Snippets Groups Projects
Commit d4d830d2 authored by Bastien Gorissen's avatar Bastien Gorissen
Browse files

Introduces parallel visualization. Surely needs some more polish and testing.

parent f801a13d
No related branches found
No related tags found
No related merge requests found
......@@ -32,6 +32,7 @@ option(ENABLE_MATHEX "Enable MathEx expression parser" ON)
option(ENABLE_MED "Enable MED mesh and post-processing file formats" ON)
option(ENABLE_MESH "Build the mesh module" ON)
option(ENABLE_METIS "Enable Metis mesh partitioner" ON)
option(ENABLE_MPI "Enable MPI parallelization" OFF)
option(ENABLE_MSVC_STATIC_RUNTIME "Use static Visual C++ runtime" OFF)
option(ENABLE_NATIVE_FILE_CHOOSER "Enable native file chooser in GUI" ON)
option(ENABLE_NETGEN "Enable Netgen mesh generator" ON)
......@@ -433,6 +434,19 @@ if(ENABLE_MATHEX)
list(APPEND CONFIG_OPTIONS "MathEx")
endif(ENABLE_MATHEX)
if(ENABLE_MPI)
find_package(MPI)
if(MPI_FOUND)
message("-- Found MPI")
set(HAVE_MPI TRUE)
list(APPEND CONFIG_OPTIONS "MPI")
list(APPEND EXTERNAL_INCLUDES ${MPI_INCLUDE_DIR})
list(APPEND EXTERNAL_LIBRARIES ${MPI_LIBRARIES})
INCLUDE(CMakeForceCompiler)
CMAKE_FORCE_CXX_COMPILER(${MPI_COMPILER} "MPI C++ Compiler")
endif(MPI_FOUND)
endif(ENABLE_MPI)
if(ENABLE_METIS)
add_subdirectory(contrib/Metis)
set(HAVE_METIS TRUE)
......
......@@ -9,18 +9,25 @@
#include "OpenFile.h"
#include "OS.h"
#include "VertexArray.h"
#include "GmshRemote.h"
#if defined(HAVE_POST)
#include "PView.h"
#include "PViewOptions.h"
#include "PViewData.h"
#include "PViewDataRemote.h"
#endif
static void computeAndSendVertexArrays(GmshClient *client)
#if defined(HAVE_MPI)
#include <mpi.h>
#endif
static void computeAndSendVertexArrays(GmshClient *client, bool compute=true)
{
#if defined(HAVE_POST)
for(unsigned int i = 0; i < PView::list.size(); i++){
PView *p = PView::list[i];
if (compute)
p->fillVertexArrays();
PViewData *data = p->getData();
PViewOptions *opt = p->getOptions();
......@@ -46,15 +53,114 @@ static void computeAndSendVertexArrays(GmshClient *client)
#endif
}
// This version sends VArrays using MPI
static void computeAndSendVertexArrays()
{
#if defined(HAVE_POST) && defined(HAVE_MPI)
// compute...
for(unsigned int i = 0; i < PView::list.size(); i++)
PView::list[i]->fillVertexArrays();
// ...and send
int nbArrays = PView::list.size()* 4;
MPI_Send(&nbArrays, 1, MPI_INT, 0, MPI_GMSH_DATA_READY, MPI_COMM_WORLD);
for(unsigned int i = 0; i < PView::list.size(); i++){
PView *p = PView::list[i];
PViewData *data = p->getData();
PViewOptions *opt = p->getOptions();
double min = data->getMin(), max = data->getMax();
if(opt->rangeType == PViewOptions::PerTimeStep){
min = data->getMin(opt->timeStep);
max = data->getMax(opt->timeStep);
}
VertexArray *va[4] =
{p->va_points, p->va_lines, p->va_triangles, p->va_vectors};
for(int type = 0; type < 4; type++){
if(va[type]){
int len;
char *str = va[type]->toChar
(p->getNum(), data->getName(), type + 1, min, max,
data->getNumTimeSteps(), data->getTime(opt->timeStep),
data->getBoundingBox(), len);
MPI_Send(&len, 1, MPI_INT, 0, MPI_GMSH_VARRAY_LEN, MPI_COMM_WORLD);
MPI_Send(str, len, MPI_CHAR, 0, MPI_GMSH_VARRAY, MPI_COMM_WORLD);
delete [] str;
}
}
}
#endif
}
// Merge the vertex arrays
void addToVertexArrays(const char* bytes, int len) {
int is = sizeof(int), ds = sizeof(double);
std::string name;
int index = 0;
int num; memcpy(&num, &bytes[index], is); index += is;
int ss; memcpy(&ss, &bytes[index], is); index += is;
if(ss){
std::vector<char> n(ss);
memcpy(&n[0], &bytes[index], ss); index += ss;
for(unsigned int i = 0; i < n.size(); i++) name += n[i];
}
int type; memcpy(&type, &bytes[index], is); index += is;
PView *p = PView::list[num-1];
PViewData *data = p->getData();
PViewOptions *opt = p->getOptions();
VertexArray *varrays[4] =
{p->va_points, p->va_lines, p->va_triangles, p->va_vectors};
VertexArray *va = varrays[type-1];
double min; memcpy(&min, &bytes[index], ds); index += ds;
double max; memcpy(&max, &bytes[index], ds); index += ds;
int numsteps; memcpy(&numsteps, &bytes[index], is); index += is;
double time; memcpy(&time, &bytes[index], ds); index += ds;
double xmin; memcpy(&xmin, &bytes[index], ds); index += ds;
double ymin; memcpy(&ymin, &bytes[index], ds); index += ds;
double zmin; memcpy(&zmin, &bytes[index], ds); index += ds;
double xmax; memcpy(&xmax, &bytes[index], ds); index += ds;
double ymax; memcpy(&ymax, &bytes[index], ds); index += ds;
double zmax; memcpy(&zmax, &bytes[index], ds); index += ds;
if (data->getMin() > min) data->setMin(min);
if (data->getMax() < max) data->setMax(max);
SBoundingBox3d bbox(xmin, ymin, zmin, xmax, ymax, zmax);
SBoundingBox3d bb = data->getBoundingBox();
bb += bbox;
data->setBoundingBox(bb);
if (type == 4) type = 2;
VertexArray* toAdd = new VertexArray(type,100);
toAdd->fromChar(bytes,0);
va->merge(toAdd);
delete toAdd;
}
int GmshRemote()
{
GmshClient *client = Msg::GetClient();
if(!client) return 0;
int rank = Msg::GetCommRank();
int nbDaemon = Msg::GetCommSize();
computeAndSendVertexArrays(client);
if(!client && rank == 0) return 0;
if(client && nbDaemon < 2) computeAndSendVertexArrays(client);
while(1){
// On the node with MPI rank 0, communicate through a
// socket.
if (rank == 0) {
// stop if we have no communications for 5 minutes
int ret = client->Select(300, 0);
if(!ret){
......@@ -84,15 +190,61 @@ int GmshRemote()
break;
}
else if(type == GmshSocket::GMSH_VERTEX_ARRAY){
ParseString(msg);
computeAndSendVertexArrays(client);
#if defined(HAVE_MPI)
client->Info("Sending vertex arrays...");
// Tell every node to start computing
int mpi_msg = MPI_GMSH_COMPUTE_VIEW;
MPI_Bcast(&mpi_msg, 1, MPI_INT, 0, MPI_COMM_WORLD);
// Fill the arrays on the master node
for(unsigned int i = 0; i < PView::list.size(); i++)
PView::list[i]->fillVertexArrays();
// Wait and send the data from every other node
for (int i = 0; i < nbDaemon-1; i++) {
int nbArrays;
MPI_Status status;
MPI_Recv(&nbArrays, 1, MPI_INT, MPI_ANY_SOURCE,
MPI_GMSH_DATA_READY, MPI_COMM_WORLD, &status);
int source = status.MPI_SOURCE;
// Get each varray in turn, then add it to the varrays of the master node
for (int j = 0; j < nbArrays; j++) {
int len;
MPI_Status status2;
MPI_Recv(&len, 1, MPI_INT, status.MPI_SOURCE,
MPI_GMSH_VARRAY_LEN, MPI_COMM_WORLD, &status2);
char str[len];
MPI_Recv(str, len, MPI_CHAR, status.MPI_SOURCE,
MPI_GMSH_VARRAY, MPI_COMM_WORLD, &status2);
addToVertexArrays(str,len);
}
}
computeAndSendVertexArrays(client,false);
#endif
}
else if(type == GmshSocket::GMSH_MERGE_FILE){
MergeFile(msg);
#if defined(HAVE_MPI)
int mpi_msg = MPI_GMSH_MERGE_FILE;
MPI_Bcast(&mpi_msg, 1, MPI_INT, 0, MPI_COMM_WORLD);
MPI_Bcast(&length, 1, MPI_INT, 0, MPI_COMM_WORLD);
MPI_Bcast(msg, length, MPI_CHAR, 0, MPI_COMM_WORLD);
#else
computeAndSendVertexArrays(client);
#endif
}
else if(type == GmshSocket::GMSH_PARSE_STRING){
ParseString(msg);
#if defined(HAVE_MPI)
int mpi_msg = MPI_GMSH_PARSE_STRING;
MPI_Bcast(&mpi_msg, 1, MPI_INT, 0, MPI_COMM_WORLD);
MPI_Bcast(&length, 1, MPI_INT, 0, MPI_COMM_WORLD);
MPI_Bcast(msg, length, MPI_CHAR, 0, MPI_COMM_WORLD);
#endif
}
else if(type == GmshSocket::GMSH_SPEED_TEST){
client->Info("Sending huge array");
......@@ -104,7 +256,37 @@ int GmshRemote()
}
delete [] msg;
} else {
#if defined(HAVE_MPI)
// If we're not on the master node, we wait for him...
int mpi_msg;
MPI_Bcast(&mpi_msg, 1, MPI_INT, 0, MPI_COMM_WORLD);
if (mpi_msg == MPI_GMSH_COMPUTE_VIEW)
computeAndSendVertexArrays();
else if(mpi_msg == MPI_GMSH_SHUTDOWN)
Msg::Exit(0);
else if(mpi_msg == MPI_GMSH_PARSE_STRING){
int length;
MPI_Bcast(&length, 1, MPI_INT, 0, MPI_COMM_WORLD);
char msg[length];
MPI_Bcast(msg, length, MPI_CHAR, 0, MPI_COMM_WORLD);
ParseString(msg);
}
else if (mpi_msg == MPI_GMSH_MERGE_FILE){
int length;
MPI_Bcast(&length, 1, MPI_INT, 0, MPI_COMM_WORLD);
char msg[length];
MPI_Bcast(msg, length, MPI_CHAR, 0, MPI_COMM_WORLD);
MergeFile(msg);
}
#endif
}// if (rank != 0)
}
#if defined(HAVE_MPI)
int mpi_msg = MPI_GMSH_SHUTDOWN;
MPI_Bcast(&mpi_msg, 1, MPI_INT, 0, MPI_COMM_WORLD);
#endif
return 0;
}
......@@ -8,6 +8,14 @@
#include <string>
#define MPI_GMSH_COMPUTE_VIEW 1
#define MPI_GMSH_DATA_READY 2
#define MPI_GMSH_VARRAY 3
#define MPI_GMSH_VARRAY_LEN 4
#define MPI_GMSH_SHUTDOWN 5
#define MPI_GMSH_PARSE_STRING 6
#define MPI_GMSH_MERGE_FILE 7
int GmshRemote();
#endif
......
......@@ -296,3 +296,16 @@ void VertexArray::fromChar(const char *bytes, int swap)
memcpy(&_colors[0], &bytes[index], cs); index += cs;
}
}
void VertexArray::merge(VertexArray* arr) {
if(arr->getNumVertices() != 0) {
_vertices.insert(_vertices.end(),arr->firstVertex(),
arr->lastVertex());
_normals.insert(_normals.end(),arr->firstNormal(),
arr->lastNormal());
_colors.insert(_colors.end(),arr->firstColor(),
arr->lastColor());
_elements.insert(_elements.end(),arr->firstElementPointer(),
arr->lastElementPointer());
}
}
......@@ -142,12 +142,24 @@ class VertexArray{
// range check 2) calling this if _vertices.size() == 0 will cause
// some compilers to throw an exception)
float *getVertexArray(int i=0){ return &_vertices[i]; }
std::vector<float>::iterator firstVertex(){return _vertices.begin();}
std::vector<float>::iterator lastVertex(){return _vertices.end();}
// return a pointer to the raw normal array
char *getNormalArray(int i=0){ return &_normals[i]; }
std::vector<char>::iterator firstNormal(){return _normals.begin();}
std::vector<char>::iterator lastNormal(){return _normals.end();}
// return a pointer to the raw color array
unsigned char *getColorArray(int i=0){ return &_colors[i]; }
std::vector<unsigned char>::iterator firstColor(){return _colors.begin();}
std::vector<unsigned char>::iterator lastColor(){return _colors.end();}
// return a pointer to the raw element array
MElement **getElementPointerArray(int i=0){ return &_elements[i]; }
std::vector<MElement*>::iterator firstElementPointer(){return _elements.begin();}
std::vector<MElement*>::iterator lastElementPointer(){return _elements.end();}
// add element data in the arrays (if unique is set, only add the
// element if another one with the same barycenter is not already
// present)
......@@ -167,6 +179,8 @@ class VertexArray{
char *toChar(int num, std::string name, int type, double min, double max,
int numsteps, double time, SBoundingBox3d bbox, int &len);
void fromChar(const char *bytes, int swap);
// merge another vertex array into this one
void merge(VertexArray* arr);
};
#endif
......@@ -183,6 +183,9 @@ static void file_remote_cb(Fl_Widget *w, void *data)
FlGui::instance()->updateViews();
drawContext::global()->draw();
}
else if(str == "varrays"){
server->SendString(GmshSocket::GMSH_VERTEX_ARRAY, " ");
}
else if(str == "test"){
server->SendString(GmshSocket::GMSH_SPEED_TEST, "Speed test");
}
......@@ -2203,6 +2206,7 @@ static Fl_Menu_Item bar_table[] = {
{"Start...", 0, (Fl_Callback *)file_remote_cb, (void*)"start"},
{"Merge...", 0, (Fl_Callback *)file_remote_cb, (void*)"merge"},
{"Clear", 0, (Fl_Callback *)file_remote_cb, (void*)"clear"},
{"Get vertex arrays", 0, (Fl_Callback *)file_remote_cb, (void*)"varrays"},
{"Stop", 0, (Fl_Callback *)file_remote_cb, (void*)"stop"},
{0},
{"New Window", 0, (Fl_Callback *)file_window_cb, (void*)"new"},
......
......@@ -65,12 +65,15 @@ class PViewData {
// get the time value associated with the step-th time step
virtual double getTime(int step){ return 0.; }
// get min/max for given step (global over all steps if step=-1)
// get/set min/max for given step (global over all steps if step=-1)
virtual double getMin(int step=-1) = 0;
virtual double getMax(int step=-1) = 0;
virtual void setMin(double min) = 0;
virtual void setMax(double max) = 0;
// get the bounding box
// get/set the bounding box
virtual SBoundingBox3d getBoundingBox(int step=-1) = 0;
virtual void setBoundingBox(SBoundingBox3d& box) = 0;
// get the number of elements of a given type, for a given step
virtual int getNumScalars(int step=-1){ return 0; }
......
......@@ -60,9 +60,9 @@ class stepData{
double getTime(){ return _time; }
void setTime(double time){ _time = time; }
double getMin(){ return _min; }
void setMin(double min ){ _min = min; }
double setMin(double min){ _min = min; }
double getMax(){ return _max; }
void setMax(double max){ _max = max; }
double setMax(double max){ _max = max; }
int getNumData()
{
if(!_data) return 0;
......@@ -132,8 +132,11 @@ class PViewDataGModel : public PViewData {
int getNumTimeSteps();
double getTime(int step);
double getMin(int step=-1);
void setMin(double min){ _min = min; }
double getMax(int step=-1);
void setMax(double max){ _max = max; }
SBoundingBox3d getBoundingBox(int step=-1);
void setBoundingBox(SBoundingBox3d& box){}
int getNumScalars(int step=-1);
int getNumVectors(int step=-1);
int getNumTensors(int step=-1);
......
// Gmsh - Copyright (C) 1997-2009 C. Geuzaine, J.-F. Remacle
//
// See the LICENSE.txt file for license information. Please report all
......@@ -61,8 +62,11 @@ class PViewDataList : public PViewData {
int getNumTimeSteps(){ return NbTimeStep; }
double getTime(int step);
double getMin(int step=-1);
void setMin(double min) {Min = min;}
double getMax(int step=-1);
void setMax(double max) {Max = max;}
SBoundingBox3d getBoundingBox(int step=-1){ return BBox; }
void setBoundingBox(SBoundingBox3d& box) {BBox = box;}
int getNumScalars(int step=-1);
int getNumVectors(int step=-1);
int getNumTensors(int step=-1);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment