Package org.openpixi.pixi.distributed

Source Code of org.openpixi.pixi.distributed.NeighborMap

package org.openpixi.pixi.distributed;

import org.openpixi.pixi.distributed.movement.boundary.BorderRegions;
import org.openpixi.pixi.physics.GeneralBoundaryType;
import org.openpixi.pixi.physics.movement.boundary.BoundaryRegions;
import org.openpixi.pixi.physics.util.IntBox;
import org.openpixi.pixi.physics.util.Point;


/**
* Maps boundary and border regions to neighbors.
* We distinguish border neighbors (those to whom we send data)
* and boundary neighbors (those from which we receive data).
* These neighbors are the same at the edges but different at the corners.
*
* Finds also the direction of the neighbors.
* The neighbor directions are necessary for
* correct particle position translation when sending the particle to neighbor
* and for correct mapping of border cells at one node to ghost cells at other node.
*
* While the periodic regions have the directions of their neighbors predefined in the fields
* boundaryNeighborsDirections and borderNeighborsDirections, for the hardwall regions it is
* easier to determine the direction based on the region neighbor.
*
* For the hardwall regions we can not have the directions predefined as the directions at the
* corner depend on the layout.
*
* On the other hand, we can not find the neighbor direction through the neighbor in periodic
* boundaries. For example, at the top edge of the global simulation area we want the neighbor
* direction to point upward and not downward!
*
* How do we find the neighbors?
* =============================
*
* First we determine for both types of neighbors (boundary and border) helper points
* which help us find the neighbors.
*
* For each boundary region we specify a point which belongs to the region.
* Afterwards we search the list of neighbors for the neighbor which contains the point.
* If such a neighbor is not found, it means that local simulation boundary
* is also global simulation boundary.
*
* Note that the situation differs between hardwall and periodic boundary types.
* While under periodic boundaries we always have a neighbor on each side,
* under hardwall boundaries this is not true.
*
* For border regions we also have the helper points which identify the potential neighbors.
* For each edge region one helper point is enough.
* However, the corner border regions have three helper points
* since they can have up to three neighbors,
* depending on boundary type and corner location.
*/
public class NeighborMap {

  /** Dummy neighbor ID signalizing that there is no neighbor. */
  public static final int NO_NEIGHBOR = -1;

  private IntBox[] partitions;
  private int thisWorkerID;
  private IntBox globalSimArea;
  private GeneralBoundaryType boundaryType;

  /** Maps boundary regions to neighbors. */
  private int[] boundaryNeighbors = new int[BoundaryRegions.NUM_OF_REGIONS];
  private Point[] boundaryPoints = new Point[BoundaryRegions.NUM_OF_REGIONS];
  /** Only used for periodic boundaries. */
  private Point[] boundaryNeighborsDirections = new Point[BoundaryRegions.NUM_OF_REGIONS];

  /** Maps border regions to neighbors. */
  private int[][] borderNeighbors = new int[BorderRegions.NUM_OF_REGIONS][];
  private Point[][] borderPoints = new Point[BorderRegions.NUM_OF_REGIONS][];
  /** Only used for periodic boundaries. */
  private Point[][] borderNeighborsDirections = new Point[BorderRegions.NUM_OF_REGIONS][];


  public int getBoundaryNeighbor(int region) {
    return boundaryNeighbors[region];
  }


  public int[] getBorderNeighbors(int region) {
    return borderNeighbors[region];
  }


  public Point getBoundaryNeighborsDirections(int region) {
    if (boundaryType == GeneralBoundaryType.Periodic) {
      return  boundaryNeighborsDirections[region];
    }
    else {
      return getNeighborDirection(getBoundaryNeighbor(region));
    }
  }


  public Point[] getBorderNeighborsDirections(int region) {
    if (boundaryType == GeneralBoundaryType.Periodic) {
      return borderNeighborsDirections[region];
    }
    else
    {
      int[] neighbors = getBorderNeighbors(region);
      Point[] directions = new Point[neighbors.length];
      for (int i = 0; i < neighbors.length; ++i) {
        directions[i] = getNeighborDirection(neighbors[i]);
      }
      return directions;
    }
  }


