<commit_before># -*- coding: utf-8 -*-
from __future__ import print_function

import numpy as np
import pyqtgraph as pg
from pyqtgraph import ptime, Transform3D, solve3DTransform

from acq4.util import Qt
from acq4.drivers.sensapex import UMP
from ..Stage import Stage, MoveFuture, CalibrationWindow

class Sensapex(Stage):
    """
    A Sensapex manipulator.
    """

    _sigRestartUpdateTimer = Qt.Signal(object)  # timeout duration

    devices = {}

    def __init__(self, man, config, name):
        self.devid = config.get("deviceId")
        self.scale = config.pop("scale", (1e-6, 1e-6, 1e-6))
        self.xPitch = config.pop("xPitch", 0)  # angle of x-axis. 0=parallel to xy plane, 90=pointing downward
        self.maxMoveError = config.pop("maxError", 1e-6)

        address = config.pop("address", None)
        address = None if address is None else address.encode()
        group = config.pop("group", None)
        if man.config.get("drivers", {}).get("sensapex", {}).get("driverPath", None) is not None:
            UMP.set_library_path(man.config["drivers"]["sensapex"]["driverPath"])
        ump = UMP.get_ump(address=address, group=group)
        # create handle to this manipulator
        self.dev = ump.get_device(self.devid)

        Stage.__init__(self, man, config, name)
        # Read position updates on a timer to rate-limit
        self._updateTimer = Qt.QTimer()
        self._updateTimer.timeout.connect(self._getPosition)
        self._lastUpdate = 0

        self._sigRestartUpdateTimer.connect(self._restartUpdateTimer)

        # note: n_axes is used in cases where the device is not capable of answering this on its own
        if "nAxes" in config:
            self.dev.set_n_axes(config["nAxes"])
        if "maxAcceeration" in config:
            self.dev.set_max_acceleration(config["maxAcceleration"])

        self.dev.add_callback(self._positionChanged)

        # force cache update for this device.
        # This should also verify that we have a valid device ID
        self.dev.get_pos()

        self._lastMove = None
        man.sigAbortAll.connect(self.stop)

        # clear cached position for this device and re-read to generate an initial position update
        self._lastPos = None
        self.getPosition(refresh=True)

        # TODO: set any extra parameters specified in the config
        Sensapex.devices[self.devid] = self

    def axes(self):
        return "x", "y", "z"

    def capabilities(self):
        """Return a structure describing the capabilities of this device"""
        if "capabilities" in self.config:
            return self.config["capabilities"]
        else:
            return {
                "getPos": (True, True, True),
                "setPos": (True, True, True),
                "limits": (False, False, False),
            }

    def axisTransform(self):
        if self._axisTransform is None:
            # sensapex manipulators do not have orthogonal axes, so we set up a 3D transform to compensate:
            a = self.xPitch * np.pi / 180.0
            s = self.scale
            pts1 = np.array([  # unit vector in sensapex space
                [0, 0, 0],
                [1, 0, 0],
                [0, 1, 0],
                [0, 0, 1],
            ])
            pts2 = np.array([  # corresponding vector in global space
                [0, 0, 0],
                [s[0] * np.cos(a), 0, -s[0] * np.sin(a)],
                [0, s[1], 0],
                [0, 0, s[2]],
            ])
            tr = solve3DTransform(pts1, pts2)
            tr[3, 3] = 1
            self._axisTransform = Transform3D(tr)
            self._inverseAxisTransform = None
        return self._axisTransform

    def stop(self):
        """Stop the manipulator immediately.
        """
        with self.lock:
            self.dev.stop()
            self._lastMove = None

    def _getPosition(self):
        # Called by superclass when user requests position refresh
        with self.lock:
            # using timeout=0 forces read from cache (the monitor thread ensures
            # these values are up to date)
            pos = self.dev.get_pos(timeout=0)[:3]
            self._lastUpdate = ptime.time()
            if self._lastPos is not None:
                dif = np.linalg.norm(np.array(pos, dtype=float) - np.array(self._lastPos, dtype=float))

            # do not report changes < 100 nm
            if self._lastPos is None or dif > 0.1:
                self._lastPos = pos
                emit = True
            else:
                emit = False

        if emit:
            # don't emit signal while locked
            self.posChanged(pos)

        return pos

    def _positionChanged(self, dev, newPos, oldPos):
        # called by driver poller when position has changed
        now = ptime.time()
        # rate limit updates to 10 Hz
        wait = 100e-3 - (now - self._lastUpdate)
        if wait > 0:
            self._sigRestartUpdateTimer.emit(wait)
        else:
            self._getPosition()

    def _restartUpdateTimer(self, wait):
        self._updateTimer.start(int(wait * 1000))

    def targetPosition(self):
        with self.lock:
            if self._lastMove is None or self._lastMove.isDone():
                return self.getPosition()
            else:
                return self._lastMove.targetPos

    def quit(self):
        Sensapex.devices.pop(self.devid, None)
        if len(Sensapex.devices) == 0:
            UMP.get_ump().poller.stop()
        Stage.quit(self)

    def _move(self, abs, rel, speed, linear):
        with self.lock:
            pos = self._toAbsolutePosition(abs, rel)
            speed = self._interpretSpeed(speed)
            self._lastMove = SensapexMoveFuture(self, pos, speed)
            return self._lastMove

    def deviceInterface(self, win):
        return SensapexInterface(self, win)

class SensapexMoveFuture(MoveFuture):
    """Provides access to a move-in-progress on a Sensapex manipulator.
    """

    def __init__(self, dev, pos, speed):
        MoveFuture.__init__(self, dev, pos, speed)
        self._interrupted = False
        self._errorMsg = None
        self._finished = False
        self._moveReq = self.dev.dev.goto_pos(pos, speed * 1e6)
        self._checked = False

    def wasInterrupted(self):
        """Return True if the move was interrupted before completing.
        """
        return self._moveReq.interrupted

    def isDone(self):
        """Return True if the move is complete.
        """
        return self._moveReq.finished

    def _checkError(self):
        if self._checked or not self.isDone():
            return

        # interrupted?
        if self._moveReq.interrupted:
            self._errorMsg = self._moveReq.interrupt_reason
        else:
            # did we reach target?
            pos = self._moveReq.last_pos
            dif = np.linalg.norm(np.array(pos) - np.array(self.targetPos))
            if dif > self.dev.maxMoveError * 1e9:  # require 1um accuracy
                # missed
                self._errorMsg = "{} stopped before reaching target (start={}, target={}, position={}, dif={}, speed={}).".format(
                    self.dev.name(), self.startPos, self.targetPos, pos, dif, self.speed
                )

        self._checked = True

    def wait(self, timeout=None, updates=False):
        """Block until the move has completed, has been interrupted, or the
        specified timeout has elapsed.

        If *updates* is True, process Qt events while waiting.

        If the move did not complete, raise an exception.
        """
        if updates is False:
            # if we don't need gui updates, then block on the finished_event for better performance
            if not self._moveReq.finished_event.wait(timeout=timeout):
                raise self.Timeout("Timed out waiting for %s move to complete." % self.dev.name())
            self._raiseError()
        else:
            return MoveFuture.wait(self, timeout=timeout, updates=updates)

    def errorMessage(self):
        self._checkError()
        return self._errorMsg

# class SensapexGUI(StageInterface):
#     def __init__(self, dev, win):
#         StageInterface.__init__(self, dev, win)
#
#         # Insert Sensapex-specific controls into GUI
#         self.zeroBtn = Qt.QPushButton('Zero position')
#         self.layout.addWidget(self.zeroBtn, self.nextRow, 0, 1, 2)
#         self.nextRow += 1
#
#         self.psGroup = Qt.QGroupBox('Rotary Controller')
#         self.layout.addWidget(self.psGroup, self.nextRow, 0, 1, 2)
#         self.nextRow += 1
#
#         self.psLayout = Qt.QGridLayout()
#         self.psGroup.setLayout(self.psLayout)
#         self.speedLabel = Qt.QLabel('Speed')
#         self.speedSpin = SpinBox(value=self.dev.userSpeed, suffix='m/turn', siPrefix=True, dec=True, limits=[1e-6, 10e-3])
#         self.psLayout.addWidget(self.speedLabel, 0, 0)
#         self.psLayout.addWidget(self.speedSpin, 0, 1)
#
#         self.zeroBtn.clicked.connect(self.dev.dev.zeroPosition)
#         self.speedSpin.valueChanged.connect(lambda v: self.dev.setDefaultSpeed(v))

class SensapexInterface(Qt.QWidget):
    def __init__(self, dev, win):
        Qt.QWidget.__init__(self)
        self.win = win
        self.dev = dev

        self.layout = Qt.QGridLayout()
        self.setLayout(self.layout)
        self.axCtrls = {}
        self.posLabels = {}

        self.positionLabelWidget = Qt.QWidget()
        self.layout.addWidget(self.positionLabelWidget, 0, 0)
        self.positionLabelLayout = Qt.QGridLayout()
        self.positionLabelWidget.setLayout(self.positionLabelLayout)
        self.positionLabelLayout.setContentsMargins(0, 0, 0, 0)

        self.globalLabel = Qt.QLabel("global")
        self.positionLabelLayout.addWidget(self.globalLabel, 0, 1)
        self.stageLabel = Qt.QLabel("stage")
        self.positionLabelLayout.addWidget(self.stageLabel, 0, 2)

        self.btnContainer = Qt.QWidget()
        self.btnLayout = Qt.QGridLayout()
        self.btnContainer.setLayout(self.btnLayout)
        self.layout.addWidget(self.btnContainer, self.layout.rowCount(), 0)
        self.btnLayout.setContentsMargins(0, 0, 0, 0)

        self.goHomeBtn = Qt.QPushButton("Home")
        self.btnLayout.addWidget(self.goHomeBtn, 0, 0)
        self.goHomeBtn.clicked.connect(self.goHomeClicked)

        self.setHomeBtn = Qt.QPushButton("Set Home")
        self.btnLayout.addWidget(self.setHomeBtn, 0, 1)
        self.setHomeBtn.clicked.connect(self.setHomeClicked)

        self.calibrateBtn = Qt.QPushButton("Calibrate")
        self.btnLayout.addWidget(self.calibrateBtn, 0, 2)
        self.calibrateBtn.clicked.connect(self.calibrateClicked)

        self.stopBtn = Qt.QPushButton("Stop!")
        self.btnLayout.addWidget(self.stopBtn, 1, 0)
        self.stopBtn.clicked.connect(self.stopClicked)
        self.stopBtn.setStyleSheet("QPushButton {background-color:red; color:white}")

        self.calibrateZeroBtn = Qt.QPushButton("Run Zero Calibration")
        self.btnLayout.addWidget(self.calibrateZeroBtn, 1, 1)
        self.calibrateZeroBtn.clicked.connect(self.calibrateZeroClicked)

        self.calibrateLoadBtn = Qt.QPushButton("Run Load Calibration")
        self.btnLayout.addWidget(self.calibrateLoadBtn, 1, 2)
        self.calibrateLoadBtn.clicked.connect(self.calibrateLoadClicked)

        self.softStartValue = Qt.QLineEdit()

        self.btnLayout.addWidget(self.softStartValue, 2, 1)
        self.softStartValue.editingFinished.connect(self.softstartChanged)
        self.getSoftStartValue()

        self.softStartBtn = Qt.QPushButton("Soft Start Enabled")
        self.softStartBtn.setCheckable(True)
        self.softStartBtn.setStyleSheet("QPushButton:checked{background-color:lightgreen; color:black}")
        self.btnLayout.addWidget(self.softStartBtn, 2, 0)
        self.softStartBtn.clicked.connect(self.softstartClicked)
        self.getSoftStartState()

        self.calibrateWindow = None

        cap = dev.capabilities()
        for axis, axisName in enumerate(self.dev.axes()):
            if cap["getPos"][axis]:
                axLabel = Qt.QLabel(axisName)
                axLabel.setMaximumWidth(15)
                globalPosLabel = Qt.QLabel("0")
                stagePosLabel = Qt.QLabel("0")
                self.posLabels[axis] = (globalPosLabel, stagePosLabel)
                widgets = [axLabel, globalPosLabel, stagePosLabel]
                if cap["limits"][axis]:
                    minCheck = Qt.QCheckBox("Min:")
                    minCheck.tag = (axis, 0)
                    maxCheck = Qt.QCheckBox("Max:")
                    maxCheck.tag = (axis, 1)
                    self.limitChecks[axis] = (minCheck, maxCheck)
                    widgets.extend([minCheck, maxCheck])
                    for check in (minCheck, maxCheck):
                        check.clicked.connect(self.limitCheckClicked)

                nextRow = self.positionLabelLayout.rowCount()
                for i, w in enumerate(widgets):
                    self.positionLabelLayout.addWidget(w, nextRow, i)
                self.axCtrls[axis] = widgets
        self.dev.sigPositionChanged.connect(self.update)

        self.update()

    def update(self):
        globalPos = self.dev.globalPosition()
        stagePos = self.dev.getPosition()
        for i in self.posLabels:
            text = pg.siFormat(globalPos[i], suffix="m", precision=5)
            self.posLabels[i][0].setText(text)
            self.posLabels[i][1].setText(str(stagePos[i]))

    def goHomeClicked(self):
        self.dev.goHome()

    def setHomeClicked(self):
        self.dev.setHomePosition()

    def calibrateClicked(self):
        if self.calibrateWindow is None:
            self.calibrateWindow = CalibrationWindow(self.dev)
        self.calibrateWindow.show()
        self.calibrateWindow.raise_()

    def calibrateZeroClicked(self):
        self.dev.dev.calibrate_zero_position()

    def calibrateLoadClicked(self):
        self.dev.dev.calibrate_load()

    def stopClicked(self):
        self.dev.dev.stop()

    def getSoftStartState(self):
        state = self.dev.dev.get_soft_start_state()

        if state == 1:
            self.softStartBtn.setChecked(True)
            self.softStartBtn.setText("Soft Start Enabled")
            self.softStartValue.setVisible(True)
            self.getSoftStartValue()
            return True

        self.softStartBtn.setChecked(False)
        self.softStartBtn.setText("Soft Start Disabled")
        self.softStartValue.setVisible(False)
        return False

    def softstartClicked(self):
        checked = self.getSoftStartState()
        if checked:
            self.dev.dev.set_soft_start_state(0)
        else:
            self.dev.dev.set_soft_start_state(1)

        self.getSoftStartState()

    def softstartChanged(self):
        value = int(self.softStartValue.text())
        self.dev.dev.set_soft_start_value(value)

    def getSoftStartValue(self):
        value = self.dev.dev.get_soft_start_value()
        self.softStartValue.setText(str(value))
