Commit d9ce5d89 authored by berenger-bramas's avatar berenger-bramas

Work in progress about loading a file in parallel

(but even if it's not finished I need to commit this work to update the svn
with other commit like cmake etc.)

git-svn-id: svn+ssh://scm.gforge.inria.fr/svn/scalfmm/scalfmm/trunk@146 2616d619-271b-44dc-8df4-d4a8f33a7222
parent dff82bab
......@@ -48,7 +48,7 @@ public:
* Must be implemented by each user Cell class
* @return the position in the tree coordinate
*/
virtual const F3DPosition& getCoordinate() const = 0;
virtual const FTreeCoordinate& getCoordinate() const = 0;
/**
* Must be implemented by each user Cell class
......
......@@ -371,7 +371,7 @@ public:
char buffer[BufferSize];
while(needToReceive){
app.receiveData( BufferSize, idxLevel, buffer, &source, &filled);
app.receiveDataFromTag( BufferSize, idxLevel, buffer, &source, &filled);
for(int idxBuff = 0 ; idxBuff < filled;){
memcpy(&position,&buffer[idxBuff],sizeof(int));
idxBuff += sizeof(int);
......@@ -627,7 +627,7 @@ public:
while(needToReceive){
FDEBUG(waitingToReceiveCounter.tic());
app.receiveData( BufferSize, idxLevel, buffer, &source, &filled);
app.receiveDataFromTag( BufferSize, idxLevel, buffer, &source, &filled);
FDEBUG(waitingToReceiveCounter.tac());
for(int idxBuff = 0 ; idxBuff < filled;){
memcpy(&position,&buffer[idxBuff],sizeof(int));
......@@ -759,7 +759,7 @@ public:
char buffer[BufferSize];
while(needToReceive){
app.receiveData( BufferSize, idxLevel, buffer, &source, &filled);
app.receiveDataFromTag( BufferSize, idxLevel, buffer, &source, &filled);
for(int idxBuff = 0 ; idxBuff < filled;){
memcpy(&position,&buffer[idxBuff],sizeof(int));
idxBuff += sizeof(int);
......
#ifndef FFMABINLOADER_HPP
#define FFMABINLOADER_HPP
// /!\ Please, you must read the license at the bottom of this page
#include <cstdio>
#include "../Utils/FGlobal.hpp"
#include "FAbstractLoader.hpp"
#include "../Utils/F3DPosition.hpp"
#include "../Utils/FDebug.hpp"
/**
* @author Berenger Bramas (berenger.bramas@inria.fr)
* @class FFmaBinLoader
* Please read the license
*
* Load a file with a format like :
* NB_particles Box_width Box_X Box_Y Box_Z // init
* X Y Z // one particle by line
* ....
* <code>
* FFmaBinLoader<FBasicParticle> loader("../FMB++/Tests/particles.basic.txt"); <br>
* if(!loader.isOpen()){ <br>
* std::cout << "Loader Error\n"; <br>
* return 1; <br>
* } <br>
* <br>
* FOctree<FBasicParticle, TestCell, FSimpleLeaf> tree(loader.getBoxWidth(),loader.getCenterOfBox()); <br>
* <br>
* for(int idx = 0 ; idx < loader.getNumberOfParticles() ; ++idx){ <br>
* FBasicParticle* const part = new FBasicParticle(); <br>
* loader.fillParticle(part); <br>
* tree.insert(part); <br>
* } <br>
* </code>
*
* Particle has to extend {FExtendPhysicalValue,FExtendPosition}
*/
template <class ParticleClass>
class FFmaBinLoader : public FAbstractLoader<ParticleClass> {
protected:
FILE* const file; //< The file to read
F3DPosition centerOfBox; //< The center of box read from file
FReal boxWidth; //< the box width read from file
int nbParticles; //< the number of particles read from file
public:
/**
* The constructor need the file name
* @param filename the name of the file to open
* you can test if file is successfuly open by calling hasNotFinished()
*/
FFmaBinLoader(const char* const filename): file(fopen(filename, "rb")){
// test if open
if(this->file != NULL) {
int sizeOfElement(0);
fread(&sizeOfElement, sizeof(int), 1, file);
FDEBUG(if(sizeOfElement != int(sizeof(FReal)) ){)
FDEBUG( FDebug::Controller.writeFromLine("Warning type size between file and FReal are differents\n", __LINE__, __FILE__); )
printf("%d sizeofelement\n",sizeOfElement);
FDEBUG(})
fread(&this->nbParticles, sizeof(int), 1, file);
fread(&this->boxWidth, sizeof(FReal), 1, file);
this->boxWidth *= 2;
FReal x,y,z;
fread(&x, sizeof(FReal), 1, file);
fread(&y, sizeof(FReal), 1, file);
fread(&z, sizeof(FReal), 1, file);
this->centerOfBox.setPosition(x,y,z);
}
else {
this->boxWidth = 0;
this->nbParticles = 0;
}
}
/**
* Default destructor, simply close the file
*/
virtual ~FFmaBinLoader(){
fclose(file);
}
/**
* To know if file is open and ready to read
* @return true if loader can work
*/
bool isOpen() const{
return this->file != NULL;
}
/**
* To get the number of particles from this loader
* @param the number of particles the loader can fill
*/
long getNumberOfParticles() const{
return this->nbParticles;
}
/**
* The center of the box from the simulation file opened by the loader
* @return box center
*/
F3DPosition getCenterOfBox() const{
return this->centerOfBox;
}
/**
* The box width from the simulation file opened by the loader
* @return box width
*/
FReal getBoxWidth() const{
return this->boxWidth;
}
/**
* Fill a particle
* @warning to work with the loader, particles has to expose a setPosition method
* @param the particle to fill
*/
void fillParticle(ParticleClass& inParticle){
FReal x,y,z,data;
fread(&x, sizeof(FReal), 1, file);
fread(&y, sizeof(FReal), 1, file);
fread(&z, sizeof(FReal), 1, file);
fread(&data, sizeof(FReal), 1, file);
inParticle.setPosition(x,y,z);
inParticle.setPhysicalValue(data);
}
};
#endif //FFmaBinLoader_HPP
// [--LICENSE--]
#ifndef FPROCFMALOADER_HPP
#define FPROCFMALOADER_HPP
// /!\ Please, you must read the license at the bottom of this page
#include <iostream>
#include <fstream>
#include "../Utils/FGlobal.hpp"
#include "FAbstractLoader.hpp"
#include "../Utils/F3DPosition.hpp"
#include "../Utils/FMpi.hpp"
/**
* @author Berenger Bramas (berenger.bramas@inria.fr)
* @class FProcFmaLoader
* Please read the license
*
* Load a file with a format like :
* NB_particles Box_width Box_X Box_Y Box_Z // init
* X Y Z // one particle by line
* ....
* <code>
* FProcFmaLoader<FBasicParticle> loader("../FMB++/Tests/particles.basic.txt"); <br>
* if(!loader.isOpen()){ <br>
* std::cout << "Loader Error\n"; <br>
* return 1; <br>
* } <br>
* <br>
* FOctree<FBasicParticle, TestCell, FSimpleLeaf> tree(loader.getBoxWidth(),loader.getCenterOfBox()); <br>
* <br>
* for(int idx = 0 ; idx < loader.getNumberOfParticles() ; ++idx){ <br>
* FBasicParticle* const part = new FBasicParticle(); <br>
* loader.fillParticle(part); <br>
* tree.insert(part); <br>
* } <br>
* </code>
*
* Particle has to extend {FExtendPhysicalValue,FExtendPosition}
*/
template <class ParticleClass>
class FProcFmaLoader : public FAbstractLoader<ParticleClass> {
protected:
F3DPosition centerOfBox; //< The center of box read from file
FReal boxWidth; //< the box width read from file
int totalNbParticles; //< the number of particles read from file
int nbParticles; //< the number of particles read from file
bool isOpenFlag; //< to knwo if the file is open now
FReal* particles; //< the particles loaded from the binary file
MPI_Offset idxParticles; //< to iterate on the particles array
public:
/**
* The constructor need the file name
* @param filename the name of the file to open
* you can test if file is successfuly open by calling hasNotFinished()
*/
FProcFmaLoader(const char* const filename, FMpi& app)
: boxWidth(0), totalNbParticles(0), nbParticles(0), isOpenFlag(false), particles(0), idxParticles(0) {
char nonConstFilename[512];
strcpy(nonConstFilename,filename);
MPI_File file;
if(MPI_File_open(MPI::COMM_WORLD, nonConstFilename, MPI::MODE_RDONLY, MPI::INFO_NULL, &file) == MPI_SUCCESS){
int sizeOfElement(0);
FReal xyzBoxWidth[4];
MPI_Status status;
if( MPI_File_read(file, &sizeOfElement, 1, MPI_INT, &status) == MPI_SUCCESS
&& MPI_File_read(file, &this->totalNbParticles, 1, MPI_INT, &status) == MPI_SUCCESS
&& MPI_File_read(file, xyzBoxWidth, 4, MPI_FLOAT, &status) == MPI_SUCCESS ){
FDEBUG(if(sizeOfElement != sizeof(FReal)){)
FDEBUG( FDebug::Controller.writeFromLine("Warning type size between file and FReal are differents\n", __LINE__, __FILE__); )
FDEBUG(})
this->boxWidth = xyzBoxWidth[3];
this->centerOfBox.setPosition(xyzBoxWidth[0],xyzBoxWidth[1],xyzBoxWidth[2]);
this->boxWidth *= 2;
this->isOpenFlag = true;
// load my particles
MPI_Offset headDataOffSet;
MPI_File_get_position(file, &headDataOffSet);
MPI_Offset filesize(0);
MPI_File_get_size(file, &filesize); /* in bytes */
filesize = (filesize - headDataOffSet) / sizeof(FReal);
if(filesize/4 != this->totalNbParticles){
printf("Error fileSize %lld, nbPart %d\n",filesize/4, this->totalNbParticles);
}
// in number of floats
const long startPart = app.getLeft(this->totalNbParticles);
const long endPart = app.getRight(this->totalNbParticles);
nbParticles = (endPart - startPart);
const int bufsize = nbParticles * 4;
// local number to read
particles = new FReal[bufsize];
MPI_File_set_view(file, headDataOffSet + startPart * 4 * sizeof(FReal), MPI_FLOAT, MPI_FLOAT, const_cast<char*>("native"), MPI_INFO_NULL);
MPI_File_read(file, particles, bufsize, MPI_FLOAT, &status);
// check if needed
int count(0);
MPI_Get_count(&status, MPI_INT, &count);
FDEBUG(if(count / 4 != this->nbParticles){)
FDEBUG( FDebug::Controller<< "Error read " << count << " data, nbPart is " << this->nbParticles << __LINE__ << " " << __FILE__ << "\n"; )
FDEBUG(})
}
else{
this->totalNbParticles = 0;
}
MPI_File_close(&file);
}
else {
this->boxWidth = 0;
this->totalNbParticles = 0;
}
}
/**
* Default destructor, simply close the file
*/
virtual ~FProcFmaLoader(){
if(isOpen()){
delete [] particles;
}
}
/**
* To know if file is open and ready to read
* @return true if loader can work
*/
bool isOpen() const{
return this->isOpenFlag;
}
/**
* To get the number of particles from this loader
* @param the number of particles the loader can fill
*/
long getNumberOfParticles() const{
return this->nbParticles;
}
/**
* The center of the box from the simulation file opened by the loader
* @return box center
*/
F3DPosition getCenterOfBox() const{
return this->centerOfBox;
}
/**
* The box width from the simulation file opened by the loader
* @return box width
*/
FReal getBoxWidth() const{
return this->boxWidth;
}
/**
* Fill a particle
* @warning to work with the loader, particles has to expose a setPosition method
* @param the particle to fill
*/
void fillParticle(ParticleClass& inParticle){
inParticle.setPosition(particles[idxParticles],particles[idxParticles+1],particles[idxParticles+2]);
inParticle.setPhysicalValue(particles[idxParticles+3]);
idxParticles += 4;
}
};
#endif //FPROCFMALOADER_HPP
// [--LICENSE--]
......@@ -4,6 +4,7 @@
#include "FGlobal.hpp"
#include "FMath.hpp"
#ifdef SCALFMM_USE_MPI
#include <mpi.h>
......@@ -41,19 +42,25 @@ public:
MPI_Send(inData, inSize, MPI_CHAR , inReceiver, inTag, MPI_COMM_WORLD);
}
void receiveData(const int inSize, void* const inData, int* const inSource, int* const inTag, int* const inFilledSize){
void receiveData(const int inSize, void* const inData, int* const inSource = 0, int* const inTag = 0, int* const inFilledSize = 0){
MPI_Status status;
MPI_Recv(inData, inSize, MPI_CHAR, MPI_ANY_SOURCE, MPI_ANY_TAG,MPI_COMM_WORLD, &status);
*inSource = status.MPI_SOURCE;
*inTag = status.MPI_TAG;
MPI_Get_count(&status,MPI_CHAR,inFilledSize);
if(inSource) *inSource = status.MPI_SOURCE;
if(inTag) *inTag = status.MPI_TAG;
if(inFilledSize) MPI_Get_count(&status,MPI_CHAR,inFilledSize);
}
void receiveData(const int inSize, const int inTag, void* const inData, int* const inSource, int* const inFilledSize){
void receiveDataFromTag(const int inSize, const int inTag, void* const inData, int* const inSource = 0, int* const inFilledSize = 0){
MPI_Status status;
MPI_Recv(inData, inSize, MPI_CHAR, MPI_ANY_SOURCE, inTag, MPI_COMM_WORLD, &status);
*inSource = status.MPI_SOURCE;
MPI_Get_count(&status,MPI_CHAR,inFilledSize);
if(inSource) *inSource = status.MPI_SOURCE;
if(inFilledSize) MPI_Get_count(&status,MPI_CHAR,inFilledSize);
}
void receiveDataFromTagAndSource(const int inSize, const int inTag, const int inSource, void* const inData, int* const inFilledSize = 0){
MPI_Status status;
MPI_Recv(inData, inSize, MPI_CHAR, inSource, inTag, MPI_COMM_WORLD, &status);
if(inFilledSize) MPI_Get_count(&status,MPI_CHAR,inFilledSize);
}
bool receivedData(){
......@@ -90,13 +97,38 @@ public:
MPI_Abort(MPI_COMM_WORLD, inErrorCode);
}
template < class T >
MPI_Datatype getType(){
return MPI_INT;
}
template< class T >
T reduceSum(T data){
T result;
MPI_Reduce( &data, &result, 1, getType<T>(), MPI_SUM, 0, MPI_COMM_WORLD );
return result;
}
template< class T >
T reduceMin(T myMin){
T result;
MPI_Reduce( &myMin, &result, 1, getType<T>(), MPI_MIN, 0, MPI_COMM_WORLD );
return result;
}
double reduceSum(double data){
double result;
MPI_Reduce( &data, &result, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD );
template< class T >
T reduceMax(T myMax){
T result;
MPI_Reduce( &myMax, &result, 1, getType<T>(), MPI_MAX, 0, MPI_COMM_WORLD );
return result;
}
template< class T >
T broadcast(T value, const int from = 0){
MPI_Bcast ( &value, 1, getType<T>(), from, MPI_COMM_WORLD );
return value;
}
#else
////////////////////////////////////////////////////////
// Without MPI
......@@ -106,15 +138,19 @@ public:
void sendData(const int, const int, void* const, const int ){}
void receiveData(const int, void* const, int* const inSource, int* const inTag, int* const inFilledSize){
*inSource = 0;
*inTag = 0;
*inFilledSize = 0;
void receiveData(const int, void* const, int* const inSource = 0, int* const inTag = 0, int* const inFilledSize = 0){
if(inSource) *inSource = 0;
if(inTag) *inTag = 0;
if(inFilledSize) *inFilledSize = 0;
}
void receiveData(const int , const int , void* const , int* const inSource, int* const inFilledSize){
*inSource = 0;
*inFilledSize = 0;
void receiveDataFromTag(const int , const int , void* const , int* const inSource = 0, int* const inFilledSize = 0){
if(inSource) *inSource = 0;
if(inFilledSize) *inFilledSize = 0;
}
void receiveDataFromTagAndSource(const int , const int , const int , void* const , int* const inFilledSize = 0){
if(inFilledSize) *inFilledSize = 0;
}
bool receivedData(){
......@@ -139,10 +175,26 @@ public:
exit(inErrorCode);
}
double reduceSum(double data){
template< class T >
T reduceSum(T data){
return data;
}
template< class T >
T reduceMin(T myMin){
return myMin;
}
template< class T >
T reduceMax(T myMax){
return myMax;
}
template< class T >
T broadcast(T value, const int = 0){
return value;
}
#endif
////////////////////////////////////////////////////////
......@@ -159,8 +211,53 @@ public:
bool isSlave() {
return processId();
}
template< class T >
T getLeft(const T inSize) {
const float step = (float(inSize) / processCount());
return T(FMath::Ceil(step * processId()));
}
template< class T >
T getRight(const T inSize) {
const float step = (float(inSize) / processCount());
const T res = T(FMath::Ceil(step * (processId()+1)));
if(res > inSize) return inSize;
else return res;
}
template< class T >
T getOtherRight(const T inSize, const int other) {
const float step = (float(inSize) / processCount());
const T res = T(FMath::Ceil(step * (other+1)));
if(res > inSize) return inSize;
else return res;
}
template< class T >
int getProc(const int position, const T inSize) {
const float step = (float(inSize) / processCount());
return int(position/step);
}
};
#ifdef SCALFMM_USE_MPI
template <>
MPI_Datatype FMpi::getType<long long>(){
return MPI_LONG_LONG;
}
template <>
MPI_Datatype FMpi::getType<double>(){
return MPI_DOUBLE;
}
template <>
MPI_Datatype FMpi::getType<int>(){
return MPI_INT;
}
#endif
#endif //FMPI_HPP
// [--LICENSE--]
This diff is collapsed.
// /!\ Please, you must read the license at the bottom of this page
#include <iostream>
#include <fstream>
#include <cstdio>
#include <stdlib.h>
#include <time.h>
#include "../Src/Utils/FGlobal.hpp"
#include "../Src/Utils/FParameters.hpp"
// This file can generate basic particles files in the FMA format
// g++ testLoaderFMACreate.cpp -o testLoaderFMACreate.exe
int main(int argc, char ** argv){
///////////////////////What we do/////////////////////////////
std::cout << ">> This executable can create a FMA particles files\n";
std::cout << ">> You can pass a filename in parameter else the program will use\n";
std::cout << ">> a default filename.\n";
std::cout << ">> The format of the file is : \n";
std::cout << ">> [number of particles] \n";
std::cout << ">> [boxe width] [boxe x center] [boxe y center] [boxe z center]\n";
std::cout << ">> [x] [y] [z] [physical value]...\n";
//////////////////////////////////////////////////////////////
// Nb of particles
const long NbParticles = FParameters::getValue(argc,argv,"-nb", 50000L);
// Center of the box
const FReal XCenter = 0.5;
const FReal YCenter = 0.5;
const FReal ZCenter = 0.5;
// Box width
const FReal BoxWidth = 1.0/2;
// Output file please let .temp extension
const char * const defaultFilename = "testLoaderFMA.fma";
const char* Output;
if(argc == 1){
std::cout << "You have to give a filename in argument.\n";
std::cout << "The program will create one with a default name : " << defaultFilename << "\n";
Output = defaultFilename;
}
else{
Output = argv[1];
std::cout << "Creating : " << Output << "\n";
}
// Create file
FILE* const myfile = fopen(Output, "wb");
if(!myfile){
std::cout << "Cannot create " << Output << "\n";
return 1;
}
std::cout << "Generating " << NbParticles << " in " << Output << "\n";
std::cout << "Working...\n";
// System properties
const int sizeOfFreal = int(sizeof(FReal));
fwrite(&sizeOfFreal, sizeof(int), 1, myfile);
fwrite(&NbParticles, sizeof(int), 1, myfile);
fwrite(&BoxWidth, sizeof(FReal), 1, myfile);
fwrite(&XCenter, sizeof(FReal), 1, myfile);
fwrite(&YCenter, sizeof(FReal), 1, myfile);
fwrite(&ZCenter, sizeof(FReal), 1, myfile);
FReal data[4];
data[3] = 0.1;
// Generate particles
for( long idx = 0 ; idx < NbParticles ; ++idx ){
/*data[0] = ((FReal(rand())/RAND_MAX) * BoxWidth * 2) + XCenter - BoxWidth;
data[1] = ((FReal(rand())/RAND_MAX) * BoxWidth * 2) + YCenter - BoxWidth;
data[2] = ((FReal(rand())/RAND_MAX) * BoxWidth * 2) + ZCenter - BoxWidth;*/
data[0] = ((FReal(idx)/NbParticles) * BoxWidth * 2) + XCenter - BoxWidth;
data[1] = ((FReal(idx)/NbParticles) * BoxWidth * 2) + YCenter - BoxWidth;
data[2] = ((FReal(idx)/NbParticles) * BoxWidth * 2) + ZCenter - BoxWidth;
fwrite(&data, sizeof(FReal), 4, myfile);
}