  public NeighborMap(int thisWorkerID, IntBox[] partitions,
                     IntBox globalSimArea, GeneralBoundaryType boundaryType) {
    this.partitions = partitions;
    this.thisWorkerID = thisWorkerID;
    this.globalSimArea = globalSimArea;
    this.boundaryType = boundaryType;

    initBoundaryNeighbors();
    initBoundaryPoints(partitions[thisWorkerID]);
    initBoundaryNeighborsDirections(partitions[thisWorkerID]);

    initBorderNeighbors();
    initBorderPoints(partitions[thisWorkerID]);
    initBorderNeighborsDirections(partitions[thisWorkerID]);

    if (boundaryType == GeneralBoundaryType.Hardwall) {
      setHardwallBoundaryNeighbors();
      setHardwallBorderNeighbors();
    } else if (boundaryType == GeneralBoundaryType.Periodic) {
      setPeriodicBoundaryNeighbors();
      setPeriodicBorderNeighbors();
    } else {
      throw new RuntimeException("Unsupported boundary type!");
    }
  }


  private void initBoundaryNeighbors() {
    for (int region = 0; region < BoundaryRegions.NUM_OF_REGIONS; ++region) {
      boundaryNeighbors[region] = NO_NEIGHBOR;
    }
  }


  private void initBorderNeighbors() {
    for (int region = 0; region < BorderRegions.NUM_OF_REGIONS; ++region) {
      borderNeighbors[region] = new int[] {};
    }
  }


  private void initBoundaryPoints(IntBox partition) {

    int xmid = partition.xmin() + partition.xsize() / 2;
    int ymid = partition.ymin() + partition.ysize() / 2;

    boundaryPoints[BoundaryRegions.X_MIN + BoundaryRegions.Y_MIN] =
        new Point(partition.xmin() - 1, partition.ymin() - 1);
    boundaryPoints[BoundaryRegions.X_MIN + BoundaryRegions.Y_CENTER] =
        new Point(partition.xmin() - 1, ymid);
    boundaryPoints[BoundaryRegions.X_MIN + BoundaryRegions.Y_MAX] =
        new Point(partition.xmin() - 1, partition.ymax() + 1);

    boundaryPoints[BoundaryRegions.X_CENTER + BoundaryRegions.Y_MIN] =
        new Point(xmid, partition.ymin() - 1);
    // The point for the center region remains null.
    boundaryPoints[BoundaryRegions.X_CENTER + BoundaryRegions.Y_MAX] =
        new Point(xmid, partition.ymax() + 1);

    boundaryPoints[BoundaryRegions.X_MAX + BoundaryRegions.Y_MIN] =
        new Point(partition.xmax() + 1, partition.ymin() - 1);
    boundaryPoints[BoundaryRegions.X_MAX + BoundaryRegions.Y_CENTER] =
        new Point(partition.xmax() + 1, ymid);
    boundaryPoints[BoundaryRegions.X_MAX + BoundaryRegions.Y_MAX] =
        new Point(partition.xmax() + 1, partition.ymax() + 1);
  }


  private void initBoundaryNeighborsDirections(IntBox partition) {

    boundaryNeighborsDirections[BoundaryRegions.X_MIN + BoundaryRegions.Y_MIN] =
        new Point(-1, -1);
    boundaryNeighborsDirections[BoundaryRegions.X_MIN + BoundaryRegions.Y_CENTER] =
        new Point(-1, 0);
    boundaryNeighborsDirections[BoundaryRegions.X_MIN + BoundaryRegions.Y_MAX] =
        new Point(-1, +1);

    boundaryNeighborsDirections[BoundaryRegions.X_CENTER + BoundaryRegions.Y_MIN] =
        new Point(0, -1);
    boundaryNeighborsDirections[BoundaryRegions.X_CENTER + BoundaryRegions.Y_MAX] =
        new Point(0, +1);

    boundaryNeighborsDirections[BoundaryRegions.X_MAX + BoundaryRegions.Y_MIN] =
        new Point(+1, -1);
    boundaryNeighborsDirections[BoundaryRegions.X_MAX + BoundaryRegions.Y_CENTER] =
        new Point(+1, 0);
    boundaryNeighborsDirections[BoundaryRegions.X_MAX + BoundaryRegions.Y_MAX] =
        new Point(+1, +1);
  }


