package org.openpixi.pixi.distributed; import org.openpixi.pixi.distributed.ibis.WorkerToWorker; import org.openpixi.pixi.distributed.util.BooleanLock; import org.openpixi.pixi.distributed.util.IncomingCellsHandler; import org.openpixi.pixi.distributed.util.IncomingParticlesHandler; import org.openpixi.pixi.distributed.util.IncomingPointsHandler; import org.openpixi.pixi.physics.particles.Particle; import org.openpixi.pixi.physics.grid.Cell; import org.openpixi.pixi.physics.grid.Grid; import org.openpixi.pixi.physics.movement.boundary.ParticleBoundaries; import org.openpixi.pixi.physics.util.Point; import java.util.ArrayList; import java.util.List; /** * Handles the data which needs to be shared between two nodes. * Specifically, sends and receives ghost and border particles and cells. */ public class SharedData { /** Handles the network communication with neighbor. */ private WorkerToWorker communicator; /* Locks to wait for the data to be received. */ private BooleanLock arrivingParticlesLock = new BooleanLock(); private BooleanLock ghostParticlesLock = new BooleanLock(); private BooleanLock ghostCellsLock = new BooleanLock(); private BooleanLock ghostCellsIndexesLock = new BooleanLock(); /** Maps the list of outgoing border cells to remote cells (needs to be sent out at the beginning). */ private List<Point> borderCellsMap = new ArrayList<Point>(); /** Border cells which need to be send out to neighbor. */ private List<Cell> borderCells = new ArrayList<Cell>(); /** Ghost cells references which are shared with the grid class and thus are global. */ private List<Cell> globalGhostCells = new ArrayList<Cell>(); /** Ghost cells which are received from neighbor and local to this class, * not visible from outside. * It can happen that the ghost cells arrive too early (in the solve fields phase). * In such case they can not be copied to the grid cells; hence, the local list. */ private List<Cell> localGhostCells; /** Ghost particles of neighbors - particles to be send to neighbors. */ private List<Particle> borderParticles = new ArrayList<Particle>(); /** Particles leaving this node - particles to be send to neighbors. */ private List<Particle> leavingParticles = new ArrayList<Particle>(); /** Ghost particles of this node - particles to be received from neighbors. */ private List<Particle> ghostParticles = new ArrayList<Particle>(); /** Particles arriving to this node - particles to be received from neighbors. */ private List<Particle> arrivingParticles = new ArrayList<Particle>(); /** * The arriving particles need to be checked * (they become border particles + * they might need to be reflected in the case of hardwall boundaries) */ private ParticleBoundaries particleBoundaries; /** Required for registering ghost cells. */ private Grid grid; public void setParticleBoundaries(ParticleBoundaries particleBoundaries) { this.particleBoundaries = particleBoundaries; } public void setGrid(Grid grid) { this.grid = grid; } public SharedData(WorkerToWorker communicator) { this.communicator = communicator; communicator.setGhostCellsHandler(new GhostCellsHandler()); communicator.setGhostParticlesHandler(new GhostParticlesHandler()); communicator.setArrivingParticlesHandler(new ArrivingParticlesHandler()); communicator.setGhostCellsIndexesHandler(new GhostCellsIndexesHandler()); } /** * Initializes the connection + * exchanges the order of ghost cells. */ public void initializeCommunication() { communicator.initializeConnection(); communicator.sendBorderCellsMap(borderCellsMap); ghostCellsIndexesLock.waitForTrue(); } public void registerBorderCell(Cell borderCell, Point remoteCellIndex) { borderCells.add(borderCell); borderCellsMap.add(remoteCellIndex); } public void registerBorderParticle(Particle p) { borderParticles.add(p); } public void registerLeavingParticle(Particle p) { leavingParticles.add(p); } public void sendLeavingParticles() { communicator.sendLeavingParticles(leavingParticles); } public void sendBorderParticles() { communicator.sendBorderParticles(borderParticles); } public void sendBorderCells() { communicator.sendBorderCells(borderCells); } public void waitForArrivingParticles() { arrivingParticlesLock.waitForTrue(); } /** * Has a twofold function: * 1) Waits for the ghost cells to arrive. * 2) Makes the ghost cells visible to simulation and grid classes. */ public void waitForGhostCells() { ghostCellsLock.waitForTrue(); for (int i = 0; i < localGhostCells.size(); ++i) { globalGhostCells.get(i).copyFrom(localGhostCells.get(i)); } } /** * Blocks until the arriving particles are received. */ public List<Particle> getArrivingParticles() { waitForArrivingParticles(); return arrivingParticles; } /** * Blocks until the ghost particles are received. */ public List<Particle> getGhostParticles() { ghostParticlesLock.waitForTrue(); return ghostParticles; } public List<Particle> getLeavingParticles() { return leavingParticles; } /** * Resets the particle lists waiting locks. * Resets the particle lists which are send to neighbors. * => Should be called at the end of particle communication. */ public void cleanUpParticleCommunication() { ghostParticlesLock.reset(); arrivingParticlesLock.reset(); leavingParticles.clear(); borderParticles.clear(); } /** * Resets the cell list waiting lock. * => Should be called at the end of cell communication. */ public void cleanUpCellCommunication() { ghostCellsLock.reset(); } public void closeSendPorts() { communicator.closeSendPorts(); } public void closeReceivePorts() { communicator.closeReceivePorts(); } private class GhostCellsIndexesHandler implements IncomingPointsHandler { /** * Registers the ghost cells in the same order * as the corresponding border cells at the neighbor. */ public void handle(List<Point> ghostCellsMap) { assert grid != null; for (Point cellIndex: ghostCellsMap) { globalGhostCells.add(grid.getCell(cellIndex.x, cellIndex.y)); } ghostCellsIndexesLock.setToTrue(); } } private class GhostCellsHandler implements IncomingCellsHandler { public void handle(List<Cell> cells) { assert cells.size() == globalGhostCells.size(); localGhostCells = cells; ghostCellsLock.setToTrue(); } } private class GhostParticlesHandler implements IncomingParticlesHandler { public void handle(List<Particle> particles) { ghostParticles = particles; ghostParticlesLock.setToTrue(); } } private class ArrivingParticlesHandler implements IncomingParticlesHandler { /** * All arriving particles have to be checked with boundary classes. * All arriving particle become right away also border particles. * Furthermore, they might also lie outside of the simulation area. */ public void handle(List<Particle> particles) { arrivingParticles = particles; for (Particle particle: particles) { /** * The nulls won't work with hardwall boundaries!!! * TODO inject the solver, force and time step into shared data from classes above */ particleBoundaries.applyOnParticleCenter(null, null, particle, 0); } arrivingParticlesLock.setToTrue(); } } }