Beispiel #1
0
double ic_energy(double x, double y, scalar& dx, scalar& dy)
{
  return calc_energy(RHO_EXT, RHO_EXT*V1_EXT, RHO_EXT*V2_EXT, P_EXT);
}
Beispiel #2
0
int main(int argc, char* argv[])
{
	/*!
	 * \page Vector_5_md_vl_sym_crs Vector 5 molecular dynamic with symmetric Verlet list crossing scheme
	 *
	 * ## Simulation ## {#md_e5_sym_sim_crs}
	 *
	 * The simulation is equal to the simulation explained in the example molecular dynamic
	 *
	 * \see \ref md_e5_sym
	 *
	 * The difference is that we create a symmetric Verlet-list for crossing scheme instead of a normal one
	 * \snippet Vector/5_molecular_dynamic_sym_crs/main.cpp sim verlet
	 *
	 * The rest of the code remain unchanged
	 *
	 * \snippet Vector/5_molecular_dynamic_sym_crs/main.cpp simulation
	 *
	 */

	//! \cond [simulation] \endcond

	double dt = 0.00025;
	double sigma = 0.1;
	double r_cut = 3.0*sigma;
	double r_gskin = 1.3*r_cut;
	double sigma12 = pow(sigma,12);
	double sigma6 = pow(sigma,6);

	openfpm::vector<double> x;
	openfpm::vector<openfpm::vector<double>> y;

	openfpm_init(&argc,&argv);
	Vcluster & v_cl = create_vcluster();

	// we will use it do place particles on a 10x10x10 Grid like
	size_t sz[3] = {10,10,10};

	// domain
	Box<3,float> box({0.0,0.0,0.0},{1.0,1.0,1.0});

	// Boundary conditions
	size_t bc[3]={PERIODIC,PERIODIC,PERIODIC};

	// ghost, big enough to contain the interaction radius
	Ghost<3,float> ghost(r_gskin);
	ghost.setLow(0,0.0);
	ghost.setLow(1,0.0);
	ghost.setLow(2,0.0);

	vector_dist<3,double, aggregate<double[3],double[3]> > vd(0,box,bc,ghost,BIND_DEC_TO_GHOST);

	size_t k = 0;
	size_t start = vd.accum();

	auto it = vd.getGridIterator(sz);

	while (it.isNext())
	{
		vd.add();

		auto key = it.get();

		vd.getLastPos()[0] = key.get(0) * it.getSpacing(0);
		vd.getLastPos()[1] = key.get(1) * it.getSpacing(1);
		vd.getLastPos()[2] = key.get(2) * it.getSpacing(2);

		vd.template getLastProp<velocity>()[0] = 0.0;
		vd.template getLastProp<velocity>()[1] = 0.0;
		vd.template getLastProp<velocity>()[2] = 0.0;

		vd.template getLastProp<force>()[0] = 0.0;
		vd.template getLastProp<force>()[1] = 0.0;
		vd.template getLastProp<force>()[2] = 0.0;

		k++;
		++it;
	}

	vd.map();
	vd.ghost_get<>();

	timer tsim;
	tsim.start();

	//! \cond [sim verlet] \endcond

	// Get the Cell list structure
	auto NN = vd.getVerletCrs(r_gskin);;

	//! \cond [sim verlet] \endcond

	// calculate forces
	calc_forces(vd,NN,sigma12,sigma6,r_cut);
	unsigned long int f = 0;

	int cnt = 0;
	double max_disp = 0.0;

	// MD time stepping
	for (size_t i = 0; i < 10000 ; i++)
	{
		// Get the iterator
		auto it3 = vd.getDomainIterator();

		double max_displ = 0.0;

		// integrate velicity and space based on the calculated forces (Step1)
		while (it3.isNext())
		{
			auto p = it3.get();

			// here we calculate v(tn + 0.5)
			vd.template getProp<velocity>(p)[0] += 0.5*dt*vd.template getProp<force>(p)[0];
			vd.template getProp<velocity>(p)[1] += 0.5*dt*vd.template getProp<force>(p)[1];
			vd.template getProp<velocity>(p)[2] += 0.5*dt*vd.template getProp<force>(p)[2];

			Point<3,double> disp({vd.template getProp<velocity>(p)[0]*dt,vd.template getProp<velocity>(p)[1]*dt,vd.template getProp<velocity>(p)[2]*dt});

			// here we calculate x(tn + 1)
			vd.getPos(p)[0] += disp.get(0);
			vd.getPos(p)[1] += disp.get(1);
			vd.getPos(p)[2] += disp.get(2);

			if (disp.norm() > max_displ)
				max_displ = disp.norm();

			++it3;
		}

		if (max_disp < max_displ)
			max_disp = max_displ;

		// Because we moved the particles in space we have to map them and re-sync the ghost
		if (cnt % 10 == 0)
		{
			vd.map();
			vd.template ghost_get<>();
			// Get the Cell list structure
			vd.updateVerlet(NN,r_gskin,VL_CRS_SYMMETRIC);
		}
		else
		{
			vd.template ghost_get<>(SKIP_LABELLING);
		}

		cnt++;

		// calculate forces or a(tn + 1) Step 2
		calc_forces(vd,NN,sigma12,sigma6,r_cut);

		// Integrate the velocity Step 3
		auto it4 = vd.getDomainIterator();

		while (it4.isNext())
		{
			auto p = it4.get();

			// here we calculate v(tn + 1)
			vd.template getProp<velocity>(p)[0] += 0.5*dt*vd.template getProp<force>(p)[0];
			vd.template getProp<velocity>(p)[1] += 0.5*dt*vd.template getProp<force>(p)[1];
			vd.template getProp<velocity>(p)[2] += 0.5*dt*vd.template getProp<force>(p)[2];

			++it4;
		}

		// After every iteration collect some statistic about the confoguration
		if (i % 100 == 0)
		{
			// We write the particle position for visualization (Without ghost)
			vd.deleteGhost();
			vd.write("particles_",f);

			// we resync the ghost
			vd.ghost_get<>();


			// We calculate the energy
			double energy = calc_energy(vd,NN,sigma12,sigma6,r_cut);
			auto & vcl = create_vcluster();
			vcl.sum(energy);
			vcl.max(max_disp);
			vcl.execute();

			// we save the energy calculated at time step i c contain the time-step y contain the energy
			x.add(i);
			y.add({energy});

			// We also print on terminal the value of the energy
			// only one processor (master) write on terminal
			if (vcl.getProcessUnitID() == 0)
				std::cout << "Energy: " << energy << "   " << max_disp << "   " << std::endl;

			max_disp = 0.0;

			f++;
		}
	}

	tsim.stop();
	std::cout << "Time: " << tsim.getwct()  << std::endl;

	//! \cond [simulation] \endcond

	// Google charts options, it store the options to draw the X Y graph
	GCoptions options;

	// Title of the graph
	options.title = std::string("Energy with time");

	// Y axis name
	options.yAxis = std::string("Energy");

	// X axis name
	options.xAxis = std::string("iteration");

	// width of the line
	options.lineWidth = 1.0;

	// Object that draw the X Y graph
	GoogleChart cg;

	// Add the graph
	// The graph that it produce is in svg format that can be opened on browser
	cg.AddLinesGraph(x,y,options);

	// Write into html format
	cg.write("gc_plot2_out.html");

	//! \cond [google chart] \endcond

	/*!
	 * \page Vector_5_md_vl_sym_crs Vector 5 molecular dynamic with symmetric Verlet list crossing scheme
	 *
	 * ## Finalize ## {#finalize_v_e5_md_sym_crs}
	 *
	 *  At the very end of the program we have always to de-initialize the library
	 *
	 * \snippet Vector/5_molecular_dynamic_sym_crs/main.cpp finalize
	 *
	 */

	//! \cond [finalize] \endcond

	openfpm_finalize();

	//! \cond [finalize] \endcond

	/*!
	 * \page Vector_5_md_vl_sym_crs Vector 5 molecular dynamic with symmetric Verlet list crossing scheme
	 *
	 * ## Full code ## {#full_code_v_e5_md_sym_crs}
	 *
	 * \include Vector/5_molecular_dynamic_sym_crs/main.cpp
	 *
	 */
}
Beispiel #3
0
// Equation parameters.
const double P_EXT = 2.5;         // Exterior pressure (dimensionless).
const double RHO_EXT = 1.0;       // Inlet density (dimensionless).   
const double V1_EXT = 1.25;       // Inlet x-velocity (dimensionless).
const double V2_EXT = 0.0;        // Inlet y-velocity (dimensionless).
const double KAPPA = 1.4;         // Kappa.
// Numerical flux.
// For numerical fluxes, please see hermes2d/src/numerical_flux.h
NumericalFlux num_flux(KAPPA);

