Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add generic convert function to UnitConversion class. #56

Merged
merged 3 commits into from
Nov 27, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 15 additions & 10 deletions pytac/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,20 @@
is a sextupole magnet that contains also horizontal and vertical corrector magnets
and a skew quadrupole.
"""

from pytac.exceptions import PvException
import pytac


class DeviceException(Exception):
"""Exception associated with Device misconfiguration or invalid requests."""
pass


class Device(object):
"""A device attached to an element.

Contains a control system, readback and setpoint pvs. A readback
or setpoint pv is required when creating a device otherwise a
PvException is raised. The device is enabled by default.
DeviceException is raised. The device is enabled by default.

"""

Expand Down Expand Up @@ -50,18 +53,16 @@ def put_value(self, value):
value (float): The value to set on the pv.

Raises:
PvException: An exception occured when no setpoint pv exists.
DeviceException: if no setpoint pv exists.
"""
if self.sp_pv is None:
raise PvException("""This device {0} has no setpoint pv."""
raise DeviceException("""Device {0} has no setpoint pv."""
.format(self.name))
self._cs.put(self.sp_pv, value)

def get_value(self, handle):
"""Read the value of a readback or setpoint pv.

If neither readback or setpoint pvs exist then a PvException is raised.

Args:
handle (str): Handle used to get the value off a readback or setpoint
pv.
Expand All @@ -70,14 +71,15 @@ def get_value(self, handle):
float: The value of the pv.

Raises:
PvException: In case the requested pv doesn't exist.
DeviceException: if the requested pv doesn't exist.
"""
print('getting {}'.format('handle'))
if handle == pytac.RB and self.rb_pv:
return self._cs.get(self.rb_pv)
elif handle == pytac.SP and self.sp_pv:
return self._cs.get(self.sp_pv)

raise PvException("""This device {0} has no {1} pv."""
raise DeviceException("""Device {0} has no {1} pv."""
.format(self.name, handle))

def get_pv_name(self, handle):
Expand All @@ -88,13 +90,16 @@ def get_pv_name(self, handle):

Returns:
str: A readback or setpoint pv.

Raises:
DeviceException: if the PV doesn't exist.
"""
if handle == pytac.RB and self.rb_pv:
return self.rb_pv
elif handle == pytac.SP and self.sp_pv:
return self.sp_pv

raise PvException("""This device {0} has no {1} pv."""
raise DeviceException("""Device {0} has no {1} pv."""
.format(self.name, handle))

def get_cs(self):
Expand Down
15 changes: 7 additions & 8 deletions pytac/element.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"""Module containing the element class."""

from pytac.exceptions import PvException
import pytac
from pytac.device import DeviceException


class Element(object):
Expand Down Expand Up @@ -124,7 +123,7 @@ def get_value(self, field, handle, unit=pytac.ENG, model=pytac.LIVE):
field.

Raises:
PvException: When there is no associated device on the given field.
DeviceException: When there is no associated device on the given field.
"""
if model == pytac.LIVE:
if field in self._devices:
Expand All @@ -133,7 +132,7 @@ def get_value(self, field, handle, unit=pytac.ENG, model=pytac.LIVE):
value = self._uc[field].eng_to_phys(value)
return value
else:
raise PvException("No device associated with field {0}".format(field))
raise DeviceException("No device associated with field {0}".format(field))
else:
value = self._model.get_value(field)
if unit == pytac.ENG:
Expand All @@ -154,7 +153,7 @@ def set_value(self, field, value, unit=pytac.ENG, model=pytac.LIVE):
model (str): The type of model: simulation or live

Raises:
PvException: An exception occured accessing a field with
DeviceException: An exception occured accessing a field with
no associated device.
"""
if model == pytac.LIVE:
Expand All @@ -163,7 +162,7 @@ def set_value(self, field, value, unit=pytac.ENG, model=pytac.LIVE):
value = self._uc[field].phys_to_eng(value)
self._devices[field].put_value(value)
else:
raise PvException('''There is no device associated with
raise DeviceException('''There is no device associated with
field {0}'''.format(field))
else:
if unit == pytac.ENG:
Expand All @@ -183,13 +182,13 @@ def get_pv_name(self, field, handle):
str: A readback or setpoint pv associated with the identified device.

Raises:
PvException: An exception occured accessing a field with
DeviceException: An exception occured accessing a field with
no associated device.
"""
try:
return self._devices[field].get_pv_name(handle)
except KeyError:
raise PvException('{} has no device for field {}'.format(self, field))
raise DeviceException('{} has no device for field {}'.format(self, field))

def get_cs(self, field):
return self._devices[field].get_cs()
13 changes: 0 additions & 13 deletions pytac/exceptions.py

This file was deleted.

15 changes: 7 additions & 8 deletions pytac/lattice.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
""" Representation of a lattice object which contains all the elements of the machine."""

from pytac.exceptions import PvException
from pytac.exceptions import ElementNotFoundException

class LatticeException(Exception):
pass


class Lattice(object):
Expand Down Expand Up @@ -163,13 +164,12 @@ def set_pv_values(self, family, field, values):
values(list(float)): A list of values to assign to the pvs.

Raises:
PvException: An exception raised in case the given list of values
doesn't match the number of found pvs.
LatticeException: if the given list of values doesn't match the number of found pvs.

"""
pv_names = self.get_pv_names(family, field, 'setpoint')
if len(pv_names) != len(values):
raise PvException("Number of elements in given array must be equal"
raise LatticeException("Number of elements in given array must be equal"
"to the number of elements in the lattice")
self._cs.put(pv_names, values)

Expand All @@ -185,16 +185,15 @@ def get_s(self, element):
float: the position of the given element.

Raises
ElementNotFoundException: An exception is raised in case the element
doesn't exist inside the lattice.
LatticeException: if element doesn't exist in the lattice.
"""
s_pos = 0
for el in self._lattice:
if el is not element:
s_pos += el.length
else:
return s_pos
raise ElementNotFoundException('Element {} does not exist in the lattice'.format(element))
raise LatticeException('Element {} does not exist in the lattice'.format(element))

def get_family_s(self, family):
"""Get the positions for a set of elements from the same family.
Expand Down
21 changes: 17 additions & 4 deletions pytac/units.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
""" An unit conversion object used to convert between physics and engineering units."""

import pytac
import numpy
from scipy.interpolate import PchipInterpolator
from pytac.exceptions import UniqueSolutionException


class UnitsException(Exception):
pass


def unit_function(value):
Expand Down Expand Up @@ -85,6 +88,16 @@ def phys_to_eng(self, value):
result = self._raw_phys_to_eng(x)
return result

def convert(self, value, origin, target):
if origin == target:
return value
if origin == pytac.PHYS and target == pytac.ENG:
return self.phys_to_eng(value)
if origin == pytac.ENG and target == pytac.PHYS:
return self.eng_to_phys(value)
raise UnitsException('Conversion {} to {} not understood'.format(origin,
target))


class PolyUnitConv(UnitConv):
def __init__(self, coef, post_eng_to_phys=unit_function, pre_phys_to_eng=unit_function):
Expand Down Expand Up @@ -187,8 +200,8 @@ def _raw_phys_to_eng(self, physics_value):
solution_within_bounds = True
correct_root = root
else:
raise UniqueSolutionException("The function is not invertible.")
raise UnitsException('The function {} is not invertible.'.format(new_pp))
if solution_within_bounds:
return correct_root
else:
raise UniqueSolutionException("The function does not have a solution within the bounds.")
raise UnitsException("The function {} does not have a solution within bounds.")
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ universal=1

[tool:pytest]
pep8ignore =
E121 E126 E127 E501
E121 E126 E127 E128 E501
pytac/__init__.py E402
docs/conf.py ALL

Expand Down
5 changes: 2 additions & 3 deletions test/test_device.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from pytac.exceptions import PvException
import pytac.device
import pytest
import mock
Expand All @@ -21,13 +20,13 @@ def test_set_device_value():

def test_device_invalid_sp_raise_exception():
device2 = create_device(PREFIX, RB_SUFFIX, None)
with pytest.raises(PvException):
with pytest.raises(pytac.device.DeviceException):
device2.put_value(40)


def test_get_device_value():
device = create_device()
with pytest.raises(PvException):
with pytest.raises(pytac.device.DeviceException):
device.get_value('non_existent')


Expand Down
7 changes: 3 additions & 4 deletions test/test_element.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from pytac.exceptions import PvException
import pytac.element
import pytac.device
from pytac.units import PolyUnitConv
Expand Down Expand Up @@ -94,14 +93,14 @@ def test_set_value(test_element):
test_element.set_value('x', DUMMY_VALUE_2, unit=pytac.PHYS)
test_element.get_device('x')._cs.put.assert_called_with(SP_PV, DUMMY_VALUE_2)

with pytest.raises(PvException):
with pytest.raises(pytac.device.DeviceException):
test_element.set_value('non_existent', 40.0)


def test_get_pv_exceptions(test_element):
with pytest.raises(PvException):
with pytest.raises(pytac.device.DeviceException):
test_element.get_value('setpoint', 'unknown_field')
with pytest.raises(PvException):
with pytest.raises(pytac.device.DeviceException):
test_element.get_value('unknown_handle', 'y')


Expand Down
5 changes: 2 additions & 3 deletions test/test_lattice.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import pytac.device
import mock
from pytac.units import PolyUnitConv
from pytac.exceptions import ElementNotFoundException, PvException

from constants import PREFIX, RB_SUFFIX, SP_SUFFIX, RB_PV, SP_PV, LATTICE

Expand Down Expand Up @@ -104,7 +103,7 @@ def test_set_pv_values(simple_element_and_lattice):

def test_set_pv_values_raise_exception(simple_element_and_lattice):
element, lattice = simple_element_and_lattice
with pytest.raises(PvException):
with pytest.raises(pytac.lattice.LatticeException):
lattice.set_pv_values('family', 'x', [1, 2])


Expand All @@ -124,7 +123,7 @@ def test_s_position(simple_element_and_lattice):
def test_get_s_throws_exception_if_element_not_in_lattice():
l = pytac.lattice.Lattice(LATTICE, mock.MagicMock(), 1)
element = pytac.element.Element(1, 1.0, 'Quad')
with pytest.raises(ElementNotFoundException):
with pytest.raises(pytac.lattice.LatticeException):
l.get_s(element)


Expand Down
5 changes: 2 additions & 3 deletions test/test_machine.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import re
import mock
import numpy
from pytac.exceptions import PvException, UniqueSolutionException


EPS = 1e-8
Expand Down Expand Up @@ -57,7 +56,7 @@ def test_load_bpms(ring_mode, n_bpms):
for bpm in bpms:
assert set(bpm.get_fields()) == set(('x', 'y'))
assert re.match('SR.*BPM.*X', bpm.get_pv_name('x', pytac.RB))
with pytest.raises(PvException):
with pytest.raises(pytac.device.DeviceException):
bpm.get_pv_name('x', pytac.SP)
assert len(bpms) == n_bpms
assert bpms[0].cell == 1
Expand Down Expand Up @@ -164,7 +163,7 @@ def test_quad_unitconv():

def test_quad_unitconv_raise_exception():
uc = pytac.units.PchipUnitConv([50.0, 100.0, 180.0], [-4.95, -9.85, -17.56])
with pytest.raises(UniqueSolutionException):
with pytest.raises(pytac.units.UnitsException):
numpy.testing.assert_allclose(uc.phys_to_eng(-0.7), 70.8834284954)


Expand Down
9 changes: 9 additions & 0 deletions test/test_units.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import pytest
import pytac
from pytac.units import PolyUnitConv, PchipUnitConv
import numpy

Expand Down Expand Up @@ -27,6 +28,14 @@ def test_linear_conversion():
assert machine_value == 1


def test_linear_conversion_specifying_units():
linear_conversion = PolyUnitConv([2, 3])
physics_value = linear_conversion.convert(4, pytac.ENG, pytac.PHYS)
assert physics_value == 11
machine_value = linear_conversion.convert(5, pytac.PHYS, pytac.ENG)
assert machine_value == 1


def test_quadratic_conversion():
quadratic_conversion = PolyUnitConv([1, 2, 3])
physics_value = quadratic_conversion.eng_to_phys(4)
Expand Down