Commit c3e0c4a8 authored by COULAUD Olivier's avatar COULAUD Olivier

Restore letSTF just after separation with develop

parent baf36974
......@@ -7,11 +7,12 @@ endif()
cmake_policy(SET CMP0004 NEW)
set(CMAKE_DISABLE_IN_SOURCE_BUILD ON)
set(FUSE_LIST " MPI;BLAS;FFT;STARPU;CUDA;OPENCL;OMP4;SSE;AVX;AVX2;MIC;MPI2")
#===========================================================================
# Project Declaration
#===========================================================================
project(SCALFMM C CXX)
project(SCALFMM C CXX )
# check if compiling into source directories
string(COMPARE EQUAL "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}" insource)
......@@ -215,7 +216,7 @@ if (MORSE_DISTRIB_DIR OR EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules/morse/
##############################################################################
# FUSE list #
##############################################################################
set(FUSE_LIST "")
# set(FUSE_LIST "")
# then do list(APPEND FUSE_LIST "BLAS") to protect from FUSE_BLAS
list(APPEND FUSE_LIST "MPI")
......@@ -307,7 +308,6 @@ if (MORSE_DISTRIB_DIR OR EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules/morse/
endif()
find_package(MPI REQUIRED)
if (MPI_CXX_INCLUDE_PATH)
include_directories( ${MPI_CXX_INCLUDE_PATH} )
endif()
......@@ -315,7 +315,7 @@ if (MORSE_DISTRIB_DIR OR EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules/morse/
set(SCALFMM_CXX_FLAGS "${SCALFMM_CXX_FLAGS} ${MPI_CXX_COMPILE_FLAGS}")
endif()
if (MPI_CXX_INCLUDE_PATH)
set(SCALFMM_INCLUDES "${SCALFMM_INCLUDES}; ${MPI_CXX_INCLUDE_PATH}")
set(SCALFMM_INCLUDES "${SCALFMM_INCLUDES};${MPI_CXX_INCLUDE_PATH}")
endif()
if (MPI_CXX_LINK_FLAGS)
list(APPEND "CMAKE_EXE_LINKER_FLAGS ${MPI_CXX_LINK_FLAGS}")
......@@ -821,6 +821,7 @@ if (MORSE_DISTRIB_DIR OR EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules/morse/
# Build - lib #
##################################################################
#
MESSAGE(STATUS "FUSE : ${FUSE_LIST} ")
add_subdirectory(Src)
# Link with scalfmm lib
set(scalfmm_lib scalfmm)
......
......@@ -13,6 +13,7 @@
#include "inria/utils.hpp"
#include "inria/meta.hpp"
#include <numeric>
#include <iterator>
#include <vector>
......
......@@ -189,8 +189,8 @@ create_balanced_linear_tree(
* @return [description]
*/
std::size_t send_get_max_morton_idx(
inria::mpi_config& conf,
std::size_t& max_morton_idx
inria::mpi_config& conf,
std::size_t& max_morton_idx
)
{
// Setting parametter
......@@ -291,7 +291,7 @@ std::vector<details::cblt::node_info_from_range<Range>> create_balanced_linear_t
last_morton_index = curr_idx_morton;
++nb_leaf;
}
}
}
return {begin(lin_tree), end(lin_tree)};
}
......
......@@ -14,7 +14,6 @@ file(
./*.cpp
)
# Adding the project sources dir as an include dir
INCLUDE_DIRECTORIES(
${SCALFMM_BINARY_DIR}/Src
......
......@@ -56,7 +56,7 @@ int main(int argc, char* argv[])
FHelpDescribeAndExit(argc, argv,
"Driver for HArmonic Spherical + Rotation -- kernel (1/r kernel).",
FParameterDefinitions::InputFile, FParameterDefinitions::OctreeHeight,
FParameterDefinitions::OctreeSubHeight, FParameterDefinitions::InputFile,
FParameterDefinitions::OctreeSubHeight, FParameterDefinitions::OutputFile,
FParameterDefinitions::NbThreads);
const std::string defaultFile(/*SCALFMMDataPath+*/"../Data/test20k.fma");
......@@ -188,7 +188,56 @@ int main(int argc, char* argv[])
}
// -----------------------------------------------------
// -----------------------------------------------------
if(FParameters::existParameter(argc, argv, FParameterDefinitions::OutputFile.options)){
std::string name(FParameters::getStr(argc,argv,FParameterDefinitions::OutputFile.options, "output.fma"));
FFmaGenericWriter<FReal> writer(name) ;
//
FSize NbPoints = loader.getNumberOfParticles();
FReal * particles ;
particles = new FReal[8*NbPoints] ;
memset(particles,0,8*NbPoints*sizeof(FReal));
FSize j = 0 ;
tree.forEachLeaf([&](LeafClass* leaf){
//
// Input
const FReal*const posX = leaf->getTargets()->getPositions()[0];
const FReal*const posY = leaf->getTargets()->getPositions()[1];
const FReal*const posZ = leaf->getTargets()->getPositions()[2];
const FReal*const physicalValues = leaf->getTargets()->getPhysicalValues();
const FVector<FSize>& indexes = leaf->getTargets()->getIndexes();
//
// Computed data
const FReal*const potentials = leaf->getTargets()->getPotentials();
const FReal*const forcesX = leaf->getTargets()->getForcesX();
const FReal*const forcesY = leaf->getTargets()->getForcesY();
const FReal*const forcesZ = leaf->getTargets()->getForcesZ();
//
const FSize nbParticlesInLeaf = leaf->getTargets()->getNbParticles();
for(FSize idxPart = 0 ; idxPart < nbParticlesInLeaf ; ++idxPart){
j = 8*indexes[idxPart];
particles[j] = posX[idxPart] ;
particles[j+1] = posY[idxPart] ;
particles[j+2] = posZ[idxPart] ;
particles[j+3] = physicalValues[idxPart] ;
particles[j+4] = potentials[idxPart] ;
particles[j+5] = forcesX[idxPart] ;
particles[j+6] = forcesY[idxPart] ;
particles[j+7] = forcesZ[idxPart] ;
}
});
writer.writeHeader( loader.getCenterOfBox(), loader.getBoxWidth() , NbPoints, sizeof(FReal), 8) ;
writer.writeArrayOfReal(particles, 8 , NbPoints);
delete[] particles;
//
std::string name1( "output.fma");
//
FFmaGenericWriter<FReal> writer1(name1) ;
writer1.writeDistributionOfParticlesFromOctree(&tree,NbPoints) ;
}
return 0;
}
Copyright ScalFmm 2011-2016 INRIA
Copyright ScalFmm 2011-2017 INRIA
=================================
This software is a computer program which purpose is to compute the FMM.
......
......@@ -2,9 +2,9 @@
#define FBASICCELLPOD_HPP
#include "../../Utils/FGlobal.hpp"
#include "../../Containers/FTreeCoordinate.hpp"
#include "../StarPUUtils/FStarPUDefaultAlign.hpp"
#include "../../Src/Utils/FGlobal.hpp"
#include "../../Src/Containers/FTreeCoordinate.hpp"
#include "../../Src/GroupTree/StarPUUtils/FStarPUDefaultAlign.hpp"
struct alignas(FStarPUDefaultAlign::StructAlign) FBasicCellPOD {
MortonIndex mortonIndex;
......
#ifndef FCHEBCELLPOD_HPP
#define FCHEBCELLPOD_HPP
#include "../../Utils/FGlobal.hpp"
#include "../Core/FBasicCellPOD.hpp"
#include "../StarPUUtils/FStarPUDefaultAlign.hpp"
#include "../../Kernels/Chebyshev/FChebTensor.hpp"
#include "../../Src/Utils/FGlobal.hpp"
#include "FBasicCellPOD.hpp"
#include "../Src/GroupTree/StarPUUtils/FStarPUDefaultAlign.hpp"
#include "../../Src/Kernels/Chebyshev/FChebTensor.hpp"
typedef FBasicCellPOD FChebCellPODCore;
......
#ifndef SCALFMM_STARPU_ALGO_HPP_
#define SCALFMM_STARPU_ALGO_HPP_
//@FUSE_STARPU
#include <algorithm>
#include <cmath> // Used to round box differences
#include <functional>
......@@ -9,7 +11,7 @@
#include <vector>
#include <unordered_map>
#include <starpu/1.2/starpu.h>
#include <starpu.h>
#include "Core/FCoreCommon.hpp"
#include "Containers/FTreeCoordinate.hpp"
......
......@@ -8,7 +8,9 @@
#ifndef _SCALFMM_STARPU_NODE_DATA_HANDLES_HPP_
#define _SCALFMM_STARPU_NODE_DATA_HANDLES_HPP_
#include <starpu/1.2/starpu.h>
// @FUSE_STARPU
#include <starpu.h>
#include <utility>
......
......@@ -43,9 +43,10 @@ class FOctree : public FNoCopyable {
public:
using FRealType = FReal;
using CellClassType = CellClass;
using ContainerClassType = ContainerClass;
using LeafClassType = LeafClass_; //< The type of the Leaf used in the Octree
using LeafClass = LeafClass_; //< The type of the Leaf used in the Octree
using ContainerClassType = ContainerClass; //< The type of the container used to store particles in the Octree
using LeafClassType = LeafClass_; //< The type of the Leaf used in the Octree
using LeafClass = LeafClass_; //< The type of the Leaf used in the Octree
using LeafClass_T = LeafClass_; //< The type of the Leaf used in the Octree
protected:
typedef FOctree<FReal, CellClass , ContainerClass, LeafClass, CellAllocatorClass> OctreeType;
......
......@@ -29,6 +29,27 @@ enum FFmmOperations {
//
FFmmNearAndFarFields = (FFmmNearField|FFmmFarField)
};
std::string FFmmOperations_string(/*enum FFmmOperations*/ const unsigned int & value){
//if (value & FFmmNearAndFarFields) return std::string("FFmmNearAndFarFields") ;
//if (value & FFmmFarField) return std::string("FFmmFarField") ;
//if (value & FFmmNearField) return std::string("FFmmNearField" );
std::string op("");
if (value & FFmmP2P)
op += " FFmmP2P |";
if (value & FFmmP2M)
op += " FFmmP2M |";
if (value & FFmmM2M)
op += " FFmmM2M |";
if (value & FFmmM2L)
op += " FFmmM2L |";
if (value & FFmmL2L)
op += " FFmmL2L |";
if (value & FFmmL2P)
op += " FFmmL2P |";
op.erase(op.size()-2,op.size()-1);
return op;
};
/**
* \brief Algorithm interface
......@@ -98,7 +119,6 @@ protected:
FAssertLF(FAbstractAlgorithm::upperWorkingLevel <= FAbstractAlgorithm::lowerWorkingLevel);
FAssertLF(2 <= FAbstractAlgorithm::upperWorkingLevel);
}
virtual void executeCore(const unsigned operationsToProceed) = 0;
public:
......
......@@ -24,6 +24,8 @@
template <class FReal>
class FAbstractLoader {
public:
using dataType= FReal ;
/** Default destructor */
virtual ~FAbstractLoader(){
}
......
#ifndef _F_BLOCKED_MPI_INTERPOLATION_HPP_
#define _F_BLOCKED_MPI_INTERPOLATION_HPP_
#include "../../Src/Utils/FGlobal.hpp"
#include "../../Src/GroupTree/Core/FGroupTree.hpp"
#include "../../Src/Components/FSimpleLeaf.hpp"
#include "../../Src/Components/FSymbolicData.hpp"
#include "../../Src/Containers/FVector.hpp"
#include "../../Src/Kernels/P2P/FP2PParticleContainer.hpp"
#include "../../Src/Utils/FMath.hpp"
#include "../../Src/Utils/FMemUtils.hpp"
#include "../../Src/Utils/FParameters.hpp"
#include "../../Src/Files/FRandomLoader.hpp"
#include "../../Src/Files/FFmaGenericLoader.hpp"
#include "../../Src/GroupTree/Core/FGroupSeqAlgorithm.hpp"
#include "../../Src/GroupTree/Core/FGroupTaskAlgorithm.hpp"
#include "../../Src/GroupTree/Core/FGroupTaskStarpuAlgorithm.hpp"
#include "../../Src/GroupTree/Core/FP2PGroupParticleContainer.hpp"
#include "../../Src/Utils/FParameterNames.hpp"
#include "../../Src/Components/FTestParticleContainer.hpp"
#include "../../Src/Components/FTestCell.hpp"
#include "../../Src/Components/FTestKernels.hpp"
#include "../../Src/Core/FFmmAlgorithmThreadProc.hpp"
#include "../../Src/Files/FMpiTreeBuilder.hpp"
#include "../../Src/GroupTree/Core/FGroupTaskStarpuMpiAlgorithm.hpp"
#include "../../Src/Core/FFmmAlgorithm.hpp" //For validation
#include "../../Src/Files/FMpiFmaGenericLoader.hpp"
#include "../../Src/Containers/FCoordinateComputer.hpp"
#include "../../Src/GroupTree/StarPUUtils/FStarPUKernelCapacities.hpp"
#include <memory>
using namespace std;
namespace blockedMpiInterpolation{
//Function header
void timeAverage(int mpi_rank, int nproc, double elapsedTime);
FSize getNbParticlesPerNode(FSize mpi_count, FSize mpi_rank, FSize total);
template<
class GroupCellClass,
class GroupCellUpClass,
class GroupCellDownClass,
class GroupCellSymbClass,
class KernelClass,
class MatrixKernelClass
>
auto execute_algorithm(int argc, char* argv[]){
//Define parameters
const FParameterNames LocalOptionBlocSize { {"-bs"}, "The size of the block of the blocked tree"};
const FParameterNames LocalOptionEllipsoid = {{"-ellipsoid"} , " non uniform distribution on an ellipsoid of aspect ratio given by a=0.5 b=0.25 c=0.125"};
const FParameterNames LocalOptionCube = {{"-cube", "-uniform"} , " uniform distribution on cube (default)"};
// Define types
using FReal = double;
using GroupContainerClass =
FP2PGroupParticleContainer<FReal>;
using GroupOctreeClass =
FGroupTree< FReal, GroupCellSymbClass, GroupCellUpClass, GroupCellDownClass, GroupContainerClass, 1, 4, FReal>;
using GroupKernelClass =
FStarPUAllCpuCapacities<KernelClass>;
using GroupCpuWrapper =
FStarPUCpuWrapper<typename GroupOctreeClass::CellGroupClass, GroupCellClass, GroupKernelClass, typename GroupOctreeClass::ParticleGroupClass, GroupContainerClass> ;
using GroupAlgorithm =
FGroupTaskStarPUMpiAlgorithm<GroupOctreeClass, typename GroupOctreeClass::CellGroupClass, GroupKernelClass, typename GroupOctreeClass::ParticleGroupClass, GroupCpuWrapper> ;
// Init MPI_COM
FMpi mpiComm(argc,argv);
// Init timer
FTic timer;
// Getting parameters
const int groupSize =
FParameters::getValue(argc,argv,LocalOptionBlocSize.options, 250);
const unsigned int TreeHeight =
FParameters::getValue(argc, argv, FParameterDefinitions::OctreeHeight.options, 5);
const FSize totalNbParticles =
FParameters::getValue(argc,argv,FParameterDefinitions::NbParticles.options, FSize(20));
const FSize NbParticles =
getNbParticlesPerNode(mpiComm.global().processCount(), mpiComm.global().processId(), totalNbParticles);
// init particles position and physical value
struct TestParticle{
FPoint<FReal> position;
FReal physicalValue;
const FPoint<FReal>& getPosition(){
return position;
}
const unsigned int getWriteDataSize(void) const {
return sizeof(FReal);
}
const unsigned int getWriteDataNumber(void) const {
return 3;
}
const FReal* getPtrFirstData(void) const {
return position.data();
}
};
// LOADING PARTICLE
#ifndef LOAD_FILE
FRandomLoader<FReal> loader(NbParticles, 1.0, FPoint<FReal>(0,0,0), mpiComm.global().processId());
FAssertLF(loader.isOpen());
TestParticle* allParticles = new TestParticle[loader.getNumberOfParticles()];
memset(allParticles,0,(unsigned int) (sizeof(TestParticle)* loader.getNumberOfParticles()));
for(FSize idxPart = 0 ; idxPart < loader.getNumberOfParticles() ; ++idxPart){
loader.fillParticle(&allParticles[idxPart].position);
allParticles[idxPart].physicalValue = 0.1;
}
#else
const char* const filename = FParameters::getStr(argc,argv,FParameterDefinitions::InputFile.options, "../Data/test20k.fma");
FMpiFmaGenericLoader<FReal> loader(filename,mpiComm.global());
FAssertLF(loader.isOpen());
TestParticle* allParticles = new TestParticle[loader.getMyNumberOfParticles()];
memset(allParticles,0,(unsigned int) (sizeof(TestParticle)* loader.getMyNumberOfParticles()));
for(FSize idxPart = 0 ; idxPart < loader.getMyNumberOfParticles() ; ++idxPart){
loader.fillParticle(&allParticles[idxPart].position,&allParticles[idxPart].physicalValue);
}
#endif
FVector<TestParticle> myParticles;
FLeafBalance balancer;
FMpiTreeBuilder< FReal,
TestParticle >::DistributeArrayToContainer(
mpiComm.global(),
allParticles,
loader.getNumberOfParticles(),
loader.getCenterOfBox(),
loader.getBoxWidth(),
TreeHeight,
&myParticles,
&balancer);
// Each proc need to know the righest morton index
const FTreeCoordinate host = FCoordinateComputer::GetCoordinateFromPosition<FReal>(
loader.getCenterOfBox(),
loader.getBoxWidth(),
TreeHeight,
myParticles[myParticles.getSize()-1].position );
const MortonIndex myLeftLimite = host.getMortonIndex();
MortonIndex leftLimite = -1;
if(mpiComm.global().processId() != 0){
FMpi::Assert(MPI_Recv(&leftLimite, sizeof(leftLimite), MPI_BYTE,
mpiComm.global().processId()-1, 0,
mpiComm.global().getComm(), MPI_STATUS_IGNORE), __LINE__);
}
if(mpiComm.global().processId() != mpiComm.global().processCount()-1){
FMpi::Assert(MPI_Send(const_cast<MortonIndex*>(&myLeftLimite), sizeof(myLeftLimite), MPI_BYTE,
mpiComm.global().processId()+1, 0,
mpiComm.global().getComm()), __LINE__);
}
FLOG(std::cout << "My last index is " << leftLimite << "\n");
FLOG(std::cout << "My left limite is " << myLeftLimite << "\n");
// Put the data into the tree
FP2PParticleContainer<FReal> myParticlesInContainer;
for(FSize idxPart = 0 ; idxPart < myParticles.getSize() ; ++idxPart){
myParticlesInContainer.push(myParticles[idxPart].position,
myParticles[idxPart].physicalValue);
}
GroupOctreeClass groupedTree(TreeHeight, loader.getBoxWidth(), loader.getCenterOfBox(), groupSize,
&myParticlesInContainer, true, leftLimite);
timer.tac();
std::cerr << "Done " << "(@Creating and Inserting Particles = " << timer.elapsed() << "s)." << std::endl;
int operationsToProceed = FFmmP2P | FFmmP2M | FFmmM2M | FFmmM2L | FFmmL2L | FFmmL2P;
{ // -----------------------------------------------------
const MatrixKernelClass MatrixKernel;
// Create Matrix Kernel
GroupKernelClass groupkernel(TreeHeight, loader.getBoxWidth(), loader.getCenterOfBox(), &MatrixKernel);
// Run the algorithm
GroupAlgorithm groupalgo(mpiComm.global(), &groupedTree,&groupkernel);
mpiComm.global().barrier();
timer.tic();
starpu_fxt_start_profiling();
groupalgo.execute(operationsToProceed);
mpiComm.global().barrier();
starpu_fxt_stop_profiling();
timer.tac();
timeAverage(mpiComm.global().processId(), mpiComm.global().processCount(), timer.elapsed());
}
return &groupedTree;
}
void timeAverage(int mpi_rank, int nproc, double elapsedTime){
if(mpi_rank == 0){
double sumElapsedTimeMin = elapsedTime;
double sumElapsedTimeMax = elapsedTime;
for(int i = 1; i < nproc; ++i){
double tmp;
MPI_Recv(&tmp, 1, MPI_DOUBLE, i, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
if(tmp < sumElapsedTimeMin)
sumElapsedTimeMin = tmp;
if(tmp > sumElapsedTimeMax)
sumElapsedTimeMax = tmp;
}
std::cout << "Min time per node (MPI) : " << sumElapsedTimeMin << "s" << std::endl;
std::cout << "Max time per node (MPI) : " << sumElapsedTimeMax << "s" << std::endl;
} else {
MPI_Send(&elapsedTime, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD);
}
MPI_Barrier(MPI_COMM_WORLD);
}
FSize getNbParticlesPerNode(FSize mpi_count, FSize mpi_rank, FSize total){
if(mpi_rank < (total%mpi_count))
return ((total - (total%mpi_count))/mpi_count)+1;
return ((total - (total%mpi_count))/mpi_count);
}
}
#endif
......@@ -199,7 +199,6 @@ private:
FReal * tmpVal; ///< Temporary array to read data
/// Count of other data pieces to read in a particle record after the 4 first ones.
unsigned int otherDataToRead;
void open_file(const std::string filename, const bool binary) {
if(binary) {
this->file = new std::fstream (filename.c_str(),std::ifstream::in| std::ios::binary);
......@@ -216,6 +215,7 @@ private:
}
public:
using dataType= FReal ; // Just to what kind of data we handle
/**
* This constructor opens a file using the given mode and reads its
* header. The file will be kept opened until destruction of the object.
......@@ -543,8 +543,8 @@ template <class FReal>
class FFmaGenericWriter {
protected:
std::fstream *file; ///< the stream used to read the file
bool binaryFile ; ///< if true the file to read is in binary mode
std::fstream *file; ///< the stream used to write the file
bool _binaryFile ; ///< if true the file is in binary mode
public:
/**
......@@ -555,11 +555,11 @@ public:
*
* @param filename the name of the file to open.
*/
FFmaGenericWriter(const std::string & filename): binaryFile(false) {
FFmaGenericWriter(const std::string & filename): _binaryFile(false) {
std::string ext(".bfma");
// open particle file
if(filename.find(".bfma") !=std::string::npos) {
binaryFile = true;
_binaryFile = true;
this->file = new std::fstream (filename.c_str(),std::ifstream::out| std::ios::binary);
}
else if(filename.find(".fma")!=std::string::npos ) {
......@@ -583,7 +583,7 @@ public:
* @param filename the name of the file to open.
* @param binary true if the file to open is in binary mode
*/
FFmaGenericWriter(const std::string & filename, const bool binary ) : file(nullptr), binaryFile(binary)
FFmaGenericWriter(const std::string & filename, const bool binary ) : file(nullptr), _binaryFile(binary)
{
if(binary) {
this->file = new std::fstream (filename.c_str(),std::ifstream::out| std::ios::binary);
......@@ -616,6 +616,14 @@ public:
}
/**
* To know if opened file is in binary mode
* @return true ifopened file is in binary mode
*/
bool isBinary() const{
return this->_binaryFile;
}
/**
* Writes the header of the FMA file
* \warning All values inside typePart should be of the same type (float or double)
*
......@@ -633,7 +641,7 @@ public:
typeFReal[1] = ndata;
}
FReal x = boxWidth * FReal(0.5);
if(this->binaryFile) {
if(this->_binaryFile) {
this->writerBinaryHeader(centerOfBox,x,nbParticles,typeFReal);
}
else {
......@@ -656,7 +664,7 @@ public:
const unsigned int dataType, const unsigned int nbDataPerRecord) {
unsigned int typeFReal[2] = {dataType , nbDataPerRecord };
FReal x = boxWidth * FReal(0.5);
if(this->binaryFile) {
if(this->_binaryFile) {
this->writerBinaryHeader(centerOfBox,x,nbParticles,typeFReal);
}
else {
......@@ -698,7 +706,7 @@ public:
template <class dataPart>
void writeArrayOfParticles(const dataPart *dataToWrite, const FSize N){
// std::cout << "NB points to write: "<< N <<std::endl;
if(binaryFile){
if(_binaryFile){
unsigned int recordSize= dataToWrite[0].getWriteDataSize() ;
unsigned int typeFReal[2] = {sizeof(FReal) , sizeof(dataPart) / sizeof(FReal) };
// std::cout << "typeData "<< typeFReal[0] << " "<< typeFReal[1] <<" "<< std::endl;
......@@ -755,7 +763,7 @@ public:
* \endcode
*/
void writeArrayOfReal(const FReal *dataToWrite, const FSize nbData, const FSize N){
if(binaryFile){
if(_binaryFile){
file->write((const char*)(dataToWrite), N*nbData*sizeof(FReal));
}
else{
......
......@@ -8,6 +8,8 @@
#ifndef FMPIFMAGENERICLOADER_HPP
#define FMPIFMAGENERICLOADER_HPP
#include <cstdlib>
#include <vector>
#include "Utils/FMpi.hpp"
#include "Files/FFmaGenericLoader.hpp"
......@@ -69,5 +71,269 @@ public:
}
};
/**
*
* \brief Writes a set of distributed particles to an FMA formated file.
*
* The file may be in ASCII or binary mode. The example below shows how to use the class.
*
* \code
* // Instanciate the writer with a binary fma file (extension .bfma).
* \endcode
* ----------------------------------------
* FMA is a simple format to store particles in a file. It is organized as follow.
*
* file
*/
template <class FReal>
class FMpiFmaGenericWriter : public FFmaGenericWriter<FReal> {
protected:
const FMpi* _parallelManager ;
bool _writeDone ;
int _headerSize;
int _nbDataTowritePerRecord ; //< number of data to write for one particle
FSize _numberOfParticles ; //< number of particle (global) to write in the file
using FFmaGenericWriter<FReal>::file;
MPI_File _mpiFile; //< MPI pointer on data file (write mode)
public:
/**
* This constructor opens a file to be written to.
*
* - The opening mode is guessed from the file extension : `.fma` will open
* in ASCII mode, `.bfma` will open in binary mode.
*
* @param filename the name of the file to open.
*/
FMpiFmaGenericWriter(const std::string inFilename, const FMpi& para) : FFmaGenericWriter<FReal>(inFilename),
_parallelManager(&para),_writeDone(false),_headerSize(0),_nbDataTowritePerRecord(8),_numberOfParticles(0)
{
if ( ! this->isBinary()){
std::cout << "FMpiFmaGenericWriter only works with binary file (.bfma)." << std::endl;
std::exit(EXIT_FAILURE);
}
int fileIsOpen = MPI_File_open( _parallelManager->global().getComm(), inFilename.c_str(),
MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_INFO_NULL, &_mpiFile );
// Is it open?
if(fileIsOpen != MPI_SUCCESS){
std::cout << "Cannot create parallel file, FMpiFmaGenericWriter constructeur abort." << std::endl;
std::exit(EXIT_FAILURE);
return;
}
}
/**
* Writes the header of FMA file.
*
* Should be used if we write the particles with writeArrayOfReal method
*
* @param centerOfBox The center of the Box (FPoint<FReal> class)
* @param boxWidth The width of the box
* @param nbParticles Number of particles in the box (or to save)
* @param dataType Size of the data type of the values in particle
* @param nbDataPerRecord Number of record/value per particle
*/
void writeHeader(const FPoint<FReal> &centerOfBox,const FReal &boxWidth, const FSize &nbParticles,
const unsigned int dataType, const unsigned int nbDataPerRecord) {
// * \code
// * DatatypeSize Number_of_record_per_line
// * NB_particles half_Box_width Center_X Center_Y Center_Z
// * Particle_values
// * \endcode
_headerSize = 0 ;
_nbDataTowritePerRecord = nbDataPerRecord ;
_numberOfParticles = nbParticles ;
if(_parallelManager->global().processId()==0){
int sizeType=0 ;
int ierr = 0 ;
MPI_Datatype mpiFSize_t = _parallelManager->GetType(nbParticles) ;
MPI_Datatype mpiFReal_t = _parallelManager->GetType(boxWidth) ;
//
unsigned int typeFReal[2] = {sizeof(FReal) , nbDataPerRecord};
ierr =MPI_File_write_at(_mpiFile, 0, &typeFReal, 2, MPI_INT, MPI_STATUS_IGNORE);
MPI_Type_size(MPI_INT, &sizeType) ;
_headerSize += sizeType*2 ;
ierr =MPI_File_write_at(_mpiFile, _headerSize, &nbParticles, 1, mpiFSize_t, MPI_STATUS_IGNORE);
MPI_Type_size(mpiFSize_t, &sizeType) ;
_headerSize += sizeType*1 ;
FReal boxSim[4] = {boxWidth ,centerOfBox.getX() , centerOfBox.getX() , centerOfBox.getX() } ;
ierr =MPI_File_write_at(_mpiFile, _headerSize, &boxSim[0], 4, mpiFReal_t, MPI_STATUS_IGNORE);