Simplesequence triggers correctly
This commit is contained in:
@@ -709,15 +709,22 @@ class aa1AxisPsoDistance(aa1AxisPsoBase):
|
||||
|
||||
# ########################################################################
|
||||
# Bluesky flyer interface
|
||||
def prepare(self) -> DeviceStatus:
|
||||
def prepare(self, distance=None) -> DeviceStatus:
|
||||
""" Arm trigger for a synchronous or asynchronous acquisition"""
|
||||
if self._distance_value is not None:
|
||||
# Rearm the configured array
|
||||
if isinstance(self._distance_value, (np.ndarray, list, tuple)):
|
||||
self.dstArrayRearm.set(1).wait()
|
||||
# Start monitoring the counters
|
||||
self.dstEventsEna.set("On").wait()
|
||||
self.dstCounterEna.set("On").wait()
|
||||
if distance is not None:
|
||||
# Write a new array
|
||||
if isinstance(distance, (float, int)):
|
||||
self.dstDistance.set(distance).wait()
|
||||
elif isinstance(distance, (np.ndarray, list, tuple)):
|
||||
self.dstDistanceArr.set(distance).wait()
|
||||
else:
|
||||
if self._distance_value is not None:
|
||||
# Rearm the already configured array
|
||||
if isinstance(self._distance_value, (np.ndarray, list, tuple)):
|
||||
self.dstArrayRearm.set(1).wait()
|
||||
# Start monitoring the counters
|
||||
self.dstEventsEna.set("On").wait()
|
||||
self.dstCounterEna.set("On").wait()
|
||||
status = DeviceStatus(self)
|
||||
status.set_finished()
|
||||
return status
|
||||
|
||||
@@ -73,17 +73,24 @@ program
|
||||
PsoDistanceEventsOff($axis)
|
||||
PsoWindowConfigureEvents($axis, PsoWindowEventMode.None)
|
||||
PsoWaveformOff($axis)
|
||||
var $iPsoArrayPosAddr as integer = PSO_ADDR
|
||||
// Simple PSO trigger pattern
|
||||
var $iPsoArrayPos[] as real = [{% for psoDist in scan.psoBoundsPos[:-1] %} UnitsToCounts($axis, {{ psoDist }}), {% endfor %} UnitsToCounts($axis, {{ scan.psoBoundsPos[-1] }}) ]
|
||||
var $iPsoArrayNeg[] as real = [{% for psoDist in scan.psoBoundsNeg[:-1] %} UnitsToCounts($axis, {{ psoDist }}), {% endfor %} UnitsToCounts($axis, {{ scan.psoBoundsNeg[-1] }}) ]
|
||||
var $iPsoArrayPosAddr as integer = PSO_ADDR
|
||||
var $iPsoArrayPosSize as integer = {{ scan.psoBoundsPosSize }}
|
||||
var $iPsoArrayNegSize as integer = {{ scan.psoBoundsNegSize }}
|
||||
// Calculate negative array offset (in bytes)
|
||||
var $iPsoArrayNegAddr as integer = ($iPsoArrayPosAddr + length($iPsoArrayPos)) * 4
|
||||
|
||||
var $iPsoArrayPos[] as real = [{% for psoDist in scan.psoBoundsPos[:-1] %} UnitsToCounts($axis, {{ psoDist }}), {% endfor %} UnitsToCounts($axis, {{ scan.psoBoundsPos[-1] }}) ]
|
||||
DriveArrayWrite($axis, $iPsoArrayPos, $iPsoArrayPosAddr, length($iPsoArrayPos), DriveArrayType.PsoDistanceEventDistances)
|
||||
|
||||
{% if scan.psoBoundsNeg|length > 0 %}
|
||||
var $iPsoArrayNegAddr as integer = ($iPsoArrayPosAddr + length($iPsoArrayPos)) * 4
|
||||
var $iPsoArrayNegSize as integer = {{ scan.psoBoundsNegSize }}
|
||||
var $iPsoArrayNeg[] as real = [{% for psoDist in scan.psoBoundsNeg[:-1] %} UnitsToCounts($axis, {{ psoDist }}), {% endfor %} UnitsToCounts($axis, {{ scan.psoBoundsNeg[-1] }}) ]
|
||||
DriveArrayWrite($axis, $iPsoArrayNeg, $iPsoArrayNegAddr, length($iPsoArrayNeg), DriveArrayType.PsoDistanceEventDistances)
|
||||
{% else %}
|
||||
var $iPsoArrayNegAddr as integer = ($iPsoArrayPosAddr + length($iPsoArrayPos)) * 4
|
||||
var $iPsoArrayNegSize as integer = 0
|
||||
var $iPsoArrayNeg[] as real = []
|
||||
// DriveArrayWrite($axis, $iPsoArrayNeg, $iPsoArrayNegAddr, length($iPsoArrayNeg), DriveArrayType.PsoDistanceEventDistances)
|
||||
{% endif %}
|
||||
|
||||
|
||||
PsoDistanceConfigureArrayDistances($axis, $iPsoArrayPosAddr, length($iPsoArrayPos), 0)
|
||||
PsoDistanceCounterOn($axis)
|
||||
@@ -113,33 +120,15 @@ program
|
||||
///////////////////////////////////////////////////////////
|
||||
// Start the actual scanning
|
||||
///////////////////////////////////////////////////////////
|
||||
for $ii = 0 to ($iNumRepeat-1)
|
||||
// Feedback on progress
|
||||
$rglobal[4] = $ii
|
||||
|
||||
if $eScanType == ScanType.POS
|
||||
PsoDistanceConfigureArrayDistances($axis, $iPsoArrayPosAddr, $iPsoArrayPosSize, 0)
|
||||
MoveAbsolute($axis, $fPosEnd, $fVelScan)
|
||||
WaitForInPosition($axis)
|
||||
MoveAbsolute($axis, $fPosStart, $fVelScan)
|
||||
WaitForInPosition($axis)
|
||||
elseif $eScanType == ScanType.NEG
|
||||
PsoDistanceConfigureArrayDistances($axis, $iPsoArrayPosAddr, $iPsoArrayPosSize, 0)
|
||||
MoveAbsolute($axis, $fPosEnd, $fVelScan)
|
||||
WaitForInPosition($axis)
|
||||
MoveAbsolute($axis, $fPosStart, $fVelScan)
|
||||
WaitForInPosition($axis)
|
||||
elseif $eScanType == ScanType.POSNEG
|
||||
if ($ii % 2) == 0
|
||||
PsoDistanceConfigureArrayDistances($axis, $iPsoArrayPosAddr, $iPsoArrayPosSize, 0)
|
||||
MoveAbsolute($axis, $fPosEnd, $fVelScan)
|
||||
WaitForInPosition($axis)
|
||||
elseif ($ii % 2) == 1
|
||||
PsoDistanceConfigureArrayDistances($axis, $iPsoArrayNegAddr, $iPsoArrayNegSize, 0)
|
||||
MoveAbsolute($axis, $fPosStart, $fVelScan)
|
||||
WaitForInPosition($axis)
|
||||
end
|
||||
elseif $eScanType == ScanType.NEGPOS
|
||||
if $eScanType == ScanType.POS || $eScanType == ScanType.NEG
|
||||
PsoDistanceConfigureArrayDistances($axis, $iPsoArrayPosAddr, $iPsoArrayPosSize, 0)
|
||||
MoveAbsolute($axis, $fPosEnd, $fVelScan)
|
||||
WaitForInPosition($axis)
|
||||
elseif $eScanType == ScanType.POSNEG || $eScanType == ScanType.NEGPOS
|
||||
for $ii = 0 to ($iNumRepeat-1)
|
||||
// Feedback on progress
|
||||
$rglobal[4] = $ii
|
||||
if ($ii % 2) == 0
|
||||
PsoDistanceConfigureArrayDistances($axis, $iPsoArrayPosAddr, $iPsoArrayPosSize, 0)
|
||||
MoveAbsolute($axis, $fPosEnd, $fVelScan)
|
||||
@@ -149,13 +138,16 @@ program
|
||||
MoveAbsolute($axis, $fPosStart, $fVelScan)
|
||||
WaitForInPosition($axis)
|
||||
end
|
||||
Dwell(0.2)
|
||||
end
|
||||
Dwell(0.2)
|
||||
end
|
||||
|
||||
// Directly after scan
|
||||
PsoDistanceCounterOff($axis)
|
||||
DriveDataCaptureOff($axis, 0)
|
||||
DriveDataCaptureOff($axis, 1)
|
||||
// move back to start position
|
||||
MoveAbsolute($axis, $fPosStart, $fVelJog)
|
||||
WaitForInPosition($axis)
|
||||
end
|
||||
|
||||
|
||||
@@ -211,7 +211,7 @@ class SimpleFlyer(AsyncFlyScanBase):
|
||||
|
||||
def unstage(self):
|
||||
""" Wait for DAQ before unstaging"""
|
||||
time.sleep(5)
|
||||
time.sleep(1)
|
||||
yield from super().unstage()
|
||||
|
||||
|
||||
@@ -311,7 +311,7 @@ class GigaStepScanBase(ScanBase):
|
||||
|
||||
def unstage(self):
|
||||
""" Wait for DAQ before unstaging"""
|
||||
time.sleep(5)
|
||||
time.sleep(1)
|
||||
yield from super().unstage()
|
||||
|
||||
|
||||
@@ -396,7 +396,7 @@ class SnapAndStepScanBase(TemplatedScanBase):
|
||||
|
||||
def unstage(self):
|
||||
""" Wait for DAQ before unstaging"""
|
||||
time.sleep(5)
|
||||
time.sleep(1)
|
||||
yield from super().unstage()
|
||||
|
||||
|
||||
@@ -433,7 +433,7 @@ class SequenceScanBase(TemplatedScanBase):
|
||||
self.gate_high = gate_high
|
||||
self.gate_low = gate_low
|
||||
self.scan_repnum = repeats
|
||||
self.scan_repmode = repmode
|
||||
self.scan_repmode = repmode.upper()
|
||||
self.exp_time = exp_time
|
||||
self.exp_frames = exp_frames
|
||||
|
||||
@@ -501,24 +501,17 @@ class SequenceScanBase(TemplatedScanBase):
|
||||
|
||||
def prepare_positions(self):
|
||||
# Fill PSO vectors according to scan direction
|
||||
# NOTE: Distance counter is bidirectional
|
||||
self.psoBoundsPos = []
|
||||
self.psoBoundsNeg = []
|
||||
if self.scan_repmode in ("pos", "Pos"):
|
||||
if self.scan_repmode in ("pos", "Pos", "POS", "neg", "Neg", "NEG"):
|
||||
self.psoBoundsPos.append(self.scan_accdistance)
|
||||
for ii in range(self.scan_repnum):
|
||||
self.psoBoundsPos += [self.gate_high, self.gate_low]
|
||||
# self.psoBoundsPos[-1] = 10* (self.scan_accdistance+self.gate_low)
|
||||
if self.scan_repmode in ("neg", "Neg"):
|
||||
self.psoBoundsNeg.append(self.scan_accdistance)
|
||||
for ii in range(self.scan_repnum):
|
||||
self.psoBoundsNeg += [self.gate_high, self.gate_low]
|
||||
# self.psoBoundsNeg[-1] = 10* (self.scan_accdistance+self.gate_low)
|
||||
if self.scan_repmode in ("posneg", "PosNeg"):
|
||||
self.psoBoundsPos = self.psoBoundsPos[:-1]
|
||||
if self.scan_repmode in ("posneg", "PosNeg", "POSNEG", "negpos", "NegPos", "NEGPOS"):
|
||||
self.psoBoundsPos = [self.scan_accdistance, self.gate_high]
|
||||
self.psoBoundsNeg = [self.scan_accdistance + self.gate_low, self.gate_high]
|
||||
if self.scan_repmode in ("negpos", "NegPos"):
|
||||
self.psoBoundsNeg = [self.scan_accdistance, self.gate_high]
|
||||
self.psoBoundsPos = [self.scan_accdistance + self.gate_low, self.gate_high]
|
||||
|
||||
self.filesubs['psoBoundsPos'] = self.psoBoundsPos
|
||||
self.filesubs['psoBoundsNeg'] = self.psoBoundsNeg
|
||||
@@ -529,7 +522,7 @@ class SequenceScanBase(TemplatedScanBase):
|
||||
|
||||
def unstage(self):
|
||||
""" Wait for DAQ before unstaging"""
|
||||
time.sleep(5)
|
||||
time.sleep(1)
|
||||
yield from super().unstage()
|
||||
|
||||
|
||||
|
||||
@@ -68,4 +68,134 @@ def demosequencescan(scan_start, gate_high, gate_low, repeats=1, repmode="PosNeg
|
||||
raise RuntimeError("Beamline is not in ready state")
|
||||
|
||||
print("Handing over to 'scans.line_scan'")
|
||||
scans.sequencescan(scan_start, gate_high, gate_low, exp_time=exp_time, exp_frames=exp_frames, repeats=repeats, repmode=repmode)
|
||||
scans.sequencescan(scan_start, gate_high, gate_low, exp_time=exp_time, exp_frames=exp_frames, repeats=repeats, repmode=repmode)
|
||||
|
||||
|
||||
def becsequencescan(scan_start, gate_high, gate_low, repeats=1, repmode="PosNeg",
|
||||
exp_time=0.005, exp_frames=180, sync='pso'):
|
||||
""" Demo sequence scan with GigaFrost
|
||||
|
||||
This is a small BEC user-space sequence scan at the microXAS testbench
|
||||
triggering a customized scripted scan on the controller. The scan uses
|
||||
a pre-written custom low-level sequence scan, so it is really minimal.
|
||||
|
||||
NOTE: It calls the AeroScript template version.
|
||||
|
||||
Example:
|
||||
--------
|
||||
>>> demosequencescan(33, 180, 180, exp_time=0.005, exp_frames=1800, repeats=10)
|
||||
"""
|
||||
if not bl_check_beam():
|
||||
raise RuntimeError("Beamline is not in ready state")
|
||||
|
||||
# Parameter validation before scan
|
||||
if exp_frames <=0:
|
||||
raise RuntimeError(f"Requires at least one frame per cycle, got {self.exp_frames}")
|
||||
|
||||
# Synthetic values
|
||||
scan_roix = 2016
|
||||
scan_roiy = 2016
|
||||
scan_repnum = repeats
|
||||
scan_repmode = repmode.upper()
|
||||
scan_velocity = gate_high / (exp_time * exp_frames)
|
||||
scan_acceleration = 500
|
||||
scan_safedistance = 10
|
||||
scan_accdistance = scan_safedistance + 0.5* scan_velocity * scan_velocity / scan_acceleration
|
||||
scan_ntotal = exp_frames * repeats
|
||||
|
||||
if scan_repmode in ("POS", "NEG"):
|
||||
scan_range = repeats *(gate_high + gate_low)
|
||||
if scan_repmode=="POS":
|
||||
scan_end = scan_start + scan_range + scan_accdistance
|
||||
if scan_repmode=="NEG":
|
||||
scan_end = scan_start - scan_range - scan_accdistance
|
||||
elif scan_repmode in ("POSNEG", "NEGPOS"):
|
||||
scan_range = gate_high + gate_low
|
||||
if scan_repmode=="POSNEG":
|
||||
scan_end = scan_start + scan_range + scan_accdistance
|
||||
if scan_repmode=="NEGPOS":
|
||||
scan_end = scan_start - scan_range - scan_accdistance
|
||||
else:
|
||||
raise RuntimeError(f"Unsupported repetition mode: {repmode}")
|
||||
|
||||
|
||||
# Aerotech DDC settings: Internal event trigger: PsoEvent = 1
|
||||
t_modes = {'pso': 0, 'event': 1, 'inp0': 2, 'inp1': 4}
|
||||
p_modes = {'pso': 'PsoOutput', 'event': 'PsoEvent', 'inp0': 'HighSpeedInput0RisingEdge', 'inp1': 'HighSpeedInput1RisingEdge'}
|
||||
daq_trigger = t_modes[sync]
|
||||
pso_trigger = p_modes[sync]
|
||||
|
||||
# Drice data collection config
|
||||
daqname = "es1_ddaq"
|
||||
daqcfg = {'ntotal': scan_ntotal, 'trigger': daq_trigger}
|
||||
# Gigafrost config
|
||||
camname = "gfclient"
|
||||
camcfg = {
|
||||
"ntotal": scan_ntotal,
|
||||
"nimages": exp_frames,
|
||||
"exposure": 1000 * exp_time,
|
||||
"period": 2000*exp_time,
|
||||
"pixel_width": scan_roix,
|
||||
"pixel_height": scan_roiy
|
||||
}
|
||||
|
||||
# Fill PSO vectors according to scan direction
|
||||
# NOTE: Distance counter is bidirectional
|
||||
psoBoundsPos = []
|
||||
psoBoundsNeg = []
|
||||
if scan_repmode in ("POS", "NEG"):
|
||||
psoBoundsPos.append(scan_accdistance)
|
||||
for ii in range(scan_repnum):
|
||||
psoBoundsPos += [gate_high, gate_low]
|
||||
if scan_repmode in ("POSNEG", "NEGPOS"):
|
||||
psoBoundsPos = [scan_accdistance, gate_high]
|
||||
psoBoundsNeg = [scan_accdistance + gate_low, gate_high]
|
||||
|
||||
# PSO config
|
||||
psocfg = {
|
||||
"distance": psoBoundsPos,
|
||||
"wmode": "toggle"
|
||||
}
|
||||
|
||||
# Move to start position
|
||||
dev.es1_roty.move(scan_start).wait()
|
||||
|
||||
# Configure all devices
|
||||
dev.gfclient.configure(camcfg)
|
||||
dev.es1_ddaq.configure(daqcfg)
|
||||
dev.es1_psod.configure(psocfg)
|
||||
|
||||
# Stage all devices
|
||||
dev.gfclient.stage()
|
||||
dev.es1_ddaq.stage()
|
||||
dev.es1_psod.stage()
|
||||
dev.daq_stream1.stage()
|
||||
|
||||
# Kick off devices
|
||||
dev.gfclient.kickoff()
|
||||
dev.es1_ddaq.kickoff()
|
||||
dev.es1_psod.kickoff()
|
||||
print("Handing over to 'scans.line_scan'")
|
||||
|
||||
if scan_repmode in ["POS", "NEG"]:
|
||||
dev.es1_psod.prepare(psoBoundsPos)
|
||||
dev.es1_roty.move(scan_end).wait()
|
||||
elif scan_repmode in ["POSNEG", "NEGPOS"]:
|
||||
for ii in range(scan_repnum):
|
||||
if ii%2==0:
|
||||
dev.es1_psod.prepare(psoBoundsPos)
|
||||
dev.es1_roty.move(scan_end).wait()
|
||||
if ii%2==1:
|
||||
dev.es1_psod.prepare(psoBoundsNeg)
|
||||
dev.es1_roty.move(scan_start).wait()
|
||||
|
||||
# Stage all devices
|
||||
dev.gfclient.unstage()
|
||||
dev.es1_ddaq.unstage()
|
||||
dev.es1_psod.unstage()
|
||||
dev.daq_stream1.unstage()
|
||||
|
||||
# Move back to start
|
||||
dev.es1_roty.move(scan_start).wait()
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user