<commit_msg>sensapex can do linear or not, but only if we tell it to<commit_after># -*- coding: utf-8 -*-
from __future__ import print_function

import numpy as np
import pyqtgraph as pg
from pyqtgraph import ptime, Transform3D, solve3DTransform

from acq4.util import Qt
from acq4.drivers.sensapex import UMP
from ..Stage import Stage, MoveFuture, CalibrationWindow

class Sensapex(Stage):
    """
    A Sensapex manipulator.
    """

    _sigRestartUpdateTimer = Qt.Signal(object)  # timeout duration

    devices = {}

    def __init__(self, man, config, name):
        self.devid = config.get("deviceId")
        self.scale = config.pop("scale", (1e-6, 1e-6, 1e-6))
        self.xPitch = config.pop("xPitch", 0)  # angle of x-axis. 0=parallel to xy plane, 90=pointing downward
        self.maxMoveError = config.pop("maxError", 1e-6)

        address = config.pop("address", None)
        address = None if address is None else address.encode()
        group = config.pop("group", None)
        if man.config.get("drivers", {}).get("sensapex", {}).get("driverPath", None) is not None:
            UMP.set_library_path(man.config["drivers"]["sensapex"]["driverPath"])
        ump = UMP.get_ump(address=address, group=group)
        # create handle to this manipulator
        self.dev = ump.get_device(self.devid)

        Stage.__init__(self, man, config, name)
        # Read position updates on a timer to rate-limit
        self._updateTimer = Qt.QTimer()
        self._updateTimer.timeout.connect(self._getPosition)
        self._lastUpdate = 0

        self._sigRestartUpdateTimer.connect(self._restartUpdateTimer)

        # note: n_axes is used in cases where the device is not capable of answering this on its own
        if "nAxes" in config:
            self.dev.set_n_axes(config["nAxes"])
        if "maxAcceeration" in config:
            self.dev.set_max_acceleration(config["maxAcceleration"])

        self.dev.add_callback(self._positionChanged)

        # force cache update for this device.
        # This should also verify that we have a valid device ID
        self.dev.get_pos()

        self._lastMove = None
        man.sigAbortAll.connect(self.stop)

        # clear cached position for this device and re-read to generate an initial position update
        self._lastPos = None
        self.getPosition(refresh=True)

        # TODO: set any extra parameters specified in the config
        Sensapex.devices[self.devid] = self

    def axes(self):
        return "x", "y", "z"

    def capabilities(self):
        """Return a structure describing the capabilities of this device"""
        if "capabilities" in self.config:
            return self.config["capabilities"]
        else:
            return {
                "getPos": (True, True, True),
                "setPos": (True, True, True),
                "limits": (False, False, False),
            }

    def axisTransform(self):
        if self._axisTransform is None:
            # sensapex manipulators do not have orthogonal axes, so we set up a 3D transform to compensate:
            a = self.xPitch * np.pi / 180.0
            s = self.scale
            pts1 = np.array([  # unit vector in sensapex space
                [0, 0, 0],
                [1, 0, 0],
                [0, 1, 0],
                [0, 0, 1],
            ])
            pts2 = np.array([  # corresponding vector in global space
                [0, 0, 0],
                [s[0] * np.cos(a), 0, -s[0] * np.sin(a)],
                [0, s[1], 0],
                [0, 0, s[2]],
            ])
            tr = solve3DTransform(pts1, pts2)
            tr[3, 3] = 1
            self._axisTransform = Transform3D(tr)
            self._inverseAxisTransform = None
        return self._axisTransform

    def stop(self):
        """Stop the manipulator immediately.
        """
        with self.lock:
            self.dev.stop()
            self._lastMove = None

    def _getPosition(self):
        # Called by superclass when user requests position refresh
        with self.lock:
            # using timeout=0 forces read from cache (the monitor thread ensures
            # these values are up to date)
            pos = self.dev.get_pos(timeout=0)[:3]
            self._lastUpdate = ptime.time()
            if self._lastPos is not None:
                dif = np.linalg.norm(np.array(pos, dtype=float) - np.array(self._lastPos, dtype=float))

            # do not report changes < 100 nm
            if self._lastPos is None or dif > 0.1:
                self._lastPos = pos
                emit = True
            else:
                emit = False

        if emit:
            # don't emit signal while locked
            self.posChanged(pos)

        return pos

    def _positionChanged(self, dev, newPos, oldPos):
        # called by driver poller when position has changed
        now = ptime.time()
        # rate limit updates to 10 Hz
        wait = 100e-3 - (now - self._lastUpdate)
        if wait > 0:
            self._sigRestartUpdateTimer.emit(wait)
        else:
            self._getPosition()

    def _restartUpdateTimer(self, wait):
        self._updateTimer.start(int(wait * 1000))

    def targetPosition(self):
        with self.lock:
            if self._lastMove is None or self._lastMove.isDone():
                return self.getPosition()
            else:
                return self._lastMove.targetPos

    def quit(self):
        Sensapex.devices.pop(self.devid, None)
        if len(Sensapex.devices) == 0:
            UMP.get_ump().poller.stop()
        Stage.quit(self)

    def _move(self, abs, rel, speed, linear):
        with self.lock:
            pos = self._toAbsolutePosition(abs, rel)
            speed = self._interpretSpeed(speed)
            self._lastMove = SensapexMoveFuture(self, pos, speed, linear)
            return self._lastMove

    def deviceInterface(self, win):
        return SensapexInterface(self, win)

class SensapexMoveFuture(MoveFuture):
    """Provides access to a move-in-progress on a Sensapex manipulator.
    """

    def __init__(self, dev, pos, speed, linear):
        MoveFuture.__init__(self, dev, pos, speed)
        self._linear = linear
        self._interrupted = False
        self._errorMsg = None
        self._finished = False
        self._moveReq = self.dev.dev.goto_pos(pos, speed * 1e6, simultaneous=linear, linear=linear)
        self._checked = False

    def wasInterrupted(self):
        """Return True if the move was interrupted before completing.
        """
        return self._moveReq.interrupted

    def isDone(self):
        """Return True if the move is complete.
        """
        return self._moveReq.finished

    def _checkError(self):
        if self._checked or not self.isDone():
            return

        # interrupted?
        if self._moveReq.interrupted:
            self._errorMsg = self._moveReq.interrupt_reason
        else:
            # did we reach target?
            pos = self._moveReq.last_pos
            dif = np.linalg.norm(np.array(pos) - np.array(self.targetPos))
            if dif > self.dev.maxMoveError * 1e9:  # require 1um accuracy
                # missed
                self._errorMsg = "{} stopped before reaching target (start={}, target={}, position={}, dif={}, speed={}).".format(
                    self.dev.name(), self.startPos, self.targetPos, pos, dif, self.speed
                )

        self._checked = True

    def wait(self, timeout=None, updates=False):
        """Block until the move has completed, has been interrupted, or the
        specified timeout has elapsed.

        If *updates* is True, process Qt events while waiting.

        If the move did not complete, raise an exception.
        """
        if updates is False:
            # if we don't need gui updates, then block on the finished_event for better performance
            if not self._moveReq.finished_event.wait(timeout=timeout):
                raise self.Timeout("Timed out waiting for %s move to complete." % self.dev.name())
            self._raiseError()
        else:
            return MoveFuture.wait(self, timeout=timeout, updates=updates)

    def errorMessage(self):
        self._checkError()
        return self._errorMsg

# class SensapexGUI(StageInterface):
#     def __init__(self, dev, win):
#         StageInterface.__init__(self, dev, win)
#
#         # Insert Sensapex-specific controls into GUI
#         self.zeroBtn = Qt.QPushButton('Zero position')
#         self.layout.addWidget(self.zeroBtn, self.nextRow, 0, 1, 2)
#         self.nextRow += 1
#
#         self.psGroup = Qt.QGroupBox('Rotary Controller')
#         self.layout.addWidget(self.psGroup, self.nextRow, 0, 1, 2)
#         self.nextRow += 1
#
#         self.psLayout = Qt.QGridLayout()
#         self.psGroup.setLayout(self.psLayout)
#         self.speedLabel = Qt.QLabel('Speed')
#         self.speedSpin = SpinBox(value=self.dev.userSpeed, suffix='m/turn', siPrefix=True, dec=True, limits=[1e-6, 10e-3])
#         self.psLayout.addWidget(self.speedLabel, 0, 0)
#         self.psLayout.addWidget(self.speedSpin, 0, 1)
#
#         self.zeroBtn.clicked.connect(self.dev.dev.zeroPosition)
#         self.speedSpin.valueChanged.connect(lambda v: self.dev.setDefaultSpeed(v))

