Files
csaxs_bec/docs/user/ptychography/lamni.md
T

30 KiB
Raw Blame History

(user.ptychography.lamni)=

LamNI

LamNI is an instrument for 3D ptychography via ptychographic X-ray computed laminography (PyXL). The instrument is described in detail here.

How to LamNI

… a step-by-step guide for beamline staff and expert users.

Sample change and alignment

The access to the sample region is blocked by the flight tube during measurement. To get the flight tube out of the way use
lamni.leye_in().
Mount the new sample. The X-ray eye is already in, but the X-ray optics needs to be moved out of the beam path by
lamni.loptics_out(). Potentially a larger area needs to be illuminated to properly see the sample, which can be done by open slits.

Coarse axis alignment

The effective position of the axis of rotation shifts with sample thickness or mounting position of the sample along the axis of rotation. The position of the axis of rotation is controlled by user parameters center of the lsamx and lsamy stages.

The recommended way to (re-)measure center for a new sample is the GUI-driven procedure below. It replaces the fully manual jog-by-hand steps that used to live here; those are kept further down as a fallback for when the automated procedure or the GUI is unavailable.

Automated rotation-center calibration

This opens the X-ray eye widget and walks through the calibration interactively. Pick the function based on what's mounted:

  • lamni.xrayeye_rotation_center_calibration_isolated() — for a sparse/isolated particle. You submit its centre position once at 0° and once at 180°; the midpoint of the two is the rotation axis' projected position (this works regardless of the axis tilt). No further confirmation step.
  • lamni.xrayeye_rotation_center_calibration_extended() — for a non-isolated/textured sample where the rotation centre can be identified visually. The sample sweeps 0° → 180° → 0° with the live view left open so you can watch for the point that doesn't move, then you submit a single click at 0°. The correction is applied, a short verification sweep (0° → 45° → 0°) runs, and you're asked "Alignment acceptable — stop here?" — answer n to refine further.

At the end you're shown the computed lsamx_center/lsamy_center and asked to confirm before they're written via dev.lsamx.update_user_parameter(...) / dev.lsamy.update_user_parameter(...).

Pass keep_shutter_open=True if it's hard to relocate the sample between steps, matching xrayeye_alignment_start() below. Interrupt with Ctrl-C to abort; the crosshair and DAP forwarding are cleaned up automatically.

Experimental: continuous-rotation "smear" aid

lamni.xrayeye_rotation_center_calibration_smear_experimental(sweep_deg=360.0, keep_shutter_open=False) is an experimental alternative to ..._extended() for the same non-isolated-sample case. Instead of judging the rotation centre from a single instant of live rotation, it rotates lsamrot continuously through sweep_deg (default a full circle) while accumulating a max-projection ("star-trail") composite from the camera: off-axis features smear into circular arcs, and the common center of curvature of those arcs is the rotation axis — usually an easier target to click than one live frame. sweep_deg can be reduced below 360 (even below 180) if a shorter arc already shows enough curvature. There is no automatic circle fitting — you still submit the centre by eye, same click mechanism as ..._extended(), and the same iterate/verify/apply flow follows. Not yet merged into the production branch; try it from experimental/rotation_center_smear.

Manual fallback

To observe the axis of rotation obtain the position of the Fresnel zone plate on the X-ray eye, possibly in the ueye gui by:

  1. lamni.lfzp_in(), move the FZP in
  2. dev.rtx.controller.feedback_disable(), disable feedback to allow lsam movements
  3. fshopen(), open the shutter
  4. umv(dev.lsamrot,90) to rotate the sample. One might observe the center of rotation at 0 and 180 degrees.
  5. umvr(dev.lsamx,0.01) to move lsamx and lsamy such that the center of rotation is at the center of the X-ray beam
  6. dev.lsamx and dev.lsamy will print current position and the center value. Update the center value by
    dev.lsamx.update_user_parameter({'center':8.69})
    dev.lsamy.update_user_parameter({'center':8.69})
  7. close the shutter: dev.omnyfsh.fshclose()

X-ray eye alignment

The BEC GUI is used to obtain a coarse sample alignment. Start the alignment process (which clears any previous alignment) by
lamni.xrayeye_alignment_start()

This opens the X-ray eye widget automatically. The procedure collects the sample centre position at 8 angles (0°–315° in 45° steps, full 360° rotation). At each angle the user clicks the sample centre in the image and presses Submit. After all 8 angles the data is sent to the Fit tab of the GUI where a sinusoidal fit runs automatically in both x and y directions. The fit parameters are loaded automatically at the end of the procedure.

