Skip to content

Commit

Permalink
Remove auto_heater stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
gfabbris committed Jan 17, 2022
1 parent a3c3c92 commit 3fcc904
Showing 1 changed file with 38 additions and 181 deletions.
219 changes: 38 additions & 181 deletions apstools/devices/lakeshore_controllers.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,18 +54,20 @@ class LakeShore336_LoopControl(PVPositionerSoftDoneWithStop):
"""

# position
# FIXME: Resolve this code:
# FIXME:
# GF: I believe this is fixed.
# Resolve this code:
# setpoint is the temperature to be reached
# readback is the current temperature
# XXXXX is the interim setpoint for the PID loop
readback = FormattedComponent(
EpicsSignalRO, "{prefix}IN{loop_number}", auto_monitor=True, kind="hinted"
EpicsSignalRO,
"{prefix}IN{loop_number}",
auto_monitor=True,
kind="hinted"
)
setpoint = FormattedComponent(
EpicsSignalWithRBV,
"{prefix}OUT{loop_number}:SP",
put_complete=True,
kind="normal",
EpicsSignalWithRBV, "{prefix}OUT{loop_number}:SP", put_complete=True
)

# FIXME: refactor (per above)
Expand All @@ -79,7 +81,10 @@ class LakeShore336_LoopControl(PVPositionerSoftDoneWithStop):
)

heater = FormattedComponent(
EpicsSignalRO, "{prefix}HTR{loop_number}", auto_monitor=True, kind="normal"
EpicsSignalRO,
"{prefix}HTR{loop_number}",
auto_monitor=True,
kind="normal"
)
heater_range = FormattedComponent(
EpicsSignalWithRBV,
Expand Down Expand Up @@ -119,15 +124,14 @@ class LakeShore336_LoopControl(PVPositionerSoftDoneWithStop):
EpicsSignalWithRBV, "{prefix}OUT{loop_number}:Mode", kind="config"
)

auto_heater = Component(BooleanSignal, value=False, kind="config")

# This must be modified either here, or before using auto_heater.
_auto_ranges = None

def __init__(self, *args, loop_number=None, timeout=10 * HOUR, **kwargs):
self.loop_number = loop_number
super().__init__(
*args, timeout=timeout, tolerance=0.1, target_attr="target", **kwargs
*args,
timeout=timeout,
tolerance=0.1,
target_attr="target",
**kwargs
)
self._settle_time = 0

Expand All @@ -146,54 +150,9 @@ def settle_time(self, value):
def egu(self):
return self.units.get(as_string=True)

def stop(self, *, success=False):
if success is False:
self.setpoint.put(self._position)
super().stop(success=success)

def pause(self):
self.setpoint.put(self._position)

@auto_heater.sub_value
def _subscribe_auto_heater(self, value=None, **kwargs):
if value:
self.setpointRO.subscribe(self._switch_heater, event_type="value")
else:
self.setpointRO.clear_subs(self._switch_heater)

def _switch_heater(self, value=None, **kwargs):
# TODO: Find a better way to do this, perhaps with an array?
for _heater_range, _temp_range in self._auto_ranges.items():
if _temp_range:
if _temp_range[0] < value <= _temp_range[1]:
self.heater_range.put(_heater_range)

@property
def auto_ranges(self):
return self._auto_ranges

@auto_ranges.setter
def auto_ranges(self, value):
if not isinstance(value, dict):
raise TypeError("auto_ranges must be a dictionary.")

for _heater_range, _temp_range in value.items():
if _heater_range not in self.heater_range.enum_strs:
raise ValueError(
"The input dictionary keys must be one of "
f"these: {self.heater_range.enum_strs}, but "
f"{_heater_range} was entered."
)

if _temp_range is not None and len(_temp_range) != 2:
raise ValueError(
f"The value {_temp_range} is invalid! It "
"must be either None or an iterable with two "
"items."
)

self._auto_ranges = value


class LakeShore336_LoopRO(Device):
"""
Expand All @@ -215,68 +174,9 @@ def __init__(self, *args, loop_number=None, **kwargs):
self.loop_number = loop_number
super().__init__(*args, **kwargs)


class LakeShore336_LoopBase(PVPositionerSoftDoneWithStop):
"""
One control loop of the LakeShore 336 temperature controller.
Each control loop is a separate process controller.
DEFAULTS:
- timeout: 10 hours
- tolerance: 0.1
"""

readback = FormattedComponent(
EpicsSignalRO, "{prefix}IN{loop_number}", auto_monitor=True, kind="hinted"
)
setpoint = FormattedComponent(
EpicsSignalWithRBV,
"{prefix}OUT{loop_number}:SP",
put_complete=True,
kind="normal",
)

def __init__(self, *args, loop_number=None, timeout=10 * HOUR, **kwargs):
self.loop_number = loop_number
super().__init__(*args, timeout=timeout, tolerance=0.1, **kwargs)


class LakeShore336_LoopMore(LakeShore336_LoopBase):
"""
Additional controls for LakeShore 336 loop1 and loop2: heater, pid, & ramp.
Only used on loops 1 & 2.
"""