class SensapexInterface(Qt.QWidget):
    def __init__(self, dev, win):
        Qt.QWidget.__init__(self)
        self.win = win
        self.dev = dev

        self.layout = Qt.QGridLayout()
        self.setLayout(self.layout)
        self.axCtrls = {}
        self.posLabels = {}

        self.positionLabelWidget = Qt.QWidget()
        self.layout.addWidget(self.positionLabelWidget, 0, 0)
        self.positionLabelLayout = Qt.QGridLayout()
        self.positionLabelWidget.setLayout(self.positionLabelLayout)
        self.positionLabelLayout.setContentsMargins(0, 0, 0, 0)

        self.globalLabel = Qt.QLabel("global")
        self.positionLabelLayout.addWidget(self.globalLabel, 0, 1)
        self.stageLabel = Qt.QLabel("stage")
        self.positionLabelLayout.addWidget(self.stageLabel, 0, 2)

        self.btnContainer = Qt.QWidget()
        self.btnLayout = Qt.QGridLayout()
        self.btnContainer.setLayout(self.btnLayout)
        self.layout.addWidget(self.btnContainer, self.layout.rowCount(), 0)
        self.btnLayout.setContentsMargins(0, 0, 0, 0)

        self.goHomeBtn = Qt.QPushButton("Home")
        self.btnLayout.addWidget(self.goHomeBtn, 0, 0)
        self.goHomeBtn.clicked.connect(self.goHomeClicked)

        self.setHomeBtn = Qt.QPushButton("Set Home")
        self.btnLayout.addWidget(self.setHomeBtn, 0, 1)
        self.setHomeBtn.clicked.connect(self.setHomeClicked)

        self.calibrateBtn = Qt.QPushButton("Calibrate")
        self.btnLayout.addWidget(self.calibrateBtn, 0, 2)
        self.calibrateBtn.clicked.connect(self.calibrateClicked)

        self.stopBtn = Qt.QPushButton("Stop!")
        self.btnLayout.addWidget(self.stopBtn, 1, 0)
        self.stopBtn.clicked.connect(self.stopClicked)
        self.stopBtn.setStyleSheet("QPushButton {background-color:red; color:white}")

        self.calibrateZeroBtn = Qt.QPushButton("Run Zero Calibration")
        self.btnLayout.addWidget(self.calibrateZeroBtn, 1, 1)
        self.calibrateZeroBtn.clicked.connect(self.calibrateZeroClicked)

        self.calibrateLoadBtn = Qt.QPushButton("Run Load Calibration")
        self.btnLayout.addWidget(self.calibrateLoadBtn, 1, 2)
        self.calibrateLoadBtn.clicked.connect(self.calibrateLoadClicked)

        self.softStartValue = Qt.QLineEdit()

        self.btnLayout.addWidget(self.softStartValue, 2, 1)
        self.softStartValue.editingFinished.connect(self.softstartChanged)
        self.getSoftStartValue()

        self.softStartBtn = Qt.QPushButton("Soft Start Enabled")
        self.softStartBtn.setCheckable(True)
        self.softStartBtn.setStyleSheet("QPushButton:checked{background-color:lightgreen; color:black}")
        self.btnLayout.addWidget(self.softStartBtn, 2, 0)
        self.softStartBtn.clicked.connect(self.softstartClicked)
        self.getSoftStartState()

        self.calibrateWindow = None

        cap = dev.capabilities()
        for axis, axisName in enumerate(self.dev.axes()):
            if cap["getPos"][axis]:
                axLabel = Qt.QLabel(axisName)
                axLabel.setMaximumWidth(15)
                globalPosLabel = Qt.QLabel("0")
                stagePosLabel = Qt.QLabel("0")
                self.posLabels[axis] = (globalPosLabel, stagePosLabel)
                widgets = [axLabel, globalPosLabel, stagePosLabel]
                if cap["limits"][axis]:
                    minCheck = Qt.QCheckBox("Min:")
                    minCheck.tag = (axis, 0)
                    maxCheck = Qt.QCheckBox("Max:")
                    maxCheck.tag = (axis, 1)
                    self.limitChecks[axis] = (minCheck, maxCheck)
                    widgets.extend([minCheck, maxCheck])
                    for check in (minCheck, maxCheck):
                        check.clicked.connect(self.limitCheckClicked)

                nextRow = self.positionLabelLayout.rowCount()
                for i, w in enumerate(widgets):
                    self.positionLabelLayout.addWidget(w, nextRow, i)
                self.axCtrls[axis] = widgets
        self.dev.sigPositionChanged.connect(self.update)

        self.update()

    def update(self):
        globalPos = self.dev.globalPosition()
        stagePos = self.dev.getPosition()
        for i in self.posLabels:
            text = pg.siFormat(globalPos[i], suffix="m", precision=5)
            self.posLabels[i][0].setText(text)
            self.posLabels[i][1].setText(str(stagePos[i]))

    def goHomeClicked(self):
        self.dev.goHome()

    def setHomeClicked(self):
        self.dev.setHomePosition()

    def calibrateClicked(self):
        if self.calibrateWindow is None:
            self.calibrateWindow = CalibrationWindow(self.dev)
        self.calibrateWindow.show()
        self.calibrateWindow.raise_()

    def calibrateZeroClicked(self):
        self.dev.dev.calibrate_zero_position()

    def calibrateLoadClicked(self):
        self.dev.dev.calibrate_load()

    def stopClicked(self):
        self.dev.dev.stop()

    def getSoftStartState(self):
        state = self.dev.dev.get_soft_start_state()

        if state == 1:
            self.softStartBtn.setChecked(True)
            self.softStartBtn.setText("Soft Start Enabled")
            self.softStartValue.setVisible(True)
            self.getSoftStartValue()
            return True

        self.softStartBtn.setChecked(False)
        self.softStartBtn.setText("Soft Start Disabled")
        self.softStartValue.setVisible(False)
        return False

    def softstartClicked(self):
        checked = self.getSoftStartState()
        if checked:
            self.dev.dev.set_soft_start_state(0)
        else:
            self.dev.dev.set_soft_start_state(1)

        self.getSoftStartState()

    def softstartChanged(self):
        value = int(self.softStartValue.text())
        self.dev.dev.set_soft_start_value(value)

    def getSoftStartValue(self):
        value = self.dev.dev.get_soft_start_value()
        self.softStartValue.setText(str(value))
<|endoftext|>


<commit_before>#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.
#

load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")

def graknlabs_common():
    git_repository(
        name = "graknlabs_common",
        remote = "https://github.com/graknlabs/common",
        commit = "c712b98c1ccb53661701a74b2152b6c1fa8be19e" # sync-marker: do not remove this comment, this is used for sync-dependencies by @graknlabs_common
    )

def graknlabs_dependencies():
    git_repository(
        name = "graknlabs_dependencies",
        remote = "https://github.com/graknlabs/dependencies",
        commit = "2c1c17ecf27374f603ade164f1cf2724b3c47d5d", # sync-marker: do not remove this comment, this is used for sync-dependencies by @graknlabs_dependencies
    )

def graknlabs_verification():
    git_repository(
        name = "graknlabs_verification",
        remote = "https://github.com/graknlabs/verification",
        commit = "38aa2a4486c8b820e724e738880e024ce28f9ff1"
    )
<commit_msg>Bump @graknlabs_verification<commit_after>#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.
#

load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")

def graknlabs_common():
    git_repository(
        name = "graknlabs_common",
        remote = "https://github.com/graknlabs/common",
        commit = "c712b98c1ccb53661701a74b2152b6c1fa8be19e" # sync-marker: do not remove this comment, this is used for sync-dependencies by @graknlabs_common
    )

def graknlabs_dependencies():
    git_repository(
        name = "graknlabs_dependencies",
        remote = "https://github.com/graknlabs/dependencies",
        commit = "2c1c17ecf27374f603ade164f1cf2724b3c47d5d", # sync-marker: do not remove this comment, this is used for sync-dependencies by @graknlabs_dependencies
    )

def graknlabs_verification():
    git_repository(
        name = "graknlabs_verification",
        remote = "https://github.com/graknlabs/verification",
        commit = "434b2376c7bfea1f3dbe96713765c02ac0bbe627"
    )
<|endoftext|>


<commit_before>"""
SAM alignment format. There are other tools that handles better SAM and BAM.
This script simply parses the lines in SAM into human readable fields.

http://samtools.sourceforge.net/SAM1.pdf
"""

import os.path as op
import sys
import logging

from itertools import groupby
from optparse import OptionParser

from Bio import SeqIO
from jcvi.formats.base import LineFile
from jcvi.formats.fasta import Fasta
from jcvi.utils.cbook import fill
from jcvi.assembly.base import Astat
from jcvi.apps.base import ActionDispatcher, sh, debug
debug()

class SamLine (object):

    def __init__(self, row):

        args = row.strip().split("\t")
        self.qname = args[0]
        self.flag = args[1]
        self.rname = args[2]
        self.pos = args[3]
        self.mapq = args[4]
        self.cigar = args[5]
        self.mrnm = args[6]
        self.mpos = args[7]
        self.isize = args[8]
        self.seq = args[9]
        self.qual = args[10]

    @property
    def pairline(self):
        qpos = self.cigar.split('H', 1)[0]
        return "%s:%s\t%s:%s" % (self.qname, qpos, self.rname, self.pos)

class Sam (LineFile):

    def __init__(self, filename, callback=None):

        fp = open(filename)
        for row in fp:
            if row[0] == '@':
                continue
            s = SamLine(row)
            if callback:
                callback(s)

def main():

    actions = (
        ('pair', 'parse sam file and get pairs'),
        ('chimera', 'parse sam file from `bwasw` and list multi-hit reads'),
        ('ace', 'convert sam file to ace'),
        ('index', 'convert to bam, sort and then index'),
            )

    p = ActionDispatcher(actions)
    p.dispatch(globals())

def chimera(args):
    """
    %prog index samfile

    Parse SAM file from `bwasw` and list multi-hit reads.
    """
    p = OptionParser(chimera.__doc__)
    opts, args = p.parse_args(args)
    if len(args) != 1:
        sys.exit(p.print_help())

    samfile, = args
    fp = open(samfile)

    def key_fun(x):
        if x[0] == '@':
            return x[0]
        s = SamLine(x)
        return s.qname, s.rname

    for read, samlines in groupby(fp, key=key_fun):
        nlines = len(list(samlines))
        if nlines == 1:
            continue
        print read

def index(args):
    """
    %prog index samfile/bamfile

    If SAM file, convert to BAM, sort and then index, using SAMTOOLS
    """
    p = OptionParser(index.__doc__)
    p.add_option("--fasta", dest="fasta", default=None,
            help="add @SQ header to the BAM file [default: %default]")
    p.add_option("--unique", default=False, action="store_true",
            help="only retain uniquely mapped reads [default: %default]")

    opts, args = p.parse_args(args)
    if len(args) != 1:
        sys.exit(p.print_help())

    samfile, = args
    fastafile = opts.fasta
    if fastafile:
        assert op.exists(fastafile)

    bamfile = samfile.replace(".sam", ".bam")
    if fastafile:
        faifile = fastafile + ".fai"
        if not op.exists(faifile):
            sh("samtools faidx {0}".format(fastafile))
        cmd = "samtools view -bt {0} {1} -F 4 -o {2}".\
                format(faifile, samfile, bamfile)
    else:
        cmd = "samtools view -bS {0} -F 4 -o {1}".\
                format(samfile, bamfile)

    if opts.unique:
        cmd += " -q 1"

    if samfile.endswith(".sam"):
        sh(cmd)

    prefix = bamfile.replace(".bam", "")
    sortedbamfile = prefix + ".sorted.bam"
    if op.exists(bamfile):
        sh("samtools sort {0} {1}.sorted".format(bamfile, prefix))

    if op.exists(sortedbamfile):
        sh("samtools index {0}".format(sortedbamfile))

