package org.openpixi.pixi.distributed.grid;
import org.openpixi.pixi.distributed.SharedDataManager;
import org.openpixi.pixi.parallel.particleaccess.ParticleAction;
import org.openpixi.pixi.parallel.particleaccess.ParticleIterator;
import org.openpixi.pixi.physics.particles.Particle;
import org.openpixi.pixi.physics.grid.Grid;
import org.openpixi.pixi.physics.grid.Interpolation;
import org.openpixi.pixi.physics.grid.InterpolatorAlgorithm;
import org.openpixi.pixi.physics.util.DoubleBox;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Does the necessary communication before interpolation.
*/
public class DistributedInterpolation extends Interpolation {
private SharedDataManager sharedDataManager;
/**
* Determines the zone of particles where we can safely interpolate to the particles
* without any need of cells from neighbors.
*/
private DoubleBox zoneOfLocalInfluence;
private List<Particle> particlesWithOutsideInfluence =
Collections.synchronizedList(new ArrayList<Particle>());
/* These are passed to inner classes as a parameter to theirs methods. */
private Grid grid;
private double timeStep;
private ParticleIterator particleIterator;
private InterpolateToInsideParticle interpolateToInsideParticle = new InterpolateToInsideParticle();
private InterpolateToOutsideParticle interpolateToOutsideParticle = new InterpolateToOutsideParticle();
private InterpolateToGrid interpolateToGrid = new InterpolateToGrid();
public DistributedInterpolation(
InterpolatorAlgorithm interpolator,
SharedDataManager sharedDataManager,
DoubleBox zoneOfLocalInfluence,
ParticleIterator particleIterator) {
super(interpolator);
this.sharedDataManager = sharedDataManager;
this.zoneOfLocalInfluence = zoneOfLocalInfluence;
this.particleIterator = particleIterator;
}
/**
* When interpolating to grid we need also the arriving particles and border particles
* from neighbors.
* In order not to wait too much for network communication we interleave the communication
* and computation.
* While the crossing and border particles are being exchanged,
* we interpolate our local particles.
*/
@Override
public void interpolateToGrid(List<Particle> localParticles, Grid grid, double timeStep) {
sharedDataManager.startExchangeOfParticles();
grid.resetCurrent();
// Remove leaving particles
List<Particle> leavingParticles = sharedDataManager.getLeavingParticles();
for (Particle leavingParticle: leavingParticles) {
localParticles.remove(leavingParticle);
}
this.grid = grid;
this.timeStep = timeStep;
// Interpolate local particles
particleIterator.execute(localParticles, interpolateToGrid);
// Interpolate arriving particles
List<Particle> arrivingParticles = sharedDataManager.getArrivingParticles();
particleIterator.execute(arrivingParticles, interpolateToGrid);
// Interpolate ghost particles
List<Particle> ghostParticles = sharedDataManager.getGhostParticles();
particleIterator.execute(ghostParticles, interpolateToGrid);
// Add arriving particles to the list of local particles
localParticles.addAll(arrivingParticles);
sharedDataManager.cleanUpParticleCommunication();
}
/**
* When interpolating to particles we need also the cells from our neighbors.
* Similarly as with interpolateToGrid() we interleave the communication and computation.
* We first interpolate to particles which are not influenced by cells from neighbors and
* only when all the cells from neighbors arrived we interpolate to the rest of the particles.
*/
@Override
public void interpolateToParticle(List<Particle> particles, Grid grid) {
// Initiate the exchange of cells
sharedDataManager.exchangeCells();
// Here, due to an "if" statement (see the inner class),
// we can not reuse the local interpolation and we have to do the iteration ourselves.
this.grid = grid;
particleIterator.execute(particles, interpolateToInsideParticle);
sharedDataManager.waitForGhostCells();
particleIterator.execute(particlesWithOutsideInfluence, interpolateToOutsideParticle);
sharedDataManager.cleanUpCellCommunication();
particlesWithOutsideInfluence.clear();
}
@Override
public void interpolateChargedensity(List<Particle> particles, Grid grid) {
throw new UnsupportedOperationException(
"Interpolation of charge density is done only once when the grid is initialized " +
"before the Poisson solver is called. " +
"Thus, it is expected to be done by non-distributed interpolation.");
}
private class InterpolateToInsideParticle implements ParticleAction {
public void execute(Particle particle) {
if (zoneOfLocalInfluence.contains(particle.getX(), particle.getY())) {
interpolator.interpolateToParticle(particle, grid);
}
else {
particlesWithOutsideInfluence.add(particle);
}
}
}
private class InterpolateToOutsideParticle implements ParticleAction {
public void execute(Particle particle) {
interpolator.interpolateToParticle(particle, grid);
}
}
private class InterpolateToGrid implements ParticleAction {
public void execute(Particle particle) {
interpolator.interpolateToGrid(particle, grid, timeStep);
}
}
}