OpenFPM_pdata  4.1.0 Project that contain the implementation of distributed structures
Searching...
No Matches
Vector 0 simple

# Simple Vector example

This example show several basic functionalities of the distributed vector, A distributed vector is nothing else than a set of particles in an N dimensional space

Video 2

## inclusion

In order to use distributed vectors in our code we have to include the file Vector/vector_dist.hpp

#include <stddef.h>
#include "Vector/vector_dist.hpp"

## Initialization

Here we

• Initialize the library
• we create a Box that define our domain
• An array that define our boundary conditions
• A Ghost object that will define the extension of the ghost part in physical units
// initialize the library
openfpm_init(&argc,&argv);
// Here we define our domain a 2D box with internals from 0 to 1.0 for x and y
Box<2,float> domain({0.0,0.0},{1.0,1.0});
// Here we define the boundary conditions of our problem
size_t bc[2]={PERIODIC,PERIODIC};
// extended boundary around the domain, and the processor domain
Ghost<2,float> g(0.01);
This class represent an N-dimensional box.
Definition Box.hpp:61
Video 2

## Vector instantiation

Here we are creating a distributed vector defined by the following parameters

• 2 is the Dimensionality of the space where the objects live
• float is the type used for the spatial coordinate of the particles
• float,float[3],float[3][3] is the information stored by each particle a scalar float, a vector float[3] and a tensor of rank 2 float[3][3] the list of properties must be put into an aggregate data structure aggregate<prop1,prop2,prop3, ... >

vd is the instantiation of the object

• Number of particles 4096 in this case
• Domain where is defined this structure
• bc boundary conditions
• g Ghost

The following construct a vector where each processor has 4096 / N_proc (N_proc = number of processor) objects with an undefined position in space. This non-space decomposition is also called data-driven decomposition

// the scalar is the element at position 0 in the aggregate
const int scalar = 0;
// the vector is the element at position 1 in the aggregate
const int vector = 1;
// the tensor is the element at position 2 in the aggregate
const int tensor = 2;
Distributed vector.

## Assign position

Get an iterator that go through the 4096 particles. Initially all the particles has an undefined position state. In this cycle we define its position. In this example we use iterators. Iterators are convenient way to explore/iterate data-structures in an convenient and easy way

auto it = vd.getDomainIterator();
while (it.isNext())
{
auto key = it.get();
// we define x, assign a random position between 0.0 and 1.0
vd.getPos(key)[0] = (float)rand() / RAND_MAX;
// we define y, assign a random position between 0.0 and 1.0
vd.getPos(key)[1] = (float)rand() / RAND_MAX;
// next particle
++it;
}

## Mapping particles

On a parallel program, once we define the position, we distribute the particles according to the underlying space decomposition The default decomposition is created even before assigning the position to the object, and is calculated giving to each processor an equal portion of space minimizing the surface to reduce communication.

vd.map();
Video 1 Video 2
Video 3

## Assign values to particles property

We Iterate across all the particles, we count them using a local counter and we assign 1.0 to all the particles properties. Each particle has a scalar, vector and tensor property.

//Counter we use it later
size_t cnt = 0;
// Get a particle iterator
it = vd.getDomainIterator();
// For each particle ...
while (it.isNext())
{
// ... p
auto p = it.get();
// we set the properties of the particle p
// the scalar property
vd.template getProp<scalar>(p) = 1.0;
vd.template getProp<vector>(p)[0] = 1.0;
vd.template getProp<vector>(p)[1] = 1.0;
vd.template getProp<vector>(p)[2] = 1.0;
vd.template getProp<tensor>(p)[0][0] = 1.0;
vd.template getProp<tensor>(p)[0][1] = 1.0;
vd.template getProp<tensor>(p)[0][2] = 1.0;
vd.template getProp<tensor>(p)[1][0] = 1.0;
vd.template getProp<tensor>(p)[1][1] = 1.0;
vd.template getProp<tensor>(p)[1][2] = 1.0;
vd.template getProp<tensor>(p)[2][0] = 1.0;
vd.template getProp<tensor>(p)[2][1] = 1.0;
vd.template getProp<tensor>(p)[2][2] = 1.0;
// increment the counter
cnt++;
// next particle
++it;
}

## Reduce (sum numbers across processors)

