Skip to content
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
8 changes: 4 additions & 4 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ Two pieces of software influenced its design:
* APHLA, high-level applications written in Python by the NSLS-II accelerator physics group


Software Overview
=================
Overview
========

Pytac provides a Python library ``pytac`` that makes it easier to communicate with machine hardware for online applications. Although it currently works with EPICS, the `cs.ControlSystem` class may be sub-classed to allow other control systems to be used.
Pytac provides a Python library ``pytac`` that makes it easier to communicate with machine hardware for online applications. Although it currently works with EPICS, it should be possible to adapt to support other control systems.

The design is based around a ``Lattice`` object that contains a sequence of ``Element`` s. Each element may have zero or more 'fields' (examples x, y, a1 or b2), associated with which are ``Device`` objects. These devices contain the necessary information to request live data from the control system.
The design is based around a ``Lattice`` object that contains a sequence of ``Element`` s. Each element represents a physical component in accelerator, such as an electromagnet, drift or BPM. For control purposes, each element may have zero or more 'fields' that represent parameters that may change: a BPM element has fields 'x' and 'y' that represent beam position, and a quadrupole magnet has 'b1' that represents the quadrupolar magnetic field. For monitoring and controlling these fields, elements have one ``Device`` object per field. These devices contain the necessary information to get and set live data using the control system.

Data may be requested in ``ENG`` or ``PHYS`` units and will be converted as appropriate. Two types of unit conversion are available: Polynomial (often used for linear conversion) and Piecewise Cubic Hermite Interpolating Polynomial (Pchip; often used for magnet data where field may not be linear with current). In the case that measurement data (used to set up the conversion objects) is not in the same units as the physical models, further functions may be given to these objects to complete the conversion correctly.

Expand Down
89 changes: 51 additions & 38 deletions pytac/lattice.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ def __init__(self, name, control_system, energy):
for unit conversion.

Args:
name (string): The name of the lattice.
name (str): The name of the lattice.
control_system (ControlSystem): The control system used
to store the values on a pv.
energy(Number): The total energy of the lattice.
energy (float): The total energy of the lattice.

"""
self.name = name
self._lattice = []
Expand All @@ -34,19 +35,21 @@ def get_energy(self):
"""Function to get the total energy of the lattice.

Returns:
Number: The total energy of the lattice.
float: energy of the lattice

"""
return self._energy

def __getitem__(self, n):
"""Get the nth element of the lattice.
"""Get the (n + 1)th element of the lattice - i.e. index 0 represents
the first element in the lattice.

Args:
n (int): An index that represents the nth + 1 element of the
lattice.
n (int): index

Returns:
Element: The element asked by the index n.
Element: indexed element

"""

return self._lattice[n]
Expand Down Expand Up @@ -75,10 +78,11 @@ def get_length(self):
return total_length

def add_element(self, element):
"""Add an element to the lattice.
"""Append an element to the lattice.

Args:
element (Element): The element to be inserted into the lattice.
element (Element): element to append

"""
self._lattice.append(element)

Expand All @@ -90,11 +94,12 @@ def get_elements(self, family=None, cell=None):
Elements are returned in the order they exist in the ring.

Args:
family (string): Restrict elements to those in this family
cell (int): Restrict elements to those in the specified cell
family (str): requested family
cell (int): restrict elements to those in the specified cell

Returns:
list(Element): A list that contains all elements of the specified family.
list(Element): list containing all elements of the specified family

"""
elements = []
if family is None:
Expand All @@ -110,28 +115,29 @@ def get_elements(self, family=None, cell=None):
return elements

def get_all_families(self):
"""Get all available families of the lattice.
"""Get all families of elements in the lattice

Returns:
set(string): Contains all available families in the lattice.
set(str): all defined families

"""
families = set()
for element in self._lattice:
for family in element.families:
families.add(family)
families.update(element.families)

return families

def get_pv_names(self, family, field, handle):
"""Get all pv names for a specific family, field and handle.

Args:
family (string): A specific family to requests elements of.
field (string): The field to uniquely identify a device.
handle (string): It is used to identify a readback or setpoint pv.
family (str): requested family
field (str): requested field
handle (str): pytac.RB or pytac.SP

Returns:
list(string): A list of readback or setpoint pvs from the device.
list(str): list of pv names

"""
elements = self.get_elements(family)
pv_names = []
Expand Down Expand Up @@ -180,37 +186,40 @@ def set_values(self, family, field, values):
"equal to the number of elements in the lattice")
self._cs.put(pv_names, values)

def get_s(self, element):
"""Find the position of a given element in the lattice.
def get_s(self, elem):
"""Find the s position of an element in the lattice.

Note that the given element must exist in the lattice.

Args:
given_element: The element that the position is being asked for.
elem (Element): The element that the position is being asked for.

Returns:
float: the position of the given element.

Raises
LatticeException: if element doesn't exist in the lattice.

"""
s_pos = 0
for el in self._lattice:
if el is not element:
if el is not elem:
s_pos += el.length
else:
return s_pos
raise LatticeException('Element {} does not exist in the lattice'.format(element))
raise LatticeException(
'Element {} not in lattice {}'.format(elem, self)
)

def get_family_s(self, family):
"""Get the positions for a set of elements from the same family.
"""Get s positions for all elements from the same family.

Args:
family(string): The family the positions are being asked for.
family (str): requested family

Returns:
list(float): A list of floating point numbers that represent the positions
for each element.
list(float): list of s positions for each element

"""
elements = self.get_elements(family)
s_positions = []
Expand All @@ -219,14 +228,15 @@ def get_family_s(self, family):
return s_positions

def get_devices(self, family, field):
"""Get devices attached to a specific field for elements in the specfied family.
"""Get devices for a specific field for elements in the specfied family.

Typically all elements of a family will have devices associated with
the same fields - for example, BPMs each have device for fields 'x' and 'y'.
the same fields - for example, BPMs each have a device for fields
'x' and 'y'.

Args:
family: family of elements
field: field specifying the devices
family (str): family of elements
field (str): field specifying the devices

Returns:
list(devices): devices for specified family and field
Expand All @@ -242,17 +252,20 @@ def get_devices(self, family, field):
return devices

def get_device_names(self, family, field):
"""Get the names for devices attached to a specific field for elements in the specfied family.
"""Get the names for devices attached to a specific field for elements
in the specfied family.

Typically all elements of a family will have devices associated with
the same fields - for example, BPMs each have device for fields 'x' and 'y'.
the same fields - for example, BPMs each have device for fields
'x' and 'y'.

Args:
family: family of elements
field: field specifying the devices
family (str): family of elements
field (str): field specifying the devices

Returns:
list(devices): devices for specified family and field
list(str): devices names for specified family and field

"""
devices = self.get_devices(family, field)
return [device.name for device in devices]