def board_locations_from_spinner(filename):
    """Utility function which converts a CSV file produced by
    the `spinner-ethernet-chips
    <http://spinner.readthedocs.org/en/stable/spinner-ethernet-chips.html>`_
    utility into a ``board_locations`` dictionary suitable for defining
    :py:class:`.Machine` objects.

    Parameters
    ----------
    filename : str
        The name of a CSV file produced by spinner-ethernet-chips defining the
        relationship between Ethernet connected chip coordinates and physical
        board locations.

        This file is expected to have five columns (named in the first line of
        the CSV) named 'board', 'cabinet', 'frame', 'x', and 'y'.

    Returns
    -------
    {(x, y, z): (c, f, b), ...}
        The mapping from board coordinates to physical locations.
    """
    # Extract lookup from Ethernet connected chips to locations
    chip_locations = {}
    with open(filename, "r") as f:
        for entry in csv.DictReader(f):
            cfb = tuple(map(int, (entry["cabinet"],
                                  entry["frame"],
                                  entry["board"])))

            chip_xy = (int(entry["x"]), int(entry["y"]))

            assert chip_xy not in chip_locations
            chip_locations[chip_xy] = cfb

    # Infer machine dimensions
    max_x, max_y = map(max, zip(*chip_locations))
    width_triads = (max_x // 12) + 1
    height_triads = (max_y // 12) + 1

    # Convert from chip to board coordinates
    return {
        chip_to_board(chip_x, chip_y, width_triads * 12, height_triads * 12):
        cfb
        for (chip_x, chip_y), cfb in iteritems(chip_locations)
    }
Example #2
0
    def where_is(self, **kwargs):
        """Find out where a SpiNNaker board or chip is located, logically and
        physically.

        May be called in one of the following styles::

            >>> # Query by logical board coordinate within a machine.
            >>> where_is(machine=..., x=..., y=..., z=...)

            >>> # Query by physical board location within a machine.
            >>> where_is(machine=..., cabinet=..., frame=..., board=...)

            >>> # Query by chip coordinate (as if the machine were booted as
            >>> # one large machine).
            >>> where_is(machine=..., chip_x=..., chip_y=...)

            >>> # Query by chip coordinate, within the boards allocated to a
            >>> # job.
            >>> where_is(job_id=..., chip_x=..., chip_y=...)

        Returns
        -------
        {"machine": ..., "logical": ..., "physical": ..., "chip": ..., \
                "board_chip": ..., "job_chip": ..., "job_id": ...} or None
            If a board exists at the supplied location, a dictionary giving the
            location of the board/chip, supplied in a number of alternative
            forms. If the supplied coordinates do not specify a specific chip,
            the chip coordinates given are those of the Ethernet connected chip
            on that board.

            If no board exists at the supplied position, None is returned
            instead.

            ``machine`` gives the name of the machine containing the board.

            ``logical`` the logical board coordinate, (x, y, z) within the
            machine.

            ``physical`` the physical board location, (cabinet, frame, board),
            within the machine.

            ``chip`` the coordinates of the chip, (x, y), if the whole machine
            were booted as a single machine.

            ``board_chip`` the coordinates of the chip, (x, y), within its
            board.

            ``job_id`` is the job ID of the job currently allocated to the
            board identified or None if the board is not allocated to a job.

            ``job_chip`` the coordinates of the chip, (x, y), within its
            job, if a job is allocated to the board or None otherwise.
        """
        with self._lock:
            # Initially, we normalise the input coordinate into:
            #
            #     machine_name, chip_x, chip_y
            #
            # and then convert this back into all the output formats required.
            # At various points, if we encounter a board/job/chip which doesn't
            # exist we'll drop out.

            keywords = set(kwargs)
            if keywords == set("machine x y z".split()):
                # Covert from logical position
                machine_name = kwargs["machine"]
                chip_x, chip_y = board_to_chip(
                    kwargs["x"], kwargs["y"], kwargs["z"])
            elif keywords == set("machine cabinet frame board".split()):
                # Covert from physical position (fail if location does not
                # exist)
                machine_name = kwargs["machine"]
                xyz = self.get_board_at_position(machine_name,
                                                 kwargs["cabinet"],
                                                 kwargs["frame"],
                                                 kwargs["board"])
                if xyz is None:
                    return None
                chip_x, chip_y = board_to_chip(*xyz)
            elif keywords == set("machine chip_x chip_y".split()):
                # Covert from chip location
                machine_name = kwargs["machine"]
                chip_x = kwargs["chip_x"]
                chip_y = kwargs["chip_y"]
            elif keywords == set("job_id chip_x chip_y".split()):
                # Covert from job-relative chip location
                job = self._jobs.get(kwargs["job_id"], None)
                if job is None or job.boards is None:
                    return None
                machine_name = job.allocated_machine.name
                job_x, job_y, job_z = map(min, zip(*job.boards))
                dx, dy = board_to_chip(job_x, job_y, job_z)
                chip_x = kwargs["chip_x"] + dx
                chip_y = kwargs["chip_y"] + dy

                # NB: We double-check later that this coordinate is actually a
                # board within the boards allocated to the job!
            else:
                raise TypeError(
                    "Invalid arguments: {}".format(", ".join(keywords)))

            # Get the actual Machine
            machine = self._machines.get(machine_name, None)
            if machine is None:
                return None

            # Compensate chip coordinates for wrap-around
            chip_w, chip_h = triad_dimensions_to_chips(
                self._machines[machine_name].width,
                self._machines[machine_name].height,
                WrapAround.both)
            chip_x %= chip_w
            chip_y %= chip_h

            # Determine the chip within the board
            # Workaround: spinn5_chip_coord (until at least Rig 0.13.2) returns
            # numpy integer types which are not JSON serialiseable.
            board_chip_x, board_chip_y = map(
                int, spinn5_chip_coord(chip_x, chip_y))

            # Determine the logical board coordinates (and compensate for
            # wrap-around)
            x, y, z = chip_to_board(chip_x, chip_y, chip_w, chip_h)

            # Determine the board's physical location (fail if board does not
            # exist)
            cfb = self.get_board_position(machine_name, x, y, z)
            if cfb is None:
                return None
            cabinet, frame, board = cfb

            # Determine what job is running on that board
            for job_id, job in iteritems(self._jobs):
                # NB: If machine is defined, boards must also be defined.
                if (job.allocated_machine == machine and
                        (x, y, z) in job.boards):
                    # Found the job
                    break
            else:
                # No job is allocated to the board
                job_id = None
                job = None

            # If selected by job, make sure the board found is actually running
            # that job (this won't be the case, e.g. if a user specifies a
            # board within their machine which is actually dead or allocated to
            # a neighbouring job)
            if "job_id" in kwargs and job_id != kwargs["job_id"]:
                return None

            # Determine chip coordinate within job
            if job is not None:
                # Determine the board coordinate within the job
                job_x, job_y, job_z = map(min, zip(*job.boards))
                job_x = x - job_x
                job_y = y - job_y
                job_z = z - job_z

                # Turn that into a chip coordinate and wrap-around according to
                # the boards actually available in the allocated machine
                job_chip_x, job_chip_y = board_to_chip(job_x, job_y, job_z)
                job_chip = ((job_chip_x + board_chip_x) % job.width,
                            (job_chip_y + board_chip_y) % job.height)
            else:
                job_chip = None

            return {
                "machine": machine_name,
                "logical": (x, y, z),
                "physical": (cabinet, frame, board),
                "chip": (chip_x, chip_y),
                "board_chip": (board_chip_x, board_chip_y),
                "job_id": job_id,
                "job_chip": job_chip,
            }
Example #3
0
def test_chip_to_board(bxyz, cxywh):
    assert chip_to_board(*cxywh) == bxyz
def test_chip_to_board(bxyz, cxywh):
    assert chip_to_board(*cxywh) == bxyz