Commit d2bca29a authored by COULAUD Olivier's avatar COULAUD Olivier

New Fma reader and writer

parent 935a7bca
......@@ -62,8 +62,8 @@ SET(SCALFMM_LIBRARIES "")
SET(ScaLFMM_CXX_FLAGS "")
#
# Compile option
#
SET(ScaLFMM_CXX_FLAGS "-std=c++11 -Wall -Wshadow -Wpointer-arith -Wcast-qual -Wconversion -fpic")
# -Wall Wnosign-conversion
SET(ScaLFMM_CXX_FLAGS "-std=c++11 -Wshadow -Wpointer-arith -Wcast-qual -Wconversion -fpic")
#
# Test if openmp is here
#
......
8 4
100 20 0 0 0
0.998298 0.0088693 0.576438 0.396465
0.107422 -0.2487 -9.62605 0.840485
......
8 4
20 10.002 0.0 0.0 0.0
-0.381596 -0.909478 -1.65028 7.82637e-06
-0.328097 -0.475796 -8.1607 0.131538
......
8 4
20000
0.5 0.5 0.5 0.5
0.840188 0.394383 0.783099 0.01 1
......
......@@ -25,18 +25,18 @@
#include "Files/FFmaGenericLoader.hpp"
#include "../../Src/Kernels/Chebyshev/FChebCell.hpp"
#include "../../Src/Kernels/Interpolation/FInterpMatrixKernel.hpp"
#include "../../Src/Kernels/Chebyshev/FChebSymKernel.hpp"
#include "Kernels/Chebyshev/FChebCell.hpp"
#include "Kernels/Interpolation/FInterpMatrixKernel.hpp"
#include "Kernels/Chebyshev/FChebSymKernel.hpp"
#include "../../Src/Components/FSimpleLeaf.hpp"
#include "../../Src/Kernels/P2P/FP2PParticleContainerIndexed.hpp"
#include "Components/FSimpleLeaf.hpp"
#include "Kernels/P2P/FP2PParticleContainerIndexed.hpp"
#include "../../Src/Utils/FParameters.hpp"
#include "Utils/FParameters.hpp"
#include "../../Src/Containers/FOctree.hpp"
#include "Containers/FOctree.hpp"
#include "../../Src/Core/FFmmAlgorithmThread.hpp"
#include "Core/FFmmAlgorithmThread.hpp"
/**
* This program runs the FMM Algorithm with the Chebyshev kernel and compares the results with a direct computation.
......@@ -104,6 +104,7 @@ int main(int argc, char* argv[])
////////////////////////////////////////////////////////////////////
bool binaryMode = false;
if(FParameters::existParameter(argc, argv, "-bin")){
binaryMode = true;
}
......
......@@ -10,10 +10,13 @@
#include <fstream>
#include <sstream>
#include <string>
//
#include "Utils/FGlobal.hpp"
#include "Utils/FMath.hpp"
#include "Utils/FPoint.hpp"
#include "Utils/FGenerateDistribution.hpp"
#include "Files/FFmaGenericLoader.hpp"
//
/// \file generateDistributions.cpp
//!
......@@ -32,7 +35,7 @@
//! <b> General arguments:</b>
//! \param -help (-h) to see the parameters available in this driver
//! \param -N The number of points in the distribution (default 20000)
//! \param -filename name: generic name for files (without extension) and save data
//! \param -filename name: generic name for files (with extension) and save data
//! with following format in name.fma or name.bfma in -bin is set"
//! \param -visufmt format for the visu file (vtk, vtp, cvs or cosmo). vtp is the default
//! \param -extraLength value extra length to add to the boxWidth (default 0.0)
......@@ -65,7 +68,7 @@
//!
//! generateDistributions -cuboid 2:2:4 -filename cuboid -visufmt vtp -charge -zeromean
//!
//
//
//
......@@ -98,7 +101,6 @@ void genDistusage() {
<< " Output " << std::endl
<< " -filename name: generic name for files (without extension) and save data" <<std::endl
<< " with following format in name.fma or name.bfma in -bin is set" <<std::endl
<< " -bin save output in binary file name.txt" <<std::endl
<< " -visufmt vtk, vtp, cosmo or cvs format " <<std::endl;
}
......@@ -120,6 +122,8 @@ int main(int argc, char ** argv){
FReal * particles ;
particles = new FReal[4*NbPoints] ;
memset(particles,0,4*NbPoints*sizeof(FReal));
FmaBasicParticle *ppart = (FmaBasicParticle*)(&particles[0]);
//
// Generate physical values
//
......@@ -153,7 +157,7 @@ int main(int argc, char ** argv){
if(FParameters::existParameter(argc, argv, "-unitCube")){
unifRandonPointsOnUnitCube(NbPoints, particles) ;
Centre.setPosition(0.5,0.5,0.5);
BoxWith = 0.5 ;
BoxWith = 1.0 ;
}
else if(FParameters::existParameter(argc, argv, "-cuboid")){
std::string dd(":"),aspectRatio = FParameters::getStr(argc,argv,"-lengths", "1:1:2");
......@@ -162,13 +166,13 @@ int main(int argc, char ** argv){
pos = aspectRatio.find(":"); aspectRatio.replace(pos,1," ");
std::stringstream ss(aspectRatio); ss >>A >> B >> C ;
unifRandonPointsOnCube(NbPoints, A,B,C,particles) ;
BoxWith = 0.5*FMath::Max(A,FMath::Max(B,C) );
BoxWith = FMath::Max(A,FMath::Max(B,C) );
FReal halfBW = BoxWith;
Centre.setPosition(halfBW,halfBW,halfBW);
}
else if(FParameters::existParameter(argc, argv, "-unitSphere")){
unifRandonPointsOnUnitSphere(NbPoints, particles) ;
BoxWith = 1.0 ;
BoxWith = 2.0 ;
}
else if(FParameters::existParameter(argc, argv, "-sphere")){
const FReal Radius = FParameters::getValue(argc,argv,"-radius", 2.0);
......@@ -211,53 +215,28 @@ int main(int argc, char ** argv){
/////////////////////////////////////////////////////////////////////////
// Save data
/////////////////////////////////////////////////////////////////////////
//
// Generate file for ScalFMM Loader
// Generate FMA file for FFmaGenericLoader Loader
//
if(FParameters::existParameter(argc, argv, "-extraLength")){
extraRadius = FParameters::getValue(argc,argv,"-extraLength", 0.0);
BoxWith += 2*extraRadius ;
}
if( ! FParameters::existParameter(argc, argv, "-bin")){
std::string name( genericFileName+ ".fma");
std::ofstream outfileA(name.c_str(), std::ofstream::out);
if(!outfileA) {
std::cout << "Cannot open file."<< std::endl;
exit(-1) ;
}
std::cout << "Writes in ascii FMA format in file "<<name <<std::endl ;
std::cout << " Points are in a cube of size "<< BoxWith << " Centered in the Origin"<<std::endl;
//
outfileA << NbPoints << " " << BoxWith << " " << Centre.getX() << " " << Centre.getY() << " " << Centre.getZ() << std::endl;
j=0;
for(int i = 0 ; i< NbPoints; ++i, j+=4){
outfileA << particles[j] << " " << particles[j+1] << " " << particles[j+2] << " " << particles[j+3] <<std::endl;
}
bool binaryMode = false;
std::string name(genericFileName);
if( FParameters::existParameter(argc, argv, "-bin")){
binaryMode = true;
name += ".bfma";
}
else{
std::string name( genericFileName+ ".bfma");
std::fstream outfile(name.c_str(),std::ifstream::out| std::ios::binary| std::ios::trunc);
if(!outfile) {
std::cout << "Cannot open file."<< std::endl;
return 1;
}
std::cout << "Writes in binary FMA format in file "<< name<<std::endl ;
std::cout << " Points are in a cube of size "<< BoxWith << " Centered in the Origin"<<std::endl;
//
int typeFReal = sizeof(FReal) ;
outfile.write((char* )&typeFReal,sizeof(int));
outfile.write((char* )const_cast<int*>(&NbPoints),sizeof(FSize));
outfile.write((char*)&BoxWith,sizeof(BoxWith));
outfile.write((char*)Centre.getDataValue(),sizeof(FReal)*3);
//
outfile.write ((char* )&particles[0], 4*sizeof(FReal)*NbPoints);
outfile.flush();
//
else {
name += ".fma";
}
FFmaGenericWriter writer(name,binaryMode) ;
writer.writeHeader(Centre,BoxWith, NbPoints, *ppart) ;
writer.writeArrayOfParticles(ppart, NbPoints);
//
//
// Generate file for visualization
//
if(FParameters::existParameter(argc, argv, "-visufmt")){
std::string visufile(""), fmt(FParameters::getStr(argc,argv,"-visufmt", "vtp"));
......
......@@ -450,9 +450,9 @@ private:
FLOG( FLog::Controller << "\tFinished (@Upward Pass (M2M) = " << counterTime.tacAndElapsed() << " s)\n" );
FLOG( FLog::Controller << "\t\t Computation : " << computationCounter.cumulated() << " s\n" );
FLOG( FLog::Controller << "\t\t Prepare : " << prepareCounter.cumulated() << " s\n" );
FLOG( FLog::Controller << "\t\t Wait : " << waitCounter.cumulated() << " s\n" );
FLOG( FLog::Controller << "\t\t Computation : " << computationCounter.cumulated() << " s\n" );
FLOG( FLog::Controller << "\t\t Prepare : " << prepareCounter.cumulated() << " s\n" );
FLOG( FLog::Controller << "\t\t Wait : " << waitCounter.cumulated() << " s\n" );
}
......
......@@ -27,6 +27,107 @@
#include "FAbstractLoader.hpp"
#include "Utils/FPoint.hpp"
//
//! \class FmaBasicParticle
//!
//! \brief Basic Particle class used in FMA loader and writer
//!
//! Here we consider the position, the physical value in the structure
//! but we read only the four first values the position, the physical value
//! this class is used in the generateDistributions example.
//!
class FmaBasicParticle {
public:
FPoint position; ///< position of the particle
// FReal x,y,z; ///< position of the particle
FReal physicalValue; ///< its physical value
/**
* return a pointer on the first value of the structure
*/
FReal * getPtrFirstData()
{return position.getDataValue() ;}
const FReal * getPtrFirstData() const
{return position.getDataValue() ;}
/**
* return The number of data to read. it is used in FMAGenericLoader (here 4)
*/
int getReadDataNumber()
{ return 4;}
/**
* return The number of data to write. it is used in FMAGenericWriter (here 4)
*/
int getWriteDataNumber() const
{ return 4;}
/**
* return size in byte of the structure. it is used in FMAGenericWriter
*/
unsigned int getWriteDataSize() const
{ return sizeof(FmaBasicParticle);}
};
//! \class FmaRParticle
//!
//! \brief The Particle class used in FMA loader and writer
//!
//! Here we consider the position, the physical value, the potential and the force in the structure
//! but we read only the four first values the position, the physical value and we write all the data in a file.
//! This class is used if you create an array of particles and you read them from a file generate by gerateDistributions
//! and you want to store the result.
//!
class FmaRParticle {
public:
FPoint position; ///< position of the particle
FReal physicalValue; ///< its physical value (mass or charge
FReal potential; ///< the potential
FReal forces[3]; ///<the force
/**
* return a pointer on the first value of the structure
*/
FReal * getPtrFirstData()
{return position.getDataValue() ;}
const FReal * getPtrFirstData() const
{return position.getDataValue() ;}
/**
* return The number of data to read. it is used in FMAGenericLoader (here 4)
*/
int getReadDataNumber()
{ return 4;}
/**
* return The number of data to write. it is used in FMAGenericWriter (here 8)
*/
int getWriteDataNumber() const
{ return 8;}
/**
* return size in byte of the structure. it is used in FMAGenericWriter
*/
unsigned int getWriteDataSize() const
{ return sizeof(FmaRParticle);}
};
//
//! \class FmaParticle
//!
//! \brief The Particle class used in FMA loader and writer
//!
//! Here we consider the position, the physical value, the potential and the force in the structure
//! and we read and write all the data in the structure
//! This class is used if you create an array of particles from a file generate by a previous computation (directComputation or a FMM computation)
//! and you want to compare the result.
//!
class FmaParticle : public FmaRParticle {
public:
/**
* return The number of data to read. it is used in FMAGenericLoader (here 8)
* Useful to read the result of the output of DirectComputation and to compare the potential and the force
* with the FMM computation
*/
int getReadDataNumber()
{ return 8;}
};
//
//! \class FFmaGenericLoader
//!
......@@ -35,49 +136,58 @@
//! The FMA format is a simplest format to store the particles in a file.
//!
//! It is organized as follow<br>
//! DatatypeSise Number_of_record_per_line <br>
//! NB_particles half_Box_width Center_X Center_Y Center_Z <br>
//! X Y Z PhysicalValue // one particle by line
//! Particle Values
//!
//! if Number_of_record_per_line is <br>
//! 4 the Particle Values are X Y Z Q <br>
//! 8 the Particle Values are X X Y Z Q P FX FY FZ<br>
//!
//! There is 3 methods to read the data from the file <br>
//! 1) fillParticle(FPoint*, FReal*);<br>
//! 2) fillParticle(FReal*, int);<br>
//! 3 fillParticle(PartClass);<br>
//!
//! \code
//! FFmaGenericLoader loader("../ADir/Tests/particles.basic.txt"); // default ascii format
//! if(!loader.isOpen()){
//! std::cout << "Loader Error\n";
//! return 1;
//! }
//! FFmaGenericLoader loader("../Data/unitCubeXYZQ20k.fma"); // extension fma --> ascii format
//!
//! FOctree<FBasicParticle, TestCell, FSimpleLeaf> tree(loader.getBoxWidth(),loader.getCenterOfBox());
//! FmaRParticle * const particles = new FmaRParticle[nbParticles];
//! memset(particles, 0, sizeof(FmaRParticle) * nbParticles) ;
//!
//! FPoint position ;
//! Freal physicalValue ;
//! for(int idx = 0 ; idx < loader.getNumberOfParticles() ; ++idx){
//! loader.fillParticle(&position, &physicalValue);
//! tree.insert(position, physicalValue);
//! loader.fillParticle(particles[idx]);
//! }
//! \endcode
//!
//! \warning It works only in shared memory (doesn't work with MPI)
//!
//!
//
class FFmaGenericLoader : public FAbstractLoader {
//
class FFmaGenericLoader : public FAbstractLoader {
protected:
std::fstream *file; ///< the stream used to read the file
bool binaryFile ; ///< if true the file to read is in binary mode
FPoint 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)
FSize nbParticles; ///< the number of particles (read from file)
unsigned int typeData[2]; ///< {Size of the data to read, number of data on 1 line}
private:
FReal *tmpVal ; /// Temporary array to read data
int otherDataToRead ; ///< <<number of other data (>4)to read in a particle record
public:
/**
* The constructor need the file name
* @param filename the name of the file to open
* @param binary true if the file to open is in binary mode
*
* This function also read the header of the fma file (First line)
* This function also read the header of the fma file (Two first lines)
* This means that we can obtain after the call the number of particles, ...
* you can test if file is successfully open by calling hasNotFinished()
*/
FFmaGenericLoader(const std::string & filename,const bool binary = false) :file(nullptr),binaryFile(binary),
centerOfBox(0.0,0.0,0.0),boxWidth(0.0),nbParticles(0){
FFmaGenericLoader(const std::string & filename,const bool binary ) :file(nullptr),binaryFile(binary),
centerOfBox(0.0,0.0,0.0),boxWidth(0.0),nbParticles(0),tmpVal(nullptr),otherDataToRead(0){
if(binary) {
this->file = new std::fstream (filename.c_str(),std::ifstream::in| std::ios::binary);
}
......@@ -85,29 +195,48 @@ public:
this->file = new std::fstream(filename.c_str(),std::ifstream::in) ;
}
// test if open
if(this->file->is_open()){
if(binaryFile){
this->readBinaryHeader();
}
else {
this->readAscciHeader();
}
if(! this->file->is_open()){
std::cerr << "File "<< filename<<" not opened! " <<std::endl;
exit(-1);
}
else {
this->boxWidth = 0;
this->nbParticles = -10;
this->readHeader();
}
/**
* The constructor need the file name
* @param filename the name with the extension .fma, .bfma of the file to open. We check the extension to know if the file is in ASCII mode or binary mode
*
* This function also read the header of the file (Two first lines)
* This means that we can obtain after the call the number of particles, ...
* you can test if file is successfully open by calling hasNotFinished()
*/
FFmaGenericLoader(const std::string & filename) : binaryFile(false) ,tmpVal(nullptr),otherDataToRead(0){
std::string ext(".bfma");
// open particle file
if(filename.find(ext) != std::string::npos) {
binaryFile = true;
this->file = new std::fstream (filename.c_str(),std::ifstream::in| std::ios::binary);
}
else if(filename.find(".fma")!=std::string::npos ) {
this->file = new std::fstream(filename.c_str(),std::ifstream::in) ;
}
else {
std::cout << "Input file not allowed only .fma or .bfma extensions" <<std::endl;
exit (-1) ;
}
// test if open
if(! this->file->is_open()){
std::cerr << "File "<< filename<<" not opened! " <<std::endl;
exit(-1);
}
std::cout << " nbParticles: " <<this->nbParticles << std::endl
<< " Box width: " <<this->boxWidth << std::endl
<< " Center: " << this->centerOfBox << std::endl;
this->readHeader();
}
/**
* Default destructor, simply close the file
*/
virtual ~FFmaGenericLoader(){
file->close();
delete file ;
delete tmpVal;
}
/**
......@@ -123,7 +252,7 @@ public:
* @param the number of particles the loader can fill
*/
FSize getNumberOfParticles() const{
return FSize(this->nbParticles);
return this->nbParticles;
}
/**
......@@ -133,7 +262,6 @@ public:
FPoint getCenterOfBox() const{
return this->centerOfBox;
}
/**
* The box width from the simulation file opened by the loader
* @return box width
......@@ -141,49 +269,448 @@ public:
FReal getBoxWidth() const{
return this->boxWidth;
}
/**
* The box width from the simulation file opened by the loader
* @return the number of data per record (Particle)
*/
unsigned int getNbRecordPerline(){
return typeData[1]; }
/**
* To know if the data are in float or in double type
* @return the type of the values float (4) or double (8)
*/
unsigned int getDataType(){
return typeData[0]; }
/**
* Fill a particle form th curent position in the file
* @warning to work with the loader, particles has to expose a setPosition method
* @param the particle to fill
* Fill a particle form the current position in the file
*
* @param outParticlePositions the position of particle to fill (FPoint class)
* @param outPhysicalValue the physical value of particle to fill (FReal)
*
*/
void fillParticle(FPoint*const outParticlePositions, FReal*const outPhysicalValue){
if(binaryFile){
file->read((char*)(outParticlePositions), sizeof(FReal)*3);
file->read((char*)(outPhysicalValue), sizeof(FReal));
if(otherDataToRead> 0){
file->read((char*)(this->tmpVal), sizeof(FReal)*otherDataToRead);
}
}
else{
FReal x,y,z;
// (*this->file) >> &outParticlePositions>> &outPhysicalValue;
// (*this->file) >> &outParticlePositions>> &outPhysicalValue;
(*this->file) >> x >> y >> z >> (*outPhysicalValue);
outParticlePositions->setPosition(x,y,z);
if(otherDataToRead> 0){
for (int i = 0 ; i <otherDataToRead; ++i){
(*this->file) >> x ;
}
}
}
// std::cout << "X Y Z Q " << *outParticlePositions<<" "<<*outPhysicalValue <<std::endl;
}
/**
* Fill a particle form the current position in the file
* @param dataToRead is an array of type FReal. It contains all the values of a particles (for instance X,Y,Z,Q, ..
* @param nbDataToRead number of value to read (I.e. size of the array)
*/
void fillParticle(FReal* dataToRead, const int nbDataToRead){
if(binaryFile){
file->read((char*)(dataToRead), sizeof(FReal)*nbDataToRead);
if(nbDataToRead< typeData[1]){
file->read((char*)(this->tmpVal), sizeof(FReal)*(typeData[1]-nbDataToRead));
}
}
// std::cout << "X Y Z Q " << *outParticlePositions<<" "<<*outPhysicalValue <<std::endl;
else{
for (int i = 0 ; i <nbDataToRead; ++i){
(*this->file) >>dataToRead[i];
}
if(nbDataToRead< typeData[1]){
FReal x;
for (int i = 0 ; i <typeData[1]-nbDataToRead; ++i){
(*this->file) >> x ;
}
}
}
}
/**
* Fill a particle form the current position in the file
* @param dataToRead is the particle class. If the class is different from FmaBasicParticle, FmaRParticle or FmaParticle the we have to implement the following method
* getPtrFirstData(), getReadDataNumber() see FmaBasicParticle class for more details.
*/
template <class dataPart>
void fillParticle(dataPart &dataToRead){
int otherDataToRead = typeData[1] - dataToRead.getReadDataNumber() ;
if(binaryFile){
file->read((char*)(dataToRead.getPtrFirstData()), sizeof(FReal)*(dataToRead.getReadDataNumber()));
if( otherDataToRead > 0){
file->read((char*)(this->tmpVal), sizeof(FReal)*(otherDataToRead));
}
}
else{
FReal * val = dataToRead.getPtrFirstData();
for (int i = 0 ; i <dataToRead.getReadDataNumber(); ++i){
(*this->file) >>*val;
++val;
}
if( otherDataToRead > 0){
FReal x;
for (int i = 0 ; i <otherDataToRead ;++i){
(*this->file) >>x;
}
}
}
}
/**
* Fill a set of particles form the current position in the file.
* If the file is a binary file and we read all record per particle then we read and fill the array in one instruction
* @param dataToRead is an array of the particle class. If the class is different from FmaBasicParticle, FmaRParticle or FmaParticle the we have to implement the following method
* getPtrFirstData(), getReadDataNumber() see FmaBasicParticle class for more details.
*/
template <class dataPart>
void fillParticle(dataPart *dataToRead, const int N){
int otherDataToRead = typeData[1] - (*dataToRead).getReadDataNumber() ;
if(binaryFile && otherDataToRead == 0 ){
file->read((char*)((*dataToRead).getPtrFirstData()), sizeof(FReal)*(N*(*dataToRead).getReadDataNumber()));
}
else {
for (int i = 0 ; i <N; ++i){
this->fillParticle(dataToRead[i]) ;
}
}
}
private:
void readHeader() {
if(this->binaryFile){
this->readBinaryHeader();
}
else {
this->readAscciHeader();
}
std::cout << " nbParticles: " <<this->nbParticles << std::endl
<< " Box width: " <<this->boxWidth << std::endl
<< " Center: " << this->centerOfBox << std::endl;
}
void readAscciHeader() {
std::cout << " File open in ASCII mode "<< std::endl ;
FReal x,y,z;
(*this->file) >> typeData[0]>> typeData[1];
std::cout << " Datatype "<< typeData[0] << " "<< typeData[1] << std::endl;
(*this->file) >> this->nbParticles >> this->boxWidth >> x >> y >> z;
this->centerOfBox.setPosition(x,y,z);
this->boxWidth *= 2;
otherDataToRead = typeData[1] -4;
};
void readBinaryHeader(){
std::cout << " File open in binary mode "<< std::endl;
file->seekg (std::ios::beg);
file->read((char*)&typeData,2*sizeof(unsigned int));
std::cout << " Datatype "<< typeData[0] << " "<< typeData[1] << std::endl;
if(typeData[0] != sizeof(FReal)){
std::cerr << "Size of elements in part file " << typeData[0] << " is different from size of FReal " << sizeof(FReal)<<std::endl;
exit(-1);
}
else{