package org.openpixi.pixi.distributed.grid; import org.openpixi.pixi.distributed.SharedData; import org.openpixi.pixi.distributed.SharedDataManager; import org.openpixi.pixi.distributed.movement.boundary.BorderRegions; 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.util.DoubleBox; import org.openpixi.pixi.physics.util.IntBox; import org.openpixi.pixi.physics.util.Point; import java.util.List; /** * Creates grid with boundaries to neighboring nodes. */ public class DistributedGridFactory { private Settings settings; private Cell[][] cellsFromMaster; /** Partition of this worker in global coordinates. */ private IntBox myPartGlobal; private SharedDataManager sharedDataManager; public DistributedGridFactory( Settings settings, IntBox myPartGlobal, Cell[][] cellsFromMaster, SharedDataManager sharedDataManager) { this.settings = settings; this.myPartGlobal = myPartGlobal; this.cellsFromMaster = cellsFromMaster; this.sharedDataManager = sharedDataManager; } public Grid create() { Cell[][] myCells = setUpCellValues(); setUpBorderCells(myCells); return new Grid(settings, myCells); } /** * Determines the border cells and the indices of the corresponding ghost cells at remote nodes. * Since the corresponding border and ghost cells must have the same order, * the ghost cells are registered once the ghost cell indices (border cells map) is exchanged. */ private void setUpBorderCells(Cell[][] myCells) { DoubleBox simAreaDouble = new DoubleBox( 0, settings.getSimulationWidth(), 0, settings.getSimulationHeight()); DoubleBox innerSimAreaDouble = new DoubleBox( settings.getCellWidth(), settings.getSimulationWidth() - settings.getCellWidth(), settings.getCellHeight(), settings.getSimulationHeight() - settings.getCellHeight()); BorderRegions borders = new BorderRegions(simAreaDouble, innerSimAreaDouble); int xmin = -Grid.INTERPOLATION_RADIUS; int xmax = myPartGlobal.xsize() + Grid.INTERPOLATION_RADIUS - 1; int ymin = -Grid.INTERPOLATION_RADIUS; int ymax = myPartGlobal.ysize() + Grid.INTERPOLATION_RADIUS - 1; for (int x = xmin; x <= xmax; x++) { for (int y = ymin; y <= ymax; y++) { double simX = x * settings.getCellWidth() + settings.getCellWidth() / 2; double simY = y * settings.getCellHeight() + settings.getCellHeight() / 2; int region = borders.getRegion(simX, simY); List<SharedData> sharedDatas = sharedDataManager.getBorderSharedData(region); List<Point> directions = sharedDataManager.getBorderDirections(region); assert sharedDatas.size() == directions.size(); for (int i = 0; i < sharedDatas.size(); ++i) { Point remoteGhostCellIndex = getRemoteGhostCellIndex(x, y, directions.get(i)); sharedDatas.get(i).registerBorderCell( myCells[realIndex(x)][realIndex(y)], remoteGhostCellIndex); } } } } /** * Translates the local border cell index to remote ghost cell index. */ private Point getRemoteGhostCellIndex(int x, int y, Point direction) { int xoffset = direction.x * settings.getGridCellsX(); int yoffset = direction.y * settings.getGridCellsY(); return new Point(x - xoffset, y - yoffset); } private Cell[][] setUpCellValues() { int xcells = myPartGlobal.xsize() + Grid.EXTRA_CELLS_BEFORE_GRID + Grid.EXTRA_CELLS_AFTER_GRID; int ycells = myPartGlobal.ysize() + Grid.EXTRA_CELLS_BEFORE_GRID + Grid.EXTRA_CELLS_AFTER_GRID; Cell[][] myCells = new Cell[xcells][ycells]; int xmin = -Grid.EXTRA_CELLS_BEFORE_GRID; int xmax = myPartGlobal.xsize() + Grid.EXTRA_CELLS_AFTER_GRID - 1; int ymin = -Grid.EXTRA_CELLS_BEFORE_GRID; int ymax = myPartGlobal.ysize() + Grid.EXTRA_CELLS_AFTER_GRID - 1; for (int x = xmin; x <= xmax; x++) { for (int y = ymin; y <= ymax; y++) { myCells[realIndex(x)][realIndex(y)] = cellsFromMaster[realIndex(x)][realIndex(y)]; } } return myCells; } /** * Converts grid indexing * from (-1,0,..) -> user index * to (0,1,..) -> real index */ private int realIndex(int userIndex) { return userIndex + Grid.EXTRA_CELLS_BEFORE_GRID; } }