  private void initBorderPoints(IntBox partition) {

    /*
     * Corner points - can have up to 3 neighbors => 3 points to identify the neighbors.
     * The first point always identifies the corner neighbor.
     */

    borderPoints[BorderRegions.X_BORDER_MIN + BorderRegions.Y_BORDER_MIN] =
        new Point[] {
            new Point(partition.xmin() - 1, partition.ymin() - 1),
            new Point(partition.xmin(), partition.ymin() - 1),
            new Point(partition.xmin() - 1, partition.ymin())
        };

    borderPoints[BorderRegions.X_BORDER_MIN + BorderRegions.Y_BORDER_MAX] =
        new Point[] {
            new Point(partition.xmin() - 1, partition.ymax() + 1),
            new Point(partition.xmin(), partition.ymax() + 1),
            new Point(partition.xmin() - 1, partition.ymax())
        };

    borderPoints[BorderRegions.X_BORDER_MAX + BorderRegions.Y_BORDER_MIN] =
        new Point[] {
            new Point(partition.xmax() + 1, partition.ymin() - 1),
            new Point(partition.xmax(), partition.ymin() - 1),
            new Point(partition.xmax() + 1, partition.ymin())
        };

    borderPoints[BorderRegions.X_BORDER_MAX + BorderRegions.Y_BORDER_MAX] =
        new Point[] {
            new Point(partition.xmax() + 1, partition.ymax() + 1),
            new Point(partition.xmax(), partition.ymax() + 1),
            new Point(partition.xmax() + 1, partition.ymax())
        };

    /*
     * Outside hardwall corner points (only needed at the edges of the global simulation).
     * It is important to note that for region X_BORDER_MIN + Y_BOUNDARY_MIN (region 1)
     * the point which identifies the neighbor is from region X_BOUNDARY_MIN + Y_BORDER_MIN
     * (region 2). In another words, the data from region 1 needs to be sent to region 2.
     */

    borderPoints[BorderRegions.X_BORDER_MIN + BorderRegions.Y_BOUNDARY_MIN] =
        new Point[] { new Point(partition.xmin() - 1, partition.ymin()) };
    borderPoints[BorderRegions.X_BORDER_MAX + BorderRegions.Y_BOUNDARY_MIN] =
        new Point[] { new Point(partition.xmax() + 1, partition.ymin()) };

    borderPoints[BorderRegions.X_BORDER_MIN + BorderRegions.Y_BOUNDARY_MAX] =
        new Point[] { new Point(partition.xmin() - 1, partition.ymax()) };
    borderPoints[BorderRegions.X_BORDER_MAX + BorderRegions.Y_BOUNDARY_MAX] =
        new Point[] { new Point(partition.xmax() + 1, partition.ymax()) };

    borderPoints[BorderRegions.X_BOUNDARY_MIN + BorderRegions.Y_BORDER_MIN] =
        new Point[] { new Point(partition.xmin(), partition.ymin() - 1) };
    borderPoints[BorderRegions.X_BOUNDARY_MIN + BorderRegions.Y_BORDER_MAX] =
        new Point[] { new Point(partition.xmin(), partition.ymax() + 1) };

    borderPoints[BorderRegions.X_BOUNDARY_MAX + BorderRegions.Y_BORDER_MIN] =
        new Point[] { new Point(partition.xmax(), partition.ymin() - 1) };
    borderPoints[BorderRegions.X_BOUNDARY_MAX + BorderRegions.Y_BORDER_MAX] =
        new Point[] { new Point(partition.xmax(), partition.ymax() + 1) };

    /*
     * Edge points.
     */

    int xmid = partition.xmin() + partition.xsize() / 2;
    int ymid = partition.ymin() + partition.ysize() / 2;

    borderPoints[BorderRegions.X_BORDER_MIN + BorderRegions.Y_CENTER] =
        new Point[] { new Point(partition.xmin() - 1, ymid) };
    borderPoints[BorderRegions.X_BORDER_MAX + BorderRegions.Y_CENTER] =
        new Point[] { new Point(partition.xmax() + 1, ymid) };
    borderPoints[BorderRegions.X_CENTER + BorderRegions.Y_BORDER_MIN] =
        new Point[] { new Point(xmid, partition.ymin() - 1) };
    borderPoints[BorderRegions.X_CENTER + BorderRegions.Y_BORDER_MAX] =
        new Point[] { new Point(xmid, partition.ymax() + 1) };
  }


