package org.openpixi.pixi.distributed;
import org.openpixi.pixi.distributed.grid.DistributedGridFactory;
import org.openpixi.pixi.distributed.grid.DistributedInterpolation;
import org.openpixi.pixi.distributed.ibis.IbisRegistry;
import org.openpixi.pixi.distributed.ibis.WorkerToMaster;
import org.openpixi.pixi.distributed.movement.boundary.DistributedParticleBoundaries;
import org.openpixi.pixi.distributed.util.BooleanLock;
import org.openpixi.pixi.distributed.util.IncomingProblemHandler;
import org.openpixi.pixi.physics.particles.Particle;
import org.openpixi.pixi.physics.Settings;
import org.openpixi.pixi.physics.Simulation;
import org.openpixi.pixi.physics.grid.Cell;
import org.openpixi.pixi.physics.grid.Grid;
import org.openpixi.pixi.physics.grid.Interpolation;
import org.openpixi.pixi.physics.movement.boundary.ParticleBoundaries;
import org.openpixi.pixi.physics.util.ClassCopier;
import org.openpixi.pixi.physics.util.DoubleBox;
import org.openpixi.pixi.physics.util.IntBox;
import java.io.IOException;
import java.util.List;
/**
* Receives the problem, calculates the problem, sends back results.
*/
public class Worker {
private WorkerToMaster communicator;
/* Local and global settings differ only in settings connected to simulation size. */
private Settings localSettings;
private Settings globalSettings;
/** ID of this worker. */
private int workerID;
private Simulation simulation;
private SharedDataManager sharedDataManager;
/* Received problem */
private IntBox[] partitions;
private List<Particle> particles;
private Cell[][] cells;
private BooleanLock recvProblemLock = new BooleanLock();
public Worker(IbisRegistry registry, Settings settings) {
this.globalSettings = settings;
try {
communicator = new WorkerToMaster(registry, new ProblemHandler());
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
workerID = registry.convertIbisIDToWorkerID(registry.getIbis().identifier());
}
public void step() {
simulation.step();
}
public void receiveProblem() {
recvProblemLock.waitForTrue();
recvProblemLock.reset();
createSimulation();
}
public void sendResults() {
Cell[][] finalCells = getFinalCells(simulation.grid);
// The results can come in arbitrary order; thus,
// we have to send also the id of the node which is sending the result.
try {
communicator.sendResults(
workerID,
simulation.particles,
finalCells);
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
/**
* If the local simulation is at the edge of global simulation,
* we also need to include the extra cells to the master
* (because of hardwall boundaries).
*/
private Cell[][] getFinalCells(Grid grid) {
IntBox mypart = partitions[workerID];
int xstart = 0;
int ystart = 0;
int xend = mypart.xsize() - 1;
int yend = mypart.ysize() - 1;
if (mypart.xmin() == 0) {
xstart -= Grid.EXTRA_CELLS_BEFORE_GRID;
}
if (mypart.xmax() == globalSettings.getGridCellsX() - 1) {
xend += Grid.EXTRA_CELLS_AFTER_GRID;
}
if (mypart.ymin() == 0) {
ystart -= Grid.EXTRA_CELLS_BEFORE_GRID;
}
if (mypart.ymax() == globalSettings.getGridCellsY() - 1) {
yend += Grid.EXTRA_CELLS_AFTER_GRID;
}
Cell[][] finalCells = new Cell[xend - xstart + 1][yend - ystart + 1];
for (int x = xstart; x <= xend ; ++x) {
for (int y = ystart; y <= yend; ++y) {
finalCells[x - xstart][y - ystart] = grid.getCell(x,y);
}
}
return finalCells;
}
private void createSimulation() {
createLocalSettings();
sharedDataManager = createSharedDataManager();
ParticleBoundaries particleBoundaries = createParticleBoundaries(sharedDataManager);
sharedDataManager.setParticleBoundaries(particleBoundaries);
Grid grid = createGrid(sharedDataManager);
Interpolation interpolation = createInterpolationIterator(sharedDataManager);
sharedDataManager.setGrid(grid);
sharedDataManager.initializeCommunication();
this.simulation = new Simulation(
localSettings, grid, particles,
particleBoundaries, interpolation);
}
/**
* Some settings (e.g. simulation width and height) pertain to the global simulation
* and are incorrect for the local simulation.
* Thus, we need to correct them, so that they correspond to the local simulation.
*/
private void createLocalSettings() {
IntBox mypart = partitions[workerID];
double cellWidth = globalSettings.getCellWidth();
double cellHeight = globalSettings.getCellHeight();
localSettings = ClassCopier.copy(globalSettings);
localSettings.setGridCellsX(mypart.xsize());
localSettings.setGridCellsY(mypart.ysize());
localSettings.setSimulationWidth(cellWidth * mypart.xsize());
localSettings.setSimulationHeight(cellHeight * mypart.ysize());
}
private Interpolation createInterpolationIterator(SharedDataManager sharedDataManager) {
DoubleBox zoneOfLocalInfluence = new DoubleBox(
(Grid.INTERPOLATION_RADIUS - 1) * localSettings.getCellWidth(),
localSettings.getSimulationWidth() -
Grid.INTERPOLATION_RADIUS * localSettings.getCellWidth(),
(Grid.INTERPOLATION_RADIUS - 1) * localSettings.getCellHeight(),
localSettings.getSimulationHeight() -
Grid.INTERPOLATION_RADIUS * localSettings.getCellHeight());
return new DistributedInterpolation(
localSettings.getInterpolator(),
sharedDataManager, zoneOfLocalInfluence, localSettings.getParticleIterator());
}
private SharedDataManager createSharedDataManager() {
IntBox simulationAreaInCellDimensions = new IntBox(
0, globalSettings.getGridCellsX() - 1, 0, globalSettings.getGridCellsY() - 1);
return new SharedDataManager(
workerID,
partitions,
simulationAreaInCellDimensions,
localSettings.getBoundaryType(),
communicator.getRegistry());
}
private Grid createGrid(SharedDataManager sharedDataManager) {
DistributedGridFactory gridFactory = new DistributedGridFactory(
localSettings, partitions[workerID],
cells, sharedDataManager);
return gridFactory.create();
}
private ParticleBoundaries createParticleBoundaries(SharedDataManager sharedDataManager) {
DoubleBox simulationAreaInParticleDimensions = new DoubleBox(
0, localSettings.getSimulationWidth(), 0, localSettings.getSimulationHeight());
DoubleBox innerSimulationArea = new DoubleBox(
0, localSettings.getSimulationWidth() - localSettings.getCellWidth(),
0, localSettings.getSimulationHeight() - localSettings.getCellHeight());
return new DistributedParticleBoundaries(
simulationAreaInParticleDimensions, innerSimulationArea,
localSettings.getParticleBoundary(), sharedDataManager);
}
public void close() {
communicator.close();
sharedDataManager.close();
}
private class ProblemHandler implements IncomingProblemHandler {
public void handle(IntBox[] partitions, List<Particle> particles, Cell[][] cells) {
Worker.this.partitions = partitions;
Worker.this.particles = particles;
Worker.this.cells = cells;
recvProblemLock.setToTrue();
}
}
}