Package org.openpixi.pixi.distributed

Source Code of org.openpixi.pixi.distributed.Master$ResultHandler

package org.openpixi.pixi.distributed;

import org.openpixi.pixi.distributed.ibis.IbisRegistry;
import org.openpixi.pixi.distributed.ibis.MasterToWorkers;
import org.openpixi.pixi.distributed.partitioning.Partitioner;
import org.openpixi.pixi.distributed.partitioning.SimplePartitioner;
import org.openpixi.pixi.distributed.util.CountLock;
import org.openpixi.pixi.distributed.util.IncomingResultHandler;
import org.openpixi.pixi.physics.particles.Particle;
import org.openpixi.pixi.physics.ParticleGridInitializer;
import org.openpixi.pixi.physics.Settings;
import org.openpixi.pixi.physics.grid.Cell;
import org.openpixi.pixi.physics.grid.Grid;
import org.openpixi.pixi.physics.grid.LocalInterpolation;
import org.openpixi.pixi.physics.util.ClassCopier;
import org.openpixi.pixi.physics.util.IntBox;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
* Distributes the problem and collects the results.
* To each worker we assign exactly one problem.
*/
public class Master {

  private MasterToWorkers communicator;
  private Settings settings;

  private Grid initialGrid;
  private List<Particle> initialParticles;

  private Grid finalGrid;
  private List<Particle> finalParticles;

  /**
   * Problem decomposition table.
   * N-th element in the table belongs to the n-th worker.
   */
  private IntBox[] partitions;

  /* Results received from workers */
  private Cell[][][] gridPartitions;
  private List<List<Particle>> particlePartitions = new ArrayList<List<Particle>>();

  private CountLock resultsLock;


  public Grid getFinalGrid() {
    return finalGrid;
  }

  public List<Particle> getFinalParticles() {
    return finalParticles;
  }


  public Master(IbisRegistry registry, Settings settings) {
    this.settings = settings;
    try {
      communicator = new MasterToWorkers(registry, new ResultHandler());
    } catch (Exception e) {
      e.printStackTrace();
      throw new RuntimeException(e);
    }

    // Initialize the grid

    initialGrid = new Grid(settings);
    initialParticles = settings.getParticles();

    ParticleGridInitializer pgi = new ParticleGridInitializer();
    pgi.initialize(
        new LocalInterpolation(
            settings.getInterpolator(), settings.getParticleIterator()),
        settings.getPoissonSolver(),
        initialParticles,
        initialGrid);

    // Initialize the classes holding the result
    gridPartitions = new Cell[settings.getNumOfNodes()][][];
    for (int i = 0; i < settings.getNumOfNodes(); i++) {
      particlePartitions.add(new ArrayList<Particle>());
    }

    resultsLock = new CountLock(settings.getNumOfNodes());
  }


  public void distributeProblem() {
    // Partition the problem
    Partitioner partitioner = new SimplePartitioner();
    partitions = partitioner.partition(
        settings.getGridCellsX(), settings.getGridCellsY(), settings.getNumOfNodes());

    // Log the partitioning scheme
    Logger logger = LoggerFactory.getLogger(this.getClass());
    logger.debug("Problem partitioning:\n{}", partitioner);

    // Partition the data
    List<Particle> initialParticlesCopy = copyInitialParticles();
    List<List<Particle>> particlePartitions = partitionParticles(
        partitions, initialParticlesCopy);
    Cell[][][] gridPartitions = partitionGrid(partitions, initialGrid);

    // Send to each worker
    for (int workerID = 0; workerID < partitions.length; workerID++) {
      try {
        communicator.sendProblem(
            workerID, partitions,
            particlePartitions.get(workerID), gridPartitions[workerID]);
      } catch (IOException e) {
        e.printStackTrace();
        throw new RuntimeException(e);
      }
    }
  }


  private List<Particle> copyInitialParticles() {
    List<Particle> copy = new ArrayList<Particle>();
    for (Particle p: initialParticles) {
      copy.add(ClassCopier.copy(p));
    }
    return copy;
  }


  /**
   * Divides cells according to partitions.
   */
  private Cell[][][] partitionGrid(IntBox[] partitions, Grid grid) {
    Cell[][][] gridPartitions = new Cell[partitions.length][][];
    for (int i = 0; i < partitions.length; ++i) {
      gridPartitions[i] = getSubgrid(partitions[i], grid);
    }
    return gridPartitions;
  }


