Vector 4 complex properties
This example show how we can use complex properties in a vector
Initialization and vector creation
We first initialize the library and define useful constants
- See Also
- Initialization
openfpm_init(&argc,&argv);
size_t bc[2]={PERIODIC,PERIODIC};
constexpr int scalar = 0;
constexpr int vector = 1;
constexpr int point = 2;
constexpr int list = 3;
constexpr int listA = 4;
constexpr int listlist = 5;
We also define a custom structure
struct A
{
float p1;
int p2;
A() {};
A(float p1, int p2)
:p1(p1),p2(p2)
{}
};
After we initialize the library we can create a vector with complex properties with the following line
float[3],
Point<3,double>,
openfpm::vector<float>,
openfpm::vector<A>,
vd(4096,domain,bc,g);
In this this particular case every particle carry a scalar, a vector in form of float[3], a Point, a list in form of vector of float and a list of custom structures, and a vector of vector. In general particles can have properties of arbitrary complexity.
- Warning
- For arbitrary complexity mean that we can use any openfpm data structure with and arbitrary nested complexity. For example a openfpm::vector<aggregate<grid_cpu<openfpm::vector<aggregate<double,double[3]>>>,openfpm::vector<float>> is valid
particle
*
vector
/ \
/ \
grid vector<float>
/\
/ \
double double[3]
*
Our custom data-structure A is defined below. Note that this data-structure does not have pointers
struct A
{
float p1;
int p2;
A() {};
A(float p1, int p2)
:p1(p1),p2(p2)
{}
};
- Warning
- custom data structure are allowed only if they does not have pointer. In case they have pointer we have to define how to serialize our data-structure
- See Also
- Vector 4 property serialization
Assign values to properties
Assign values to properties does not changes, from the simple case. Consider now that each particle has a list, so when we can get the property listA for particle p and resize such list with vd.getProp<listA>(p).resize(...). We can add new elements at the end with vd.getProp<listA>(p).add(...) and get some element of this list with vd.getProp<listA>(p).get(i). More in general vd.getProp<listA>(p) return a reference to the openfpm::vector contained by the particle.
while (it.isNext())
{
vd.
getPos(p)[0] = (float)rand() / RAND_MAX;
vd.
getPos(p)[1] = (float)rand() / RAND_MAX;
size_t n_cp = (float)10.0 * rand()/RAND_MAX;
for (size_t i = 0 ; i < n_cp ; i++)
{
vd.
getProp<listA>(p).
get(i) = A(i+10.0,i+20.0);
}
vd.
getProp<listlist>(p).
get(0).resize(2);
vd.
getProp<listlist>(p).
get(1).resize(2);
vd.
getProp<listlist>(p).
get(0).get(0) = 1.0;
vd.
getProp<listlist>(p).
get(0).get(1) = 2.0;
vd.
getProp<listlist>(p).
get(1).get(0) = 3.0;
vd.
getProp<listlist>(p).
get(1).get(1) = 4.0;
++it;
}
Mapping and ghost_get
Particles are redistributed across processors all properties are communicated but instead of using map we use map_list that we can use to select properties. A lot of time complex properties can be recomputed and communicate them is not a good idea. The same concept also apply for ghost_get. In general we choose which properties to communicate
- See Also
- Mapping particles
-
Ghost
vd.
map_list<scalar,vector,point,list,listA,listlist>();
vd.
ghost_get<scalar,vector,point,listA,listlist>();
Output and VTK visualization
Vector with complex properties can be still be visualized, because unknown properties are automatically excluded
- See Also
- Visualization, write VTK files
Print 4 particles in the ghost area
Here we print that the first 4 particles to show that the list of A and the list of list are filled and the ghosts contain the correct information
{
{
std::cout << "List of A" << std::endl;
for (
size_t i = 0 ; i < vd.
getProp<listA>(fg).size() ; i++)
std::cout <<
"Element: " << i <<
" p1=" << vd.
getProp<listA>(fg).get(i).p1 <<
" p2=" << vd.
getProp<listA>(fg).
get(i).p2 << std::endl;
std::cout << "List of list" << std::endl;
for (
size_t i = 0 ; i < vd.
getProp<listlist>(fg).size() ; i++)
{
for (
size_t j = 0 ; j < vd.
getProp<listlist>(fg).
get(i).size() ; j++)
std::cout <<
"Element: " << i <<
" " << j <<
" " << vd.
getProp<listlist>(fg).get(i).get(j) << std::endl;
}
}
}
Finalize
At the very end of the program we have always to de-initialize the library
Full code
#include "Vector/vector_dist.hpp"
int main(int argc, char* argv[])
{
openfpm_init(&argc,&argv);
size_t bc[2]={PERIODIC,PERIODIC};
constexpr int scalar = 0;
constexpr int vector = 1;
constexpr int point = 2;
constexpr int list = 3;
constexpr int listA = 4;
constexpr int listlist = 5;
struct A
{
float p1;
int p2;
A() {};
A(float p1, int p2)
:p1(p1),p2(p2)
{}
};
float[3],
Point<3,double>,
openfpm::vector<float>,
openfpm::vector<A>,
vd(4096,domain,bc,g);
while (it.isNext())
{
vd.
getPos(p)[0] = (float)rand() / RAND_MAX;
vd.
getPos(p)[1] = (float)rand() / RAND_MAX;
size_t n_cp = (float)10.0 * rand()/RAND_MAX;
for (size_t i = 0 ; i < n_cp ; i++)
{
vd.
getProp<listA>(p).
get(i) = A(i+10.0,i+20.0);
}
vd.
getProp<listlist>(p).
get(0).resize(2);
vd.
getProp<listlist>(p).
get(1).resize(2);
vd.
getProp<listlist>(p).
get(0).get(0) = 1.0;
vd.
getProp<listlist>(p).
get(0).get(1) = 2.0;
vd.
getProp<listlist>(p).
get(1).get(0) = 3.0;
vd.
getProp<listlist>(p).
get(1).get(1) = 4.0;
++it;
}
vd.
map_list<scalar,vector,point,list,listA,listlist>();
vd.
ghost_get<scalar,vector,point,listA,listlist>();
{
{
std::cout << "List of A" << std::endl;
for (
size_t i = 0 ; i < vd.
getProp<listA>(fg).size() ; i++)
std::cout <<
"Element: " << i <<
" p1=" << vd.
getProp<listA>(fg).get(i).p1 <<
" p2=" << vd.
getProp<listA>(fg).
get(i).p2 << std::endl;
std::cout << "List of list" << std::endl;
for (
size_t i = 0 ; i < vd.
getProp<listlist>(fg).size() ; i++)
{
for (
size_t j = 0 ; j < vd.
getProp<listlist>(fg).
get(i).size() ; j++)
std::cout <<
"Element: " << i <<
" " << j <<
" " << vd.
getProp<listlist>(fg).get(i).get(j) << std::endl;
}
}
}
openfpm_finalize();
}