heater = FormattedComponent(
EpicsSignalRO, "{prefix}HTR{loop_number}", auto_monitor=True, kind="normal"
)
heater_range = FormattedComponent(
EpicsSignalWithRBV,
"{prefix}HTR{loop_number}:Range",
kind="config",
auto_monitor=True,
string=True,
)

pid_P = FormattedComponent(
EpicsSignalWithRBV, "{prefix}P{loop_number}", kind="config"
)
pid_I = FormattedComponent(
EpicsSignalWithRBV, "{prefix}I{loop_number}", kind="config"
)
pid_D = FormattedComponent(
EpicsSignalWithRBV, "{prefix}D{loop_number}", kind="config"
)

ramp_rate = FormattedComponent(
EpicsSignalWithRBV, "{prefix}RampR{loop_number}", kind="config"
)
ramp_on = FormattedComponent(
EpicsSignalWithRBV, "{prefix}OnRamp{loop_number}", kind="config"
)
@property
def egu(self):
return self.units.get(as_string=True)


class LakeShore336Device(Device):
Expand All @@ -289,10 +189,18 @@ class LakeShore336Device(Device):
- loop 4: temperature positioner
"""

loop1 = FormattedComponent(LakeShore336_LoopMore, "{self.prefix}", loop_number=1)
loop2 = FormattedComponent(LakeShore336_LoopMore, "{self.prefix}", loop_number=2)
loop3 = FormattedComponent(LakeShore336_LoopBase, "{self.prefix}", loop_number=3)
loop4 = FormattedComponent(LakeShore336_LoopBase, "{self.prefix}", loop_number=4)
loop1 = FormattedComponent(
LakeShore336_LoopControl, "{self.prefix}", loop_number=1
)
loop2 = FormattedComponent(
LakeShore336_LoopControl, "{self.prefix}", loop_number=2
)
loop3 = FormattedComponent(
LakeShore336_LoopRO, "{self.prefix}", loop_number=3
)
loop4 = FormattedComponent(
LakeShore336_LoopRO, "{self.prefix}", loop_number=4
)

# same names as apstools.synApps._common.EpicsRecordDeviceCommonAll
scanning_rate = Component(EpicsSignal, "read.SCAN", kind="omitted")
Expand All @@ -302,7 +210,7 @@ class LakeShore336Device(Device):
serial = Component(AsynRecord, "serial", kind="omitted")


class LS340_LoopBase(PVPositionerSoftDoneWithStop): # TODO: check, check, check
class LS340_LoopBase(PVPositionerSoftDoneWithStop):
""" Base settings for both sample and control loops. """

# position
Expand Down Expand Up @@ -374,11 +282,6 @@ def settle_time(self, value):
def egu(self):
return self.units.get(as_string=True)

def stop(self, *, success=False):
if success is False:
self.setpoint.put(self._position)
super().stop(success=success)

def pause(self):
self.setpoint.put(self._position, wait=True)

Expand Down Expand Up @@ -407,63 +310,17 @@ class LakeShore340Device(Device):

heater = Component(EpicsSignalRO, "Heater")
heater_range = Component(
EpicsSignal, "Rg_rdbk", write_pv="HeatRg", kind="normal", put_complete=True
EpicsSignal,
"Rg_rdbk",
write_pv="HeatRg",
kind="normal",
put_complete=True
)

auto_heater = Component(BooleanSignal, value=False, kind="config")

read_pid = Component(EpicsSignal, "readPID.PROC", kind="omitted")

# same names as apstools.synApps._common.EpicsRecordDeviceCommonAll
scanning_rate = Component(EpicsSignal, "read.SCAN", kind="omitted")
process_record = Component(EpicsSignal, "read.PROC", kind="omitted")

serial = Component(AsynRecord, "serial", kind="omitted")

# This must be modified either here, or before using auto_heater.
_auto_ranges = None

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# TODO: I don't know why this has to be done, otherwise it gets hinted.
self.control.readback.kind = "normal"

@auto_heater.sub_value
def _subscribe_auto_heater(self, value=None, **kwargs):
if value:
self.control.setpoint.subscribe(self._switch_heater, event_type="value")
else:
self.control.setpoint.clear_subs(self._switch_heater)

def _switch_heater(self, value=None, **kwargs):
# TODO: Find a better way to do this, perhaps with an array?
for _heater_range, _temp_range in self._auto_ranges.items():
if _temp_range:
if _temp_range[0] < value <= _temp_range[1]:
self.heater_range.put(_heater_range)

@property
def auto_ranges(self):
return self._auto_ranges

@auto_ranges.setter
def auto_ranges(self, value):
if not isinstance(value, dict):
raise TypeError("auto_ranges must be a dictionary.")

for _heater_range, _temp_range in value.items():
if _heater_range not in self.heater_range.enum_strs:
raise ValueError(
"The input dictionary keys must be one of "
f"these: {self.heater_range.enum_strs}, but "
f"{_heater_range} was entered."
)

if _temp_range is not None and len(_temp_range) != 2:
raise ValueError(
f"The value {_temp_range} is invalid! It "
"must be either None or an iterable with two "
"items."
)

self._auto_ranges = value

0 comments on commit 3fcc904

Please sign in to comment.