@@ -328,3 +328,140 @@ Claude updated the code in [scantools:issue/4850](https://code.ornl.gov/idac/cs/
## Prompt 3
You are working in the tasking project, bl4b-alignment-integration branch. The code uses the Experimental Physics Industrial Control System (EPICS) as its basis. Inspect bl4b-scripts; it is currently on the ScriptScan/2026A branch. Read the file bl4b-scripts/flying_z.py - it is a recent example of a very efficient way to opitimize the position of BL4B:Mot:hs. Read the file bl4b-scripts/CHI_scan.py. Please make a plan to synthesize a new file bl4b-scripts/flying_chi.py that performs the function of CHI_scan.py using the efficient camonitor callback and timestamp correlation technique in flying_z.py. You may freely inspect the git log of all code repositories as you need to develop your understanding of the scan system, including modifications to the existing functions as that may be informative towards the types of parameterizations that are needed. If you need a tool to analyze the code or artifacts, please ask me to fetch it for you. If you run into an issue where you need sudo, ask me to execute the line in a separate terminal.
```
● I've read flying_z.py, CHI_scan.py, CHI_measurement.py, move_align.py, and the analysis-chis-scan-integration.md notes. Here's my
plan.
Plan: bl4b-scripts/flying_chi.py
Core idea
Replace CHI_scan.py's 11-step move → accumulate Cv=1.0 mC → read XY image → compute σ loop with one continuous chis sweep from -1.8°
→ +1.8°. Run camonitor callbacks on timestamped PV updates, then np.interp each observable onto the chis.RBV timeline just like
flying_z.py does. Fit the resulting curve the same way CHI_scan.py already fits step-scan data.
Key PV difference from flying_z
flying_z reduces to a single scalar (BL4B:Det:N1:Det1:EventRate_RBV). CHI_scan needs beam shape, not rate. The scantools integration
work (analysis-chis-scan-integration.md §4 / §9) confirms ADnED publishes pre-computed 1D projections we can camonitor directly:
- BL4B:Det:N1:Det1:XY:Stat:ProfileAverageX_RBV (256-element X profile)
- BL4B:Det:N1:Det1:XY:Stat:ProfileAverageY_RBV (304-element Y profile)
That avoids shipping the full 256×304 XY:Array:ArrayData waveform through every callback. Each profile update is ~1 KB and can be
reduced to (MeanX, SigmaX, totalX) inside the callback.
Proposed structure
1. User parameters at top (match CHI_scan.py naming):
b. Set slits (si:Y, s1:Y = SlitHeight; s2:Y = 2 × SlitHeight), wait idle.
c. Move chis to startCHI, wait idle.
d. Register the four camonitor callbacks.
e. StartDiag.put(1), chis.put(endCHI), wait idle, StopDiag.put(1).
f. camonitor_clear all four PVs.
g. Restore EventUpdatePeriod, BDST, VELO; reset slits to nominal (0.25/0.25/0.5) the way CHI_scan.py does.
6. Post-process (mirror flying_z lines 112–138, then CHI_scan lines 245–326):
- Extract (tCHI, vCHI), (tPC, vPC), and the (t, mean, sigma, total) tuples for each profile.
- np.interp each derived observable (sigmaX, sigmaY, totalX) onto tCHI.
- For intensity fits, normalize by np.gradient(PC_on_chi, tCHI) (proton-charge rate).
- Fit per enabled mode:
- FitXdist → Gauss_ConstantBkg(vCHI, sigmaX_interp) → max σₓ
- FitYdist → GaussDip_ConstantBkg(vCHI, sigmaY_interp) → min σᵧ
- FitIdist → Gauss_ConstantBkg(vCHI, totalX_interp / dPC) → max intensity
- Plot the chosen curve(s) with fit centerline + FWHM, same style as CHI_scan.
- If MoveToXFit and the fit center lies inside [startCHI, endCHI], CHI.put(fit_center).
Open questions for you before I code it
1. Flight velocity for chis — flying_z.py pins hs at VMAX=VELO=2 mm/s. For a 3.6° chis sweep we need to pick a VELO that's (a) safe
for the stage and (b) slow enough that each ~10 ms profile update covers <<1 chi FWHM. Do you have a target °/s in mind (or should I
camonitor chis during a current CHI_scan step-scan to measure the stage's typical slew rate, then pick ~25%)?
2. VELO/VMAX restore on exit — flying_z does not restore these. Is that intentional, or should flying_chi restore them? (I'd
recommend save-and-restore; happy to do the same in a follow-up to flying_z.)
3. Drop FitImage? — the N-slice line-fit (CHI_scan.py lines 176–224) needs the full 2D image at each chi. In a flying scan, that'd
mean camonitoring XY:Array:ArrayData at ~10 Hz — doable but ~3 MB/s and a lot of per-callback work. I'd like to omit FitImage from v1
and rely on the X/Y profile PVs only. Acceptable?
4. EventUpdatePeriod units — I'm assuming the 10 in flying_z is ms (so ~100 Hz). Can you confirm, or point me at where the IOC DB
declares it? I need it to size the sweep duration properly.
5. Profile-PV update cadence — do the ProfileAverage{X,Y}_RBV waveforms republish on every EventUpdatePeriod tick, or on a separate
Stats-plugin clock? If separate, we may need to coerce it (or pick a matching value).
If you want, I can dig (Q4/Q5) from the running IOC — would need you to run a cainfo + a timed camonitor on the three detector PVs
for me to read back. Say the word and I'll hand you the exact commands.
```
### Prompt 3.1
> Good! To answer your questions:
> Re: 1) Code an optional function to analyze the slew rate for the target motor (in this case BL4B:Mot:chis{.RBV}). This would be used once choose the required VELO to optimize statistics for the target motor. If unset, use the values as configured (do not alter, nor restore).
> Re: 2) good catch, thanks! Yes, please code restore code on exit, subject to 1) above.
> Re: 3) Yes, you may defer FitImage to this version and rely on X/Y profile PVs only.
> Re: 4) You can read the units of EventUpdatePeriod from the PV directly: BL4B:Det:N1:EventUpdatePeriod.EGU (a caget for me gives 'ms', so confirmed).
> Re: 5) For this one, lets dig it from the running IOC, go ahead and give me a command to run to inform your plan
```
● Here's the diagnostic command. We want to see how often each of the three detector PVs posts updates, at both the current and the
flying_z setting of EventUpdatePeriod. Please run this at the BL4B DASsrv where caget/camonitor/caput resolve the BL4B PVs and paste
back the output:
# --- A. Baseline at the current EventUpdatePeriod ---