OpenFPM_pdata  4.1.0
Project that contain the implementation of distributed structures
 
Loading...
Searching...
No Matches
In this example we show how to switch at runtime between serial and parallel

Parallel and serial

In this example we discuss how to switch from Parallel to serial and from serial to parallel. This is in general useful if you are trying to port a serial program into openfpm, and you want to do it progressively or in parts

Initialization

Before using any functionality the library must be initialized. After initialization we can create the Vcluster object

openfpm_init(&argc,&argv);
Vcluster<> & v_cl = create_vcluster();
Implementation of VCluster class.
Definition VCluster.hpp:59

Serial section

First we start from a serial section in which we have one external std::vector<my_particle> containing particles position and properties. Because the code is serial the full serial part is enclosed into an if condition that only processor 0 execute the code. Processor 0 only execute the code and create 100 particles.

{
double x[2];
double prop0;
long int prop1;
};
double x[2]
position
Definition main.cpp:27
double prop0
property 0
Definition main.cpp:30
long int prop1
property 1
Definition main.cpp:33
std::vector<my_particle> parts;
// id of the processor calling this function
long int proc_id = v_cl.getProcessUnitID();
if (proc_id == 0)
{
// We create 100 particles randomly between (0,0) and (2.0,3.0) serially
for (size_t i = 0 ; i < 100 ; i++)
{
p.x[0] = 2.0*(double)rand()/RAND_MAX;
p.x[1] = 3.0*(double)rand()/RAND_MAX;
p.prop0 = 0;
p.prop1 = 0;
parts.push_back(p);
}
}
size_t getProcessUnitID()
Get the process unit id.

Parallel section

The parallel section instead require an equivalent vector_dist. In particular we initialize the vector dist with 0 particles on a domain from (0.0,0.0) to (2.0,3.0).

Box<2,double> domain({0.0,0.0},{2.0,3.0});
Ghost<2,double> gs(0.02);
size_t bc[2] = {PERIODIC,PERIODIC};
This class represent an N-dimensional box.
Definition Box.hpp:61
Distributed vector.

As soon as we want to go parallel we want to convert the information from the std::vector to vector_dist. To do this, we call the function serial_to_parallel that convert the serial std::vector into vector_dist. After we did the conversion we can use pparts to do operations on it.

serial_to_parallel function

void serial_to_parallel(std::vector<my_particle> & parts,
{
auto & v_cl = create_vcluster();
pparts.clear();
if (v_cl.getProcessUnitID() == 0)
{
for (size_t i = 0 ; i < parts.size() ; i++)
{
pparts.add();
pparts.getLastPos()[0] = parts[i].x[0];
pparts.getLastPos()[1] = parts[i].x[1];
pparts.getLastProp<0>() = parts[i].prop0;
pparts.getLastProp<1>() = parts[i].prop1;
}
}
pparts.map<Error>();
pparts.addComputationCosts();
pparts.getDecomposition().decompose();
pparts.map<Error>();
}
Out-of-bound policy kill the program.
aggregate of properties, from a list of object if create a struct that follow the OPENFPM native stru...

This function convert the serial set of particles into the parallel set of particles To do this we first clear pparts than only the processor 0 fill pparts from the serial set of particles parts. After we filled pparts we redistribute the particles across processors using the function map. If the particles are uniformly distributed we can skip the second part an comment addComputationCosts(),decompose(),and the second map(). Otherwise these three lines redistribute the particles across processors in order to have (almost) an equal number of particles across processors independently from their density

Serial section (again)

To reconvert to serial we use the function parallel_to_serial this function does the opposite to convert the vector_dist pparts into std::vector parts. Once we have converted we can use parts, in this case we simply move the particles of 0.01 on x and 0.01 on y

parallel_to_serial function

void parallel_to_serial(std::vector<my_particle> & parts,
{
auto & v_cl = create_vcluster();
// here we collect on the processor 0
auto & pos = pparts.getPosVector();
auto & prp = pparts.getPropVector();
std::remove_reference<decltype(pos)>::type pos_collect;
std::remove_reference<decltype(prp)>::type prp_collect;
// we collecto everything on processor 0 on pos_collect and prp_collect
v_cl.SGather(pos,pos_collect,0);
v_cl.SGather(prp,prp_collect,0);
if (v_cl.getProcessUnitID() == 0)
{
parts.clear();
for (size_t i = 0 ; i < pos_collect.size() ; i++)
{
struct my_particle p;
p.x[0] = pos_collect.get<POS_>(i)[0];
p.x[1] = pos_collect.get<POS_>(i)[1];
p.prop0 = prp_collect.get<0>(i);
p.prop1 = prp_collect.get<1>(i);
parts.push_back(p);
}
}
}
bool SGather(T &send, S &recv, size_t root)
Semantic Gather, gather the data from all processors into one node.
Definition VCluster.hpp:450

This function convert the parallel set of particles into the serial set of particles. To do this we first get the position and properties particle vector from each processor. Than we create two other equivalent vector that will contain the collected vector of position and vector of properties. We use the function SGather to collect on processor 0 all the data. Once collected we move the data from the collected vectors into parts

Finalize

At the very end of the program we have always to de-initialize the library

openfpm_finalize();