With LamNI it can be difficult to relocate the sample between rotations. To keep the shutter open throughout, pass:
lamni.xrayeye_alignment_start(keep_shutter_open=True)

To manually reload the fit parameters after the procedure has completed:
lamni.read_xray_eye_correction_from_gui()
Note: this reads from the live GUI widget via the omny_xray_gui device. It only works as long as the XRayEye GUI window remains open. If the window has been closed, reload from the archived text files instead:
lamni.read_xray_eye_correction()
(these files are written to ~/Data10/specES1/internal/xrayeye_alignmentvalues at the end of every alignment run)

The correction is applied at each projection angle via
lamni.lamni_compute_additional_correction_xeye_mu(angle)
which is called automatically inside lamni.tomo_scan_projection().

To capture a single fresh frame without running the full alignment:
lamni.xrayeye_update_frame()
or with the shutter left open: lamni.xrayeye_update_frame(keep_shutter_open=True)

  • If slits were opened during alignment, close the slits: slits 1 to around 0.3
  • lamni.leye_out() remove the X-ray eye and move the flight tube in
  • possibly check slit0wh, idgap

Fine alignment

The sample fine alignment can be obtained using ptychography. For this a short laminogram has to be recorded.

  • lamni.tomo_parameters() adjust the ptychographic scan parameters for the alignment scan (FOV/step size/counting time) — tomo_type and number of projections are ignored, since the alignment scan always runs its own fixed 12 points spread evenly across the full 360 degrees, independent of the main tomogram's settings.
  • lamni.tomo_alignment_scan() perform the alignment scan. Requires x-ray-eye alignment to have already been done — it will abort with a message otherwise. Scan numbers, angles and the existing x-ray-eye-fit offset at each angle are written to ~/data/raw/logs/ptychotomoalign_scannum.txt and also printed at the end.
  • Run BEC_ptycho_align (in Matlab, force ptycho=1, and correct scan numbers) using the printed/logged scan numbers.
  • Click the sample position in the Matlab GUI and then load the generated file by, for example
    lamni.read_additional_correction('/sls/X12SA/data/e20632/Data10/cxs_software/ptycho/correction_lamni_um_S05389_lamni_fit.txt')
  • With this alignment a second iteration could be performed. To read the second correction file use lamni.read_additional_correction_2()

Shifting the FOV

  • lamni.tomo_fovx/y_offset=value [mm] will shift the field of view. Perform this adjustment from projections collected at lsamrot 0 degrees. This shift will rotate. In contrast the manual shift will be a constant shift, identical at all angles.

(user.ptychography.lamni.laminography)=

Laminography scan

Start the laminography scan by

  1. lamni.tomo_parameters() adjust the parameters to the desired settings.
  2. for test scans run
    lamni.tomo_scan_projection(angle)
    lamni.tomo_reconstruct()
  3. lamni.tomo_scan() to start the laminography scan

During the scan, a live progress report is printed (subtomogram/projection counters and an estimated time of completion). Gaps significantly longer than a normal acquisition cycle (e.g. a beamline-down interruption, or a crash followed by a restart) are detected automatically from the time between consecutive projections and excluded from the time estimate; the total time lost to such gaps is printed once the scan finishes.

Three angular sampling modes are implemented, same as flOMNI, but LamNI always scans the full 360 degrees — laminography's tilted sample geometry does not have the symmetry that lets flOMNI's 180-degree mode work, so there is no angular-range choice to make:

tomography mode parameters and defaults
8 sub-tomograms subtomo_start=1, start_angle=None
Golden ratio tomography (sorted in bunches) projection_number=None
Equally spaced with golden starting angle projection_number=None

The parameters above can be used to restart an interrupted acquisition manually, or - more conveniently - by running
lamni.tomo_scan_resume()
which reads the last recorded progress and resumes automatically at the exact point (subtomogram/angle, or projection for the golden ratio modes) the scan was interrupted at, without needing to look up the values by hand. When running from the tomo scan queuing system use lamni.tomo_queue_execute() instead!

In case of eight equally spaced sub-tomograms, an individual sub-tomogram can be scanned by lamni.sub_tomo_scan(subtomo_number, start_angle). If the start angle is not specified, it is computed depending on subtomo_number, ranging from 1 to 8.

Queueing multiple scans