def pair(args):
    """
    %prog pair samfile

    Parses the sam file and retrieve in pairs format,
    query:pos ref:pos
    """
    p = OptionParser(pair.__doc__)

    opts, args = p.parse_args(args)
    if len(args) != 1:
        sys.exit(p.print_help())

    def callback(s):
        print s.pairline
    sam = Sam(args[0], callback=callback)

def cigar_to_seq(a, gap='*'):
    """
    Accepts a pysam row.

    cigar alignment is presented as a list of tuples (operation,length). For
    example, the tuple [ (0,3), (1,5), (0,2) ] refers to an alignment with 3
    matches, 5 insertions and another 2 matches.

    Op BAM Description
    M 0 alignment match (can be a sequence match or mismatch)
    I 1 insertion to the reference
    D 2 deletion from the reference
    N 3 skipped region from the reference
    S 4 soft clipping (clipped sequences present in SEQ)
    H 5 hard clipping (clipped sequences NOT present in SEQ)
    P 6 padding (silent deletion from padded reference)
    = 7 sequence match
    X 8 sequence mismatch

    convert the sequence based on the cigar string. For example:
    """
    seq, cigar = a.seq, a.cigar
    start = 0
    subseqs = []
    npadded = 0
    if cigar is None:
        return None, npadded

    for operation, length in cigar:
        end = start if operation == 2 else start + length

        if operation == 0:  # match
            subseq = seq[start:end]
        elif operation == 1:  # insertion
            subseq = ""
        elif operation == 2:  # deletion
            subseq = gap * length
            npadded += length
        elif operation == 3:  # skipped
            subseq = 'N' * length
        elif operation in (4, 5):  # clip
            subseq = ""
        else:
            raise NotImplementedError

        subseqs.append(subseq)
        start = end

    return "".join(subseqs), npadded

def ace(args):
    """
    %prog ace bamfile fastafile

    convert bam format to ace format. This often allows the remapping to be
    assessed as a denovo assembly format. bam file needs to be indexed. also
    creates a .mates file to be used in amos/bambus, and .astat file to mark
    whether the contig is unique or repetitive based on A-statistics in Celera
    assembler.
    """
    p = OptionParser(ace.__doc__)
    p.add_option("--splitdir", dest="splitdir", default="outRoot",
            help="split the ace per contig to dir [default: %default]")
    p.add_option("--unpaired", dest="unpaired", default=False,
            help="remove read pairs on the same contig [default: %default]")
    p.add_option("--minreadno", dest="minreadno", default=3, type="int",
            help="minimum read numbers per contig [default: %default]")
    p.add_option("--minctgsize", dest="minctgsize", default=100, type="int",
            help="minimum contig size per contig [default: %default]")
    p.add_option("--astat", default=False, action="store_true",
            help="create .astat to list repetitiveness [default: %default]")
    p.add_option("--readids", default=False, action="store_true",
            help="create file of mapped and unmapped ids [default: %default]")

    from pysam import Samfile

    opts, args = p.parse_args(args)
    unpaired = opts.unpaired
    minreadno = opts.minreadno
    minctgsize = opts.minctgsize

    if len(args) != 2:
        sys.exit(not p.print_help())

    bamfile, fastafile = args
    astat = opts.astat
    readids = opts.readids

    f = Fasta(fastafile)
    prefix = bamfile.split(".")[0]
    acefile = prefix + ".ace"
    readsfile = prefix + ".reads"
    astatfile = prefix + ".astat"

    logging.debug("Load {0}".format(bamfile))
    s = Samfile(bamfile, "rb")

    ncontigs = s.nreferences
    genomesize = sum(x for a, x in f.itersizes())
    logging.debug("Total {0} contigs with size {1} base".format(ncontigs,
        genomesize))
    qual = "20"  # default qual

    totalreads = sum(s.count(x) for x in s.references)
    logging.debug("Total {0} reads mapped".format(totalreads))

    fw = open(acefile, "w")
    if astat:
        astatfw = open(astatfile, "w")
    if readids:
        readsfw = open(readsfile, "w")

    print >> fw, "AS {0} {1}".format(ncontigs, totalreads)
    print >> fw

    for i, contig in enumerate(s.references):
        cseq = f[contig]
        nbases = len(cseq)

        mapped_reads = [x for x in s.fetch(contig) if not x.is_unmapped]
        nreads = len(mapped_reads)

        nsegments = 0
        print >> fw, "CO {0} {1} {2} {3} U".format(contig, nbases, nreads,
                nsegments)
        print >> fw, fill(str(cseq.seq))
        print >> fw

        if astat:
            astat = Astat(nbases, nreads, genomesize, totalreads)
            print >> astatfw, "{0}\t{1:.1f}".format(contig, astat)

        text = fill([qual] * nbases, delimiter=" ", width=30)
        print >> fw, "BQ\n{0}".format(text)
        print >> fw

        rnames = []
        for a in mapped_reads:
            readname = a.qname
            rname = readname

            if readids:
                print >> readsfw, readname
            rnames.append(rname)

            strand = "C" if a.is_reverse else "U"
            paddedstart = a.pos + 1  # 0-based to 1-based
            af = "AF {0} {1} {2}".format(rname, strand, paddedstart)
            print >> fw, af

        print >> fw

        for a, rname in zip(mapped_reads, rnames):
            aseq, npadded = cigar_to_seq(a)
            if aseq is None:
                continue

            ninfos = 0
            ntags = 0
            alen = len(aseq)
            rd = "RD {0} {1} {2} {3}\n{4}".format(rname, alen, ninfos, ntags,
                    fill(aseq))
            qs = "QA 1 {0} 1 {0}".format(alen)

            print >> fw, rd
            print >> fw
            print >> fw, qs
            print >> fw

if __name__ == '__main__':
    main()
<commit_msg>add formats.sam.bcf()<commit_after>"""
SAM alignment format. There are other tools that handles better SAM and BAM.
This script simply parses the lines in SAM into human readable fields.

http://samtools.sourceforge.net/SAM1.pdf
"""

import os.path as op
import sys
import logging

from itertools import groupby
from optparse import OptionParser

from Bio import SeqIO
from jcvi.formats.base import LineFile
from jcvi.formats.fasta import Fasta
from jcvi.utils.cbook import fill
from jcvi.assembly.base import Astat
from jcvi.apps.base import ActionDispatcher, sh, debug, set_outfile
debug()

class SamLine (object):

    def __init__(self, row):

        args = row.strip().split("\t")
        self.qname = args[0]
        self.flag = args[1]
        self.rname = args[2]
        self.pos = args[3]
        self.mapq = args[4]
        self.cigar = args[5]
        self.mrnm = args[6]
        self.mpos = args[7]
        self.isize = args[8]
        self.seq = args[9]
        self.qual = args[10]

    @property
    def pairline(self):
        qpos = self.cigar.split('H', 1)[0]
        return "%s:%s\t%s:%s" % (self.qname, qpos, self.rname, self.pos)

class Sam (LineFile):

    def __init__(self, filename, callback=None):

        fp = open(filename)
        for row in fp:
            if row[0] == '@':
                continue
            s = SamLine(row)
            if callback:
                callback(s)

def main():

    actions = (
        ('pair', 'parse sam file and get pairs'),
        ('chimera', 'parse sam file from `bwasw` and list multi-hit reads'),
        ('ace', 'convert sam file to ace'),
        ('index', 'convert to bam, sort and then index'),
        ('bcf', 'run mpileup on a set of bam files'),
            )

    p = ActionDispatcher(actions)
    p.dispatch(globals())

def bcf(args):
    """
    %prog bcf fastafile bamfiles > bcffile

    Run mpileup on bam files.
    """
    p = OptionParser(bcf.__doc__)
    set_outfile(p)
    opts, args = p.parse_args(args)

    if len(args) < 2:
        sys.exit(not p.print_help())

    fastafile = args[0]
    bamfiles = args[1:]
    cmd = "samtools mpileup -P ILLUMINA -E -ugDf"
    cmd += " {0} {1}".format(fastafile, " ".join(bamfiles))
    cmd += " | bcftools view -bcvg -"
    sh(cmd, outfile=opts.outfile)

def chimera(args):
    """
    %prog index samfile

    Parse SAM file from `bwasw` and list multi-hit reads.
    """
    p = OptionParser(chimera.__doc__)
    opts, args = p.parse_args(args)
    if len(args) != 1:
        sys.exit(p.print_help())

    samfile, = args
    fp = open(samfile)

    def key_fun(x):
        if x[0] == '@':
            return x[0]
        s = SamLine(x)
        return s.qname, s.rname

    for read, samlines in groupby(fp, key=key_fun):
        nlines = len(list(samlines))
        if nlines == 1:
            continue
        print read

def index(args):
    """
    %prog index samfile/bamfile

    If SAM file, convert to BAM, sort and then index, using SAMTOOLS
    """
    p = OptionParser(index.__doc__)
    p.add_option("--fasta", dest="fasta", default=None,
            help="add @SQ header to the BAM file [default: %default]")
    p.add_option("--unique", default=False, action="store_true",
            help="only retain uniquely mapped reads [default: %default]")

    opts, args = p.parse_args(args)
    if len(args) != 1:
        sys.exit(p.print_help())

    samfile, = args
    fastafile = opts.fasta
    if fastafile:
        assert op.exists(fastafile)

    bamfile = samfile.replace(".sam", ".bam")
    if fastafile:
        faifile = fastafile + ".fai"
        if not op.exists(faifile):
            sh("samtools faidx {0}".format(fastafile))
        cmd = "samtools view -bt {0} {1} -F 4 -o {2}".\
                format(faifile, samfile, bamfile)
    else:
        cmd = "samtools view -bS {0} -F 4 -o {1}".\
                format(samfile, bamfile)

    if opts.unique:
        cmd += " -q 1"

    if samfile.endswith(".sam"):
        sh(cmd)

    prefix = bamfile.replace(".bam", "")
    sortedbamfile = prefix + ".sorted.bam"
    if op.exists(bamfile):
        sh("samtools sort {0} {1}.sorted".format(bamfile, prefix))

    if op.exists(sortedbamfile):
        sh("samtools index {0}".format(sortedbamfile))

def pair(args):
    """
    %prog pair samfile

    Parses the sam file and retrieve in pairs format,
    query:pos ref:pos
    """
    p = OptionParser(pair.__doc__)

    opts, args = p.parse_args(args)
    if len(args) != 1:
        sys.exit(p.print_help())

    def callback(s):
        print s.pairline
    sam = Sam(args[0], callback=callback)

def cigar_to_seq(a, gap='*'):
    """
    Accepts a pysam row.

    cigar alignment is presented as a list of tuples (operation,length). For
    example, the tuple [ (0,3), (1,5), (0,2) ] refers to an alignment with 3
    matches, 5 insertions and another 2 matches.

    Op BAM Description
    M 0 alignment match (can be a sequence match or mismatch)
    I 1 insertion to the reference
    D 2 deletion from the reference
    N 3 skipped region from the reference
    S 4 soft clipping (clipped sequences present in SEQ)
    H 5 hard clipping (clipped sequences NOT present in SEQ)
    P 6 padding (silent deletion from padded reference)
    = 7 sequence match
    X 8 sequence mismatch

    convert the sequence based on the cigar string. For example:
    """
    seq, cigar = a.seq, a.cigar
    start = 0
    subseqs = []
    npadded = 0
    if cigar is None:
        return None, npadded

    for operation, length in cigar:
        end = start if operation == 2 else start + length

        if operation == 0:  # match
            subseq = seq[start:end]
        elif operation == 1:  # insertion
            subseq = ""
        elif operation == 2:  # deletion
            subseq = gap * length
            npadded += length
        elif operation == 3:  # skipped
            subseq = 'N' * length
        elif operation in (4, 5):  # clip
            subseq = ""
        else:
            raise NotImplementedError

        subseqs.append(subseq)
        start = end

    return "".join(subseqs), npadded