  /**
   * At the global simulation edges we also the extra cells!
   * Since there is some initialization done on the grid
   * (density charge interpolation + poisson solver)
   * we need to distribute also the extra cells.
   *
   * At the inner partitions of global simulation we still need the ghost cells
   * for correct field solving.
   */
  private Cell[][] getSubgrid(IntBox partition, Grid grid) {
    int startX = partition.xmin() - Grid.EXTRA_CELLS_BEFORE_GRID;
    int endX = partition.xmax() + Grid.EXTRA_CELLS_AFTER_GRID;
    int startY = partition.ymin() - Grid.EXTRA_CELLS_BEFORE_GRID;
    int endY = partition.ymax() + Grid.EXTRA_CELLS_AFTER_GRID;

    Cell[][] subGrid = new Cell[endX - startX + 1][endY - startY + 1];
    for (int x = startX; x <= endX ; x++) {
      for (int y = startY; y <= endY; y++) {
        // We create a new copy of the cell so that each cell is unique.
        // In another words we want to avoid shared references
        // present in periodic boundaries.
        subGrid[x - startX][y - startY] = ClassCopier.copy(grid.getCell(x,y));
      }
    }
    return  subGrid;
  }


  /**
   * Divides particles according to partitions they belong to.
   */
  private List<List<Particle>> partitionParticles(IntBox[] partitions, List<Particle> particles) {
    List<List<Particle>> particlePartitions = new ArrayList<List<Particle>>();
    for (int i = 0; i < partitions.length; ++i) {
      particlePartitions.add(new ArrayList<Particle>());
    }

    for (Particle p: particles) {
      int partitionIndex = -1;
      int cellX = (int)Math.floor(p.getX() / initialGrid.getCellWidth());
      int cellY = (int)Math.floor(p.getY() / initialGrid.getCellHeight());

      for  (int i = 0; i < partitions.length; ++i) {
        if (partitions[i].contains(cellX, cellY)) {
          partitionIndex = i;
        }
      }

      assert partitionIndex != -1;

      // Translate particle's position
      double xmin = partitions[partitionIndex].xmin() * settings.getCellWidth();
      double ymin = partitions[partitionIndex].ymin() * settings.getCellHeight();
      p.setX(p.getX() - xmin);
      p.setY(p.getY() - ymin);

      particlePartitions.get(partitionIndex).add(p);
    }
    return particlePartitions;
  }


  public void collectResults() {
    resultsLock.waitForCount();
    resultsLock.reset();
    finalParticles = assembleParticles(particlePartitions);
    finalGrid = assembleGrid(gridPartitions);
  }


  /**
   * Puts together the particle lists coming from workers.
   */
  private List<Particle> assembleParticles(List<List<Particle>> particlePartitions) {
    List<Particle> assembledParticles = new ArrayList<Particle>();
    for (int i = 0; i < particlePartitions.size(); ++i) {

      double xmin = partitions[i].xmin() * settings.getCellWidth();
      double ymin = partitions[i].ymin() * settings.getCellHeight();

      for (Particle p: particlePartitions.get(i)) {

        // Translate particles position
        p.setX(p.getX() + xmin);
        p.setY(p.getY() + ymin);

        assembledParticles.add(p);
      }
    }
    return assembledParticles;
  }


  /**
   * Puts together the subgrids coming from workers.
   */
  private Grid assembleGrid(Cell[][][] gridPartitions) {
    int totalXCells =
        Grid.EXTRA_CELLS_BEFORE_GRID +
        settings.getGridCellsX() +
        Grid.EXTRA_CELLS_AFTER_GRID;
    int totalYCells =
        Grid.EXTRA_CELLS_BEFORE_GRID +
        settings.getGridCellsY() +
        Grid.EXTRA_CELLS_AFTER_GRID;

    Cell[][] cells = new Cell[totalXCells][totalYCells];
    for (int workerID = 0; workerID < partitions.length; ++workerID) {
      fillSubgrid(partitions[workerID], gridPartitions[workerID], cells);
    }

    return new Grid(settings, cells);
  }


  /**
   * We fill also the extra cells.
   * In case of hardwall boundary we have additional information in them.
   */
  private void fillSubgrid(IntBox partition, Cell[][] subgrid, Cell[][] cells) {
    int startX = partition.xmin();
    int endX = partition.xmax();
    int startY = partition.ymin();
    int endY = partition.ymax();
    if (startX == 0) {
      startX -= Grid.EXTRA_CELLS_BEFORE_GRID;
    }
    if (endX == settings.getGridCellsX() - 1) {
      endX += Grid.EXTRA_CELLS_AFTER_GRID;
    }
    if (startY == 0) {
      startY -= Grid.EXTRA_CELLS_BEFORE_GRID;
    }
    if (endY == settings.getGridCellsY() - 1) {
      endY += Grid.EXTRA_CELLS_AFTER_GRID;
    }

    for (int x = startX; x <= endX ; x++) {
      for (int y = startY; y <= endY; y++) {
        cells[x + Grid.EXTRA_CELLS_BEFORE_GRID][y + Grid.EXTRA_CELLS_BEFORE_GRID] =
            subgrid[x - startX][y - startY];
      }
    }
  }


  public void close() {
    communicator.close();
  }


  private class ResultHandler implements IncomingResultHandler {
    public void handle(int workerID, List<Particle> particles, Cell[][] cells) {
      gridPartitions[workerID] = cells;
      particlePartitions.set(workerID, particles);
      resultsLock.increase();
    }
  }
}
TOP

Related Classes of org.openpixi.pixi.distributed.Master$ResultHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.