Several tomo parameter sets can be queued and run sequentially on the same sample, without having to start each one by hand.

command explanation
lamni.tomo_queue_add(label=None) Snapshot the currently set tomo parameters and add them as a new job to the queue. Returns the job's index.
lamni.tomo_queue_show() Print and return the current queue, with status per job.
lamni.tomo_queue_delete(*indices) Delete one or more jobs by index.
lamni.tomo_queue_clear() Empty the queue.
lamni.tomo_queue_execute(start_index=0) Run all pending jobs in sequence, on the current sample.
lamni.tomo_queue_resume(start_index=0) Alias for tomo_queue_execute() — identical behavior, just a name that matches tomo_scan_resume().

The queue is persisted (it survives a BEC client restart). Each job's status is one of pending, running, incomplete, or done. A job that did not run to completion (an exception was caught, or the BEC client itself crashed mid-scan) is automatically resumed - rather than restarted - the next time lamni.tomo_queue_execute() is called.

If the process running the queue dies hard enough that it never gets to write a status update at all (a kernel restart, a Ctrl-C during a blocking prompt) a job can be left stuck showing running with nothing actually running. lamni.tomo_queue_delete(index) has no status guard and works on a stuck row regardless; you can also fix the status directly with lamni._tomo_queue_proxy.update_by_id(job_id, status="incomplete") (to make it resumable) or status="done" (to skip it). The GUI's Delete/Clear normally refuse to touch a running row, but detect a stale one (no recent scan heartbeat) and offer to proceed anyway with an explicit confirmation instead of blocking forever.

Example:

lamni.tomo_parameters()                  # set up parameter set #1
lamni.tomo_queue_add("fast overview")
lamni.tomo_parameters()                  # set up parameter set #2
lamni.tomo_queue_add("hires scan")
lamni.tomo_queue_show()
lamni.tomo_queue_execute()               # runs both, in order, on this sample

GUI: reusing an earlier job's settings. In the ☰ Queue control… dialog, select a single tomo job (not a command job — those have no scan parameters) and click "Load into editor" to pull its saved settings into the params panel's editor, as if you'd just clicked Edit. Nothing is written yet — review or tweak the fields, then Submit (writes live, blocked while the beamline is busy) or "Add to queue" (always allowed) as usual. If you already had an edit in progress, it asks before discarding it.

GUI: two different "Add to queue" buttons. The params panel's own "Add to queue" (visible in edit mode) queues whatever you've typed, unsubmitted. The ☰ Queue control… window's "Add current params to queue" is a different button on a different window — it always queues the live parameters, regardless of any edit open in the panel. If you have an unsaved edit open and click the queue window's button instead of the panel's, it warns and names the correct one before proceeding, since it would otherwise queue your last-submitted values, not what you just typed.

GUI: "Duplicate selected". Appends an exact copy of the selected job (any status — pending, running, incomplete, or done, and either a tomo or a command job) to the end of the queue, labeled with _dup appended, status reset to pending. Useful for re-running a job with the same settings without re-typing them, or as a starting point to tweak via "Load into editor".

Reacquiring from an earlier projection. A resumed job normally picks up exactly where it stopped. If a beamline problem means earlier projections need redoing too — even in a job that's already marked done — use:

lamni.tomo_queue_reacquire(job_index, projection_number)

job_index is the job's position, same indexing as tomo_queue_show(). projection_number is a flat, 0-indexed projection count that works the same way for all three tomography modes — for "8 sub-tomograms" it counts straight through all 8 in order (subtomogram 1's projections first, then subtomogram 2's, ...), exactly matching the running projection counter already shown in the live progress report / lamni.progress["projection"]; for the golden-ratio modes it's the same projection number those already use. This reopens the job at that point and resets every job queued after it — tomograms and command jobs alike, regardless of their own current status — to pending, so the next lamni.tomo_queue_resume() (or tomo_queue_execute()) call re-runs everything from there forward, in order. It does not run anything itself.

Example — job 0 already finished, but its last few projections (and the jobs queued after it) need redoing:

lamni.tomo_queue_show()               # find the job index and the projection number to restart at
lamni.tomo_queue_reacquire(0, 130)    # reopen job 0 at projection 130; jobs 1+ reset to pending
lamni.tomo_queue_resume()             # actually re-run, in order

Refuses (raises) if job_index points at a command job (nothing to reacquire), or if some other job in the queue is already incomplete/ running — only one job's progress can be tracked at a time, so resolve that one first (or pass its own index instead).