  private void initBorderNeighborsDirections(IntBox partition) {

    // Corner neighbors directions

    borderNeighborsDirections[BorderRegions.X_BORDER_MIN + BorderRegions.Y_BORDER_MIN] =
        new Point[] {
            new Point(-1,  -1),
            new Point(0, -1),
            new Point(-1, 0)
        };

    borderNeighborsDirections[BorderRegions.X_BORDER_MIN + BorderRegions.Y_BORDER_MAX] =
        new Point[] {
            new Point(-1, +1),
            new Point(0, +1),
            new Point(-1, 0)
        };

    borderNeighborsDirections[BorderRegions.X_BORDER_MAX + BorderRegions.Y_BORDER_MIN] =
        new Point[] {
            new Point(+1, -1),
            new Point(0, -1),
            new Point(+1, 0)
        };

    borderNeighborsDirections[BorderRegions.X_BORDER_MAX + BorderRegions.Y_BORDER_MAX] =
        new Point[] {
            new Point(+1, +1),
            new Point(0, +1),
            new Point(+1, 0)
        };

    // Edge neighbors

    borderNeighborsDirections[BorderRegions.X_BORDER_MIN + BorderRegions.Y_CENTER] =
        new Point[] { new Point(-1, 0) };
    borderNeighborsDirections[BorderRegions.X_BORDER_MAX + BorderRegions.Y_CENTER] =
        new Point[] { new Point(+1, 0) };
    borderNeighborsDirections[BorderRegions.X_CENTER + BorderRegions.Y_BORDER_MIN] =
        new Point[] { new Point(0, -1) };
    borderNeighborsDirections[BorderRegions.X_CENTER + BorderRegions.Y_BORDER_MAX] =
        new Point[] { new Point(0, +1) };
  }


  private void setHardwallBoundaryNeighbors() {

    // Map edge neighbors
    for (int region: BoundaryRegions.EDGE_REGIONS) {
      Point p = boundaryPoints[region];
      int workerID = findNeighborByPoint(p);
      boundaryNeighbors[region] = workerID;
      }

    /*
     * Map corner regions to neighbors.
     * If the true corner neighbor does not exist the region should be mapped to
     * left, right, bottom or top neighbor (if one of them exists;
     * in the corner of the global simulation area there is no neighbor).
     */

    for (int region: BoundaryRegions.CORNER_REGIONS) {
      Point p = boundaryPoints[region];
      int workerID = findNeighborByPoint(p);
      if (workerID == NO_NEIGHBOR) {
        workerID = findNeighborAroundPoint(p);
      }
      boundaryNeighbors[region] = workerID;
    }
  }


  private void setHardwallBorderNeighbors() {

    // Map edge neighbors
    for (int region: BorderRegions.EDGE_REGIONS) {
      Point[] points = borderPoints[region];
      assert points.length == 1;
      int workerID = findNeighborByPoint(points[0]);
      borderNeighbors[region] = new int[] {workerID};
      if (workerID == NO_NEIGHBOR) {
        borderNeighborsDirections[region] = new Point[] {};
      }
    }

    // Map corner neighbors
    for (int region: BorderRegions.CORNER_REGIONS) {
      Point[] points = borderPoints[region];
      assert points.length == 3;
      int[] allNeighbors = new int[points.length];
      for (int i = 0; i < points.length; ++i) {
        int workerID = findNeighborByPoint(points[i]);
        allNeighbors[i] = workerID;
        }
      borderNeighbors[region] = allNeighbors;

      // If there is no true corner neighbor we also need to map the border regions
      // lying outside of the simulation area.
      // If there is a true corner we map the outside corner regions to NO_NEIGHBOR.
      for (int i = 1; i < points.length; ++i) {
        int outsideRegion = findOutsideBorderRegionByPoint(points[i]);
        borderNeighbors[outsideRegion] = new int[] {NO_NEIGHBOR};
      }
      if (allNeighbors[0] == NO_NEIGHBOR) {
        for (int i = 1; i < points.length; ++i) {
          if (allNeighbors[i] != NO_NEIGHBOR) {
            int outsideRegion = findOutsideBorderRegionByPoint(points[i]);
            borderNeighbors[outsideRegion][0] = allNeighbors[i];
          }
        }
      }
    }
  }


