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); } } }