package org.openpixi.pixi.distributed; import org.openpixi.pixi.distributed.ibis.IbisRegistry; import org.openpixi.pixi.distributed.ibis.WorkerToWorker; import org.openpixi.pixi.physics.GeneralBoundaryType; import org.openpixi.pixi.physics.particles.Particle; import org.openpixi.pixi.physics.grid.Grid; import org.openpixi.pixi.physics.movement.boundary.ParticleBoundaries; import org.openpixi.pixi.physics.util.IntBox; import org.openpixi.pixi.physics.util.Point; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Holds shared data for each boundary and border region. * Provides access to the shared data and operations upon the shared data. * * The shared data for a specific neighbor is created according to demand on the fly. */ public class SharedDataManager { /** Maps region to neighbor. */ private NeighborMap neighborMap; /** Maps neighbor to SharedData. */ private Map<Integer, SharedData> sharedData = new HashMap<Integer, SharedData>(); private IbisRegistry registry; private Thread particleExchangeThread; public SharedDataManager( int thisWorkerID, IntBox[] partitions, IntBox globalSimArea, GeneralBoundaryType boundaryType, IbisRegistry registry) { this.registry = registry; this.neighborMap = new NeighborMap(thisWorkerID, partitions, globalSimArea, boundaryType); } //---------------------------------------------------------------------------------------------- // Methods required for initialization of distributed simulation //---------------------------------------------------------------------------------------------- public SharedData getBoundarySharedData(int boundaryRegion) { int neighbor = neighborMap.getBoundaryNeighbor(boundaryRegion); if (neighbor != NeighborMap.NO_NEIGHBOR) { return getSharedData(neighbor); } else { return null; } } public Point getBoundaryDirections(int boundaryRegion) { return neighborMap.getBoundaryNeighborsDirections(boundaryRegion); } public List<SharedData> getBorderSharedData(int borderRegion) { List<SharedData> retval = new ArrayList<SharedData>(); int[] neighbors = neighborMap.getBorderNeighbors(borderRegion); for (int neighbor: neighbors) { if (neighbor != NeighborMap.NO_NEIGHBOR) { retval.add(getSharedData(neighbor)); } } return retval; } public List<Point> getBorderDirections(int borderRegion) { List<Point> retval = new ArrayList<Point>(); Point[] directions = neighborMap.getBorderNeighborsDirections(borderRegion); if (directions != null) { for (Point direction: directions) { if (direction != null) { retval.add(direction); } } } return retval; } /** * If the SharedData for the given neighbor does not exist it is created on the fly. */ private SharedData getSharedData(int neighbor) { if (!sharedData.containsKey(neighbor)) { sharedData.put( neighbor, new SharedData(new WorkerToWorker(registry, neighbor))); } return sharedData.get(neighbor); } public void setParticleBoundaries(ParticleBoundaries particleBoundaries) { for (SharedData sd: sharedData.values()) { sd.setParticleBoundaries(particleBoundaries); } } public void setGrid(Grid grid) { for (SharedData sd: sharedData.values()) { sd.setGrid(grid); } } public void initializeCommunication() { for (SharedData sd: sharedData.values()) { sd.initializeCommunication(); } } //---------------------------------------------------------------------------------------------- // Methods required during distributed simulation //---------------------------------------------------------------------------------------------- /** * The exchange of particles can last some time as we have to wait for the arriving particles * before we send the border particles. * As we do not want to stall the calling thread, * we start the exchange of particles in a new thread. */ public void startExchangeOfParticles() { particleExchangeThread = new Thread(new Runnable() { public void run() { for (SharedData sd: sharedData.values()) { sd.sendLeavingParticles(); } // Before we send the border particles we have to wait // for all the arriving particles as they are as well border particles. waitForArrivingParticles(); for (SharedData sd: sharedData.values()) { sd.sendBorderParticles(); } } }); particleExchangeThread.start(); } public List<Particle> getArrivingParticles() { List<Particle> arrivingParticles = new ArrayList<Particle>(); for (SharedData sd: sharedData.values()) { arrivingParticles.addAll(sd.getArrivingParticles()); } return arrivingParticles; } public List<Particle> getGhostParticles() { List<Particle> ghostParticles = new ArrayList<Particle>(); for (SharedData sd: sharedData.values()) { ghostParticles.addAll(sd.getGhostParticles()); } return ghostParticles; } public List<Particle> getLeavingParticles() { List<Particle> leavingParticles = new ArrayList<Particle>(); for (SharedData sd: sharedData.values()) { leavingParticles.addAll(sd.getLeavingParticles()); } return leavingParticles; } public void exchangeCells() { for (SharedData sd: sharedData.values()) { sd.sendBorderCells(); } } public void waitForGhostCells() { for (SharedData sd: sharedData.values()) { sd.waitForGhostCells(); } } private void waitForArrivingParticles() { for (SharedData sd: sharedData.values()) { sd.waitForArrivingParticles(); } } public void cleanUpCellCommunication() { for (SharedData sd: sharedData.values()) { sd.cleanUpCellCommunication(); } } public void cleanUpParticleCommunication() { // Wait for the exchange of particles to finish // (particularly wait for finishing the sending of border particles). // Otherwise, we can end up concurrently modifying the border particles // (this thread cleans up the list of border particles). try { particleExchangeThread.join(); } catch (InterruptedException e) { e.printStackTrace(); throw new RuntimeException(e); } for (SharedData sd: sharedData.values()) { sd.cleanUpParticleCommunication(); } } public void close() { for (SharedData sd: sharedData.values()) { sd.closeSendPorts(); } for (SharedData sd: sharedData.values()) { sd.closeReceivePorts(); } } }