  private void setPeriodicBoundaryNeighbors() {

    for (int region: BoundaryRegions.EDGE_REGIONS) {
      setSinglePeriodicBoundaryNeighbor(region);
    }

    for (int region: BoundaryRegions.CORNER_REGIONS) {
      setSinglePeriodicBoundaryNeighbor(region);
    }
  }


  private void setSinglePeriodicBoundaryNeighbor(int region) {
    Point p = boundaryPoints[region];
    applyPeriodicBoundary(p);

    int workerID = findNeighborByPoint(p);
    assert workerID != NO_NEIGHBOR;

    boundaryNeighbors[region] = workerID;
  }


  private void setPeriodicBorderNeighbors() {

    for (int region: BorderRegions.EDGE_REGIONS) {
      setSinglePeriodicBorderNeighbor(region);
    }

    for (int region: BorderRegions.CORNER_REGIONS) {
      setSinglePeriodicBorderNeighbor(region);
    }

    // Outside corner regions are not used under periodic boundaries
    for (int region: BorderRegions.OUTSIDE_CORNER_REGIONS) {
      borderNeighbors[region] = new int[] {NO_NEIGHBOR};
    }
  }


  private void setSinglePeriodicBorderNeighbor(int region) {
    Point[] points = borderPoints[region];
    int[] allNeighbors = new int[points.length];

    for (int i = 0; i < points.length; ++i) {
      applyPeriodicBoundary(points[i]);

      int workerID = findNeighborByPoint(points[i]);
      assert workerID != NO_NEIGHBOR;

      allNeighbors[i] = workerID;
    }
    borderNeighbors[region] = allNeighbors;
  }


  private int findOutsideBorderRegionByPoint(Point point) {
    for (int region: BorderRegions.OUTSIDE_CORNER_REGIONS) {
      for (Point p: borderPoints[region]) {
        if (p.equals(point)) {
          return region;
        }
      }
    }
    throw new RuntimeException("Could not find outside corner border region for point: "
        + point);
  }


  private int findNeighborAroundPoint(Point p) {
    for (Point sp: getSurroundingPoints(p)) {
      int workerID = findNeighborByPoint(sp);
      if (workerID != NO_NEIGHBOR) {
        return workerID;
      }
    }
    return NO_NEIGHBOR;
  }


  private Point[] getSurroundingPoints(Point p) {
    return new Point[] {
        new Point(p.x - 1, p.y), new Point(p.x + 1, p.y),
        new Point(p.x, p.y - 1), new Point(p.x, p.y + 1)
    };
  }


  private int findNeighborByPoint(Point p) {
    for (int i = 0; i < partitions.length; ++i) {
      if (partitions[i].contains(p.x, p.y)) {
        return i;
      }
    }
    return NO_NEIGHBOR;
  }


  private Point getNeighborDirection(int neighbor) {
    if (neighbor == NO_NEIGHBOR) {
      return null;
    }

    IntBox myPart = partitions[thisWorkerID];
    IntBox neighborPart = partitions[neighbor];

    int xdirec = 0;
    int ydirec = 0;

    if (myPart.xmax() < neighborPart.xmin()) {
      xdirec = +1;
    }
    else if (neighborPart.xmax() < myPart.xmin()) {
      xdirec = -1;
    }

    if (myPart.ymax() < neighborPart.ymin()) {
      ydirec = +1;
    }
    else if (neighborPart.ymax() < myPart.ymin()) {
      ydirec = -1;
    }

    return new Point(xdirec, ydirec);
  }


  private void applyPeriodicBoundary(Point p) {

    if (p.x < globalSimArea.xmin()) {
      p.x += globalSimArea.xsize();
    } else if (p.x > globalSimArea.xmax()) {
      p.x -= globalSimArea.xsize();
    }

    if (p.y < globalSimArea.ymin()) {
      p.y += globalSimArea.ysize();
    } else if (p.y > globalSimArea.ymax()) {
      p.y -= globalSimArea.ysize();
    }
  }
}
TOP

Related Classes of org.openpixi.pixi.distributed.NeighborMap

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.