Commit 2bf1ebc9 authored by incardon's avatar incardon

Adding vortex in cell, small optimization on examples

parent 15e1675d
......@@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file.
### Added
- Introduced getDomainIterator for Cell-list
- Vortex in Cell example
- Example to show how to add sensors in SPH/particle based methods (see)
- Vortex in Cell example
- Interpolation functions (see Numerics/vortex_in_cell example)
- Gray-scott 3d example (see Grid/gray_scott_3d example)
- HDF5 Check point restart for vector_dist particles (see ...)
- Raw reader for grid (see ...)
- A way to specify names for proeprties and select properties to write
- Ghost put on grid
### Fixed
- Installation of PETSC in case with MUMPS try without MUMPS
......@@ -12,6 +21,8 @@ All notable changes to this project will be documented in this file.
- Bug in VTK writer binary in case of vectors
- Bug in VTK writer binary: long int are not supported removing output
## [0.8.0] 28 February 2016
### Added
......
include ../../example.mk
CC=mpic++
LDIR =
OBJ = main.o
%.o: %.cpp
$(CC) -O3 -c --std=c++11 -o $@ $< $(INCLUDE_PATH)
gray_scott: $(OBJ)
$(CC) -o $@ $^ $(CFLAGS) $(LIBS_PATH) $(LIBS)
all: gray_scott
run: all
mpirun -np 4 ./gray_scott
.PHONY: clean all run
clean:
rm -f *.o *~ core gray_scott
[pack]
files = main.cpp Makefile
#include "Grid/grid_dist_id.hpp"
#include "data_type/aggregate.hpp"
#include "timer.hpp"
/*!
* \page Grid_3_gs Grid 3 Gray Scott in 3D
*
* # Solving a gray scott-system in 3D # {#e3_gs_gray_scott}
*
* This example is just an extension of the 2D Gray scott example.
* Here we show how to solve a non-linear reaction diffusion system in 3D
*
* \see \ref Grid_2_solve_eq
*
* \snippet Grid/3_gray_scott/main.cpp constants
*
*/
//! \cond [constants] \endcond
constexpr int U = 0;
constexpr int V = 1;
constexpr int x = 0;
constexpr int y = 1;
constexpr int z = 2;
void init(grid_dist_id<3,double,aggregate<double,double> > & Old, grid_dist_id<3,double,aggregate<double,double> > & New, Box<3,double> & domain)
{
auto it = Old.getDomainIterator();
while (it.isNext())
{
// Get the local grid key
auto key = it.get();
// Old values U and V
Old.template get<U>(key) = 1.0;
Old.template get<V>(key) = 0.0;
// Old values U and V
New.template get<U>(key) = 0.0;
New.template get<V>(key) = 0.0;
++it;
}
grid_key_dx<3> start({(long int)std::floor(Old.size(0)*1.55f/domain.getHigh(0)),(long int)std::floor(Old.size(1)*1.55f/domain.getHigh(1)),(long int)std::floor(Old.size(1)*1.55f/domain.getHigh(2))});
grid_key_dx<3> stop ({(long int)std::ceil (Old.size(0)*1.85f/domain.getHigh(0)),(long int)std::ceil (Old.size(1)*1.85f/domain.getHigh(1)),(long int)std::floor(Old.size(1)*1.85f/domain.getHigh(1))});
auto it_init = Old.getSubDomainIterator(start,stop);
while (it_init.isNext())
{
auto key = it_init.get();
Old.template get<U>(key) = 0.5 + (((double)std::rand())/RAND_MAX -0.5)/10.0;
Old.template get<V>(key) = 0.25 + (((double)std::rand())/RAND_MAX -0.5)/20.0;
++it_init;
}
}
//! \cond [end fun] \endcond
int main(int argc, char* argv[])
{
openfpm_init(&argc,&argv);
// domain
Box<3,double> domain({0.0,0.0},{2.5,2.5,2.5});
// grid size
size_t sz[3] = {128,128,128};
// Define periodicity of the grid
periodicity<3> bc = {PERIODIC,PERIODIC,PERIODIC};
// Ghost in grid unit
Ghost<3,long int> g(1);
// deltaT
double deltaT = 1;
// Diffusion constant for specie U
double du = 2*1e-5;
// Diffusion constant for specie V
double dv = 1*1e-5;
// Number of timesteps
size_t timeSteps = 17000;
// K and F (Physical constant in the equation)
double K = 0.065;
double F = 0.034;
//! \cond [init lib] \endcond
/*!
* \page Grid_3_gs Grid 3 Gray Scott
*
* Here we create 2 distributed grid in 2D Old and New. In particular because we want that
* the second grid is distributed across processors in the same way we pass the decomposition
* of the Old grid to the New one in the constructor with **Old.getDecomposition()**. Doing this,
* we force the two grid to have the same decomposition.
*
* \snippet Grid/3_gray_scott/main.cpp init grid
*
*/
//! \cond [init grid] \endcond
grid_dist_id<3, double, aggregate<double,double>> Old(sz,domain,g,bc);
// New grid with the decomposition of the old grid
grid_dist_id<3, double, aggregate<double,double>> New(Old.getDecomposition(),sz,g);
// spacing of the grid on x and y
double spacing[3] = {Old.spacing(0),Old.spacing(1),Old.spacing(2)};
init(Old,New,domain);
// sync the ghost
size_t count = 0;
Old.template ghost_get<U,V>();
// because we assume that spacing[x] == spacing[y] we use formula 2
// and we calculate the prefactor of Eq 2
double uFactor = deltaT * du/(spacing[x]*spacing[x]);
double vFactor = deltaT * dv/(spacing[x]*spacing[x]);
for (size_t i = 0; i < timeSteps; ++i)
{
if (i % 300 == 0)
std::cout << "STEP: " << i << std::endl;
auto it = Old.getDomainIterator();
while (it.isNext())
{
auto key = it.get();
// update based on Eq 2
New.get<U>(key) = Old.get<U>(key) + uFactor * (
Old.get<U>(key.move(x,1)) +
Old.get<U>(key.move(x,-1)) +
Old.get<U>(key.move(y,1)) +
Old.get<U>(key.move(y,-1)) +
Old.get<U>(key.move(z,1)) +
Old.get<U>(key.move(z,-1)) -
6.0*Old.get<U>(key)) +
- deltaT * Old.get<U>(key) * Old.get<V>(key) * Old.get<V>(key) +
- deltaT * F * (Old.get<U>(key) - 1.0);
// update based on Eq 2
New.get<V>(key) = Old.get<V>(key) + vFactor * (
Old.get<V>(key.move(x,1)) +
Old.get<V>(key.move(x,-1)) +
Old.get<V>(key.move(y,1)) +
Old.get<V>(key.move(y,-1)) +
Old.get<V>(key.move(z,1)) +
Old.get<V>(key.move(z,-1)) -
6*Old.get<V>(key)) +
deltaT * Old.get<U>(key) * Old.get<V>(key) * Old.get<V>(key) +
- deltaT * (F+K) * Old.get<V>(key);
// Next point in the grid
++it;
}
// Here we copy New into the old grid in preparation of the new step
// It would be better to alternate, but using this we can show the usage
// of the function copy. To note that copy work only on two grid of the same
// decomposition. If you want to copy also the decomposition, or force to be
// exactly the same, use Old = New
Old.copy(New);
// After copy we synchronize again the ghost part U and V
Old.ghost_get<U,V>();
// Every 30 time step we output the configuration for
// visualization
if (i % 60 == 0)
{
Old.write("output",count,VTK_WRITER | FORMAT_BINARY);
count++;
}
}
//! \cond [time stepping] \endcond
/*!
* \page Grid_3_gs Grid 3 Gray Scott
*
* ## Finalize ##
*
* Deinitialize the library
*
* \snippet Grid/3_gray_scott/main.cpp finalize
*
*/
//! \cond [finalize] \endcond
openfpm_finalize();
//! \cond [finalize] \endcond
}
......@@ -465,7 +465,7 @@ int main(int argc, char* argv[])
//! \cond [copy write] \endcond
// Bring the solution to grid
// copy the solution to grid
fd.template copy<velocity,pressure>(x,{0,0},{sz[0]-1,sz[1]-1,sz[2]-1},g_dist);
g_dist.write("lid_driven_cavity_p_petsc");
......
......@@ -324,30 +324,19 @@ inline void DWab(Point<3,double> & dx, Point<3,double> & DW, double r, bool prin
{
const double qq=r/H;
if (qq < 1.0)
{
double qq2 = qq * qq;
double fac = (c1*qq + d1*qq2)/r;
double qq2 = qq * qq;
double fac1 = (c1*qq + d1*qq2)/r;
double b1 = (qq < 1.0)?1.0f:0.0f;
DW.get(0) = fac*dx.get(0);
DW.get(1) = fac*dx.get(1);
DW.get(2) = fac*dx.get(2);
}
else if (qq < 2.0)
{
double wqq = (2.0 - qq);
double fac = c2 * wqq * wqq / r;
double wqq = (2.0 - qq);
double fac2 = c2 * wqq * wqq / r;
double b2 = (qq >= 1.0 && qq < 2.0)?1.0f:0.0f;
DW.get(0) = fac * dx.get(0);
DW.get(1) = fac * dx.get(1);
DW.get(2) = fac * dx.get(2);
}
else
{
DW.get(0) = 0.0;
DW.get(1) = 0.0;
DW.get(2) = 0.0;
}
double factor = (b1*fac1 + b2*fac2);
DW.get(0) = factor * dx.get(0);
DW.get(1) = factor * dx.get(1);
DW.get(2) = factor * dx.get(2);
}
/*! \cond [kernel_sph_der] \endcond */
......
This diff is collapsed.
......@@ -981,7 +981,7 @@ public:
* \return the periodicity in direction i
*
*/
inline size_t periodicity(size_t i)
inline size_t periodicity(size_t i) const
{
return bc[i];
}
......@@ -1301,7 +1301,7 @@ public:
* \return The physical domain box
*
*/
const ::Box<dim,T> & getDomain()
const ::Box<dim,T> & getDomain() const
{
return domain;
}
......
/*
* SpaceDistributionWeight.hpp
*
* Created on: Apr 5, 2017
* Author: i-bird
*/
#ifndef SRC_DECOMPOSITION_DISTRIBUTION_SPACEDISTRIBUTIONWEIGHT_HPP_
#define SRC_DECOMPOSITION_DISTRIBUTION_SPACEDISTRIBUTIONWEIGHT_HPP_
#if 0
#include "util/mathutil.hpp"
#include "NN/CellList/CellDecomposer.hpp"
/*! \brief Class that distribute sub-sub-domains across processors using an hilbert curve
* to divide the space and balancing using the weight of each sub-sub-domain
*
* ### Initialize a Cartesian graph and decompose
* \snippet Distribution_unit_tests.hpp Initialize a Space Cartesian graph and decompose
*
*
*/
template<unsigned int dim, typename T>
class SpaceDistributionWeight
{
//! Vcluster
Vcluster & v_cl;
//! Structure that store the cartesian grid information
grid_sm<dim, void> gr;
//! rectangular domain to decompose
Box<dim, T> domain;
//! Global sub-sub-domain graph
Graph_CSR<nm_v, nm_e> gp;
//! Decomposition per processor
openfpm::vector<unsigned int> dec;
public:
/*! Constructor
*
* \param v_cl Vcluster to use as communication object in this class
*/
SpaceDistributionWeight(Vcluster & v_cl)
:v_cl(v_cl)
{
}
/*! Copy constructor
*
* \param pm Distribution to copy
*
*/
SpaceDistributionWeight(SpaceDistributionWeight<dim,T> && pm)
{
this->operator=(pm);
}
/*! \brief Create the Cartesian graph
*
* \param grid info
* \param dom domain
*/
void createCartGraph(grid_sm<dim, void> & grid, Box<dim, T> dom)
{
size_t bc[dim];
for (size_t i = 0 ; i < dim ; i++)
bc[i] = NON_PERIODIC;
// Set grid and domain
gr = grid;
domain = dom;
// Create a cartesian grid graph
CartesianGraphFactory<dim, Graph_CSR<nm_v, nm_e>> g_factory_part;
gp = g_factory_part.template construct<NO_EDGE, nm_v::id, T, dim - 1, 0>(gr.getSize(), domain, bc);
// Init to 0.0 axis z (to fix in graphFactory)
if (dim < 3)
{
for (size_t i = 0; i < gp.getNVertex(); i++)
gp.vertex(i).template get<nm_v::x>()[2] = 0.0;
}
for (size_t i = 0; i < gp.getNVertex(); i++)
gp.vertex(i).template get<nm_v::global_id>() = i;
}
/*! \brief Get the current graph (main)
*
*/
Graph_CSR<nm_v, nm_e> & getGraph()
{
return gp;
}
/*! \brief Create the decomposition
*
*/
void decompose()
{
// collect all the weight on the graph index + weight on master
openfpm::vector<id_w> id_w;
v_cl.SGather(id_w,0);
// Calculate the total weight
v_cl.sum();
v_cl.execute();
tot /= v_cl.getProcessingUnits();
// only master compute
if (v_cl.getProcessUnitID() == 0)
{
for (size_t i = 0 ; i < id_w.size() ; i++)
gp.template vertex_p<nm_v::computation>(id_w.get(i).id) = id_w.get(i).w;
// Get the maximum along dimensions and take the smallest n number
// such that 2^n < m. n it will be order of the hilbert curve
size_t max = 0;
for (size_t i = 0; i < dim ; i++)
{
if (max < gr.size(i))
max = gr.size(i);
}
// Get the order of the hilbert-curve
size_t order = openfpm::math::log2_64(max);
if (1ul << order < max)
order += 1;
size_t n = 1 << order;
// Create the CellDecomoser
CellDecomposer_sm<dim,T> cd_sm;
cd_sm.setDimensions(domain, gr.getSize(), 0);
// create the hilbert curve
//hilbert curve iterator
grid_key_dx_iterator_hilbert<dim> h_it(order);
T spacing[dim];
// Calculate the hilbert curve spacing
for (size_t i = 0 ; i < dim ; i++)
spacing[i] = (domain.getHigh(i) - domain.getLow(i)) / n;
// Small grid to detect already assigned sub-sub-domains
grid_cpu<dim,aggregate<long int>> g(gr.getSize());
g.setMemory();
// Reset the grid to -1
grid_key_dx_iterator<dim> it(gr);
while (it.isNext())
{
auto key = it.get();
g.template get<0>(key) = -1;
++it;
}
// Go along the hilbert-curve and divide the space
size_t proc_d = 0;
size_t ele_d = 0;
while (h_it.isNext())
{
auto key = h_it.get();
// Point p
Point<dim,T> p;
for (size_t i = 0 ; i < dim ; i++)
p.get(i) = key.get(i) * spacing[i] + spacing[i] / 2;
grid_key_dx<dim> sp = cd_sm.getCellGrid(p);
if (g.template get<0>(sp) == -1)
{
g.template get<0>(sp) = proc_d;
ele_d++;
if (ele_d >= avg)
proc_d++;
}
++h_it;
}
// Fill from the grid to the graph
// Reset the grid to -1
grid_key_dx_iterator<dim> it2(gr);
while (it2.isNext())
{
auto key = it2.get();
gp.template vertex_p<nm_v::proc_id>(gr.LinId(key)) = g.template get<0>(key);
id_w.get(g.template get<1>(key)) = g.template get<1>(key);
++it2;
}
}
// Broadcast the result to all the processors.
v_cl.Bcast(id_w);
v_cl.execute();
//
return;
}
/*! \brief Refine current decomposition
*
* Has no effect in this case
*
*/
void refine()
{
decompose();
}
/*! \brief Compute the unbalance of the processor compared to the optimal balance
*
* \return the unbalance from the optimal one 0.01 mean 1%
*/
float getUnbalance()
{
return gr.size() % v_cl.getProcessingUnits();
}
/*! \brief function that return the position of the vertex in the space
*
* \param id vertex id
* \param pos vector that will contain x, y, z
*
*/
void getSubSubDomainPosition(size_t id, T (&pos)[dim])
{
#ifdef SE_CLASS1
if (id >= gp.getNVertex())
std::cerr << __FILE__ << ":" << __LINE__ << "Such vertex doesn't exist (id = " << id << ", " << "total size = " << gp.getNVertex() << ")\n";
#endif
// Copy the geometrical informations inside the pos vector
pos[0] = gp.vertex(id).template get<nm_v::x>()[0];
pos[1] = gp.vertex(id).template get<nm_v::x>()[1];
if (dim == 3)
pos[2] = gp.vertex(id).template get<nm_v::x>()[2];
}
/*! \brief Function that set the weight of the vertex
*
* \param id vertex id
* \param weight to give to the vertex
*
*/
inline void setComputationCost(size_t id, size_t weight)
{
std::cout << __FILE__ << ":" << __LINE__ << " You are trying to set the computation cost on a fixed decomposition, this operation has no effect" << std::endl;
}
/*! \brief Checks if weights are used on the vertices
*
* \return true if weights are used in the decomposition
*/
bool weightsAreUsed()
{
return false;
}
/*! \brief function that get the weight of the vertex
*
* \param id vertex id
*
*/
size_t getSubSubDomainComputationCost(size_t id)
{
return 1.0;
}
/*! \brief Compute the processor load counting the total weights of its vertices
*
* \return the computational load of the processor graph
*/
size_t getProcessorLoad()
{
// Get the number of processing units
size_t Np = v_cl.getProcessingUnits();
// Calculate the best number of sub-domains for each
// processor
size_t N_tot = gr.size();
size_t N_best_each = N_tot / Np;
size_t N_rest = N_tot % Np;
if (v_cl.getProcessUnitID() < N_rest)
N_best_each += 1;
return N_best_each;
}
/*! \brief Set migration cost of the vertex id
*
* \param id of the vertex to update
* \param migration cost of the migration
*/
void setMigrationCost(size_t id, size_t migration)
{
}
/*! \brief Set communication cost of the edge id
*
* \param v_id Id of the source vertex of the edge
* \param e i child of the vertex
* \param communication Communication value
*/
void setCommunicationCost(size_t v_id, size_t e, size_t communication)
{
}
/*! \brief Returns total number of sub-sub-domains in the distribution graph
*
*/
size_t getNSubSubDomains()
{
return gp.getNVertex();
}
/*! \brief Returns total number of neighbors of the sub-sub-domain id
*
* \param id id of the sub-sub-domain
*/
size_t getNSubSubDomainNeighbors(size_t id)
{
return gp.getNChilds(id);
}
/*! \brief Print the current distribution and save it to VTK file
*
* \param file filename
*
*/
void write(const std::string & file)
{
VTKWriter<Graph_CSR<nm_v, nm_e>, VTK_GRAPH> gv2(gp);
gv2.write(std::to_string(v_cl.getProcessUnitID()) + "_" + file + ".vtk");
}
const SpaceDistribution<dim,T> & operator=(const SpaceDistribution<dim,T> & dist)
{
gr = dist.gr;
domain = dist.domain;
gp = dist.gp;
return *this;
}
const SpaceDistribution<dim,T> & operator=(SpaceDistribution<dim,T> && dist)
{
v_cl = dist.v_cl;
gr = dist.gr;
domain = dist.domain;
gp.swap(dist.gp);
return *this;
}
/*! \brief It return the decomposition id
*
* It just return 0
*
* \return 0