def ace(args):
    """
    %prog ace bamfile fastafile

    convert bam format to ace format. This often allows the remapping to be
    assessed as a denovo assembly format. bam file needs to be indexed. also
    creates a .mates file to be used in amos/bambus, and .astat file to mark
    whether the contig is unique or repetitive based on A-statistics in Celera
    assembler.
    """
    p = OptionParser(ace.__doc__)
    p.add_option("--splitdir", dest="splitdir", default="outRoot",
            help="split the ace per contig to dir [default: %default]")
    p.add_option("--unpaired", dest="unpaired", default=False,
            help="remove read pairs on the same contig [default: %default]")
    p.add_option("--minreadno", dest="minreadno", default=3, type="int",
            help="minimum read numbers per contig [default: %default]")
    p.add_option("--minctgsize", dest="minctgsize", default=100, type="int",
            help="minimum contig size per contig [default: %default]")
    p.add_option("--astat", default=False, action="store_true",
            help="create .astat to list repetitiveness [default: %default]")
    p.add_option("--readids", default=False, action="store_true",
            help="create file of mapped and unmapped ids [default: %default]")

    from pysam import Samfile

    opts, args = p.parse_args(args)
    unpaired = opts.unpaired
    minreadno = opts.minreadno
    minctgsize = opts.minctgsize

    if len(args) != 2:
        sys.exit(not p.print_help())

    bamfile, fastafile = args
    astat = opts.astat
    readids = opts.readids

    f = Fasta(fastafile)
    prefix = bamfile.split(".")[0]
    acefile = prefix + ".ace"
    readsfile = prefix + ".reads"
    astatfile = prefix + ".astat"

    logging.debug("Load {0}".format(bamfile))
    s = Samfile(bamfile, "rb")

    ncontigs = s.nreferences
    genomesize = sum(x for a, x in f.itersizes())
    logging.debug("Total {0} contigs with size {1} base".format(ncontigs,
        genomesize))
    qual = "20"  # default qual

    totalreads = sum(s.count(x) for x in s.references)
    logging.debug("Total {0} reads mapped".format(totalreads))

    fw = open(acefile, "w")
    if astat:
        astatfw = open(astatfile, "w")
    if readids:
        readsfw = open(readsfile, "w")

    print >> fw, "AS {0} {1}".format(ncontigs, totalreads)
    print >> fw

    for i, contig in enumerate(s.references):
        cseq = f[contig]
        nbases = len(cseq)

        mapped_reads = [x for x in s.fetch(contig) if not x.is_unmapped]
        nreads = len(mapped_reads)

        nsegments = 0
        print >> fw, "CO {0} {1} {2} {3} U".format(contig, nbases, nreads,
                nsegments)
        print >> fw, fill(str(cseq.seq))
        print >> fw

        if astat:
            astat = Astat(nbases, nreads, genomesize, totalreads)
            print >> astatfw, "{0}\t{1:.1f}".format(contig, astat)

        text = fill([qual] * nbases, delimiter=" ", width=30)
        print >> fw, "BQ\n{0}".format(text)
        print >> fw

        rnames = []
        for a in mapped_reads:
            readname = a.qname
            rname = readname

            if readids:
                print >> readsfw, readname
            rnames.append(rname)

            strand = "C" if a.is_reverse else "U"
            paddedstart = a.pos + 1  # 0-based to 1-based
            af = "AF {0} {1} {2}".format(rname, strand, paddedstart)
            print >> fw, af

        print >> fw

        for a, rname in zip(mapped_reads, rnames):
            aseq, npadded = cigar_to_seq(a)
            if aseq is None:
                continue

            ninfos = 0
            ntags = 0
            alen = len(aseq)
            rd = "RD {0} {1} {2} {3}\n{4}".format(rname, alen, ninfos, ntags,
                    fill(aseq))
            qs = "QA 1 {0} 1 {0}".format(alen)

            print >> fw, rd
            print >> fw
            print >> fw, qs
            print >> fw

if __name__ == '__main__':
    main()
<|endoftext|>


<commit_before>""" Tests to evaluate distance estimate using haversine.
"""

import numpy as np
from numpy.random import random
from maud.distance import haversine
from maud.cdistance import haversine as c_haversine
from maud.cdistance import haversine_scalar

def test_zerodistance(N=25):
    """ Distance from one point to itself
    """
    for n in range(N):
        lon = 540*random() - 180
        lat = 180*random() - 90
        assert (haversine(lon, lat, lon, lat) == 0.0)
        assert (haversine_scalar(lon, lat, lon, lat) == 0.0)

def test_360offset(N=25):
    """ Distance from itself around a full circle
    """
    X = -180 * random(N) # N values from [-180, 0]
    X = np.append([-180, 0], X) # Add the two limits -180 and 0
    Y = 90*(2*random(N)-1)
    Y = np.append([-90, 0, 90], Y)
    for x, y in zip(X, Y):
        d = haversine(x, y, x+360, y)
        c_d = haversine_scalar(x, y, x+360, y)
        assert (d<1e-3) # Less then a milimiter
        assert (c_d<1e-3) # Less then a milimiter

def test_PxC(N=25):
    """ Python and Cython should give the same answer
    """
    lon0 = 10
    lat0 = -25
    Lon = 540*random(N) - 180
    Lat = 90*(2*random(N)-1)

    Lon, Lat = np.meshgrid(Lon, Lat)

    #print("Testing scalar")
    #d = haversine(Lat[0, 0], Lon[0, 0], lat0, lon0)
    #c_d = c_haversine(Lat[0, 0], Lon[0, 0], lat0, lon0)
    #assert abs(d - c_d).max() < 1e-6

    print("Testing 1D array")
    for n in range(N):
        d = haversine(Lat[n], Lon[n], lat0, lon0)
        c_d = c_haversine(Lat[n], Lon[n], lat0, lon0)
        assert abs(d - c_d).max() < 1e-6

    print("Testing 2D array")
    d = haversine(Lat, Lon, lat0, lon0)
    c_d = c_haversine(Lat, Lon, lat0, lon0)
    assert abs(d - c_d).max() < 1e-6

#def test_haversine_scalar(N=25)
#
#    for lon, lat in zip(Lon, Lat):
#        d = haversine(lat, lon, lat0, lon0)
#        c_d = haversine_scalar(lat, lon, lat0, lon0)
#        # assert returns np.float64, while haversine_scalar returns float
#        # Should they return the same type? So which one?
#        #assert type(d) == type(c_d)
#        assert abs(d - c_d) < 1e-6

def  test_onedegreedistance(N=25):
    """
    """
    Lon, Lat = random((2, N))
    Lon = 400*(2*Lon-1)
    Lat = 89*(2*Lat-1)
    for lon, lat in zip(Lon, Lat):
        d = haversine(lat-0.5, lon, lat+0.5, lon)
        c_d = haversine_scalar(lat-0.5, lon, lat+0.5, lon)

        assert abs(d-111195)<0.1
        assert abs(c_d-111195)<0.1

<commit_msg>fixing lat, lon limmits on test_onedegreedistance<commit_after>""" Tests to evaluate distance estimate using haversine.
"""

import numpy as np
from numpy.random import random
from maud.distance import haversine
from maud.cdistance import haversine as c_haversine
from maud.cdistance import haversine_scalar

def test_zerodistance(N=25):
    """ Distance from one point to itself
    """
    for n in range(N):
        lon = 540*random() - 180
        lat = 180*random() - 90
        assert (haversine(lon, lat, lon, lat) == 0.0)
        assert (haversine_scalar(lon, lat, lon, lat) == 0.0)

def test_360offset(N=25):
    """ Distance from itself around a full circle
    """
    X = -180 * random(N) # N values from [-180, 0]
    X = np.append([-180, 0], X) # Add the two limits -180 and 0
    Y = 90*(2*random(N)-1)
    Y = np.append([-90, 0, 90], Y)
    for x, y in zip(X, Y):
        d = haversine(x, y, x+360, y)
        c_d = haversine_scalar(x, y, x+360, y)
        assert (d<1e-3) # Less then a milimiter
        assert (c_d<1e-3) # Less then a milimiter

def test_PxC(N=25):
    """ Python and Cython should give the same answer
    """
    lon0 = 10
    lat0 = -25
    Lon = 540*random(N) - 180
    Lat = 90*(2*random(N)-1)

    Lon, Lat = np.meshgrid(Lon, Lat)

    #print("Testing scalar")
    #d = haversine(Lat[0, 0], Lon[0, 0], lat0, lon0)
    #c_d = c_haversine(Lat[0, 0], Lon[0, 0], lat0, lon0)
    #assert abs(d - c_d).max() < 1e-6

    print("Testing 1D array")
    for n in range(N):
        d = haversine(Lat[n], Lon[n], lat0, lon0)
        c_d = c_haversine(Lat[n], Lon[n], lat0, lon0)
        assert abs(d - c_d).max() < 1e-6

    print("Testing 2D array")
    d = haversine(Lat, Lon, lat0, lon0)
    c_d = c_haversine(Lat, Lon, lat0, lon0)
    assert abs(d - c_d).max() < 1e-6

#def test_haversine_scalar(N=25)
#
#    for lon, lat in zip(Lon, Lat):
#        d = haversine(lat, lon, lat0, lon0)
#        c_d = haversine_scalar(lat, lon, lat0, lon0)
#        # assert returns np.float64, while haversine_scalar returns float
#        # Should they return the same type? So which one?
#        #assert type(d) == type(c_d)
#        assert abs(d - c_d) < 1e-6

def  test_onedegreedistance(N=25):
    """
    """
    Lon, Lat = random((2, N))
    Lon = 540*Lon- 180
    Lat = 89.5*(2*Lat-1)
    for lon, lat in zip(Lon, Lat):
        d = haversine(lat-0.5, lon, lat+0.5, lon)
        c_d = haversine_scalar(lat-0.5, lon, lat+0.5, lon)

        assert abs(d-111195)<0.1
        assert abs(c_d-111195)<0.1

<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

from odoo import models, fields

class Experience(models.Model):
    _name = 'company.experience'
    _description = "Data Experience"

    num_contract = fields.Char(string="Contract Number")
    job_name = fields.Char(string="Job Name", required=True)
    service_user = fields.Char(string="Service User", required=True)
    scop_service = fields.Text(string="Scop of Service", required=True)
    periode = fields.Char(string="Periode", required=True)
    start_date = fields.Date(string="Start Date", default=fields.Date.to_string)
    end_date = fields.Date(string="End Date",default=fields.Date.to_string)
    price = fields.Float(string="Price", required=True)
    status = fields.Selection(string="Status", selection=[('1','Ongoing'),('2','Pending'),('3','Finish')], required=True)
    company_id = fields.Many2one('res.company',string="Company", required=True)<commit_msg>Updated<commit_after># -*- coding: utf-8 -*-

from odoo import models, fields

class Experience(models.Model):
    _name = 'company.experience'
    _description = "Data Experience"

    num_contract = fields.Char(
        string="Contract Number"
    )
    job_name = fields.Char(
        string="Job Name",
        required=True
    )
    service_user = fields.Char(
        string="Service User",
        required=True
    )
    scope_service = fields.Text(
        string="Scop of Service",
        required=True
    )
    periode = fields.Char(
        string="Periode",
        required=True
    )
    start_date = fields.Date(
        string="Start Date",
        default=fields.Date.to_string
    )
    end_date = fields.Date(
        string="End Date",
        default=fields.Date.to_string
    )
    price = fields.Float(
        string="Price",
        required=True
    )
    status = fields.Selection(
        string="Status",
        selection=[('1','Ongoing'),('2','Pending'),('3','Finish')],
        required=True
    )
    company_id = fields.Many2one('res.company',
        string="Company",
        required=True
    )<|endoftext|>