cnt contain the number of object the local processor contain, if we are interested to count the total number across the processors we can use the function add, to sum across the processors. First we have to get an instance of Vcluster, queue an operation of add with the variable count and finally execute. All the operations are asynchronous, execute work like a barrier and ensure that all the queued operations are executed.

auto & v_cl = create_vcluster();
v_cl.sum(cnt);
v_cl.execute();

## Visualization, write VTK files

With this function we output the particle position in VTK format. A VTK file contain information about particle position and properties. Such file can be visualized with a program like paraview. In case this program run on several processor each processor generate a VTK file. VTK has two format one is the ASCII that is human readable but produce bigger file the other is the binary that produce not-human readable files, but smaller and more efficent files to read for Paraview. In order to create a Binary VTK file use the option VTK_WRITER in combination with FORMAT_BINARY. By default properties does not have name the VTK writer will label them "attr0" for the first property "attr1" for the second and so on in case we want to assign names to the properties we can use the function setPropNames

openfpm::vector<std::string> names({"scalar","vector","tensor"});
vd.setPropNames(names);
// save vtk format (vtk is always the default)
vd.write("particles");
// save in vtk binary format
vd.write("particles_bin",VTK_WRITER | FORMAT_BINARY);
// save in vtk format with time
vd.write("particles_with_time","time=1.234");
// save in vtk format with time
vd.write("particles_with_time_bin","time=1.234",VTK_WRITER | FORMAT_BINARY);
Implementation of 1-D std::vector like structure.

## Finalize

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

openfpm_finalize();

## Full code

#include <stddef.h>
#include "Vector/vector_dist.hpp"
int main(int argc, char* argv[])
{
// initialize the library
openfpm_init(&argc,&argv);
// Here we define our domain a 2D box with internals from 0 to 1.0 for x and y
Box<2,float> domain({0.0,0.0},{1.0,1.0});
// Here we define the boundary conditions of our problem
size_t bc[2]={PERIODIC,PERIODIC};
// extended boundary around the domain, and the processor domain
Ghost<2,float> g(0.01);
// the scalar is the element at position 0 in the aggregate
const int scalar = 0;
// the vector is the element at position 1 in the aggregate
const int vector = 1;
// the tensor is the element at position 2 in the aggregate
const int tensor = 2;
auto it = vd.getDomainIterator();
while (it.isNext())
{
auto key = it.get();
// we define x, assign a random position between 0.0 and 1.0
vd.getPos(key)[0] = (float)rand() / RAND_MAX;
// we define y, assign a random position between 0.0 and 1.0
vd.getPos(key)[1] = (float)rand() / RAND_MAX;
// next particle
++it;
}
vd.map();
//Counter we use it later
size_t cnt = 0;
// Get a particle iterator
it = vd.getDomainIterator();
// For each particle ...
while (it.isNext())
{
// ... p
auto p = it.get();
// we set the properties of the particle p
// the scalar property
vd.template getProp<scalar>(p) = 1.0;
vd.template getProp<vector>(p)[0] = 1.0;
vd.template getProp<vector>(p)[1] = 1.0;
vd.template getProp<vector>(p)[2] = 1.0;
vd.template getProp<tensor>(p)[0][0] = 1.0;
vd.template getProp<tensor>(p)[0][1] = 1.0;
vd.template getProp<tensor>(p)[0][2] = 1.0;
vd.template getProp<tensor>(p)[1][0] = 1.0;
vd.template getProp<tensor>(p)[1][1] = 1.0;
vd.template getProp<tensor>(p)[1][2] = 1.0;
vd.template getProp<tensor>(p)[2][0] = 1.0;
vd.template getProp<tensor>(p)[2][1] = 1.0;
vd.template getProp<tensor>(p)[2][2] = 1.0;
// increment the counter
cnt++;
// next particle
++it;
}
auto & v_cl = create_vcluster();
v_cl.sum(cnt);
v_cl.execute();
openfpm::vector<std::string> names({"scalar","vector","tensor"});
vd.setPropNames(names);
// save vtk format (vtk is always the default)
vd.write("particles");
// save in vtk binary format
vd.write("particles_bin",VTK_WRITER | FORMAT_BINARY);
// save in vtk format with time
vd.write("particles_with_time","time=1.234");
// save in vtk format with time
vd.write("particles_with_time_bin","time=1.234",VTK_WRITER | FORMAT_BINARY);
openfpm_finalize();
}