sandbox/Antoonvh/particle_classic.h

    Particles can be removed based on their position or another condition

    int remove_particle (particle p, Particles Plist) {
      long unsigned int * ind = malloc (sizeof(long int));
      int i = 0, a = 1; 
      foreach_particle_in(Plist) {
        foreach_dimension()
          if (p().x != p.x)
    	      continue;
        if (i + 1 >= a) {
          ind = realloc (ind, a*2*sizeof(long int));
          a *= 2;
        }
        ind[i++] = _j_particle;
      }
      remove_particles_index (Plist, i, ind);
      free (ind); ind = NULL;
      return i;
    }

    Utility functions

    boundary conditions

    peridoc box and _MPI boundaries.

    Periodicity in vertical does not make sense in the multilayer solver, and hence this function remains currently unchanged.

    void particle_boundary (Particles P) {
      coord mind = {X0, Y0, Z0};
      foreach_particle_in(P) {
        foreach_dimension() {
          if (p().x < mind.x) 
    	      p().x += L0;
          else if (p().x > (mind.x + L0))
    	      p().x -= L0;
        }
      }
    #if _MPI
      update_mpi (P);
    #endif
    }

    Place particles

    For already allocated particles referenced by Particles P:

    The foreach() and foreach_dimension()-iterators do not see z-axis in multilayer, and hence the support for this axis must be added manually where relevant.

    void place_in_cells (Particles P) {
      particles pp = pl[P];                 
      long unsigned int np = 0;
      foreach(serial, reduction(+:np)) {
        coord loc = {x, y,z};
        foreach_dimension()
          pp[np].x = loc.x;
        np++;
      }
    }

    Simple particles statistics

    The function computes, Average location, min, max and standard deviation vectors. The correct statistics are only available for pid() == 0.

    pstats statsp (Particles P) {
      coord avg = {0 ,0, 0}, min = {0,0,0},
        max = {0, 0, 0}, stddev = {0, 0, 0};
      foreach_dimension(3) {
        avg.x = stddev.x = 0;
        min.x = HUGE;
        max.x = -HUGE;
      }
      long unsigned int np = pn[P];
    #if _MPI
      MPI_Allreduce (MPI_IN_PLACE, &np, 1, MPI_UNSIGNED_LONG,
    		 MPI_SUM, MPI_COMM_WORLD);
    #endif
      if (np) {
        foreach_dimension() { //reduction of coord members does not work
          double avgx = 0;
          double minx = HUGE;
          double maxx = -HUGE;
          foreach_particle_in(P, reduction(+:avgx) reduction(max:maxx)
    			  reduction (min:minx), serial) {
    	  avgx += p().x;
    	  if (p().x < minx)
    	    minx = p().x;
    	  if (p().x > maxx)
    	    maxx = p().x;
          }
          avg.x = avgx/(double)np;
          min.x = minx;
          max.x = maxx;
        }
        foreach_dimension() {
          double stddevx = 0;
          foreach_particle_in(P, reduction(+:stddevx), serial) {
    	stddevx += sq(avg.x - p().x);
          }
          stddev.x = sqrt(stddevx/(double)np);
        }
      }
      
      pstats s;
      s.max = max, s.min = min, s.avg = avg, s.stddev = stddev;
      return s;
    }

    Propability density function

    Obtain a scalar PDF from particle locations

    void particle_pdf (Particles P, scalar s) {
      foreach()
        s[] = 0;
      particle_boundary (P);
      foreach_particle_in(P) {
        Point point = locate (x,y,z);
        if (point.level > 0)
          s[]++;
      }
      foreach()
        s[] /= (pn[P]*dv());
      boundary ({s});
    }

    Random step

    Particles displace a certain distance (step) in a random direction

    void random_step (Particles P, double step) {
      foreach_particle_in(P) {
        double theta = noise()*pi;
        #if (dimension == 1)
          coord d = {sign(theta)};
        #elif (dimension < 3)
          coord d = {sin(theta), cos(theta)};
        #else
          double phi = acos(noise());
          coord d = {sin(phi)*cos(theta), sin(phi)*sin(theta), cos(phi)};
        #endif
        foreach_dimension()
          p().x += d.x*step;
      }
    }

    Length of particle loop

    A function that computes the line length of particles places in a loop (mind the ordering). Special care is taken to obtain 4th order accuracy.

    double plength (Particles P) {
      double lr = 0;
      int np = pn[P];
      particles pli = pl[P];
      foreach_particle_in(P) {
        int il = _j_particle - 1 < 0 ? np - 1: _j_particle - 1;
        int ir = _j_particle + 1 >= np ? 0 : _j_particle + 1;
        coord pl = (coord){pli[il].x, pli[il].y, pli[il].z};
        coord pm = (coord){pli[_j_particle].x, pli[_j_particle].y, pli[_j_particle].z};
        coord pr = (coord){pli[ir].x, pli[ir].y, pli[ir].z};
        coord bv = {0, 0, 0}, a1 = {0,0,0};
        coord a2 = {0,0,0};
        double bl = 0, ka = 0;
        foreach_dimension() {
          a1.x = pm.x - pl.x;
          bv.x = pr.x - pl.x;
          bl += sq(bv.x);
        }
    
        bl = sqrt(bl);
        foreach_dimension()
          ka += a1.x*bv.x/bl;
    
        foreach_dimension()
          a2.x = a1.x - bv.x*ka/bl;
    
        normalize (&a2);
        double al = 0, am = 0, ar = 0;
        foreach_dimension() {
          al -= a2.x*pl.x;
          am -= a2.x*pm.x;
          ar -= a2.x*pr.x;
        }
        double C = fabs(am - al);
        double xt = 0;
        double b = 0;
        foreach_dimension() {
          xt += sq(pl.x - pm.x);
          b += sq(pl.x - pr.x);
        }
        xt = sqrt (xt - sq(C));
        b = sqrt(b);
        double A =  C/((xt*(b - xt)));
        double xp1 = 0.5*b*(1 - 1/sqrt(3));
        double xp2 = 0.5*b*(1 + 1/sqrt(3));
        double l1 = b*sqrt(1. + sq(-2*A*xp1 + A*b));
        double l2 = b*sqrt(1. + sq(-2*A*xp2 + A*b));
        lr += (l1 + l2)/4;
      }
      return lr;
    }