<commit_before>""" Helper Functions
"""
from __future__ import division

import os
import errno
import shutil
import logging

from log import CONSOLE_LOGGER_NAME

CONSOLE_LOGGER = logging.getLogger(CONSOLE_LOGGER_NAME)

def _mkdir_p(path):
    """ Make directory recursively
    """
    try:
        os.makedirs(path)
    except OSError as exc:
        if exc.errno == errno.EEXIST and os.path.isdir(path):
            pass
        else:
            raise

def _log_loop_progress(i, length, n_reports=10):
    step = int(length/n_reports) if length > 10 else 1
    log_steps = range(0, length, step)

    if i in log_steps:
        progress = i/length*100
        CONSOLE_LOGGER.info('%.0f%% complete', progress)

def estimate_species_composition(n_aw, n_sb, n_sw, n_pl):
    '''Calculates species composition based on their densities

    :param float N_Aw, N_Sb, N_Sw, and N_Pl: densities of the respective species

    '''
    n_total = n_aw + n_sb + n_sw + n_pl

    if n_total == 0:
        sc_aw = 0
        sc_sw = 0
        sc_sb = 0
        sc_pl = 0
    else:
        sc_aw = n_aw/n_total
        sc_sw = n_sw/n_total
        sc_sb = n_sb/n_total
        sc_pl = n_pl/n_total

    return sc_aw, sc_sw, sc_sb, sc_pl

def _filter_young_stands(prepped_plot_table, min_age=25):
    old_query_str = ('tage_Sw > {a} '
                     'or tage_Sb > {a} '
                     'or tage_Pl > {a} '
                     'or tage_Aw > {a}').format(a=min_age)
    old_ids = prepped_plot_table.query(old_query_str).index
    prepped_plot_table_old = prepped_plot_table[
        prepped_plot_table.index.isin(old_ids)
    ]
    prepped_plot_table_young = prepped_plot_table[
        ~prepped_plot_table.index.isin(old_ids)
    ]

    return prepped_plot_table_old, prepped_plot_table_young

def _append_file(source, dest):
    with open(dest, 'wb') as dfd:
        with open(source, 'rb') as sfd:
            shutil.copyfileobj(sfd, dfd)
<commit_msg>Add s3 utils<commit_after>""" Helper Functions
"""
from __future__ import division

import os
import errno
import shutil
import logging
from urlparse import urlparse

from log import CONSOLE_LOGGER_NAME

CONSOLE_LOGGER = logging.getLogger(CONSOLE_LOGGER_NAME)

def _mkdir_p(path):
    """ Make directory recursively
    """
    try:
        os.makedirs(path)
    except OSError as exc:
        if exc.errno == errno.EEXIST and os.path.isdir(path):
            pass
        else:
            raise

def _log_loop_progress(i, length, n_reports=10):
    step = int(length/n_reports) if length > 10 else 1
    log_steps = range(0, length, step)

    if i in log_steps:
        progress = i/length*100
        CONSOLE_LOGGER.info('%.0f%% complete', progress)

def estimate_species_composition(n_aw, n_sb, n_sw, n_pl):
    '''Calculates species composition based on their densities

    :param float N_Aw, N_Sb, N_Sw, and N_Pl: densities of the respective species

    '''
    n_total = n_aw + n_sb + n_sw + n_pl

    if n_total == 0:
        sc_aw = 0
        sc_sw = 0
        sc_sb = 0
        sc_pl = 0
    else:
        sc_aw = n_aw/n_total
        sc_sw = n_sw/n_total
        sc_sb = n_sb/n_total
        sc_pl = n_pl/n_total

    return sc_aw, sc_sw, sc_sb, sc_pl

def _filter_young_stands(prepped_plot_table, min_age=25):
    old_query_str = ('tage_Sw > {a} '
                     'or tage_Sb > {a} '
                     'or tage_Pl > {a} '
                     'or tage_Aw > {a}').format(a=min_age)
    old_ids = prepped_plot_table.query(old_query_str).index
    prepped_plot_table_old = prepped_plot_table[
        prepped_plot_table.index.isin(old_ids)
    ]
    prepped_plot_table_young = prepped_plot_table[
        ~prepped_plot_table.index.isin(old_ids)
    ]

    return prepped_plot_table_old, prepped_plot_table_young

def _append_file(source, dest):
    with open(dest, 'wb') as dfd:
        with open(source, 'rb') as sfd:
            shutil.copyfileobj(sfd, dfd)

def _parse_s3_url(url):
    s3_bucket, s3_prefix = None, None

    if url.startswith('s3://'):
        outdir_url = urlparse(url)
        s3_bucket = outdir_url.netloc
        s3_prefix = outdir_url.path.strip('/')

    return {
        'bucket': s3_bucket,
        'prefix': s3_prefix,
    }

def _copy_file_to_s3(bucket_conn, source, dest):
    bucket_conn.upload_file(source, dest)

def _copy_file(source, dest, bucket_conn=None):
    if bucket_conn is None:
        shutil.copyfile(source, dest)
    else:
        _copy_file_to_s3(bucket_conn, source, dest)
<|endoftext|>


<commit_before># Licensed under a 3-clause BSD style license - see LICENSE.rst
from __future__ import absolute_import, division, print_function, unicode_literals

import numpy as np
import warnings
from .. import units as u
from ..utils.exceptions import AstropyUserWarning

__doctest_skip__ = ['wcs_to_celestial_frame']

__all__ = ['add_stokes_axis_to_wcs', 'wcs_to_celestial_frame',
           'celestial_pixel_scale', 'non_celestial_pixel_scales']

def add_stokes_axis_to_wcs(wcs, add_before_ind):
    """
    Add a new Stokes axis that is uncorrelated with any other axes.

    Parameters
    ----------
    wcs : `~astropy.wcs.WCS`
        The WCS to add to
    add_before_ind : int
        Index of the WCS to insert the new Stokes axis in front of.
        To add at the end, do add_before_ind = wcs.wcs.naxis
        The beginning is at position 0.

    Returns
    -------
    A new `~astropy.wcs.WCS` instance with an additional axis
    """

    inds = [i + 1 for i in range(wcs.wcs.naxis)]
    inds.insert(add_before_ind, 0)
    newwcs = wcs.sub(inds)
    newwcs.wcs.ctype[add_before_ind] = 'STOKES'
    newwcs.wcs.cname[add_before_ind] = 'STOKES'
    return newwcs

def _wcs_to_celestial_frame_builtin(wcs):

    from ..coordinates import FK4, FK4NoETerms, FK5, ICRS, Galactic
    from ..time import Time
    from . import WCSSUB_CELESTIAL

    # Keep only the celestial part of the axes
    wcs = wcs.sub([WCSSUB_CELESTIAL])

    if wcs.wcs.lng == -1 or wcs.wcs.lat == -1:
        return None

    radesys = wcs.wcs.radesys

    if np.isnan(wcs.wcs.equinox):
        equinox = None
    else:
        equinox = wcs.wcs.equinox

    xcoord = wcs.wcs.ctype[0][:4]
    ycoord = wcs.wcs.ctype[1][:4]

    # Apply logic from FITS standard to determine the default radesys
    if radesys == '' and xcoord == 'RA--' and ycoord == 'DEC-':
        if equinox is None:
            radesys = "ICRS"
        elif equinox < 1984.:
            radesys = "FK4"
        else:
            radesys = "FK5"

    if radesys == 'FK4':
        if equinox is not None:
            equinox = Time(equinox, format='byear')
        frame = FK4(equinox=equinox)
    elif radesys == 'FK4-NO-E':
        if equinox is not None:
            equinox = Time(equinox, format='byear')
        frame = FK4NoETerms(equinox=equinox)
    elif radesys == 'FK5':
        if equinox is not None:
            equinox = Time(equinox, format='jyear')
        frame = FK5(equinox=equinox)
    elif radesys == 'ICRS':
        frame = ICRS()
    else:
        if xcoord == 'GLON' and ycoord == 'GLAT':
            frame = Galactic()
        else:
            frame = None

    return frame

WCS_FRAME_MAPPINGS = [[_wcs_to_celestial_frame_builtin]]

class custom_frame_mappings(object):
    def __init__(self, mappings=[]):
        if hasattr(mappings, '__call__'):
            mappings = [mappings]
        WCS_FRAME_MAPPINGS.append(mappings)

    def __enter__(self):
        pass

    def __exit__(self, type, value, tb):
        WCS_FRAME_MAPPINGS.pop()

def wcs_to_celestial_frame(wcs):
    """
    For a given WCS, return the coordinate frame that matches the celestial
    component of the WCS.

    Parameters
    ----------
    wcs : :class:`~astropy.wcs.WCS` instance
        The WCS to find the frame for

    Returns
    -------
    frame : :class:`~astropy.coordinates.baseframe.BaseCoordinateFrame` subclass instance
        An instance of a :class:`~astropy.coordinates.baseframe.BaseCoordinateFrame`
        subclass instance that best matches the specified WCS.

    Notes
    -----

    To extend this function to frames not defined in astropy.coordinates, you
    can write your own function which should take a :class:`~astropy.wcs.WCS`
    instance and should return either an instance of a frame, or `None` if no
    matching frame was found. You can register this function temporarily with::

        >>> from astropy.wcs.utils import wcs_to_celestial_frame, custom_frame_mappings
        >>> with custom_frame_mappings(my_function):
        ...     wcs_to_celestial_frame(...)

    """
    for mapping_set in WCS_FRAME_MAPPINGS:
        for func in mapping_set:
            frame = func(wcs)
            if frame is not None:
                return frame
    raise ValueError("Could not determine celestial frame corresponding to "
                     "the specified WCS object")

def celestial_pixel_scale(inwcs, allow_nonsquare=False):
    """
    For a WCS, if the pixels are square, return the pixel scale in the spatial
    dimensions

    Parameters
    ----------
    inwcs: `astropy.wcs.WCS`
        The world coordinate system object
    allow_nonsquare : bool
        Return the average of the X and Y scales if True

    Returns
    -------
    scale : float
        The square pixel scale

    Raises
    ------
    ValueError if the pixels are nonsquare and ``allow_nonsquare==False``
    """
    cwcs = inwcs.celestial
    if cwcs.wcs.ctype[0][-3:] != 'CAR':
        warnings.warn("Pixel sizes may very over the image for "
                      "projection class {0}".format(cwcs.wcs.ctype[0][-3:]),
                      AstropyUserWarning)
    scale = (cwcs.pixel_scale_matrix**2).sum(axis=0)**0.5
    if not np.allclose(scale[0],scale[1]):
        if allow_nonsquare:
            warnings.warn("Pixels are not square, using an average pixel scale")
            return np.mean(scale)*u.deg
        else:
            raise ValueError("Pixels are not square: 'pixel scale' is ambiguous")
    # Return a quantity: WCS always stores in degrees
    return scale[0]*u.deg

def non_celestial_pixel_scales(inwcs):
    """
    For a non-celestial WCS, e.g. one with mixed spectral and spatial axes, it
    is still sometimes possible to define a pixel scale.

    Parameters
    ----------
    inwcs: `astropy.wcs.WCS`
        The world coordinate system object

    Returns
    -------
    scale : `numpy.ndarray`
        The pixel scale along each axis
    """

    if inwcs.is_celestial:
        raise ValueError("WCS is celestial, use celestial_pixel_scale instead")

    pccd = inwcs.pixel_scale_matrix

    if np.allclose(np.extract(1-np.eye(*pccd.shape), pccd), 0):
        return np.abs(np.diagonal(pccd))*u.deg
    else:
        raise ValueError("WCS is rotated, cannot determine consistent pixel scales")