Command jobs — reconfiguring the beamline between scans

In addition to tomogram jobs, the same queue can hold command jobs: an ordered list of beamline reconfiguration steps (move a device, ...) that run instead of a scan. This is what lets one queue express "tomogram A, then reconfigure, then tomogram B" unattended, e.g. change energy and re-peak the undulator gap between two tomograms on the same sample.

lamni.tomo_queue_add_command(steps, label=None, idempotent=None)

  • steps: a single {"action": ..., "kwargs": {...}} dict, or a list of them run in sequence within that one job.
  • label: optional name shown by tomo_queue_show(), same as for tomo_queue_add().
  • idempotent: normally inferred (safe to blindly re-run after a crash only if every step is); override explicitly if needed.

Only actions from a fixed, reviewed registry can be queued — not arbitrary code:

action does parameters
move Move device(s) to absolute position(s). Only devices on the allow-list below can be targeted. positions: {device: target}, e.g. {"mokev": 6.2}
optimize_idgap Scan the undulator gap over a range and move to the peak. Not yet implemented (no-op stub). search_range: mm, default 0.5, range 02

Devices allowed for move: mokev (energy, keV), idgap (undulator gap, mm) — the same beamline-wide devices as flOMNI's queue. A move naming any other device is rejected, both when the job is added and again when it actually runs.

Example — change energy, then re-peak idgap, before the next laminogram:

lamni.tomo_queue_add_command(
    [{"action": "move", "kwargs": {"positions": {"mokev": 6.2}}},
     {"action": "optimize_idgap", "kwargs": {"search_range": 0.5}}],
    label="reconfigure to 6.2 keV",
)

tomo_queue_show() lists command jobs alongside tomogram jobs, e.g.:

[2]    pending  reconfigure to 6.2 keV  CMD move{'positions': {'mokev': 6.2}} > optimize_idgap{'search_range': 0.5}  [idem]

If a command job is interrupted by a crash, there is no per-step resume point — the whole job is either safe to redo from the top or it isn't:

  • If every step is idempotent (the usual case — an absolute move is harmless to repeat), lamni.tomo_queue_execute() silently re-runs the whole job from the top.
  • If any step is not idempotent, you are asked whether to re-run the job from the top or mark it done as-is.

Custom behavior at each projection angle

By default, every projection in a laminography scan is a single ptychography scan at that angle. For cases that need something more — e.g. record a projection, move a polarizer in, record again, move it back out, at every angle — write a small Python function and register it as an at_each_angle hook. Once registered, it can be selected per tomo-queue job, so the whole modulated laminogram runs unattended along with any other queued jobs.

A hook is a function func(lamni, angle), called once per projection angle instead of the normal acquisition:

def polarizer_modulation(lamni, angle):
    lamni.tomo_scan_projection(angle)
    umv(dev.polarizer, "in")
    lamni.tomo_scan_projection(angle)
    umv(dev.polarizer, "out")
command explanation
lamni.register_at_each_angle_hook("name", func) Load a hook function under name.
lamni.at_each_angle_hook = "name" Activate it — the next tomo-queue job added will use it.
lamni.at_each_angle_hook = None Deactivate it — back to normal projections for the next job.
lamni.list_at_each_angle_hooks() Print the names of all currently registered hooks (the active one is marked).
lamni.unregister_at_each_angle_hook("name") Remove a hook by name.

Example — queue a polarizer-modulated laminogram, then a normal one:

lamni.register_at_each_angle_hook("polarizer_mod", polarizer_modulation)

lamni.tomo_parameters()                        # set up the scan parameters as usual
lamni.at_each_angle_hook = "polarizer_mod"      # activate the hook
lamni.tomo_queue_add("polarizer run")

lamni.at_each_angle_hook = None                 # back to normal -- do not skip this!
lamni.tomo_queue_add("plain follow-up scan")

lamni.tomo_queue_execute()                      # runs both, hook active only for the first

Do not forget to reset lamni.at_each_angle_hook = None before adding a job that should run normally — each queued job remembers whatever at_each_angle_hook was set to at the moment it was added (like every other tomo parameter), so a job added right after a hook-using one without resetting it first will silently run with that hook still active.

Registered hooks are session-only — they live in memory and do not survive a kernel restart. If tomo_queue_execute() reaches a job whose at_each_angle_hook isn't registered in the current session (e.g. after restarting BEC), it stops with a clear error rather than silently running a plain scan; re-run register_at_each_angle_hook() for that hook, then call tomo_queue_execute() again to resume.