// Utility functions for the Euler equations.
#include "../euler-util.cpp"

// Calculated exterior energy.
double ENERGY_EXT = calc_energy(RHO_EXT, RHO_EXT*V1_EXT, RHO_EXT*V2_EXT, P_EXT);

// Diffusion parameter (diffusivity).
const double EPSILON = 0.01;

// Boundary (initial) value of the concentration.
const double CONCENTRATION_EXT = 1.0;

// Boundary markers.
const int BDY_INLET = 1;
const int BDY_OUTLET = 2;
const int BDY_SOLID_WALL_BOTTOM = 3;
const int BDY_SOLID_WALL_TOP = 4;

// Constant initial state (matching the supersonic inlet state).
double ic_density(double x, double y, scalar& dx, scalar& dy)
void
FoldingEngine<SEQ>::
stochastic_fold(const std::string& name, const SEQ& seq, uint num_samples, 
                const std::vector<float>& gamma, uint max_clusters, std::ostream& out, 
                const std::string& p_outname, float th)
{
  std::vector<BPvecPtr> bpv;
  stochastic_fold(seq, num_samples, bpv);
  
  if (max_clusters>=2)
  {
    // calculate the distance matrix
    typedef boost::multi_array<double, 2> DMatrix;
    DMatrix dmatrix(boost::extents[bpv.size()][bpv.size()]);
    for (uint i=0; i!=bpv.size(); ++i)
      for (uint j=i; j!=bpv.size(); ++j)
        dmatrix[i][j]=dmatrix[j][i]=hamming_distance(*bpv[i], *bpv[j]);

    // hierarchical clustering by DIANA
    HCLUST::Diana<DMatrix> diana(dmatrix);
    diana.build(max_clusters);
    uint opt_n = diana.optimal_size();
    std::vector<uint> res;
    std::vector<uint> num;
    diana.get_clusters(opt_n, res, num);

    // sort by size of clusters
    std::vector<uint> s(num.size(), 0);
    std::vector<uint> idx(num.size());
    for (uint i=0; i!=num.size(); ++i)
    {
      idx[i]=i;
      if (i!=0) s[i]=s[i-1]+num[i-1];
    }
    std::sort(idx.begin(), idx.end(), cmp_by_size(num));

    // centroid estimation for each cluster
    for (uint i=0; i!=idx.size(); ++i)
    {
      std::vector<BPvecPtr> v(num[idx[i]]);
      for (uint j=0; j!=v.size(); ++j) v[j] = bpv[res[s[idx[i]]+j]];
      CountBP< std::vector<BPvecPtr> > count_bp(v, seq.size());
      inside_traverse(0, seq.size()-1, count_bp);
      char buf[100];
      sprintf(buf, "%3.1f%%", static_cast<float>(num[idx[i]])/bpv.size()*100);
      out << ">" << name << " (" << i+1 << " of " << num.size() << ", size="
          << buf << ")" << std::endl
          << get_seq(seq) << std::endl;

      std::vector<float>::const_iterator g;
      for (g=gamma.begin(); g!=gamma.end(); ++g) {
        std::string paren(seq.size(), '.');
        Centroid::execute(count_bp.table, paren, *g);
        out << paren << " (g=" << *g << ",th=" << (1.0/(1.0+*g));
#ifdef HAVE_LIBRNA
        out << ",e=" << calc_energy(seq, paren);
#endif
        out << ")" << std::endl;
      }

      if (!p_outname.empty())
      {
        char buf[1024];
        snprintf(buf, sizeof(buf), "%s-%d", p_outname.c_str(), i);
        count_bp.table.save(buf, get_seq(seq), th);
      }
    }
  }
  else
  {
    CountBP< std::vector<BPvecPtr> > count_bp(bpv, seq.size());
    inside_traverse(0, seq.size()-1, count_bp);
    std::string paren(seq.size(), '.');
    std::vector<float>::const_iterator g;
    out << ">" << name << std::endl
        << get_seq(seq) << std::endl;
    for (g=gamma.begin(); g!=gamma.end(); ++g)
    {
      std::fill(paren.begin(), paren.end(), '.');
      Centroid::execute(count_bp.table, paren, *g);
      out << paren << " (g=" << *g << ",th=" << (1.0/(1.0+*g));
#ifdef HAVE_LIBRNA
      out << ",e=" << calc_energy(seq, paren);
#endif
      out << ")" << std::endl;
    }

    if (!p_outname.empty())
    {
      char buf[1024];
      snprintf(buf, sizeof(buf), "%s-1", p_outname.c_str());
      count_bp.table.save(buf, get_seq(seq), th);
    }
  }
}
static int av_is_beat(struct bd_instance_t* sh_, double* samples, int len,
                      double thr_)
{
  struct bd_avinstance_t* sh = (struct bd_avinstance_t*) sh_;
  int i;
  int raw_max = min(sh->raw_size - sh->raw_len, len);
  int block_size = sh->block_size;
  int num_blocks;
  double* buf = sh->hist_buf;
  int diff;
  double energy = 0;
  double var = 0;
  double local_energy;
  double thr;

  //  printf("len = %i\n", len);
  //  printf("raw_len = %i\n", sh->raw_len);
  //  printf("raw_max = %i\n", raw_max);
  memcpy(sh->raw_buf + sh->raw_len, samples, raw_max*sizeof(double));
  sh->raw_len += raw_max;

  num_blocks = min(sh->hist_buf_size, sh->raw_len / block_size);

  diff = max(0, (sh->buf_len + num_blocks) - sh->hist_buf_size);
  diff = min(diff, sh->buf_len);

  memmove(buf, buf+diff, (sh->buf_len-diff) * sizeof(double));
  sh->buf_len -= diff;
  for (i = 0; i < num_blocks; ++i) {
    double e = calc_energy(sh->raw_buf + i*block_size, 
                           sh->raw_buf + (i+1)*block_size) / block_size;

    buf[sh->buf_len + i] = e;
  }
  sh->raw_len -= num_blocks*block_size;
  sh->buf_len += num_blocks;

  memmove(sh->raw_buf, sh->raw_buf+num_blocks*block_size, 
          sh->raw_len * sizeof(double));
  //  printf("num_blocks: %i\n", num_blocks);
  //  printf("buffer length: %i\n", sh->buf_len);

  if (sh->buf_len < 0.5*sh->hist_buf_size)
    return 0;

  for (i = 0; i < sh->buf_len; ++i)
    {
      energy += buf[i];
    }
  energy /= ((double) sh->buf_len);
  local_energy = buf[sh->buf_len - 1];

  for (i = 0; i < sh->buf_len; ++i)
    {
      double v = (buf[i] - energy);
      var += v*v;
    }
  var /= ((double) sh->buf_len);

  thr = thr_ + 1.5 - 20*var;
  if (thr < 1)
    thr = 1;
  /*printf("var  = %f\n", var);
   printf("thr  = %f\n", thr);
   printf("ding = %f\n", local_energy / energy);*/

  if (local_energy / energy > thr)
    return 1;
  else
    return 0;
}
int main(int argc, char* argv[])
{
    /*!
     *
     * \page Vector_4_comp_reo Vector 4 computational reordering and cache friendliness
     *
     * ## Initialization ##
     *
     * The initialization is the same as the molecular dynamic example. The differences are in the
     * parameters. We will use a bigger system, with more particles. The delta time for integration
     * is chosen in order to keep the system stable.
     *
     * \see \ref e3_md_init
     *
     * \snippet Vector/4_reorder/main_comp_ord.cpp vect create
     *
     */

    //! \cond [vect create] \endcond

    double dt = 0.0001;
    float r_cut = 0.03;
    double sigma = r_cut/3.0;
    double sigma12 = pow(sigma,12);
    double sigma6 = pow(sigma,6);

    openfpm::vector<double> x;
    openfpm::vector<openfpm::vector<double>> y;

    openfpm_init(&argc,&argv);
    Vcluster & v_cl = create_vcluster();

    // we will use it do place particles on a 40x40x40 Grid like
    size_t sz[3] = {40,40,40};

    // domain
    Box<3,float> box({0.0,0.0,0.0}, {1.0,1.0,1.0});

    // Boundary conditions
    size_t bc[3]= {PERIODIC,PERIODIC,PERIODIC};

    // ghost, big enough to contain the interaction radius
    Ghost<3,float> ghost(r_cut);

    vector_dist<3,double, aggregate<double[3],double[3]> > vd(0,box,bc,ghost);

    //! \cond [vect create] \endcond

    /*!
     * \page Vector_4_comp_reo Vector 4 computational reordering and cache friendliness
     *
     * ## Particles on a grid like position ##
     *
     * Here we place the particles on a grid like manner
     *
     * \see \ref e3_md_gl
     *
     * \snippet Vector/4_reorder/main_comp_ord.cpp vect grid
     *
     */

    //! \cond [vect grid] \endcond

    auto it = vd.getGridIterator(sz);

    while (it.isNext())
    {
        vd.add();

        auto key = it.get();

        vd.getLastPos()[0] = key.get(0) * it.getSpacing(0);
        vd.getLastPos()[1] = key.get(1) * it.getSpacing(1);
        vd.getLastPos()[2] = key.get(2) * it.getSpacing(2);

        vd.template getLastProp<velocity>()[0] = 0.0;
        vd.template getLastProp<velocity>()[1] = 0.0;
        vd.template getLastProp<velocity>()[2] = 0.0;

        vd.template getLastProp<force>()[0] = 0.0;
        vd.template getLastProp<force>()[1] = 0.0;
        vd.template getLastProp<force>()[2] = 0.0;

        ++it;
    }

    //! \cond [vect grid] \endcond

    /*!
     *
     * \page Vector_4_comp_reo Vector 4 computational reordering and cache friendliness
     *
     * ## Molecular dynamic steps ##
     *
     * Here we do 30000 MD steps using verlet integrator the cycle is the same as the
     * molecular dynamic example. with the following changes.
     *
     * ### Cell lists ###
     *
     * Instead of getting the normal cell list we get an hilbert curve cell-list. Such cell list has a
     * function called **getIterator** used inside the function **calc_forces** and **calc_energy**
     * that iterate across all the particles but in a smart-way. In practice
     * given an r-cut a cell-list is constructed with the provided spacing. Suppose to have a cell-list
     * \f$ m \times n \f$, an hilbert curve \f$ 2^k \times 2^k \f$ is contructed with \f$ k = ceil(log_2(max(m,n))) \f$.
     * Cell-lists are explored according to this Hilbert curve, If a cell does not exist is simply skipped.
     *
     *
     * \verbatim
    +------+------+------+------+     Example of Hilbert curve running on a 3 x 3 Cell
    |      |      |      |      |     An hilbert curve of k = ceil(log_2(3)) = 4
    |  X+---->X   |  X +---> X  |
    |  ^   |  +   |  ^   |   +  |
    ***|******|******|****---|--+      *******
    *  +   |  v   |  +   *   v  |      *     *
    *  7   |  8+---->9   *   X  |      *     *  = Domain
    *  ^   |      |      *   +  |      *     *
    *--|-----------------*---|--+      *******
    *  +   |      |      *   v  |
    *  4<----+5   |   6<---+ X  |
    *      |  ^   |   +  *      |
    *---------|-------|--*------+
    *      |  +   |   v  *      |
    *  1+---->2   |   3+---> X  |
    *      |      |      *      |
    **********************------+

     this mean that we will iterate the following cells

     1,2,5,4,7,8,9,6,3

     Suppose now that the particles are ordered like described




    Particles   id      Cell
                 0         1
                 1         7
                 2         8
    			 3		   1
    			 4		   9
    			 5		   9
    			 6		   6
    			 7		   7
    			 8		   3
    			 9		   2
    			10		   4
    			11		   3


    The iterator of the cell-list will explore the particles in the following way

    Cell     1  2 5 4  7  8  9  6 3
       	   |   | | | |   | |   | | |
        	0,3,9,,10,1,7,2,4,5,6,8


     * \endverbatim
     *
     * We cannot explain here what is a cache, but in practice is a fast memory in the CPU able
     * to store chunks of memory. The cache in general is much smaller than RAM, but the big advantage
     * is its speed. Retrieve data from the cache is much faster than RAM. Unfortunately the factors
     *  that determine what is on cache and what is not are multiples: Type of cache, algorithm ... .
     * Qualitatively all caches will tend to load chunks of data that you read multiple-time, or chunks
     *  of data that probably you will read based on pattern analysis. A small example is a linear memory copy where
     * you read consecutively memory and you write on consecutive memory.
     * Modern CPU recognize such pattern and decide to load on cache the consecutive memory before
     *  you actually require it.
     *
     *
     * Iterating the vector in the way described above has the advantage that when we do computation on particles
     * and its neighborhood with the sequence described above it will happen that:
     *
     * * If to process a particle A we read some neighborhood particles to process the next particle A+1
     *   we will probably read most of the previous particles.
     *
     *
     * In order to show in practice what happen we first show the graph when we do not reorder
     *
     * \htmlinclude Vector/4_reorder/no_reorder.html
     *
     * The measure has oscillation but we see an asymptotic behavior from 0.04 in the initial condition to
     * 0.124 . Below we show what happen when we use iterator from the Cell list hilbert
     *
     * \htmlinclude Vector/4_reorder/comp_reord.html
     *
     * In cases where particles does not move or move very slowly consider to use data-reordering, because it can
     * give **8-10% speedup**
     *
     * \see \ref e4_reo
     *
     *  ## Timers ##
     *
     *  In order to collect the time of the force calculation we insert two timers around the function
     *  calc_force. The overall performance is instead calculated with another timer around the time stepping
     *
     * \snippet Vector/4_reorder/main_data_ord.cpp timer start
     * \snippet Vector/4_reorder/main_data_ord.cpp timer stop
     *
     * \see \ref e3_md_vi
     *
     *
     */

    //! \cond [md steps] \endcond

    // Get the Cell list structure
    auto NN = vd.getCellList_hilb(r_cut);

    // calculate forces
    calc_forces(vd,NN,sigma12,sigma6);
    unsigned long int f = 0;

    timer time2;
    time2.start();

#ifndef TEST_RUN
    size_t Nstep = 30000;
#else
    size_t Nstep = 300;
#endif

    // MD time stepping
    for (size_t i = 0; i < Nstep ; i++)
    {
        // Get the iterator
        auto it3 = vd.getDomainIterator();

        // integrate velicity and space based on the calculated forces (Step1)
        while (it3.isNext())
        {
            auto p = it3.get();

            // here we calculate v(tn + 0.5)
            vd.template getProp<velocity>(p)[0] += 0.5*dt*vd.template getProp<force>(p)[0];
            vd.template getProp<velocity>(p)[1] += 0.5*dt*vd.template getProp<force>(p)[1];
            vd.template getProp<velocity>(p)[2] += 0.5*dt*vd.template getProp<force>(p)[2];

            // here we calculate x(tn + 1)
            vd.getPos(p)[0] += vd.template getProp<velocity>(p)[0]*dt;
            vd.getPos(p)[1] += vd.template getProp<velocity>(p)[1]*dt;
            vd.getPos(p)[2] += vd.template getProp<velocity>(p)[2]*dt;

            ++it3;
        }

        // Because we mooved the particles in space we have to map them and re-sync the ghost
        vd.map();
        vd.template ghost_get<>();

        timer time;
        if (i % 10 == 0)
            time.start();

        // calculate forces or a(tn + 1) Step 2
        calc_forces(vd,NN,sigma12,sigma6);

        if (i % 10 == 0)
        {
            time.stop();
            x.add(i);
            y.add({time.getwct()});
        }

        // Integrate the velocity Step 3
        auto it4 = vd.getDomainIterator();

        while (it4.isNext())
        {
            auto p = it4.get();

            // here we calculate v(tn + 1)
            vd.template getProp<velocity>(p)[0] += 0.5*dt*vd.template getProp<force>(p)[0];
            vd.template getProp<velocity>(p)[1] += 0.5*dt*vd.template getProp<force>(p)[1];
            vd.template getProp<velocity>(p)[2] += 0.5*dt*vd.template getProp<force>(p)[2];

            ++it4;
        }

        // After every iteration collect some statistic about the confoguration
        if (i % 100 == 0)
        {
            // We write the particle position for visualization (Without ghost)
            vd.deleteGhost();
            vd.write("particles_",f);

            // we resync the ghost
            vd.ghost_get<>();

            // We calculate the energy
            double energy = calc_energy(vd,NN,sigma12,sigma6);
            auto & vcl = create_vcluster();
            vcl.sum(energy);
            vcl.execute();

            // We also print on terminal the value of the energy
            // only one processor (master) write on terminal
            if (vcl.getProcessUnitID() == 0)
                std::cout << std::endl << "Energy: " << energy << std::endl;

            f++;
        }
    }

    time2.stop();
    std::cout << "Performance: " << time2.getwct() << std::endl;

    //! \cond [md steps] \endcond

    /*!
     * \page Vector_4_comp_reo Vector 4 computational reordering and cache friendliness
     *
     * ## Plotting graphs ##
     *
     * After we terminate the MD steps our vector x contains at which iteration we benchmark the force
     * calculation time, while y contains the measured time at that time-step. We can produce a graph X Y
     *
     * \note The graph produced is an svg graph that can be view with a browser. From the browser we can
     *       also easily save the graph into pure svg format
     *
     * \snippet Vector/4_reorder/main_comp_ord.cpp google chart
     *
     */

    //! \cond [google chart] \endcond

    // Google charts options, it store the options to draw the X Y graph
    GCoptions options;

    // Title of the graph
    options.title = std::string("Force calculation time");

    // Y axis name
    options.yAxis = std::string("Time");

    // X axis name
    options.xAxis = std::string("iteration");

    // width of the line
    options.lineWidth = 1.0;

    // Object that draw the X Y graph
    GoogleChart cg;

    // Add the graph
    // The graph that it produce is in svg format that can be opened on browser
    cg.AddLinesGraph(x,y,options);

    // Write into html format
    cg.write("gc_plot2_out.html");

    //! \cond [google chart] \endcond

    /*!
     *
     * \page Vector_4_comp_reo Vector 4 computational reordering and cache friendliness
     *
     * ## Finalize ##
     *
     *  At the very end of the program we have always to de-initialize the library
     *
     * \snippet Vector/4_reorder/main_comp_ord.cpp finalize
     *
     */

    //! \cond [finalize] \endcond

    openfpm_finalize();

    //! \cond [finalize] \endcond

    /*!
     *
     * \page Vector_4_comp_reo Vector 4 computational reordering and cache friendliness
     *
     * # Full code #
     *
     * \include Vector/4_reorder/main_comp_ord.cpp
     *
     */
}
int main(int argc, char **argv)
{

	int i, j;
	int atoms;
	float **atom_positions;
	float *energies;
	float maxenergy;

	/* 
	 * Initialisierung der Atome 
	 */

	/* Vereinfachung: normalerweise von Benutzer z.B. durch Eingabedatei übergebbar */

	atoms = 10;

	/* 
	 * Allokierung des nötigen Speichers 
	 */

	/* Allokierung des 2-Dimensionalen atom_positions Arrays */

	/* Allokierung einer Liste von float Pointern (erste Dimension) */

	atom_positions = malloc(atoms * sizeof(float *));
	if (atom_positions == NULL) {
		fprintf(stderr, "out of memory\n");
		return -1;
	}
	/* Allokierung der 3 Spalten für die Positionsangaben (zweite Dimension) */
	for (i = 0; i < atoms; i++) {
		atom_positions[i] = malloc(3 * sizeof(float));
		if (atom_positions[i] == NULL) {
			fprintf(stderr, "out of memory\n");
			return -1;
		}
	}

	/* Allokierung und Initialisierung der Energie-Liste */

	energies = malloc(atoms * sizeof(float));
	if (energies == NULL) {
		fprintf(stderr, "out of memory\n");
		return -1;
	}
	for (i = 0; i < atoms; i++) {
		energies[i] = 0.0f;
	}

	/* Einlesen der Atompositionen */
	/* Vereinfachung: normalerweise von Benutzer z.B. durch Eingabedatei übergebbar */
	for (i = 0; i < atoms; i++) {
		for (j = 0; j < 3; j++) {
			atom_positions[i][j] = (i + 1) * (j + 1);
		}
	}

	/* 
	 * Berechnung 
	 */

	/* Bewege jedes Atom in eine der 3 Raumrichtungen und berechne die Energie */
	for (i = 0; i < atoms; i++) {
		/* Verschiebe Atom und bestimme jeweils die Energie 
		 *  Speicher die maximale Energie */

		/* init maxenergy */
		maxenergy = 0;

		for (j = 0; j < 3; j++) {
			/* verschieben */
			atom_positions[i][j] += 1 * i;
			/* Energie berechnen */
			maxenergy = calc_energy(atoms, atom_positions);
			if (energies[i] < maxenergy) {
				energies[i] = maxenergy;
			}
			/* zurücksetzen */
			atom_positions[i][j] -= 1 * i;
		}
		printf("Energie für Atom %d: %f \n", i + 1, energies[i]);
	}

	maxenergy = 0;
	for (i = 0; i < atoms; i++) {
		if (energies[i] > maxenergy) {
			maxenergy = energies[i];
		}
	}
	printf("Maximalenergie: %f \n", maxenergy);

	/* Allokationen freigeben */
	free(energies);
	for (i = 0; i < atoms; i++) {
		free(atom_positions[i]);
	}
	free(atom_positions);

	return 0;
}