def skycoord_to_pixel(coords, wcs, origin=0):
    """
    Convert a set of SkyCoord coordinates into pixels.

    Parameters
    ----------
    coords : `~astropy.coordinates.SkyCoord`
        The coordinates to convert.
    wcs : `~astropy.wcs.WCS`
        The WCS transformation to use.
    origin : int
        Whether to return 0 or 1-based pixel coordinates.

    Returns
    -------
    xp, yp : `numpy.ndarray`
        The pixel coordinates
    """

    from .. import units as u
    from . import WCSSUB_CELESTIAL

    if wcs.naxis != 2:
        raise ValueError("WCS should be two-dimensional")

    # Keep only the celestial part of the axes, also re-orders lon/lat
    wcs = wcs.sub([WCSSUB_CELESTIAL])

    if wcs.naxis != 2:
        raise ValueError("WCS should contain celestial component")

    # Check which frame the WCS uses
    frame = wcs_to_celestial_frame(wcs)

    # Check what unit the WCS needs
    xw_unit = u.Unit(wcs.wcs.cunit[0])
    yw_unit = u.Unit(wcs.wcs.cunit[1])

    # Convert positions to frame
    coords = coords.transform_to(frame)

    # Extract longitude and latitude. We first try and use lon/lat directly,
    # but if the representation is not spherical or unit spherical this will
    # fail. We should then force the use of the unit spherical
    # representation. We don't do that directly to make sure that we preserve
    # custom lon/lat representations if available.
    try:
        lon = coords.data.lon.to(xw_unit)
        lat = coords.data.lat.to(yw_unit)
    except AttributeError:
        lon = coords.spherical.lon.to(xw_unit)
        lat = coords.spherical.lat.to(yw_unit)

    # Convert to pixel coordinates
    print(lon.value, lat.value)
    xp, yp = wcs.wcs_world2pix(lon.value, lat.value, origin)

    return xp, yp

def pixel_to_skycoord(xp, yp, wcs, origin=0):
    """
    Convert a set of pixel coordinates into a SkyCoord coordinate.

    Parameters
    ----------
    xp, yp : float or `numpy.ndarray`
        The coordinates to convert.
    wcs : `~astropy.wcs.WCS`
        The WCS transformation to use.
    origin : int
        Whether to return 0 or 1-based pixel coordinates.

    Returns
    -------
    coords : `~astropy.coordinates.SkyCoord`
        The celestial coordinates
    """

    from .. import units as u
    from . import WCSSUB_CELESTIAL
    from ..coordinates import SkyCoord

    if wcs.naxis != 2:
        raise ValueError("WCS should be two-dimensional")

    # Keep only the celestial part of the axes, also re-orders lon/lat
    wcs = wcs.sub([WCSSUB_CELESTIAL])

    if wcs.naxis != 2:
        raise ValueError("WCS should contain celestial component")

    # Check which frame the WCS uses
    frame = wcs_to_celestial_frame(wcs)

    # Check what unit the WCS gives
    lon_unit = u.Unit(wcs.wcs.cunit[0])
    lat_unit = u.Unit(wcs.wcs.cunit[1])

    # Convert pixel coordinates to celestial coordinates
    lon, lat = wcs.wcs_pix2world(xp, yp, origin)

    # Add units to longitude/latitude
    lon = lon * lon_unit
    lat = lat * lat_unit

    # Create SkyCoord
    # TODO: use the actual frame instance, not the class, but requires fix in
    # astropy.coordinates.
    coords = SkyCoord(lon, lat, frame=frame.__class__)

    return coords
<commit_msg>Fix instantiation of SkyCoord<commit_after># Licensed under a 3-clause BSD style license - see LICENSE.rst
from __future__ import absolute_import, division, print_function, unicode_literals

import numpy as np
import warnings
from .. import units as u
from ..utils.exceptions import AstropyUserWarning

__doctest_skip__ = ['wcs_to_celestial_frame']

__all__ = ['add_stokes_axis_to_wcs', 'wcs_to_celestial_frame',
           'celestial_pixel_scale', 'non_celestial_pixel_scales']

def add_stokes_axis_to_wcs(wcs, add_before_ind):
    """
    Add a new Stokes axis that is uncorrelated with any other axes.

    Parameters
    ----------
    wcs : `~astropy.wcs.WCS`
        The WCS to add to
    add_before_ind : int
        Index of the WCS to insert the new Stokes axis in front of.
        To add at the end, do add_before_ind = wcs.wcs.naxis
        The beginning is at position 0.

    Returns
    -------
    A new `~astropy.wcs.WCS` instance with an additional axis
    """

    inds = [i + 1 for i in range(wcs.wcs.naxis)]
    inds.insert(add_before_ind, 0)
    newwcs = wcs.sub(inds)
    newwcs.wcs.ctype[add_before_ind] = 'STOKES'
    newwcs.wcs.cname[add_before_ind] = 'STOKES'
    return newwcs

def _wcs_to_celestial_frame_builtin(wcs):

    from ..coordinates import FK4, FK4NoETerms, FK5, ICRS, Galactic
    from ..time import Time
    from . import WCSSUB_CELESTIAL

    # Keep only the celestial part of the axes
    wcs = wcs.sub([WCSSUB_CELESTIAL])

    if wcs.wcs.lng == -1 or wcs.wcs.lat == -1:
        return None

    radesys = wcs.wcs.radesys

    if np.isnan(wcs.wcs.equinox):
        equinox = None
    else:
        equinox = wcs.wcs.equinox

    xcoord = wcs.wcs.ctype[0][:4]
    ycoord = wcs.wcs.ctype[1][:4]

    # Apply logic from FITS standard to determine the default radesys
    if radesys == '' and xcoord == 'RA--' and ycoord == 'DEC-':
        if equinox is None:
            radesys = "ICRS"
        elif equinox < 1984.:
            radesys = "FK4"
        else:
            radesys = "FK5"

    if radesys == 'FK4':
        if equinox is not None:
            equinox = Time(equinox, format='byear')
        frame = FK4(equinox=equinox)
    elif radesys == 'FK4-NO-E':
        if equinox is not None:
            equinox = Time(equinox, format='byear')
        frame = FK4NoETerms(equinox=equinox)
    elif radesys == 'FK5':
        if equinox is not None:
            equinox = Time(equinox, format='jyear')
        frame = FK5(equinox=equinox)
    elif radesys == 'ICRS':
        frame = ICRS()
    else:
        if xcoord == 'GLON' and ycoord == 'GLAT':
            frame = Galactic()
        else:
            frame = None

    return frame

WCS_FRAME_MAPPINGS = [[_wcs_to_celestial_frame_builtin]]

class custom_frame_mappings(object):
    def __init__(self, mappings=[]):
        if hasattr(mappings, '__call__'):
            mappings = [mappings]
        WCS_FRAME_MAPPINGS.append(mappings)

    def __enter__(self):
        pass

    def __exit__(self, type, value, tb):
        WCS_FRAME_MAPPINGS.pop()

def wcs_to_celestial_frame(wcs):
    """
    For a given WCS, return the coordinate frame that matches the celestial
    component of the WCS.

    Parameters
    ----------
    wcs : :class:`~astropy.wcs.WCS` instance
        The WCS to find the frame for

    Returns
    -------
    frame : :class:`~astropy.coordinates.baseframe.BaseCoordinateFrame` subclass instance
        An instance of a :class:`~astropy.coordinates.baseframe.BaseCoordinateFrame`
        subclass instance that best matches the specified WCS.

    Notes
    -----

    To extend this function to frames not defined in astropy.coordinates, you
    can write your own function which should take a :class:`~astropy.wcs.WCS`
    instance and should return either an instance of a frame, or `None` if no
    matching frame was found. You can register this function temporarily with::

        >>> from astropy.wcs.utils import wcs_to_celestial_frame, custom_frame_mappings
        >>> with custom_frame_mappings(my_function):
        ...     wcs_to_celestial_frame(...)

    """
    for mapping_set in WCS_FRAME_MAPPINGS:
        for func in mapping_set:
            frame = func(wcs)
            if frame is not None:
                return frame
    raise ValueError("Could not determine celestial frame corresponding to "
                     "the specified WCS object")

def celestial_pixel_scale(inwcs, allow_nonsquare=False):
    """
    For a WCS, if the pixels are square, return the pixel scale in the spatial
    dimensions

    Parameters
    ----------
    inwcs: `astropy.wcs.WCS`
        The world coordinate system object
    allow_nonsquare : bool
        Return the average of the X and Y scales if True

    Returns
    -------
    scale : float
        The square pixel scale

    Raises
    ------
    ValueError if the pixels are nonsquare and ``allow_nonsquare==False``
    """
    cwcs = inwcs.celestial
    if cwcs.wcs.ctype[0][-3:] != 'CAR':
        warnings.warn("Pixel sizes may very over the image for "
                      "projection class {0}".format(cwcs.wcs.ctype[0][-3:]),
                      AstropyUserWarning)
    scale = (cwcs.pixel_scale_matrix**2).sum(axis=0)**0.5
    if not np.allclose(scale[0],scale[1]):
        if allow_nonsquare:
            warnings.warn("Pixels are not square, using an average pixel scale")
            return np.mean(scale)*u.deg
        else:
            raise ValueError("Pixels are not square: 'pixel scale' is ambiguous")
    # Return a quantity: WCS always stores in degrees
    return scale[0]*u.deg

def non_celestial_pixel_scales(inwcs):
    """
    For a non-celestial WCS, e.g. one with mixed spectral and spatial axes, it
    is still sometimes possible to define a pixel scale.

    Parameters
    ----------
    inwcs: `astropy.wcs.WCS`
        The world coordinate system object

    Returns
    -------
    scale : `numpy.ndarray`
        The pixel scale along each axis
    """

    if inwcs.is_celestial:
        raise ValueError("WCS is celestial, use celestial_pixel_scale instead")

    pccd = inwcs.pixel_scale_matrix

    if np.allclose(np.extract(1-np.eye(*pccd.shape), pccd), 0):
        return np.abs(np.diagonal(pccd))*u.deg
    else:
        raise ValueError("WCS is rotated, cannot determine consistent pixel scales")

def skycoord_to_pixel(coords, wcs, origin=0):
    """
    Convert a set of SkyCoord coordinates into pixels.

    Parameters
    ----------
    coords : `~astropy.coordinates.SkyCoord`
        The coordinates to convert.
    wcs : `~astropy.wcs.WCS`
        The WCS transformation to use.
    origin : int
        Whether to return 0 or 1-based pixel coordinates.

    Returns
    -------
    xp, yp : `numpy.ndarray`
        The pixel coordinates
    """

    from .. import units as u
    from . import WCSSUB_CELESTIAL

    if wcs.naxis != 2:
        raise ValueError("WCS should be two-dimensional")

    # Keep only the celestial part of the axes, also re-orders lon/lat
    wcs = wcs.sub([WCSSUB_CELESTIAL])

    if wcs.naxis != 2:
        raise ValueError("WCS should contain celestial component")

    # Check which frame the WCS uses
    frame = wcs_to_celestial_frame(wcs)

    # Check what unit the WCS needs
    xw_unit = u.Unit(wcs.wcs.cunit[0])
    yw_unit = u.Unit(wcs.wcs.cunit[1])

    # Convert positions to frame
    coords = coords.transform_to(frame)

    # Extract longitude and latitude. We first try and use lon/lat directly,
    # but if the representation is not spherical or unit spherical this will
    # fail. We should then force the use of the unit spherical
    # representation. We don't do that directly to make sure that we preserve
    # custom lon/lat representations if available.
    try:
        lon = coords.data.lon.to(xw_unit)
        lat = coords.data.lat.to(yw_unit)
    except AttributeError:
        lon = coords.spherical.lon.to(xw_unit)
        lat = coords.spherical.lat.to(yw_unit)

    # Convert to pixel coordinates
    print(lon.value, lat.value)
    xp, yp = wcs.wcs_world2pix(lon.value, lat.value, origin)

    return xp, yp