Editing a hook after registering it: register_at_each_angle_hook() stores whichever function object you pass it at that moment — it is not a live link to the function's name. If you edit the function's source and re-run the def (in a cell, or reload the file it's defined in — see below), the change is picked up automatically the next time the hook runs, and a note is printed telling you so. You don't need to call register_at_each_angle_hook() again after an edit.

Recommended: define hooks in a file, not inline in the shell. For anything beyond a quick one-off, put the hook function in a .py file — ideally together with the tomo_queue_add()/at_each_angle_hook calls that use it, so the file is a single, compact record of exactly what ran during the experiment. Load it with import myhooks (or from myhooks import my_hook) and, after editing, reload with importlib.reload(myhooks) — the automatic pick-up described above still works, because it detects the change via the module's own namespace, not the local name you imported it under. %run -i myhooks.py also works (runs in the current namespace, same as a cell). Avoid plain %run myhooks.py (without -i): it executes in a fresh, throwaway namespace each time, so an edit-and-rerun is not picked up automatically and the old version keeps running silently.

Example — hook loaded from a file, changing exposure and step size for a subset of projections: a hook can also read lamni.progress and temporarily change any scan parameter (e.g. tomo_countingtime, tomo_shellstep) just for specific projections, then restore it. This example (tomo_type 1) takes a longer exposure at a finer real-space step every 5th projection within sub-tomogram 2, and a normal projection everywhere else. ~/hooks/my_hooks.py:

def high_res_every_5th(lamni, angle):
    if lamni.progress["subtomo"] == 2 and lamni.progress["subtomo_projection"] % 5 == 0:
        orig_countingtime = lamni.tomo_countingtime
        orig_shellstep = lamni.tomo_shellstep
        lamni.tomo_countingtime = 0.5   # longer exposure
        lamni.tomo_shellstep = 0.2      # finer real-space step
        try:
            lamni.tomo_scan_projection(angle)
        finally:
            # restore even if the scan above raises, so a retry or the next
            # projection doesn't silently keep running with these settings
            lamni.tomo_countingtime = orig_countingtime
            lamni.tomo_shellstep = orig_shellstep
    else:
        lamni.tomo_scan_projection(angle)

Load and use it:

import my_hooks
lamni.register_at_each_angle_hook("high_res_every_5th", my_hooks.high_res_every_5th)

lamni.tomo_parameters()                              # set up the scan parameters as usual
lamni.at_each_angle_hook = "high_res_every_5th"       # activate the hook
lamni.tomo_queue_add("subtomo 2 high-res every 5th")

lamni.at_each_angle_hook = None                       # reset the session default for whatever's queued next
lamni.tomo_queue_execute()

progress["subtomo"]/progress["subtomo_projection"] are populated the same way for tomo_types 2/3, so the same pattern works there too — just note that unlike type 1's fixed 8 sub-tomograms, those types have no fixed sub-tomogram count (see Laminography scan above), so "sub-tomogram 2" means something different (and open-ended) for them.

GUI: the tomo parameters panel has an "At-each-angle hook" dropdown, listing whatever is currently registered from the CLI (register_at_each_angle_hook()) — the GUI process can't register hooks itself, only select one by name for the job you're about to submit or add to the queue. Pick "None (default)" for a normal scan. If a job's stored hook isn't currently registered anywhere, it still shows up in the dropdown labeled "(not registered in this session)" so it's never silently hidden.

Unregistering does not clear at_each_angle_hook. unregister_at_each_angle_hook() only removes the function from this session's registry — if at_each_angle_hook (or a queued job) still names it, that reference is untouched; it just becomes an unregistered name, flagged as such wherever it's shown (CLI, GUI dropdown). Set lamni.at_each_angle_hook = None (or the GUI dropdown's "None (default)") explicitly if you want to actually clear the selection, not just remove the hook it points to.

Tips and Tricks

Reset corrections

  • lamni.reset_correction()
  • lamni.reset_correction_2()
  • lamni.reset_xray_eye_correction()

Adjusting beam size with feedback running

If the beam size needs to be changed with feedback running, e.g. to switch from near-field to far-field ptychography, following steps can be taken:

  1. dev.loptz.enable_set=True to enable loptz movements with feedback running
  2. umvr(dev.lopz,_value_) move loptz to the desired position.
  3. lamni._manual_shift_x/y = _value_ correct the stage run out from motion along the optical axis (units of um). The exact value can be checked by comparing feature positions in projections before/after adjusting loptz.
  4. Potentially correct the alignment of the OSA

BEC tips

Print all global variables bec.global_vars()

dev.lsamx/y.wm or dev.lsamx/y prints a motor position

How to setup LamNI (software)

This part of the manual describes the software structure in more detail.

start the realtime feedback loop and BEC with OMNY

The nano-positioning is controlled by a feedback loop running on a real-time linux based computer. With all related hardware connected, this loop has to be started manually.

  1. Login to the computer by ssh control@mpc2680. The password is written on the physical machine.
  2. cd OMNY/lamni/
  3. ./startLAMNI

Once the loop has started, it is possible to start bec with the LamNI configuration file.

Loading the LamNI scripts is done by starting bec as bec --session lamni

The scripts can alternatively manually be loaded by
from csaxs_bec.bec_ipython_client.plugins.LamNI import LamNI lamni = LamNI(bec)

Loading the LamNI configuration (this command will load the LamNI configuration only - isolated from the beamline)
bec.config.update_session_with_file("/bec/csaxs_bec/csaxs_bec/device_configs/lamni_config.yaml")

If the realtime system is restarted, BEC will lose communication. To restart:
lamni.rt_off() … then wait a 10 seconds
lamni.rt_on()

Initialization of the stages

The stages of LamNI are referenced in respect to their endswitches or reference marks. The stages have to be initialized at the beginning of a run or when the Galil motor controller has been reset or restarted. To see the status of the stages following commands are available:

Show the status of all galil controllers (all stepper motors and the UPR rotation stage)
dev.lsamx.controller.galil_show_all()

The same holds true for the Smaract stages which control the OSA position. Their status can be checked by
dev.losax.controller.show_all()

In case referencing of the LamNI stages is required, run
lamni.init.lamni_init_stages() This script will first verify that the stages are not in an initialized state, and then reference all stages in a safe way. The user will be warned in case of a potentially risky situation. This mainly involves a collision risk upstream with the exposure box exit window. It might be worth to check clearance prior to calling the init script.

Interferometer

The position feedback in LamNI is controlled in closed loop to an interferometric position measurement. To show the signal of the interferometers: lamni.show_signal_strength_interferometer()
Typical values with proper alignment are
TODO

Interferometer feedback commands

  • lamni.feedback_enable_with_reset()
  • lamni.feedback_disable()
  • lamni.feedback_enable_without_reset() *is only used internally by lamni methods
  • if reset of angle interferometer is required
    lamni.feedback_disable_and_even_reset_lamni_angle_interferometer()
  • lamni.feedback_enable_with_reset()

Scanning in 2D and sample alignment

The underlying scan function can be called as
scans.lamni_fermat_scan()

Use scans.lamni_fermat_scan? for detailed information. A prerequisite for scanning is a running feedback system.

GUI tools

During operation the BEC GUI will show the relevant cameras or progress information. TAB completion on lamni.lamnigui_ will show all options to control the GUI. Most useful:

  • lamni.lamnigui_show_progress() — shows the measurement progress with ring progress bar
  • lamni.lamnigui_show_xeyealign() — opens the X-ray eye alignment GUI on the Alignment tab
  • lamni.lamnigui_show_xeyealign_fittab() — opens the X-ray eye GUI on the Fit tab to inspect the sinusoidal fit
  • lamni.lamnigui_idle() — shows the LamNI idle splash screen
  • lamni.lamnigui_docs() — opens the PDF documentation viewer

X-ray optics alignment

The positions of the optics stages are stored as stage parameters and are thus linked to the configuration file.
Example: The OSAx "in" position can be reviewed by dev.losax.user_parameter
Update the value by (example "losax", "in") by dev.losax.update_user_parameter({"in":value})

lamni.lfzp_info() shows info about the available FZPs at the current energy of the beamline. Optional parameter is the photon energy in keV.
Example: lamni.lfzp_info(6.2)

The laser feedback will be disabled and fine alignment lost if foptx/y are moved!

Following functions exist to move the optics in and out, the naming is self-explaining.

  • lamni.lfzp_in()
  • lamni.loptics_in()
  • lamni.loptics_out()
  • lamni.losa_in()
  • lamni.losa_out()
  • lamni.lfzp_in()