|
49 | 49 | # SHAMROCK_I24SLITWIDTHMAX 24000 |
50 | 50 | SHUTTERMODEMIN = 0 |
51 | 51 | SHUTTERMODEMAX = 2 # Note: 1 is max on SR303, 2 is max on SR193 |
52 | | -# SHAMROCK_DET_OFFSET_MIN -240000 |
53 | | -# SHAMROCK_DET_OFFSET_MAX 240000 |
54 | | -# SHAMROCK_GRAT_OFFSET_MIN -20000 |
55 | | -# SHAMROCK_GRAT_OFFSET_MAX 20000 |
| 52 | + |
| 53 | +DET_OFFSET_MIN = -240000 |
| 54 | +DET_OFFSET_MAX = 240000 |
| 55 | +GRAT_OFFSET_MIN = -20000 |
| 56 | +GRAT_OFFSET_MAX = 20000 |
56 | 57 |
|
57 | 58 | SLIT_INDEX_MIN = 1 |
58 | 59 | SLIT_INDEX_MAX = 4 |
@@ -496,7 +497,9 @@ def __init__(self, name: str, role: str, |
496 | 497 |
|
497 | 498 | axes = {"wavelength": model.Axis(unit="m", range=wl_range, |
498 | 499 | speed=(max_speed, max_speed)), |
499 | | - "grating": model.Axis(choices=gchoices) |
| 500 | + "grating": model.Axis(choices=gchoices), |
| 501 | + "goffset": model.Axis(unit=None, |
| 502 | + range=((GRAT_OFFSET_MIN + DET_OFFSET_MIN), (GRAT_OFFSET_MAX + DET_OFFSET_MAX))) |
500 | 503 | } |
501 | 504 |
|
502 | 505 | if self.FocusMirrorIsPresent(): |
@@ -1597,14 +1600,40 @@ def _getGratingChoices(self): |
1597 | 1600 |
|
1598 | 1601 | return gchoices |
1599 | 1602 |
|
| 1603 | + def GetGoffset(self): |
| 1604 | + """ |
| 1605 | + Checks the current grating and flip-mirror positions. |
| 1606 | + Returns the grating offset, consisting of the grating_offset + the detector offset. |
| 1607 | +
|
| 1608 | + The detector offset is the equivalent grating offset that is needed to compensate for the change in |
| 1609 | + optical path length, introduced by the flip-mirrors. |
| 1610 | + This allows to maintain a stable wavelength calibration across different optical paths, rather than forcing the user |
| 1611 | + to recalibrate for every detector configuration. |
| 1612 | + """ |
| 1613 | + |
| 1614 | + grating = self.GetGrating() |
| 1615 | + if "flip-in" in self.axes: |
| 1616 | + flip_in_pos = self.GetFlipperMirror(INPUT_FLIPPER) |
| 1617 | + else: |
| 1618 | + flip_in_pos = DIRECT_PORT |
| 1619 | + |
| 1620 | + if "flip-out" in self.axes: |
| 1621 | + flip_out_pos = self.GetFlipperMirror(OUTPUT_FLIPPER) |
| 1622 | + else: |
| 1623 | + flip_out_pos = DIRECT_PORT |
| 1624 | + |
| 1625 | + goffset = self.GetGratingOffset(grating) + self.GetDetectorOffset(flip_in_pos, flip_out_pos) |
| 1626 | + return goffset |
| 1627 | + |
1600 | 1628 | # high-level methods (interface) |
1601 | 1629 | def _updatePosition(self, must_notify=False): |
1602 | 1630 | """ |
1603 | 1631 | update the position VA |
1604 | 1632 | """ |
1605 | 1633 | # TODO: support "axes" to limit the axes to update |
1606 | 1634 | pos = {"wavelength": self.GetWavelength(), |
1607 | | - "grating": self.GetGrating() |
| 1635 | + "grating": self.GetGrating(), |
| 1636 | + "goffset": self.GetGoffset() |
1608 | 1637 | } |
1609 | 1638 |
|
1610 | 1639 | if "focus" in self.axes: |
@@ -1814,6 +1843,8 @@ def moveRel(self, shift): |
1814 | 1843 | actions.append((axis, self._doSetWavelengthRel, s)) |
1815 | 1844 | elif axis == "focus": |
1816 | 1845 | actions.append((axis, self._doSetFocusRel, s)) |
| 1846 | + elif axis == "goffset": |
| 1847 | + actions.append((axis, self._doSetGoffsetRel, s)) |
1817 | 1848 | elif axis in self._slit_names.values(): |
1818 | 1849 | sid = [k for k, v in self._slit_names.items() if v == axis][0] |
1819 | 1850 | actions.append((axis, self._doSetSlitRel, sid, s)) |
@@ -1851,6 +1882,8 @@ def moveAbs(self, pos): |
1851 | 1882 | actions.append((axis, self._doSetFilter, p, check)) |
1852 | 1883 | elif axis == "focus": |
1853 | 1884 | actions.append((axis, self._doSetFocusAbs, p)) |
| 1885 | + elif axis == "goffset": |
| 1886 | + actions.append((axis, self._doSetGoffsetAbs, p)) |
1854 | 1887 | elif axis == "flip-in": |
1855 | 1888 | check = self._check_move.get(axis, True) |
1856 | 1889 | actions.append((axis, self._doSetFlipper, INPUT_FLIPPER, p, check)) |
@@ -2064,6 +2097,77 @@ def _doSetFlipper(self, flipper: int, pos: int, check: bool): |
2064 | 2097 | logging.warning("Failed to update turret position, detector offset might be incorrect", exc_info=True) |
2065 | 2098 | self._updatePosition() |
2066 | 2099 |
|
| 2100 | + |
| 2101 | + def _doSetGoffsetAbs(self, target_offset, *, allow_grating_offset=True, single_detector_mode = False): |
| 2102 | + |
| 2103 | + """ |
| 2104 | + Change grating offset, by either changing the grating offset or the detector offset. |
| 2105 | + :param target_offset (float): the new grating offset to set |
| 2106 | + :param allow_grating_offset (bool): check to allow changing the grating offset, if false, only change |
| 2107 | + detector offset. |
| 2108 | + :param single_detector_mode (bool): if true, it will always change the grating offset, |
| 2109 | + even if the output flipper is not in the direct port position. |
| 2110 | + """ |
| 2111 | + |
| 2112 | + target_offset = int(round(target_offset)) # ensure that we get integers for steps |
| 2113 | + grating = self.GetGrating() |
| 2114 | + port_index = self.GetFlipperMirror(OUTPUT_FLIPPER) |
| 2115 | + |
| 2116 | + if "flip-in" in self.axes: |
| 2117 | + flip_in_pos = self.GetFlipperMirror(INPUT_FLIPPER) |
| 2118 | + else: |
| 2119 | + flip_in_pos = DIRECT_PORT |
| 2120 | + |
| 2121 | + if "flip-out" in self.axes: |
| 2122 | + flip_out_pos = self.GetFlipperMirror(OUTPUT_FLIPPER) |
| 2123 | + else: |
| 2124 | + flip_out_pos = DIRECT_PORT |
| 2125 | + |
| 2126 | + single_detector = bool(single_detector_mode) |
| 2127 | + current_grat_offset = self.GetGratingOffset(grating) |
| 2128 | + current_det_offset = self.GetDetectorOffset(flip_in_pos, flip_out_pos) |
| 2129 | + logging.debug("Current goffset: %d (Grat: %d, Det: %d)", |
| 2130 | + (current_grat_offset + current_det_offset), |
| 2131 | + current_grat_offset, current_det_offset) |
| 2132 | + |
| 2133 | + # The detector offset compensates for small naccuracies introduced by the flip-mirror mechanism. |
| 2134 | + # This value is normally stable and seldom requires re-adjustment. |
| 2135 | + |
| 2136 | + if port_index == 0 or single_detector: |
| 2137 | + logging.debug( |
| 2138 | + "Choosing grating offset update (port_index=%s single_detector=%s)", |
| 2139 | + port_index, single_detector |
| 2140 | + ) |
| 2141 | + |
| 2142 | + # primary detector -> modify grating offset |
| 2143 | + if not allow_grating_offset: |
| 2144 | + logging.debug("Grating offset update disabled (grating=1, target=%d)", target_offset, ) |
| 2145 | + else: |
| 2146 | + grating_offset = target_offset - current_det_offset |
| 2147 | + self.SetGratingOffset(grating, grating_offset) |
| 2148 | + |
| 2149 | + # secondary detector (if multiple detectors) -> modify detector offset |
| 2150 | + else: |
| 2151 | + logging.debug( |
| 2152 | + "Choosing detector offset update (port_index=%s single_detector=%s)", |
| 2153 | + port_index, single_detector |
| 2154 | + ) |
| 2155 | + detector_offset = target_offset - current_grat_offset |
| 2156 | + self.SetDetectorOffset(flip_in_pos, flip_out_pos, detector_offset) |
| 2157 | + |
| 2158 | + self._updatePosition() |
| 2159 | + |
| 2160 | + def _doSetGoffsetRel(self, shift): |
| 2161 | + |
| 2162 | + """ |
| 2163 | + Change the grating offset by either changing the grating offset or detector offset. |
| 2164 | + :param shift (float): relative change in offset |
| 2165 | + """ |
| 2166 | + |
| 2167 | + # We expect the goffset axis to exist |
| 2168 | + current_pos = self.position.value["goffset"] |
| 2169 | + return self._doSetGoffsetAbs(current_pos + shift) |
| 2170 | + |
2067 | 2171 | def _updateShutterMode(self, pos): |
2068 | 2172 | """ |
2069 | 2173 | Update the state of the shutter depending on the detector used. |
@@ -2451,6 +2555,9 @@ def ShamrockGetDetectorOffsetEx(self, device, entrancePort, exitPort, p_offset): |
2451 | 2555 | offset.value = self._detoffset[_val(entrancePort), _val(exitPort)] |
2452 | 2556 |
|
2453 | 2557 | def ShamrockSetGratingOffset(self, device, grating, offset): |
| 2558 | + cur_offset = self._goffset[_val(grating) - 1] |
| 2559 | + new_offset = _val(offset) |
| 2560 | + time.sleep(abs(cur_offset - new_offset) / 10000) |
2454 | 2561 | self._goffset[_val(grating) - 1] = _val(offset) |
2455 | 2562 |
|
2456 | 2563 | def ShamrockGetGratingOffset(self, device, grating, p_offset): |
|
0 commit comments