def pixel_to_skycoord(xp, yp, wcs, origin=0):
    """
    Convert a set of pixel coordinates into a SkyCoord coordinate.

    Parameters
    ----------
    xp, yp : float or `numpy.ndarray`
        The coordinates to convert.
    wcs : `~astropy.wcs.WCS`
        The WCS transformation to use.
    origin : int
        Whether to return 0 or 1-based pixel coordinates.

    Returns
    -------
    coords : `~astropy.coordinates.SkyCoord`
        The celestial coordinates
    """

    from .. import units as u
    from . import WCSSUB_CELESTIAL
    from ..coordinates import SkyCoord, UnitSphericalRepresentation

    if wcs.naxis != 2:
        raise ValueError("WCS should be two-dimensional")

    # Keep only the celestial part of the axes, also re-orders lon/lat
    wcs = wcs.sub([WCSSUB_CELESTIAL])

    if wcs.naxis != 2:
        raise ValueError("WCS should contain celestial component")

    # Check which frame the WCS uses
    frame = wcs_to_celestial_frame(wcs)

    # Check what unit the WCS gives
    lon_unit = u.Unit(wcs.wcs.cunit[0])
    lat_unit = u.Unit(wcs.wcs.cunit[1])

    # Convert pixel coordinates to celestial coordinates
    lon, lat = wcs.wcs_pix2world(xp, yp, origin)

    # Add units to longitude/latitude
    lon = lon * lon_unit
    lat = lat * lat_unit

    # Create SkyCoord object
    data = UnitSphericalRepresentation(lon=lon, lat=lat)
    coords = SkyCoord(frame.realize_frame(data))

    return coords
<|endoftext|>


<commit_before># Copyright 2018 The TensorFlow Probability Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ============================================================================
"""The ExponentiatedQuadratic kernel."""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import tensorflow as tf
from tensorflow_probability.python.positive_semidefinite_kernels import positive_semidefinite_kernel as psd_kernel
from tensorflow_probability.python.positive_semidefinite_kernels.internal import util

__all__ = [
    'ExponentiatedQuadratic',
]

def _validate_arg_if_not_none(arg, assertion, validate_args):
  if arg is None:
    return arg
  with tf.control_dependencies([assertion(arg)] if validate_args else []):
    result = tf.identity(arg)
  return result

class ExponentiatedQuadratic(psd_kernel.PositiveSemidefiniteKernel):
  """The ExponentiatedQuadratic kernel.

  Sometimes called the "squared exponential", "Gaussian" or "radial basis
  function", this kernel function has the form

    ```none
    k(x, y) = amplitude**2 * exp(-||x - y||**2 / (2 * length_scale**2))
    ```

  where the double-bars represent vector length (ie, Euclidean, or L2 norm).
  """

  def __init__(self,
               amplitude=None,
               length_scale=None,
               feature_ndims=1,
               validate_args=False,
               name='ExponentiatedQuadratic'):
    """Construct an ExponentiatedQuadratic kernel instance.

    Args:
      amplitude: floating point `Tensor` that controls the maximum value
        of the kernel. Must be broadcastable with `length_scale` and inputs to
        `apply` and `matrix` methods. Must be greater than zero.
      length_scale: floating point `Tensor` that controls how sharp or wide the
        kernel shape is. This provides a characteristic "unit" of length against
        which `||x - y||` can be compared for scale. Must be broadcastable with
        `amplitude` and inputs to `apply` and `matrix` methods.
      feature_ndims: Python `int` number of rightmost dims to include in the
        squared difference norm in the exponential.
      validate_args: If `True`, parameters are checked for validity despite
        possibly degrading runtime performance
      name: Python `str` name prefixed to Ops created by this class.
    """
    with tf.compat.v1.name_scope(
        name, values=[amplitude, length_scale]) as name:
      dtype = util.maybe_get_common_dtype(
          [amplitude, length_scale])
      if amplitude is not None:
        amplitude = tf.convert_to_tensor(
            value=amplitude, name='amplitude', dtype=dtype)
      self._amplitude = _validate_arg_if_not_none(
          amplitude, tf.compat.v1.assert_positive, validate_args)
      if length_scale is not None:
        length_scale = tf.convert_to_tensor(
            value=length_scale, name='length_scale', dtype=dtype)
      self._length_scale = _validate_arg_if_not_none(
          length_scale, tf.compat.v1.assert_positive, validate_args)
    super(ExponentiatedQuadratic, self).__init__(
        feature_ndims, dtype=dtype, name=name)

  @property
  def amplitude(self):
    """Amplitude parameter."""
    return self._amplitude

  @property
  def length_scale(self):
    """Length scale parameter."""
    return self._length_scale

  def _batch_shape(self):
    scalar_shape = tf.TensorShape([])
    return tf.broadcast_static_shape(
        scalar_shape if self.amplitude is None else self.amplitude.shape,
        scalar_shape if self.length_scale is None else self.length_scale.shape)

  def _batch_shape_tensor(self):
    return tf.broadcast_dynamic_shape(
        [] if self.amplitude is None else tf.shape(input=self.amplitude),
        [] if self.length_scale is None else tf.shape(input=self.length_scale))

  def _apply(self, x1, x2, example_ndims=0):
    exponent = -0.5 * util.sum_rightmost_ndims_preserving_shape(
        tf.math.squared_difference(x1, x2), self.feature_ndims)
    if self.length_scale is not None:
      length_scale = util.pad_shape_with_ones(
          self.length_scale, example_ndims)
      exponent /= length_scale**2

    if self.amplitude is not None:
      amplitude = util.pad_shape_with_ones(
          self.amplitude, example_ndims)
      exponent += 2. * tf.math.log(amplitude)

    return tf.exp(exponent)
<commit_msg>ExponentiatedQuadratic docs for default args<commit_after># Copyright 2018 The TensorFlow Probability Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ============================================================================
"""The ExponentiatedQuadratic kernel."""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import tensorflow as tf
from tensorflow_probability.python.positive_semidefinite_kernels import positive_semidefinite_kernel as psd_kernel
from tensorflow_probability.python.positive_semidefinite_kernels.internal import util

__all__ = [
    'ExponentiatedQuadratic',
]

def _validate_arg_if_not_none(arg, assertion, validate_args):
  if arg is None:
    return arg
  with tf.control_dependencies([assertion(arg)] if validate_args else []):
    result = tf.identity(arg)
  return result

class ExponentiatedQuadratic(psd_kernel.PositiveSemidefiniteKernel):
  """The ExponentiatedQuadratic kernel.

  Sometimes called the "squared exponential", "Gaussian" or "radial basis
  function", this kernel function has the form

    ```none
    k(x, y) = amplitude**2 * exp(-||x - y||**2 / (2 * length_scale**2))
    ```

  where the double-bars represent vector length (ie, Euclidean, or L2 norm).
  """

  def __init__(self,
               amplitude=None,
               length_scale=None,
               feature_ndims=1,
               validate_args=False,
               name='ExponentiatedQuadratic'):
    """Construct an ExponentiatedQuadratic kernel instance.

    Args:
      amplitude: floating point `Tensor` that controls the maximum value
        of the kernel. Must be broadcastable with `length_scale` and inputs to
        `apply` and `matrix` methods. Must be greater than zero. A value of None is treated like 1.
      length_scale: floating point `Tensor` that controls how sharp or wide the
        kernel shape is. This provides a characteristic "unit" of length against
        which `||x - y||` can be compared for scale. Must be broadcastable with
        `amplitude` and inputs to `apply` and `matrix` methods. A value of None is treated like 1.
      feature_ndims: Python `int` number of rightmost dims to include in the
        squared difference norm in the exponential.
      validate_args: If `True`, parameters are checked for validity despite
        possibly degrading runtime performance
      name: Python `str` name prefixed to Ops created by this class.
    """
    with tf.compat.v1.name_scope(
        name, values=[amplitude, length_scale]) as name:
      dtype = util.maybe_get_common_dtype(
          [amplitude, length_scale])
      if amplitude is not None:
        amplitude = tf.convert_to_tensor(
            value=amplitude, name='amplitude', dtype=dtype)
      self._amplitude = _validate_arg_if_not_none(
          amplitude, tf.compat.v1.assert_positive, validate_args)
      if length_scale is not None:
        length_scale = tf.convert_to_tensor(
            value=length_scale, name='length_scale', dtype=dtype)
      self._length_scale = _validate_arg_if_not_none(
          length_scale, tf.compat.v1.assert_positive, validate_args)
    super(ExponentiatedQuadratic, self).__init__(
        feature_ndims, dtype=dtype, name=name)

  @property
  def amplitude(self):
    """Amplitude parameter."""
    return self._amplitude

  @property
  def length_scale(self):
    """Length scale parameter."""
    return self._length_scale

  def _batch_shape(self):
    scalar_shape = tf.TensorShape([])
    return tf.broadcast_static_shape(
        scalar_shape if self.amplitude is None else self.amplitude.shape,
        scalar_shape if self.length_scale is None else self.length_scale.shape)

  def _batch_shape_tensor(self):
    return tf.broadcast_dynamic_shape(
        [] if self.amplitude is None else tf.shape(input=self.amplitude),
        [] if self.length_scale is None else tf.shape(input=self.length_scale))

  def _apply(self, x1, x2, example_ndims=0):
    exponent = -0.5 * util.sum_rightmost_ndims_preserving_shape(
        tf.math.squared_difference(x1, x2), self.feature_ndims)
    if self.length_scale is not None:
      length_scale = util.pad_shape_with_ones(
          self.length_scale, example_ndims)
      exponent /= length_scale**2

    if self.amplitude is not None:
      amplitude = util.pad_shape_with_ones(
          self.amplitude, example_ndims)
      exponent += 2. * tf.math.log(amplitude)

    return tf.exp(exponent)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

from django.conf.urls import patterns, url

urlpatterns = patterns('apps.article.dashboard.views',
    url(r'^$', 'article_index', name='dashboard_article_index'),
    url(r'^create/$', 'article_create_or_edit', name='dashboard_article_create'),
    url(r'^edit/(?P<article_id>\d+)/(?P<article_slug>[a-zA-Z0-9_-]+)$', 'article_create_or_edit', name='dashboard_article_edit'),

    url(r'^tag/$', 'tag_index', name='dashboard_tag_index'),
    url(r'^tag/create$', 'tag_create_or_edit', name='dashboard_tag_create'),
    url(r'^tag/edit/(?P<name>[^\.]+)/(?P<slug>[^\.]+)$', 'tag_create_or_edit', name='dashboard_tag_edit'),
)<commit_msg>Renamed article dashboard urls<commit_after># -*- coding: utf-8 -*-

from django.conf.urls import patterns, url

urlpatterns = patterns('apps.article.dashboard.views',
    url(r'^$', 'article_index', name='dashboard_article_index'),
    url(r'^create/$', 'article_create', name='dashboard_article_create'),
    url(r'^change/(?P<article_id>\d+)/$', 'article_change', name='dashboard_article_change'),

    url(r'^tag/$', 'tag_index', name='dashboard_tag_index'),
    url(r'^tag/create/$', 'tag_create', name='dashboard_tag_create'),
    url(r'^tag/change/(?P<tag_id>\d+)/$', 'tag_change', name='dashboard_tag_change'),
)<|endoftext|>