<<

TkI - The Perl/ Interface to Online Version November 6, 2019 by Thorsten Kracht Contents

1 The Introduction 6

2 Acknowledgments 7

3 Whattodo,if... 8 3.1 GRA GCI:Usedmemory¿90%oftotalspace ...... 8 3.2 online -tki: START TIMER:T1isbusy...... 8 3.3 online -tki: no file scan list.pl ...... 8

4 News 9

5 General Remarks 11 5.1 CommandLineOptions...... 11 5.2 Tango: Alternative online. ...... 11 5.3 Tango: Use tags for selecting devices from .xml file ...... 12 5.3.1 Tags,usecase1:detectors ...... 13 5.3.2 Tags, use case 2: user vs. expert view ...... 13

6 The Toplevel Widget 15 6.1 TheStartupScriptTkIrc.pl...... 15 6.2 TheFileMenuButton ...... 16 6.3 TheScanMenuButton...... 17 6.4 TheDiffMenuButton ...... 17 6.5 TheMiscMenuButton...... 17 6.6 TheOptionsMenuButton ...... 19 6.7 TheTableMenuButton ...... 20 6.8 TheDiagMenuButton...... 21 6.9 SelectableApplications ...... 23 6.10 BeamlineSpecificCode ...... 24 6.11 StopFunction...... 24

7 Scans 29 7.1 TheScanWidget...... 29 7.1.1 ’PrepareRegions’Menu...... 30 7.1.2 Scan’Options’Menu ...... 31 7.1.3 Scan’Utils’menu ...... 33 7.1.4 Scan’Types’menu...... 34 7.1.5 Scan’Flags’menu...... 35 7.2 The ’Scan Device Selection’ Menu ...... 40 7.2.1 TheWidget...... 40 7.2.2 VirtualCounters ...... 42 7.2.3 %Spectra::data scan...... 42 7.2.4 Extracode ...... 43 7.3 ContinuousScans...... 43 7.3.1 Scanintervaltoosmall...... 45 7.4 NexusOutput...... 45 7.5 Performance ...... 46

1 8 Diffractometer 47 8.1 Creating the Diffractometer Server ...... 47 8.1.1 4-Circle ...... 47 8.1.2 6-Circle ...... 49 8.2 E4Cvs.E6C ...... 50 8.3 The Diffractometer GUI (SOLEIL) ...... 51 8.4 TheOrientation...... 51 8.4.1 Differences: Petra III (SOLEIL) and DORIS ...... 51 8.5 TheUBMatrixWidget...... 53 8.6 The Diffractometer Alignment Widget ...... 56 8.7 ThehklScanWidget ...... 58 8.8 ThePerlInterface ...... 60 8.9 The.graInterface...... 62

9 Sweep 63 9.1 TheWidget ...... 63 9.2 SweepList.pl ...... 65 9.3 SweepList.pl with device specification ...... 66

10 Preliminary: The General Scan 68 10.1 A Template for a General Scan Module ...... 69

11 The Move Widget 76 11.1 TheMotorPropertiesWidget ...... 77 11.2 TheEncoderWidget ...... 78 11.3 VirtualMotors ...... 79 11.4 Slits...... 79

12 The MCA Widget 81

13 The DSO Widget 84

14 Beamline Specific Code by Examples 86 14.1 ’Helloworld’,Button...... 86 14.2 Energy ...... 87 14.3 EntryWidgets ...... 87 14.4 Buttons,Keithley-428 ...... 88 14.5 Motors ...... 90 14.6 Monochromator ...... 90 14.7 hkl ...... 92 14.8 Pilatus-300K, B1, BW4, P03, P09 ...... 93 14.9 MAXVEncoder,Tango ...... 96 14.10Spk/Slt,Tango ...... 97 14.11VHSC005N,HVPS,ISEG...... 99 14.12 Lom, Compound Device, P08, Tango ...... 100 14.13 FMB Oxford DCM, CalibrationUnits, P01, P02, Tango ...... 101 14.14MAR-CCD...... 104 14.15 Hexapod, Tango, P03 ...... 104 14.16 Analyzer, Tango, P09 ...... 105 14.17 MultipleMotors, Tango, P09 ...... 106 14.18 Lenses Box, Tango, P10 ...... 108 14.19LCX,P10...... 109 14.20 Photonic Science Camera, P03 ...... 110 14.21 VFCADC, gain, offset and polarity ...... 111 14.22PerkinElmerDetector ...... 112 14.23ProsilicaCamera ...... 114 14.24MythenDetector ...... 114 14.25TwoThetaP07...... 116 14.26PCO4000Detector ...... 116 14.27RoperQuadRO...... 119 14.28MarCCD ...... 124 14.29PiezoPiE712 ...... 124 14.30GalilSlit ...... 126

15 Symbols 129 15.1 Introduction...... 129 15.2 DORIS MCA...... 129 15.3 FLAG TKI STOP ...... 129 15.4 INTERRUPT SCAN ...... 129 15.5 RETURN VALUE ...... 129 15.6 SCAN NAME DONE...... 129

16 Functions 130 16.1 Util::display text() ...... 130 16.2 Util::edit file() ...... 130 16.3 FileSelector...... 130 16.4 Util::log()...... 130 16.5 Util::prompt()...... 130 16.6 Util::refresh()...... 131 16.7 Util::yesno() ...... 131 16.8 Util::zoom() ...... 131

17 Examples 132 17.1 Access device selection in before-code, P03, Lambda ...... 132 17.2 Sweep with outer loop motor, P10 ...... 132 17.3 PE image series, incl. loop over SDD positions, P02 ...... 134 17.4 Interrupting Perl code that was started from online -tki(P10)...... 136 17.5 Optimizing a motor position, while the MCA menu is active(P01)...... 137 List of Figures

6.1 TheTkIToplevelMenu...... 16 6.2 TheZoomMenu ...... 17 6.3 TheTkIFileMenu ...... 18 6.4 TheTkIScanMenu...... 19 6.5 TheTkIDiffractometerMenu ...... 20 6.6 TheTkIMiscMenu...... 21 6.7 TheMoveSlitMenu ...... 22 6.8 TheMOSTABMenu ...... 23 6.9 TheMonitorWidget ...... 23 6.10 TheMonitorConfiguration ...... 24 6.11 ThePerlScriptsMenu ...... 24 6.12 TheTkIOptionsMenu ...... 25 6.13 SelectWorkstationViewport ...... 26 6.14 TheTkITableMenu ...... 27 6.15 TheTkIDiagnosticsMenu ...... 28 6.16TheVMEWidget...... 28

7.1 TheTkIScanWidget ...... 29 7.2 CM Scans (Combined Moves Scans) ...... 31 7.3 2DScans ...... 31 7.4 3DScans ...... 32 7.5 TheOuterLoopList ...... 32 7.6 TheRegionsWidget ...... 33 7.7 TheEXAFSRegionsWidget ...... 34 7.8 TheScanOptionsMenu ...... 35 7.9 TheScanParametersMenu...... 35 7.10 TheScanUtilsMenu ...... 36 7.11 The EXAFS Sample Scan Menu ...... 36 7.12 TheScanTypesMenu...... 37 7.13 TheScanFlagsMenu...... 37 7.14 TheScanDeviceSelection ...... 40 7.15 AVirtualCounter...... 42 7.16 TheVirtualCounterFileMenu ...... 43 7.17 TheVirtualCounterVersions ...... 44 7.18 AnExtraCodeExample ...... 45

8.1 : Create Diffractometer Server ...... 47 8.2 Jive: Diffractometer Properties ...... 48 8.3 Jive:CreatePseudoAxis ...... 48 8.4 Jive: PseudoAxis Properties, h, E4C ...... 49 8.5 Jive: PseudoAxes Properties, hkl, E4C ...... 50 8.6 Jive: PseudoAxes Properties, Psi, E4C ...... 51 8.7 Jive: PseudoAxes Properties, q, E4C ...... 52 8.8 Jive: Create Diffractometer Server, E6C ...... 52 8.9 Jive: Diffractometer Properties, E6C ...... 53 8.10 Jive: Create PseudoAxis, E6C ...... 53 8.11 Jive: PseudoAxis Properties, h, E6C ...... 54 8.12 Jive:Diffractometer,E6C...... 54 8.13 Jive: PseudoAxes Properties, hkl, E6C ...... 55 8.14 Jive: PseudoAxes Properties, Psi, E6C ...... 55

4 8.15 Jive: PseudoAxes Properties, q2, E6C ...... 56 8.16 TheUBMatrixWidget ...... 56 8.17 The Diffractometer Alignment Widget ...... 57 8.18 ThehklScanWidget...... 59 8.19 ’DisplayAngles’output...... 60

9.1 TheSweepWidget ...... 64

10.1 TheTkIScanGWidget ...... 68 10.2 The TkI ScanG Widget, Module Popup Menu ...... 69 10.3 The TkI ScanG Widget, Flags Popup Menu ...... 69 10.4 TheTkIScanGWidget,2D...... 70 10.5 TheTkIScanGWidget,3D...... 70

11.1 TheMoveWidget...... 76 11.2 TheMotorSelector ...... 77 11.3 TheMotorPropertiesWidget ...... 78 11.4 TheEncoderWidget ...... 79 11.5 TheSlitSelector ...... 80

12.1TheMCAWidget...... 81 12.2 TheMCAOptionsMenu ...... 83 12.3 The MCA Select Devices Menu ...... 83

13.1TheDSOWidget ...... 84

14.1HelloWorld...... 86 14.2Energy...... 87 14.3 TheVoltagesInterface ...... 88 14.4 TheK-428Interface...... 89 14.5Motors...... 90 14.6 TheMCInterfaceatX1...... 92 14.7ThehklWidget ...... 93 14.8 Pilatus-300K,P03,P09 ...... 95 14.9 An OMS MAXV controller with an encoder ...... 98 14.10Spk ...... 99 14.11BLSC:VHSC005N ...... 101 14.12BLSC:Lom...... 102 14.13BLSC:FMB,P01...... 103 14.14BLSC:Hexapod,P03 ...... 105 14.15BLSC:Analyzer,P09 ...... 106 14.16BLSC: MultipleMotor, P09 ...... 107 14.17BLSC:LensesBox,P10 ...... 108 14.18BLSC:LCXCamera,P10...... 110 14.19BLSC: Photonic Science Camera, P03 ...... 111 14.20BLSC: Perkin Elmer Detector, P02 ...... 113 14.21BLSC:Mythen ...... 115 14.22BLSC:TwoThetaP07 ...... 117 14.23BLSC:Pco4000...... 119 14.24BLSC:RoperQuadRO ...... 123 14.25BLSC:MarCCD ...... 125 14.26BLSC:PiezoPiE712...... 127 14.27BLSC:Galil...... 128 Chapter 1

The Introduction

TkI is an is the to Online. It is written in Perl [1] using the Perl/Tk module [2].

6 Chapter 2

Acknowledgments

J. Medved created the record procedure and also the corresponding Online widget. The implemented diffractometer features are based on software has been created at SOLEIL. We would like to express our appreciation for granting us the permission to use of it. Furthermore we would like to thank Fred´ eric-Emmanuel´ Picca for his explanations and kind support. Several authors made contributions, all are from SOLEIL:

• The hkl library (version 3.0.0) was coded by Fred´ eric-Emmanuel´ Picca

• The diffractometer server was coded by Vincent Delos, Sylvain Dupuy, Vincent Hardion and Fred´ eric-Emmanuel´ Picca.

• The GUI was coded by Sylvain Dupuy, Vincent Hardion and Assane Diouf.

7 Chapter 3

What to do, if ...

This chapter contains instructions about what to do, if an error occurred.

3.1 GRA GCI: Used memory ¿ 90% of total space

This message is indicates that the internal storage is almost exhausted. The command cleanup deletes all data which have been written to a disk file and which are currently not displayed. After the data are internally deleted, cleanup does a compress (garbage collection). In fact, cleanup is automatically executed at the end of each scan which is started from the Scan widget. The inspect the amount of free memory: * = memory_free(). The inspect the amount of total memory: * = memory_total().

3.2 online -tki: START TIMER: T1 is busy

This error occurs in the TkI Scan menu. If it’s not a hardware problem, it may be due to the fact that the timer is declared to run in preset mode (software) but from the hardware side it is operated as a normal timer. Remember, if a timer is operated in preset mode, it opens that gate until it receives a certain number of counts, from a monitor counter. Normal timer operation means that the gate is opened for a selected time. User Action: Enter the Scan-Options-Select Scan Devices menu and make sure that the timer is not in preset mode. Then stop the timer by issuing a * = stop_timer(tXX) command. Replace tXX with the corresponding timer name.

3.3 online -tki: no file scan list.pl

This error occurs, if the ’List’ option of the scan menu is unintentionaly enabled. Enabling this option requires that the file scan list.pl has been prepared. User Action: Disable the ’List’ option. The button is located at the bottom part of the scan menu.

8 Chapter 4

News

This chapter lists the most recent changes. November 6, 2019 Latest LaTex run of this manual. 18.4.2007 New option in the toplevel-Diag menu: ’Show errors’, displays the errors that occured in the current session. 4.4.2007 New MOSTAB feature: ’Use I1’. If disabled the I1 input (I-Doris) is ignored. 18.1.2007 New option for the select scan devices widget (7.14): SUM-SCA. If selected an additional SCAN is created that stores the sum of the SCAs. 11.5.2006 The EXAFS signal I0 and I1 can be selected (7.9). 11.5.2006 Added the ESS (EXAFS Sample Scan) menu (7.11). 10.5.2006 Added the Record option to the toplevel file menu (CD/DvD burner). 27.4.2006 Moved the scan options into a single menu (7.9). 6.4.2006 Introduced raw continuous scans. They can be executed with non-empty during-files, allowing for VCs, etc. at a cost of reduced temporal coverage. 19.12.2005 The heatup time, which is used for the ”Automatic Beam Shutter” option, can be changed. Accessible via Scan-Options. 29.11.2005 Introduced the ”Net SCAs” flag in the Select Scan Devices menu. If enabled a linear background is subtracted from the SCA values. 23.11.2005 Introduced File-¿”Flush online.db”, closes and opens the file /online dir/online.db which stores scan limits, etc. 10.11.2005 New command line options for font selection: -bold -small -tiny -pico -clean -fixed -courier 19.10.2005 Fixed the ”C1, C2, C3, C10” bug 7.10.2005 Scan Menu: Some ”Flags” remain changeable during scans.

9 6.10.2005 Scan Menu: Lin/Log scale selection during scans possible. 3.10.2005 New feature for ”Select Scan Devices”: Profile. Profiles store states of the menu, can be stored and loaded. 27.9.2005 Changed the assignment of the ”+” and ”-” buttons of the zoom widget. 26.9.2005 A warning is generated, if the memory usage exceeds 90%. 23.9.2005 MCA: Dropped ”Do you really ...” question before clearing the MCA. 22.9.2005 Implemented: move by increments without backlash. 20.9.2005 Implemented command line history for TkI. 10.5.2005 Changed the assignment of the ZOOM keys. 19.5.2004 New feature: beamline specific code (monochromator, table, etc.), see section 14. 18.5.2004 TkI startup : /online dir/TkIrc.pl 27.4.2005 Changed PS file names to SCAN NAME.ps 2.5.2005 TkI: Changed MCA storage for repeated scans. Every repeat sweep has its own MCA subdirectory. 14.4.2005 TkI: Changed ’extra code’ feature: The Before_during code is insert at the beginning of the during file, the After_during code at the end of the during file. 6.4.2005 FIOViewer: The Options pull-down menu includes a check button for Show texts. If enabled, TEXT GQEs are displayed in the GQEs window. The sequence MB-1 (select GQE) followed by MB-3 invokes a toolbox widget for TEXTs. 5.4.2005 MCA menu: Changed the position of the title string slightly, y => 1.12 to y => 1.08. 5.4.2005 Scan Menu: If the flag Auto return is to No and a scan is interrupted, motors will no longer be moved back to their starting positions but stay where they are. 4.4.2005 Move menu: If the option Display Signal is selected, but no symbol Signal exists, motors are stopped and the option is cancelled (although the check button stays high-lighted). The symbol Signal is usually defined in /online_dir/exp_ini.exp, e.g.: signal = [vfc(c1, t1, 0.1)]

22.3.2005 Implementation of virtual motors. Chapter 5

General Remarks

• New features are listed under the toplevel help topic News. • In order to avoid mouse clicks, many actions have been bound to Alt-Keys. The key assignment can be found in the help topic of the widget, in the pop-up menus, e.g.: Postscript Atl-p or on the action button itself. If a letter is underlined, like in ’’, the letter can be used with the Alt key to trigger the action that is associated with the button. All Widgets can be closed with Alt-x.

• The term symbol denotes Spectra symbols. Symbols that are relevant for online applications are typically defined in /online dir/exp ini.exp. They can be accessed from Perl via the hash %Spectra::SYM, e.g.: $Spectra::SYM{ scan_name}.

• The term scan denotes a procedure whereas SCAN stands for a piece of data, a graphical queue element (GQE). SCANs consists of 2 columns ( x and y) and contain some additional information.

• The term toplevel widget denotes the widget that appears after > online -tki. It is titled ’On- linehostname’.

• The toplevel widget displays the motor positions and motor parameters. These items are updated when motors are moved. If the toplevel widget is iconized, there is no update and dead time of measurements can be considerable reduced.

5.1 Command Line Options

The program is started by the following command: online -tki

Fonts are selected by:

Weight: -bold -medium Size: -14 -13 -12 -11 -10 Family: -clean -courier -fixed -helvetica -lucida -lucidatypewriter -screen -times -utopia

The default is ’-courier -14’. Other possible commands are ’online -tki -fixed -13’ and ’online -tki -11 -helvetica’. They select smaller fonts thereby produce smaller widgets. On non-experiment an Online session can be simulated: online -tki -sim

5.2 Tango: Alternative online.xml

The file /online dir/online.xml contains the Tango devices that are used by an online session. It is possible to use an alternative version of the file, e.g.: online -tki - online_galil.xml

11 Depending on the selections which are made by the alternative .xml file, it may be necessary to do some changes to /online dir/exp ini.exp and to /online dir/TkIrc.pl. The following lines could be part of exp ini.exp. They modify its behaviour depending on which .xml file is loaded: beamline = haspp23 ! ! (1) ! if compare( "online_galil.xml", trnlnm( online_xml)) beamline = dummy_line endif

! ! (2) ! if compare( "online.xml", trnlnm( online_xml)) def vm1 def vm2 def vm3 endif

Here are the explanations:

(1) If the symbol beamline is set to dummy line, online does not try to identify the monochromator device.

(2) In this example the virtual motors are defined for the ’normal’ session only. Most likely because the virtual motors use real motors that are not listed in online galil.xml.

Here is the begin of a TkIrc.pl file which is modified to take alternative .xml files into account: if( $ENV{’ONLINE_XML’} eq "online.xml") { $Spc::res_h{ blsc} = "usr, lom500, pilatus, microscope, abs, det, bst, slit, pumpGL"; }

In short: beamline-specific code is enabled only, if online.xml was loaded. The reason is that the BLSC widgets may depend on devices which are not contained in the aternative .xml file.

5.3 Tango: Use tags for selecting devices from .xml file

The file /online dir/online.xml or an alternative .xml file contains the Tango devices that are used by an online session. The device selection can be further specialized with the help of tags. They appear on the command line and in the .xml file, e.g.: online -tki -tags user online -tki -tags eh1,oh1

Note that there is no blank space in the string “eh1,oh1”. Here is a device definition in an .xml file:

exp_vfc01 expert,eh1 adc vfcadc p09/vfc/exp.01 tango haso107tk:10000

The file /online dir/exp ini.exp may contain code that is executed depending on the tag specification: if ( trnlnm( online_xml_tags), expert) say " we are experts" wait endif

A device is selected for an Online session, if one of the following conditions applies:

• there is no ’-tags ...’ parameter on the command line • at least on element of the ¡tags¿ section of the device matches at least one ’-tags’ element of the command line.

The implementation of the tags feature may change, if use cases show up that are not covered by the current imple- mentation. However the typical applications are described in the following subsections.

5.3.1 Tags, use case 1: detectors Consider an experiment where Tango is used only to control a Pilatus or a Mythen detector. Both of the detectors are not mounted all the time. In this case online.xml looks like this:

pilatus pilatus DETECTOR PILATUS100K h1/pilatus/300k tango hash1:10000

mythenII mythenII type_tango module_tango h1/exp/mythenii tango hash1:10000

Depending on the available hardware Online will be started by one of the commands: online -tki -tags pilatus online -tki -tags mythenII online -tki -tags None online -tki

If ’-tags None’ is supplied, none of the detectors will be defined for the Online session because there is no matching ¡tags¿ field. If the ’-tags’ parameter is omitted, both detectors are defined.

5.3.2 Tags, use case 2: user vs. expert view Consider an experiment where only a part of the devices should be visible to the general user but all devices should be available for an expert. Here is an excerpt from online.xml:

.... eh1a_mot01 expert,user stepping_motor oms58 p20/motor/eh1a.01 tango haspp20oh1:10000 eh1a_mot02 expert stepping_motor oms58 p20/motor/eh1a.02 tango haspp20oh1:10000 ....

All devices have an ’expert’ tag. A subset of the devices is tagged with ’user’. The following commands are possible: online -tki -tags user online -tki -tags expert online -tki

Notice that in this case the ’-tags expert’ and the last command which has no tags parameter are equivalent. Notice also that all devices have to be tagged with ’expert’ because otherwise they would no be excluded by ’-tags user’. Chapter 6

The Toplevel Widget

The toplevel widget is displayed in figure 6.1. It is divided into the frame containing the menu buttons, including the status information, the listbox, a log widget, a command entry field and the button line. The listbox displays a table which contains information about the devices. The table type can be selected by a menu button, see 6.7. If motor positions are displayed in the listbox, the program execution might slow down considerably depending on the number of motors and how they are connected. Section 6.7 gives hints how to avoid this behaviour. The status information: in the upper right corner is a string that displays the motor status. It can be Idle, Moving, etc. At the left side of this status string is a user status string which is optional. Whether it is displayed depends on an assignment in /online dir/TkIRc.pl. If the variable $Spc::res h{ user status} exists it will be evaluated and the return value is displayed, example: # file: /online_dir/TkIrc.pl $Spc::res_h{ user_status} = sub { return "UserStatus";}; The explanation of the buttons: Move: Calls the Move widget for the motor that has been moved before (section 11). Scan: Calls the Scan widget for the device that has been used before (section 7.1). MCA: Calls the MCA widget (section 12). Zoom: Invokes a widget that zooms the displayed data (6.2). The buttons + and - zoom in and out, < and > move the window left and right. Zoom changes the axes settings of all displayed SCANs. Display Refreshes the graphical screen. Viewer Launches the FIOViewer. The instance of this viewer adresses the same memory as the Online process. Stop Stops all motor movements and interrupts scans. the stop function is called if defined, see 6.11.

6.1 The Startup Script TkIrc.pl

The file /online_dir/TkIrc.pl is executed during program start once per session. If it has been changed, Online has to be re-started before the changes come into effect. TkIRc.pl can be changed from within online -tki. There is an item ’ TkIrc.pl’ in the Misc menu button. The startup files are executed in this order: 1. /online_dir/exp_ini.exp 2. ./spectra_ini.gra 3. /online_dir/TkIrc.pl The purpose of TkIrc.pl is: • Select applications, see section 6.9 for details. • Introduce beam line specific code, see section 14. • Define functions that can be use from virtual motors, virtual counters, scripts, etc. • Load the Tango configuration file /online dir/online.xml. This is done by the statement: Spectra::load configuration(); More details about online.xml can be found in the Online manual.

15 Figure 6.1: The TkI Toplevel Menu

6.2 The File Menu Button

Figure 6.3 shows the File menu button of the toplevel widget:

BLC (jddd): Launches the beamline control jddd application. Postscript: Creates laser.ps and sends it to the printer. The workstation viewport is temporarily changed to A4. The destination is specified by the symbol PRINTER, the environment variable PRINTER and the environ- ment variable LPDEST. In that order. Create motors.lis: Creates a new version of /online dir/motors.lis. The file contains the motor positions, aliases, limits and register contents. Clear log Clears the log widget. Refresh Refreshes the motor list box. Figure 6.2: The Zoom Menu

Update timer This check-box starts and cancels a timer that updates all widgets periodically. Message box Opens/closes the message bos which is mostly used to display motor positions.

Exit to CLI: Exit to the command line interface. Exit:

6.3 The Scan Menu Button

The Scan menu button is displayed in the following figure: It is used to invoke the different scan types. The scan menu is described in an extra section of this manual (7.1).

6.4 The Diff Menu Button

Depending on the hardware setup of the experiment, there can be a Diffractometer menu (fig. 6.5).

hklScan The hklScan widget is explained in section ??. Alignment Invokes a widget that is used during the alignment of the diffractometer (8.6). UB Matrix Invokes a widget that is usued to setup and calculate the UB matrix (8.5). Scan 2-Theta, Omega, Chi, Phi Invokes the scan widget for the selected diffractometer angle. Scan Om Tt Invokes the scan widget for a theta-2theta scan. Scan Tt Om Invokes the scan widget for a 2theta-theta scan. Reflection Scans Invokes a widget supports scans of several reflections. This feature hasn’t been tested so far.

6.5 The Misc Menu Button

The Misc menu contains the following items (6.6):

Move slit: Invokes a menu that is displayed in figure 6.7. The user may select slit coordinates and move them, including the display of a signal.

MOSTAB: Invokes a menu to change the MOSTAB (monochromator stabilizer) settings (6.8). The upper part of the widget contains buttons that send MOSTAB commands to the device. The middle part of the widget is used to specify the setpoint, e.g. 70% and ’Left edge’. There is also a button that sends the current setpoint selection to the MOSTAB, ’Send Setpoint’. Figure 6.3: The TkI File Menu

The third labframe contains checkbuttons for the ’Analog’, ’Use I1’, ’Peak search before scan’ and ’Use MOSTAB’ flags. Changing one of these flags, has no immediate effect. It is is relevant for scans only. The flag ’Use I1’ de- termines whether I-Doris is used by the MOSTAB at all, ’Analog’ selects how I-Doris is supplied, by an analog voltage which is delivered via cable or by a digital value which is read from a server. ’Peak search before scan’ is normally enabled. However, there are cases when users want to disable this feature. ’Use MOSTAB’ is the main switch that determines wheter the MOSTAB is operated during scans. This flag shadows the corresponding flag of the scan widget. Depending on the status of ’Use MOSTAB’ the other three flags are disabled or not. Note that, if the ’Use MOSTAB’ flag is changed from the scan menu, the three flags are not updated. 3D Scan: The explanation is given in section ??. Monitor: Invokes a widget that displays the count rates of selected counters. The rates are normalized and offset-subtracted. The widget is displayed in figure 6.9. It is configures by 6.10. Monochromator, SLTC, ···: Invokes widgets that are generated by beam line specific code. This feature is explained in chapter 14. emacs exp ini.exp, TkIrc.pl: Starts the emacs for the startup scripts. Figure 6.4: The TkI Scan Menu

emacs vm1.pl: Starts the emacs for a virtual motor. The corresponding file is stored in /online dir. Virtual motors are described in chapter ??. Perl scripts: Invokes a widget that handles Perl scripts (6.11). The code is stored internally. Online keeps track of older code versions. The files can be found in ˜/prog.

6.6 The Options Menu Button

The Options menu (6.12) contains the following items:

Select WS Viewport: Invokes a widget which changes the size of the graphical window (6.13). The button Pop restores the previous viewport size. Palette: selected colours, many colours: Colour selectors. Smart listbox update: The listbox turns blank during scans. Figure 6.5: The TkI Diffractometer Menu

Move selects blank table: If move are started from TkI the blank table is selected. Errors halt execution: Can be disabled, if series of scans should not be interrupted due to some well-known but unimportant errors.

6.7 The Table Menu Button

The Table menu (6.14) allows you to select what is to be displayed in the main widget. Depending on your selection different actions are bound to the mouse buttons, e.g.: if the ADCs are selected, a MB-1 reads the ADC. Notice that a blank table can be selected to avoid program slowdowns due to motor position updates. This feature is of special importance, if some of the motors are connected by slow busses. The functions Spectra::TkITableBlank() and Spectra::TkITablePop() can be used in Perl scripts to control this feature. Figure 6.6: The TkI Misc Menu

6.8 The Diag Menu Button

The Diagnostics menu (6.15) contains the following items:

Show errors: Searches online.log for error messages and displays them. VME: Invokes a widget which can be used to address VME space (6.16). I/Os with different addess/data modes can be performed. Shell: Invokes a menu that allows the user to enter shell commands, executes them and displays the result in a log window. Perl: Invokes a menu which executes some Perl code. The output is displayed in a log widget. Debug mode (TkI): A flag that enables debugging of the TkI code. Debug mode (Spectra): A flag that enables debugging of Spectra. Error in before : If enabled, an error is generated during the execution of the before macro. Figure 6.7: The Move Slit Menu

Error in during macro: If enabled, an error is generated during the execution of the during macro. Inspect before script: The before script is displayed, not edited. Flush online.db: The file /online dir/online.db is updated. That file stores the current user selections, scan limits, etc., a debugging feature. Inspect online.db: Opens an editor window for a file that is filled with the contents of /online dir/online.db, a debugging feature. Inspect before script: Opens an editor window for the file that is executed once when a scan begins. This file shouldn’d be edited because it is created automatically when the scan device selection changes and also before a scan starts. Inspect during script: Opens an editor window for the file that is executed for every scan point after the moves are stopped. This file shouldn’d be edited because it is created automatically when the scan device selection changes and also before a scan starts. Inspect after script: Opens an editor window for the file that is executed once when a scan ends. This file shouldn’d be edited because it is created automatically when the scan device selection changes and also before a scan starts. Disable script generation: If enabled, there is no automatic script generation when a scan starts. Figure 6.8: The MOSTAB Menu

Figure 6.9: The Monitor Widget

$status TkI to ”idle”: The $status TkI has to be idle on image exit. If not, you are asked to exit in a clean way.

kill -1 $$: Stop the current process. The device list and log files are written to disk.

kill -9 $$: Stop the current process.

6.9 Selectable Applications

There are TkI applications that not useful at all beam lines. Therefore beam line scientist may wish to hide them in order not to confuse the users. This is done by setting the variable $Spc::res{ applications}. If this variable is not defined, all applications are visible to the user. Otherwise only those applications are displayed that are selected. Here is the complete list:

$Spc::res_h{ applications} = "ESS, EXAFS, MARCCD, MOSTAB, XSW";

The variable is defined in the TkI startup file: Figure 6.10: The Monitor Configuration

Figure 6.11: The Perl Scripts Menu

/online_dir/TkIrc.pl.

The q-space widgets are automatically enabled, if a beamline has a diffractometer. The DSO widget is enabled, if a DSO has been defined. The MCA widget is enabled, if a MCA has been defined. ESS invokes the EXAFS Sample Scan widget, used at A1.

6.10 Beamline Specific Code

It is possible to create widgets for special purposes. Section 14 describes how this is done and gives some examples.

6.11 Stop Function

Online calls a user defined stop function, if the stop button of the toplevel widget or the scan widget is pressed. This is how the stop function is defined: Figure 6.12: The TkI Options Menu

# # the following lines are part of /online_dir/TkIrc.pl # package Spectra;

$Spc::res_h{ stop_function} = \&someFuntion; sub someFunction { Util::log( "this is someFunction); } Figure 6.13: Select Workstation Viewport Figure 6.14: The TkI Table Menu Figure 6.15: The TkI Diagnostics Menu

Figure 6.16: The VME Widget Chapter 7

Scans

7.1 The Scan Widget

Figure 7.1 displays the Scan widget.

Figure 7.1: The TkI Scan Widget

The explanation of the elements:

Scan name: Scan names are composed of a generic part (prefix) and a combination of numbers and letters that make the name unique. The generic part of the scan name is specified by the user. It can be changed by clicking into the Scan name widget. Position frame

MOT1(Alias): The scan device. The widget is clickable. If invoked, the available motors, virtual motors, etc. are displayed and the user may choose one of them. Move to: The scan device is moved to the position that is specified in the adjacent entry widget.

Limits frame

Start, Stop, Step width: The scan limits. They can be given in different ways. A selector button (StartStop) offers these modes: ∗ Start, stop, step width ∗ Start, stop, np

29 ∗ Range, np ∗ Regions ∗ EXAFS ∗ SingleShot Selecting a new mode may change the meaning of the entry widgets. If Regions or EXAFS are selected, the entry widgets are disabled and the Prepare regs button is enabled. Section 7.1.1 displays the widgets and exaplains their items.

Parameter frame

Sample time: Update: If set to 1, the display is updated at every stop. Repeats: Wait time: Online waits this time interval after the scan device has been moved to a new position before it calls the during-macro. This feature is intended to reduce the effect of mechanical instabilities. Auto return: Where the device is moved after the scan is finished. These are the options: No: Remain at the end position of the scan. Yes: Go back to the position before the scan started. Midpoint: Move to the midpoint (SSA result). CMS: Move to the CMS (SSA result). Peak: Move to the highest point (SSA result). Start: Move to the starting point of the scan. Scan Par.: An application dependent parameter.

Comment: The comment line is displayed on the graphics screen and stored in the output file. CM: This checkbutton selects the combined move mode, see figure (7.2). The scan limits are supplied for one motor, the other motor follows. There is a factor between the two scan ranges: CM-factor. This factor can be changed in the options menu (7.8). 2D: Selects a 2d scan, see figure (7.3). The limits of the outer loop motor can be specified in terms of start, stop and step width or as a list of positions. A file ¡scanName¿.log is created and contains log information about the scan. 3D: Selects a 3d scan, see figure (7.4). The limits of the outer loop motor can be specified in terms of start, stop and step width or as a list of positions. A file ¡scanName¿.log is created and contains log information about the scan. List: The outer loop is specified by a list of commands. That means, before an inner loop scan is started, Online executes a command from the list. Figure 7.5 shows an example for such a list. Notice that the return string ’error’ indicates a failure and interrupts the procedure. The list mode can be used with 1D and 2D scans, including CM option. A file ¡scanName¿.log is created and contains log information about the scan. Start: Starts a scan. Stop: Stops all moves and stop the scan. Pressing the ¡esc¿ key has the same effect. The stop function, see 6.11, is also called. Stop rpts: For repeated scans: make this sweep the final sweep.

7.1.1 ’Prepare Regions’ Menu For normal (i.e. non-EXAFS) region scans the Prepare regs button invokes a widget that is displayed here 7.6. The region limits, the sept width and the sample time can be supplied. The buttons ’Reg 1’, ’Reg 2’, etc. can be used to delete or duplicate regions. For EXAFS scans the Prepare regs button invokes a widget that has additional columns for an edge position and an exponent. If the edge position of a region is set to 0, it is transversed with constasnt energy steps. Otherwise the steps are adjusted to be constant in k. The exponent column allows an adjustment of the sample time for constant-k st st kp ower k regions: → × n . n is the normalized momentum. It is 1 at the start of a region. Online makes sure that sample time is always a multiple of 20 msec in order to avoid interferences with a 50 Hz background. Figure 7.2: CM Scans (Combined Moves Scans)

Figure 7.3: 2D Scans

7.1.2 Scan ’Options’ Menu The Options menu (7.8) contains the following items:

Select Scan devices: The widget is described in section 7.2.

Scan Parameters Invokes a widget that handles several scan parameters (7.9).

MOSTAB A widget for the specification of MOSTAB parameters. It can also be used to send commands (6.8).

The Scan Parameters menu (7.9) contains the following items: Figure 7.4: 3D Scans

Figure 7.5: The Outer Loop List

EXAFS Options: Counters for the I0 (before the sample) and I1 (behind the sample) signals can be specified. If set to N.N., Online takes the first 2 selected counters for I0 and I1. If a reference sample is mounted, an additional counter can be selected ( Ref. Counter). The flag Log. Scale determines whether the EXAFS signal is displayed on a logarithmic scale. The ESS-Motor is used by the EXAFS sample scan. A menu that allows you to define several sample positions (7.11). Miscellaneous: Preset Timer Time-out: The time-out for timers that are operated in preset mode, def.: 10s. Figure 7.6: The Regions Widget

CM-Factor: The combined move factor. If set to 2, the second motor move twice as far as the scan motor. Continuous Scan Clock: The clock is used to measure the elapsed time during continuous scans. Stack Plots: A feature for repeated scans (/OPT DER). If enabled, the display is not cleared after the sweeps. Instead the data of all sweeps are displayed. It is not possible to generate postscript output for each sweep, while this option is active. Powder Options: Certain powder measurements require an auxiliary motor that rotates the sample while the counters are active.

7.1.3 Scan ’Utils’ menu The Utils menu (7.10) contains the items:

Cursor: Invokes the cursor widget for an active SCAN. The cursor widget can manouver through the list of SCAN GQEs.

Move to cursor: The scan device is moved to the current cursor position.

ESS (EXAFS Feature: Invokes the EXAFS sample scan menu (7.11). Display:

The ESS menu (7.9) repeats EXAFS scans for different samples. It contains the following items:

No. of Samples:

E-Cal.: Where the monochromator was calibrated.

Reg. File: The file that contains the EXAFS regions.

Name: The sample name. Figure 7.7: The EXAFS Regions Widget

MOT7: The motor that moves the sample into the beam.

Repeats: No. of repeats for a specific sample.

Comment: Additional information about the sample.

7.1.4 Scan ’Types’ menu The Types menu is displayed in 7.12.

Energy:

Wavelength:

EXAFS: Energy scans with EXAFS regions. Motor:

Dummy: Time scan. Behaves like a motor scan without actually moving a motor.

Slit: Scans a slit coordinate. It can be a jaw, the center of the slit or the opening. Section 11.4 explains how slits are defined.

2-Theta, Omega, Chi, Phi, Psi: Diffractometer scans, the Euler angles. Om tt, Tt om: Omega-2Theta or 2Theta-Omega scans. Figure 7.8: The Scan Options Menu

Figure 7.9: The Scan Parameters Menu

7.1.5 Scan ’Flags’ menu The Flags menu is shown in 7.13. Create PS File: A postscript file is created after the scan. Print PS File: A postscript file is printed after the scan. Automatic Beam Shutter: This flag enables a procedure that interrupts scans when an injection occurs and waits for the beam to return. It is done by the function was injection(). The incoming flux is measured by the “Flux counter” and the selected scan timer. It is compared with the minimum count rate. The counter, the timer and the minimum rate are defined in 7.14. After the beam returns, Online waits Heatup Time seconds ( specified in 7.9) before it continues to scan. Use MOSTAB: The MOSTAB is operated in the following way: it needs a setpoint, a flux input and a signal for the DORIS current. The setpoint is specified usig the MOSTAB widget 6.8. An example for a setpoint is 70%, Figure 7.10: The Scan Utils Menu

Figure 7.11: The EXAFS Sample Scan Menu

left edge. The DORIS signal can be an analog input which fed into the front panel by a cable or it can be a digital value which is read from a server (and multiplied with 100). The source of the DORIS signal is selected by the ’Analog’ button of the MOSTAB widget. ’Analog’ means input via cable. When the scan is started, the setpoint is sent to the MOSTAB and a peak search is initiated. In addition Online sets the symbol MOSTAB SP. This symbol is intended to be used for optional MOSTAB corrections during the scan. In this case the user has to prepare some extra code for the during˜ file. After the scan finished, the MOSTAB is set to idle.

Automatic : An absorber is adjusted. SIGNAL is kept between FILTER MIN and FILTER MAX. The ab- sorber is moved in steps of FILTER DELTA. The procedure FC ADJUST FILTER() is called before the during- macro is executed. This feature is beam line specific. Talk to an expert before enabling this flag.

Automatic Filter (Script): An automatic absorber procedure which is implemented by user-supplied Perl code. Figure 7.12: The Scan Types Menu

Figure 7.13: The Scan Flags Menu

An example can be found here 7.1.5. At the end of the scan the absorber is moved to its maximum. This feature is beam line specific. Talk to an expert before enabling this flag.

’Write to disk’ is always true: The data is written to disk without asking for confirmation.

Include motor positions: The output file contains the motor positions.

Include regions: The output file contains the scan regions, valid only for EXAFS and other regions scans.

Additional fio comments: Online evaluates the function Spectra::fio comments(). The result is copied into the comment section of the output file. The user defines Spectra::fio comments() in /online dir/TkIrc.pl. An example can be found here 7.1.5. The feature can also be invoked by setting the symbol flag additional fio comments to 1.

Additional fio parameter: Online evaluates the function Spectra::fio parameters(). The result is copied into the parameter section of the output file. The user defines Spectra::fio parameters() in /online dir/TkIrc.pl. An example can be found here 7.1.5. Bell on scan end:

Use SSA: The SSA (Simple Scan Analysis) procedure is run on scan name at the end of the scan. The result is written to the output file. It can be used by the auto-return option.

Display Deadtime: The deadtime [%] is defined as (elapsedTime - sampleTime)/elapsedTime. The main con- tributions to the deadtime are the motor movements and GUI updates. The fraction of the movements can be estimated by executing a dummy scan with the same scan device selection. The GUI update speed can be en- hanced by disabling the update of the motor list box. See flag below.

Log Scale for MCAs: Selects a logarithmic scale for MCAs.

Smart listbox update: An option to speed-up the scans: the motor listbox of the toplevel menu is not updated when the scan is active. You may also consider to iconize the toplevel widget which also prevents it from being updated. Continuous scan mode: Continuous scans are described in a separate section (7.3). No MCAs and VCs are allowed for this scan mode.

Continuous scan mode (raw): A motor is started and the during-file is repeatedly executed as long as the motor is moving. In contrast to the normal continuous scan mode, VCs, MCAs and SCAs may be selected. The price that one has to pay is a reduced temporal coverage, e.g.: while the MCAs are read-out, the timer is inactive (the motor is moving and nobody is watching). It makes no sense to use the raw mode without reading MCAs or VCs.

Automatic filter (Script) This subsection gives a simple example of an implementation of an automatic absorber procedure. The main code is part of Online. It calls functions that are supplied by the user, normally in /online_dir/TkIrc.pl:

• Filter::set( $value) Changes the absorber thickness.

• Filter::get() Returns the absorber thickness. • Filter::signal() Returns the signal.

• Filter::absorption() Returns the absorption factor ( == 1, if no filter is in the beam).

In addition the following symbols have to be provided by the user:

• $Filter::signal_min, $Filter::signal_max The procedure tries to keep the signal between the limits by changing the absorber.

• $Filter::filter_min, $Filter::filter_max The limits for the absorber position.

• $Filter::delta The absober is changed by this quantity.

In our example a motor, mot54, is moved in the range from 20 to 30 to keep the signal between 1000 and 5000 counts. The position of the motor is changed by 0.5 units. The signal comes from c1 which is gated by t1. The sample time is 0.1 s: package Filter; use vars qw( $signal_min $signal_max $delta $filter_max $filter_min);

$delta = 0.5; ( $signal_min, $signal_max) = (1000, 5000); ( $filter_min, $filter_max) = ( 20, 30); sub set { return Spectra::move( mot54 => $_[0]); } sub get { return Spectra::gmup( "mot54"); } sub signal { return (Spectra::vfc( "c1", "t1", 0.1)*10); } sub absorption { my $ret = Filter::get(); return( POSIX::exp( $ret)); }

’Additional fio comment’ function The following script can be part of /online dir/TkIrc.pl. The function returns a string. In practice the string may be constructed from some values that are created at run-time. sub Spectra::fio_comments { my ($status, $ret, $line); $line = " "; foreach my $adr( qw( 10 11 12)) { gpib_write( $adr, "U0X"); $status = gpib_read( $adr, 30); $ret = substr( $status, 24, 3); $line .= " K_$adr $ret"; } return $line; } A SCAN GQE can have up to 10 lines of comment. However, it is possible to write some unofficial comment lines into the fio file. These lines have to be preceeded by an (!). Here is a second example. It demonstrates how Tango attributes are read: sub Spectra::fio_comments { my $line = " "; if( search_device( "mca10")) { $line .= "MCA10 live " . Spectra::tng_attrDoubleRd( "MCA10", "livetime") . " real " . Spectra::tng_attrDoubleRd( "MCA10", "realtime"); } if( search_device( "mca11")) { $line .= ", MCA11 live " . Spectra::tng_attrDoubleRd( "MCA11", "livetime") . " real " . Spectra::tng_attrDoubleRd( "MCA11", "realtime"); } return $line; }

’Additional fio parameter’ function The following script can be part of /online dir/TkIrc.pl. The function returns a string. In practice the string may be constructed from some values that are created at run-time. sub Spectra::fio_parameters { my ($status, $ret, $line); $line = ""; foreach my $adr( qw( 10 11 12)) { gpib_write( $adr, "U0X"); $status = gpib_read( $adr, 30); $ret = substr( $status, 24, 3); $line .= " K_$adr = $ret \n"; } return $line; }

7.2 The ’Scan Device Selection’ Menu 7.2.1 The Widget Figure 7.14 displays the Scan Device Selection menu.

Figure 7.14: The Scan Device Selection

The Counter/Timer frame Timer: t1 The menu button displays the selected timer. It can be clicked to display the available timers. Preset mode This flag determines whether the device is operated as an ordinary timer or a preset timer (constant flux). An ordinary timer opens a gate for sample time seconds. A preset timer loads an internal register with some value and waits for an external signal to decrement the register contents. The gate is open as long as the register is non-zero. The preset value is supplied by the user in the same entry widget as the sample time. If the elapsed wait time exceeds WAIT TIME PRESET MAX, the wait state is terminated and ONLINE waits for TIME HEATUP seconds (default 30) before it re-measures the last point. This procedure has been implemented for injection recovery. Sel.: Counters are seleted for measurements, if buttons in this column are activated. Dis.: An activated button in this column indicates that a selected counter is displayed. Flux counter: This counter is used by the Automatic Beam Shutter Option. If the option is enabled and the flux counter falls below the minimum count rate, Online enters a wait state until the beam returns. Min. count rate: This number is used by the Automatic Beam Shutter Option. If the option is enabled and the flux counter falls below this value, Online enters a wait state until the beam returns. Heatup Time: This parameter shadows the symbol TIME HEATUP. It is used by the ”Automatic Beam Shutter” option. Online waits as many seconds to heatup the optical components after the beam returns. Be sure to update the symbol TIME HEATUP in exp ini.exp, if you changed it here. Normalize counts: The counter readings are divided by the sample time before they are stored. Measure offsets: Since the counters get the input mostly from VFCs, offsets need to be measured. Clear offsets: Offsets are set to 0.

The MCA/SCA frame

MCA Timer: The timer that gates the ADCs. MCA1 ADC MCA Enables the MCA 2048: The no. of channels can be selected. zip MCA Files: MCA data is stored in a subdirectory. This flag determines whether the contents of the directory is zipped. Logarithmic Scale: MCAs can be displayed on a logarithmic scale. SCA1: The user may specify regions of interest that define the limits of software SCAs. SCA-SUM: If selected, a SCAN is created that stores the sum of the SCA SCANs. Net SCAs: A simple linear background subtraction. The first an the last point of an ROI is connected. All entries below this line are subtracted.

The Encoder frame

HHE1 The encoder positions are read, displayed and written to the disk file.

The Virtual Counter frame Virtual counters can be selected like other counters. Details can be found in section 7.2.2. The Extra Code frame When the user starts a scan, Online creates the scan scripts before auto scan.pl, during auto scan.pl and after auto scan.pl according to the selected devices. It may occur that the device selection is not suf- ficient to cover the needs. Therefore the extra code feature has been introduced. Click on the buttons to edit the extra code lines. Section 7.2.4 gives more information. The Profiles menu Configurations of selected devices can be stored and loaded. The Debug menu This menu offers the opportunity to inspect the scan scripts. The scripts updated before the display windows opens. If the checkbutton Disable macro update is enabled, Online does not create new scan macros are when a scan starts. Instead it executes the current versions of before auto scan.pl, during auto scan.pl and after auto scan.pl as they are in ˜/prog. You may want to edit these files to include some debug statements. 7.2.2 Virtual Counters Virtual counters appear in the Scan Device Selection widget (7.14). They can be selected like other counters. Virtual counters are pieces of Perl code that respond to the methods reset and read. Here is an example 7.15:

Figure 7.15: A Virtual Counter

The virtual counter code is used in the following way. It is inserted in the during-scan macro at two places. First in the section where all devices are resetted and second at the end where all the devices are read. Both times the code is taken as an argument of an Perl statement. In the first case Online includes the statement my $method = "reset"; in the second Online includes my $method = "read";. How an error is raised: a virtual counter may return 0, of course. So this is no way to tell Online to interrupt the scan. Instead the user has to set the Spectra symbol INTERRUPT SCAN. This is done in the following way: $Spectra::SYM interrupt scan = 1;. For virtual counters the following statements :

• The virtual counter code is stored in the directory ˜/prog. • The file names are ˜/prog/Code_VCi.pl with i=1, 2, ... 8. • Pressing the Apply button overwrites the file ˜/prog/Code_VCi.pl and creates a new version, e.g.: ˜/prog/Code_VCi_00007.pl • The file ˜/prog/Code_VCi.pl is inserted into the during-scan macro when a scan is started. That means that the virtual counter scripts may also be changed by an editor that is independent of Online.

• The widget 7.15 can be used to maintain the virtual counter code (figures 7.16 and 7.17) and also to it. The disadvantage of the widget is only that it has very limited editing capabilities.

7.2.3 %Spectra::data scan %Spectra::data scan is a string indexed array (hash) that stores the most recent counter readings and other scalar quantities that appear in the during-scan-macro. The hash is intended to be used by virtual counters. If required, this hash can be extended. The keys in %Spectra::data scan are counter, sca and virtual counter names. They can be found by inspecting the during-scan-macro. Here is an example of a virtual counter which returns a normalized SCA value: Figure 7.16: The Virtual Counter File Menu if( $method =˜ /reset/i) { return 1; } if( $method =˜ /read/i) { return $Spectra::data_scan{ "SCA1"}/Spectra::doris(); }

7.2.4 Extra code Extra code can be enabled using the Select Scan Devices widget. It is inserted in the scan macros when the scan is started. Figure 7.18 shows an example. The code is stored in the files ˜/prog/Code_before.pl, ˜/prog/Code_before_during.pl, ˜/prog/Code_after_during.pl, ˜/prog/Code_after.pl.

The ˜/prog directory stores also the file versions, e.g.: ˜/prog/Code_before_00001.pl. The treatment of the extra code files is very similar compared to virtual counters (see section 7.2.2): • The extra code is read from a disk file and inserted into the scan macros when the scan is started. • Apply overwrite the file and creates a new file version, e.g.: ˜/prog/Code_before_00007.pl. • Extra code is executed by an eval Perl statement. If the return code is 0, Online terminates the scan.

7.3 Continuous Scans

Continuous mode scans are measurements on-the-fly: Motors are running from start to stop while the counters are read. Here are the details: Figure 7.17: The Virtual Counter Versions

The scan timer must be of th the type DGG or DGG2. The user may select a scan clock (Continuous scan options), also DGG or DGG2. The default number of points is 5000. It can be increased on demand. The user specifies start, stop, step width and Sweep time. The sample time is calculated using the number of stops and the sweep time. The position is read before and after the counters are busy. The current position is set to the mean of both readings and stored in the x-column of scan name. The difference of both readings is stored in scan name dp. The step position is stored in scan name steps. It is also the mean of two readings. The description of the scan cycle:

The position is read, stored in pos1. Wait for scan timer. The counters are read. If scan clock is supplied, the elapsed time is stored in scan name time [microseconds]. The counts are stored after the offset has been subtracted. The counters are cleared. The current position is replaced by (pos2+pos1)*0.5. The current step position (steps pos2+steps pos1)*0.5 is stored in scan name steps. scan name dp is filled (pos1 - pos2). scan timer is started using sample time. The position is read, stored in pos2. Display after update-cycle

Note:

i There are restrictions on the devices that can be used in continuous scans: no MCAs or virtual counters. Figure 7.18: An Extra Code Example

ii There is no strict relation between position reading and counter reading. The maximum difference can be found in the SCAN scan name dp.

iii There is a multi channel scaler (MCS) that garantees a strict relation between the motor positions and the counter readings. Ask for an implementation, if you need it.

7.3.1 Scan interval too small For continuous scans there is a restriction when choosing the scan interval. If the interval is too small for the motor to reach the slew rate, an error is generated.

7.4 Nexus Output

Nexus files are written by the NexusWriter. This Tango server is configured with an XML string (aka configuration) which is created by the NexusConfigurationServer, a Tango server. The configuration includes all selected components. A component specifies how data are stored in the Nexus file. The command AvailableComponents displays the list of available components. Components are selected from the Online command line, e.g.: set write_nexus on * = nexus_add_component( pilatus300k, default) * = nexus_add_component( slit1, slit2, slit3, slit4)

After these commands are issued Nexus files are created after each scan. Before the Nexus file is created Online does the following checks:

• Online assures that all user-selected components are in the list AvailableComponents.

• Online reads the MandatoryComponents and assure that they are in the list of user-selected components.

• Online compares the list of selected devices (scan device selection) with the list of data sources of the selected components. If a device does not appear in the data sources list, a dynamic component is created that allocates space for this device.

Components have be be prepared with a special designer. 7.5 Performance

In the following we give the scan dead times for different device selections. The scan device is dummy, the sample time is 1s, the wait time is 0s. The scans consist of 11 points from 0 to 10. The option “Smart listbox update” is selected. Here are the numbers: Devices Dead time [%] C1 - C4 2 C1 - C4, VC2( random()) 4 C1 - C4, MCA1 (2048) 10 C1 - C4, MCA1 - MCA7 (2048) 35 C1 - C4, SCA1 - SCA7 29 “C1 - C4” means that counter C1, C2, C3 and C4 are selected and displayed. “VC2( random())” means that the virtual counter VC2, which happens to return a random number, has been selected and displayed. “MCA1 (2048)” means that the 2048 channels of MCA1 are read and displayed. “SCA1 - SCA7” means that 7 regions of interest have been defined. They are read and displayed. It may be interesting to compare these numbers with those that have been generated using the old VT100-style menus: C1 - C4, 0.4%, C1 - C4, MCA1, 8.3% and C1 - C4, MCA1 - MCA7, 31%. To conclude: the PerlTk interface adds dead time in the order of 2 - 4%. Note that the Online manual contains some discussion about how to scans. Chapter 8

Diffractometer

This chapter explains the widgets that are used for operating a diffractometer, so far only in E4C mode. The diffrac- tometer implementation relies on work which has done at SOLEIL. See chapter 2 for a list of authors.

8.1 Creating the Diffractometer Server 8.1.1 4-Circle Starting from scratch, we have to begin with preparing the diffractometer server. Use Jive, Edit, Create Server.

Figure 8.1: Jive: Create Diffractometer Server

The server needs properties (the motor names are just an example): The class PseudoAxis has to be added to the server by right-clicking PETRA-3 (of ds Diffractometer) and selecting ’Add Class’. The newly created devices need these properties. p07/e4c/diffrac-h DiffractometerProxy p07/e4cv/diffrac PseudoAxisName h p07/e4c/diffrac-k DiffractometerProxy p07/e4cv/diffrac PseudoAxisName k p07/e4c/diffrac-l DiffractometerProxy p07/e4cv/diffrac PseudoAxisName l The diffractometer server is running now. Before we can operate it with the SOLEIL-GUI, Online or Spock we have to create a new crystal (UB matrix) using Jive. The command AddNewCrystal is executed with the argument ”Cr1” on the diffractometer server and the attribute Crystal is set to ”Cr1”.

47 Figure 8.2: Jive: Diffractometer Properties

Figure 8.3: Jive: Create PseudoAxis

Online needs a reference to the diffractometer server. For this the following lines have to be copied to /online dir/online.xml. The name ”dffrctmtr” is fixed, the Tango device name ”p09/e4c/diffrac” and the hostname have to be selected accord- ingly.

... other devices dffrctmtr diffractometer e4c Figure 8.4: Jive: PseudoAxis Properties, h, E4C

p07/e4cv/diffrac tango hasgksspp07XXX:10000

8.1.2 6-Circle Starting from scratch, we have to begin with preparing the diffractometer server. Use Jive, Edit, Create Server. The server needs two properties (the motor names are just an example): The class PseudoAxis has to be added to the server by right-clicking PETRA-3 (of ds Diffractometer) and selecting ’Add Class’. The newly created devices need these properties. p09/e4c/diffrac-h DiffractometerProxy p09/e6c/diffrac PseudoAxisName h p09/e4c/diffrac-k DiffractometerProxy p09/e6c/diffrac PseudoAxisName k p09/e4c/diffrac-l DiffractometerProxy p09/e6c/diffrac PseudoAxisName l

The diffractometer server is started by Astor. The following figure shows the diffractometer devices. The diffractometer server is running now. Before we can operate it with the SOLEIL-GUI, Online or Spock we have to create a new crystal (UB matrix) using Jive. The command AddNewCrystal is executed with the argument ”Cr1” on the diffractometer server and the attribute Crystal is set to ”Cr1”. Online needs a reference to the diffractometer server. For this the following lines have to be copied to /online dir/online.xml. The name ”dffrctmtr” is fixed, the Tango device name ”p09/e6c/diffrac” and the hostname have to be selected accord- ingly. Figure 8.5: Jive: PseudoAxes Properties, hkl, E4C

... other devices dffrctmtr diffractometer e6c p09/e6c/diffrac tango haso107tk:10000

8.2 E4C vs. E6C

The following table displays the relation between different axis assignments.

You | Soleil | E4C ------Phi | Phi | Phi Chi | Chi | Chi Eta | Omega | Omega Delta | Delta | TwoTheta Mu | Mu | 0 Nu | Gamma | 0

The column ’You’ refers to the paper, “Angle calculations for a ’4s+2D’ six-circle difractometer”, H. You, J. Appl. Cryst. (1999), 32, 614-623. Figure 8.6: Jive: PseudoAxes Properties, Psi, E4C

8.3 The Diffractometer GUI (SOLEIL)

After the diffractometer server has been started, the diffractometer GUI can be used to operate/monitor it. It is started from the command line:

jdiff

This is an alias that translates to (depending on the beamline): alias jdiff=’/home/experiment/Tango/diffractometer//diffractometer p09/e4c/diffrac &’

8.4 The Orientation

Movements in momentum space are possible after the UB matrix has been setup. We begin by supplying the lattice parameters a, , c, alpha, beta, gamma (e.g. 5.43, 5.43, 5.43, 90, 90, 90). This is easily done with the UbMatrix widget of Online (called from Online, Diff), see section 8.5. The lattice parameters are written to the server by pressing ’UpdDiffSrv’. The UB matrix is automatically read-back. At this point it contains only the transformation from direct to reciprocal space, no rotations are taken into account so far. The Alignement widget (called from Online, Diff), section 8.6, helps us during the orientation. scans are used to find reflections. After two reflections have been found, the ’ComputeU’ button of the UbMatrix widget computes the UB matrix and we are done. In addition to the command ’ComputeU’ which uses the lattice and two reflections there is the command ’Affine’ which uses the simplex method to compute the lattice parameters and the U matrix. ’Afffine’ needs more than 2 reflections as input.

8.4.1 Differences: Petra III (SOLEIL) and DORIS It has been said that we are using the SOLEIL software suite to control the diffractometers at Petra III. Unfortunately there are differences compared with our previous system used at DORIS. Figure 8.7: Jive: PseudoAxes Properties, q, E4C

Figure 8.8: Jive: Create Diffractometer Server, E6C

The hkl vector is rotated, in short: Petra/SOLEIL( 1, 2, 3) corresponds to Doris( 3, 2, 1). In the SOLEIL world h points in the direction of the x-rays and l points upwards.

The elements of the UB matrix differ by a factor of 2*PI: UB(PETRA, SOLEIL) = UB(DORIS,RAFIN)*2*PI. The definition of PSI: for DORIS experiments PSI == 0 for the bisecting setup, for PETRA III PSI is the angle between a reference direction (1, 0, 0) projected on the plane which diffracts (normal = Q) and the diffraction plane defined by the incomming and outgoing beam. Note that there is a way to change the reference direction for the psi calculation: you may store a reference vector in the attribute “parameters” in the diffrac-sim-psi Tango device. Figure 8.9: Jive: Diffractometer Properties, E6C

Figure 8.10: Jive: Create PseudoAxis, E6C

8.5 The UB Matrix Widget

The figure below displays the UbMatrix widget. The explanation of the elements:

Crystal

Delete Deletes the current crystal. New Creates a new crystal. The name is prompted. Misc

Alignment Starts the alignment widget. UB Matrix It is read from the diffractometer server. The server calculates the UB matrix using the lattice parameters and two reflections (ComputeU) or using the lattice parameters and the U vector (UpdDiffSrv). Figure 8.11: Jive: PseudoAxis Properties, h, E6C

Figure 8.12: Jive: Diffractometer, E6C

Reflections The reflections are used to find the orientation of the crystal (ComputeU, Affine). They are stored by th Align- ment widget. U Vector Describes the rotations about the various axes. The angles are specified in degree. The U vector is read/write. For the ’UpdDiffSrv’ command it is an input and in case the ’ComputeU’ command has been executed, it displays the result. Lattice The entry widgets contain the lattice parameters. Depending on the way how the UB matrix is calculated these parameters are input or output. ComputeU: The lattice parameters are supplied by the user. If the ’ComputeU’ button is pressed the parameters are copied to the server and the UB matrix is calculated using the first two reflections. Affine: The lattice parameters are copied from the server after the UB matrix is calculated from more than 2 reflections. Parameters:

Mode This menu button specifies the constraints. Figure 8.13: Jive: PseudoAxes Properties, hkl, E6C

Figure 8.14: Jive: PseudoAxes Properties, Psi, E6C

ASN A point in momentum space corresponds to various sets of angles. ASN is an index that selects one of these sets. ASN = 0 points to the nearest angular combination. Xtal Selects the current crystal (UB matrix). Wavelength The current wavelength.

Edit Reflections Invokes a widget that allows you to change the parameters of the reflections and to change the order of the reflections. Note the ’ComputeU’ looks at the first two reflection. UpdDiffSrv Writes the lattice parameters and the U vector to the diffractometer server and reads the UB matrix. ComputeU Executes the ComputeU command on the diffractometer server. The lattice parameters and the first two reflec- tions are used to calculate the UB matrix and the U vector. Affine Uses the simplex method to calculate the lattice parameters and the U matrix. Needs at least 3 reflections. The SOLEIL GUI can be used to select the parameters that are optimized. ’Affine’ is not fully tested. Figure 8.15: Jive: PseudoAxes Properties, q2, E6C

Figure 8.16: The UB Matrix Widget

8.6 The Diffractometer Alignment Widget

The following figure displays the Diffractometer Alignment widget. The purpose of this widget is to find reflections by varying the diffractometer angles. If a reflection has been found, it can be stored. The UbMatrix widget uses reflections for the orientation of the crystal. The explanation of the elements:

Options Figure 8.17: The Diffractometer Alignment Widget

Alignment params Invokes a widget that selects two parameters: Peak definition CMS, y-max or Midpoint. CV RATIO Tells Online when the centering procedure is terminated. The conditions is abs( posMax - posNew- Max)/width < CV RATIO. hkl2Angles A widget that displays the angles, if hkl is supplied.

Select Signal A widget which selects the signal. Misc

UbMatrix Invokes the UbMatrix widget.

Cursor Invokes the cursor widget. Angles This frame displays the current angular positions and allows the user to enter new values in the entry fields. The move is started by the ’Move’ button. hkl This frame displays the current position in momentum space and allows the user to enter new values in the entry fields. The move is started by the ’Move’ button. Scans Exec Scan The buttons in this line start various angular scans. Range Defines the range of the angular scans. The range can be enlarged, if no peaks are found during the search.

To max After angular scans have been executed the buttons in the line move the corresponding axis to the maximum. Centering order Tell Online in which order the angular scans are executed during the centering procedure, e.g.: OCT means that omega is optimized first, then chi, then two-theta. Np The no. of points in the angular scans. N iter The maximum number of iterations that are used to find the center of a reflection. One iteration includes the optimization of omega, chi and two-theta, if selected. The centering procedure terminates earlier, if there are no significant shift between two consecutive iterations. Coarse Scans The scanning interval is not adjusted. Stop Stop all movements. Move Executes a movement. The destination is supplied on the ’Angles’ or ’hkl’ frame. Center reflection Starts the centering sequence. ONLINE performs angular scans to find the maximum of a reflection. The order in which the angles are changed is determined by ’Centering order’. Every angle undergoes a coarse scan first. The coarse scan is used to determine the scan range (2×FWHM). If the fine scan range is less than 50% of the old one, ONLINE repeats the angular scan before it changes the next angle. If the signal does not go down to half of the maximum, the scan range is doubled. The maximum of a scan is defined to be the CMS, y-max or Midpoint depending on the selection of the ’Alignment Parameters. If the angular scans pass the convergence test, the program terminates. Otherwise the fine scans are repeated N INTER times. Store reflection Copies the current position, hkl and angles, to the diffractometer server. Reflections are used to orient the UB matrix.

8.7 The hklScan Widget

Figure 7.1 displays the Scan widget. The explanation of the elements:

File

Postscript Creates a postscript file. Write Creates a .fio file. Exit Quits the widget. Options

Select Scan Devices Invokes a widget that select the devices that are using during a scan (7.2.1). Alignment Invokes the diffractometer alignment widget. Figure 8.18: The hklScan Widget

UbMatrix Invokes the UbMatrix widget. Flags The scan flags are explained in section 7.1.5. Scan name Scan names are composed of a generic part (prefix) and a combination of numbers and letters that make the name unique. The generic part of the scan name is specified by the user. It can be changed by clicking into the Scan name widget. Position/Limits frame

Position Displays the current hkl position. Move to A line of entry widgets that are used to specify the final position for movements. The movements are executed by pressing the ”Move” button. Start/Stop The scan limits. Angles This frame displays the current positions of the diffractometer angles. Paramters

Np The number of points of the scan. Sample time The sample time. The timer is selected using the select-scan-devices widget, called from the pop-up menu ’Options’. Auto return Where the motors move after the scan is finished. Mode Selects the way how the diffractometers angles are constraint. The bottom frame Start Starts a scan. Stop Interrupts a scan. Move Start a movement. The final positions are given by the ’Move to’ entry widgets. Display Angles The diffractometer angles are plotted for the requested scan range. No movements are involved. Figure 8.7 shows the graphical output.

Figure 8.19: ’Display Angles’ output

8.8 The Perl Interface

This section contains the Perl functions the operate the diffractometer server:

# # read the angles # my ( $mu, $omega, $chi, $phi, $gamma, $delta) = Spectra::angles(); # # read hkl and psi # my ($h, $k, $l, $psi) = Spectra::hkl(); # # move several angles # Spectra::angles( mu => $mu, omega => $omega, chi => $chi, phi => $phi, gamma => $gamma, delta => $delta); # # read single angles # $mu = Spectra::mu(); $omega = Spectra::omega(); $chi = Spectra::chi(); $phi = Spectra::phi(); $gamma = Spectra::gamma(); $delta = Spectra::delta(); # # move single angles # Spectra::mu( $mu); Spectra::omega( $omega); Spectra::chi( $chi); Spectra::phi( $phi); Spectra::gamma( $gamma); Spectra::delta( $delta); # # read hkl and psi individually # $h = Spectra::h(); $k = Spectra::k(); $l = Spectra::l(); $psi = Spectra::psi(); # # or # $h = Spectra::hkl( "h"); $k = Spectra::hkl( "k"); $l = Spectra::hkl( "l"); $psi = Spectra::hkl( "psi"); # # move hkl and psi individually # Spectra::h( $h); Spectra::k( $k); Spectra::l( $l); Spectra::psi( $psi); # # move hkl and psi # Spectra::hkl( h => $h, k => $k, l => $l, psi => $psi); # # hkl scan # Spectra::scan( type => "hkl", start_hkl => [1, 1, 0], stop_hkl => [1.1, 1.2, 0], sample_time => 0.1, np => 11); # # h scan # Spectra::scan( type => "hkl", start_h => 1, stop_h => 3, sample_time => 0.1, np => 11); # # angle scans # diff_mu, diff_omega, diff_chi, diff_phi, diff_gamma, diff_delta # Spectra::scan( type => "diff_mu", start => 1, stop => 3, sample_time => 0.1, np => 11); # # scan reflection # Spectra::scan( type => "reflection", auto_filter => 0, centering_order => "moc", coarse => 0, np_scan => 11, nobackground_subtraction => 0, range_mu => 0.5, range_omega => 0.5, range_chi => 0.5, store => 1);

8.9 The .gra Interface

This section contains the .gra interface to the diffractometer server:

! ! hkl ! * = diff_h() * = diff_k() * = diff_l() diff_h() = 1 diff_k() = 2 diff_l() = 3 ! ! angles ! * = diff_two_theta() * = diff_omega() * = diff_chi() * = diff_phi() diff_two_theta() = 20 diff_omega() = 10 diff_chi() = 45 diff_phi() = 90 Chapter 9

Sweep

This widget has been created to minimize the dead time during MCA scans. The operation is basically that one motor, the inner loop motor, is continuously moved while MCAs and counters are active. In addition, two other motors can be handled by this widget to allow for 2D or 3D scans. The sweep mode can be disabled to execute MCA measurements while all motors stand still. The devices that are active during the measurments can be specified by Options->’Select scan devices’:

9.1 The Widget

Figure 9.1 shows the Sweep menu. Here is the explanation of the items:

Scan name: A button that displays the current scan name. The generic part can be changed by click this button. The scan name is actually the name of the directory that stores the MCA files. In addition, Files.lis contains the motor positions and the corresponding MCA file names and also the counter values. A temporary version of the file, Files temp.lis is maintained. It can be used by an analysis program. Sample time: For non-sweep measurements this is just the gate time for the MCAs and the counters at some fixed position. For sweep-mode operation the sample time is an input for the calculation of the slew rate that is used during the sweeps. Another input is the number of intervals. Inner loop motor: This frame allows the user to specify the details for the sweeps. A motor can be selected by a click on the button, the limits of the sweeps can be supplied and the size of the interval. Middle, outer loop motor: Used for defining 2D or 3D scans. These motors are not used in the sweep mode. Comment: The comment is stored in the MCA files. Statistics: This frame is of importance for sweep-mode measurements only. It is filled after the scan parameters are supplied and the Test button is pressed.

St+Ovrhd: The total sample time of a sweep including the IOT and some extra time. Move: The time it takes for the motor to move over the sweep range with the default slew rate. Back: The time it takes for the motor to move back, including backlash. Slew: The default slew rate. Slew sweep: The adjusted slew rate that takes the sample time, the number of intervals and the overhead time into account. NP extra: The user may add some extra intervals to the sweep. Use Options->Configure to specify this value. The extra points have been introduced to make sure that all sweeps have the same number of points. As a consequence the last MCA spectra of a sweep may be measured at the same position. NP inner: The number of intervals of the sweep. NP middle: The number of points of the ’middle’ loop. NP outer: The number of points of the ’outer’ loop. Swp+back: Sweep time plus time to move back. Total: ’Swp+back’ times the number of sweeps.

63 Figure 9.1: The Sweep Widget

Elapsed: Elapsed time of the scan. This includes the time that is used for the movements. St total: The total sample time. It is updated at the and of each sweep. Sweep total: The total time which was spent in the inner loop. It is updated at the end of each sweep. Coverage: The ratio of ’St total’/’Sweep total’. For sweep mode measurements this ratio should be near 100% whixch would mean that the MCAs were active during all the time the sweep motor was moving. The ration is updated at the end of each sweep. Time that is used for middle and outer loop movements has no effect on the coverage. In case of non-sweep mode scans the ratio can be smaller. This is because the MCAs are only active when the motors stand still. The time that is used for motor movements reduces the ratio. IOT: The user supplied value of the IOT (I/O time). IOTCurr: The current value of the IOT. IOTMean: The mean value of the IOT.

Sweep: This checkbutton enables/disables the sweep mode.

Move: Every motor has an entry field to specify a new position. Pressing this button starts the move. Start: Starts the measurement.

Stop: Interrupts the measurement.

Test: Fills the ’Statistics’ frame. Exit: Destroys the widget.

The problem for setting up a sweep is to determine the IOT. This can be done with the ConfigureXIA widget from the Options menu. The IOT can be measured, as a first guess, and then it is monitored during a test sweep, then set by the user. If IOT is too low, dp is constantly inceasing and the motion terminates too early. If IOT is too high, there is a feedback for every point and the motion terminates too late. A typical value is 0.02s.

9.2 SweepList.pl

This section demonstrates how the Sweep widget is controlled from a macro. The script executes two measurements. The first is a 3D scan, the second a 2D scan. The makro inserts values to the entry widgets that define the scan, like a user would do it. Finally the measurement is started by invoking the procedure that is attached to the Start button. This script can be started from the command line of the toplevel widget: run SweepList.pl.

#!/usr/bin/env perl use strict; use Spectra; # # the list of runs # my @list = ( # # first area, an example for a 3D scan # { w_sample_time => 0.49, w_start_inner => 3015, w_stop_inner => 3115, w_delta_inner => 5, w_start_middle => 10320, w_stop_middle => 10330, w_delta_middle => 10, w_delta_middle => 10, w_start_outer => 0, w_stop_outer => 1, w_delta_outer => 0.5,}, # # second area, 2D # { w_sample_time => 0.51, w_start_inner => 3015, w_stop_inner => 3115, w_delta_inner => 5, w_start_middle => 10340, w_stop_middle => 10350, w_delta_middle => 10,}, ); # # make sure that the Sweep menu is visible # Sweep::main(); foreach my $run ( @list) { # # the outer loop is disabled by default # $Sweep::h{ flag_outer} = 0; $Sweep::h{ flag_outer} = 1 if( defined( $run->{ w_start_outer})) $Sweep::h{ flag_middle} = 1; foreach my $key ( keys %$run) { if( $key =˜ /ˆw_.+/) { $Sweep::h{ ${key}}->delete( ’0’, ’end’); $Sweep::h{ ${key}}->insert( ’0’, $run->{ $key}); } else { $Sweep::h{ $key} = $run->{ $key}; } } $Sweep::h{ w_test}->invoke(); finish if( !Spectra::yesno( "Start to measure"));

$Sweep::h{ w_start}->invoke();

goto finish if( $Spectra::SYM{interrupt_scan}); } finish: 1;

9.3 SweepList.pl with device specification

The following piece of code demonstrates who devices can be selected for Sweep measurements. It is done very much in the same way as in the case of scans. A profile parameter is introduced that points to an anonymous hash which stores the selection. In our examples a timer is selected, two counters, one encoder, one virtual counter, two MCAs and two SCAs. The DORIS current is logged anyway.

#!/usr/bin/env perl use strict; use Spectra; # # the list of runs # my @list = ( # # an area scan that uses the ’profile’ option # { w_sample_time => 0.5, w_start_inner => 3015, w_stop_inner => 3115, w_delta_inner => 10, w_start_middle => 10320, w_stop_middle => 10330, w_delta_middle => 10, profile => { timer => "t1", counter => [ qw( c1 c2 hhe9 vc3)], mca1 => { channels => 2024}, mca2 => { channels => 4048}, sca1 => { mca => "mca1", min => 500, max => 1000}, sca2 => { mca => "mca2", min => 600, max => 1000}, }}, ); # # make sure that the Sweep menu is visible # Sweep::main(); my $flag_profile = 0; foreach my $run ( @list) { $flag_profile = 0; if( defined( $run->{ profile})) { if( !Util::setup_ssd_profile( $run->{ profile})) { Spectra::error( "SweepList: error from Util::setup_ssd_profile"); goto finish; } $flag_profile = 1; delete $run->{ profile}; } # # the outer loop is disabled by default # $Sweep::h{ flag_outer} = 0; $Sweep::h{ flag_outer} = 1 if( defined( $run->{ w_start_outer})); $Sweep::h{ flag_middle} = 1;

foreach my $key ( keys %$run) { if( $key =˜ /ˆw_.+/) { $Sweep::h{ ${key}}->delete( ’0’, ’end’); $Sweep::h{ ${key}}->insert( ’0’, $run->{ $key}); } else { $Sweep::h{ $key} = $run->{ $key}; } } $Sweep::h{ w_test}->invoke(); goto finish if( !Spectra::yesno( "Start to measure"));

$Sweep::h{ w_start}->invoke();

Util::load_ssd_profile( "Profile-temp") if( $flag_profile);

goto finish if( $Spectra::SYM{interrupt_scan}); } finish: Util::load_ssd_profile( "Profile-temp") if( $flag_profile);

1; Chapter 10

Preliminary: The General Scan

The General Scan widget extends the capabilities of the Scan Menu 7.1. It is more flexible at the cost of being more complicated. Therefore, a user should consider the ’normal’ scan menu first before diving into secrets of General Scans. Figure 10.1 displays the General Scan widget. This menu is the user interface to a that executes the scan. A template for such a Perl module is given in 10.1.

Figure 10.1: The TkI ScanG Widget

The explanation of the elements:

Scan name: Scan names are composed of a generic part (prefix) and a combination of numbers and letters that make the name unique. The generic part of the scan name is specified by the user. It can be changed by clicking into the Scan name widget. Module: Specifies a Perl module that defines the scan. It can be found in /online_dir/. The file GS.pm serves as a template. MOT1: The motor that drives the axis a1 (1D scan). It can be dummy1. ’Entry widget’: The target position for an a1-motor move. The move is started by clicking the Move button. Start, Stop, Step width, ST: The scan limits and the sample time. They can be given in several ways. A selector button (StartStop) offers these modes:

– Start, stop, step width – Start, stop, np – Range, np – List – Commands – Regions, for a1-motor only

68 – EXAFS, for a1-motor only

1D: Selects a a1-scan. The other options of this menu button are 2D 10.4 and 3D 10.5. Start: Starts a scan.

Stop: Stops a scan. Pressing the space bar has the same effect.

Refresh: Refreshes the widget. Useful after the module has changed or after EXAFS regions have been changed.

The Module popup menu allows you to edit the selected module or to display the contents of the hash %GS::h. This stores the internal parameters of the module. Some of the keys are mandatory, some not. See the section about the template below for explanations.

Figure 10.2: The TkI ScanG Widget, Module Popup Menu

Figure 10.3: The TkI ScanG Widget, Flags Popup Menu

10.1 A Template for a General Scan Module

In the following you find a template for a general scan module. It has a mandatory data structure %GS::h and some mandatory functions. Let’s start with the hash %GS::h, a string-indexed array. All data that control a scan are stored here. This data structure is displayed, if the user selects Module-Info. The key a1 has the value MOT1 in this example. It is used by the functions get position() and set position(). It is a possible value of the $axis. a1 can be assigned to a motor name, a virtual motor name, dummy1 or energy. Figure 10.4: The TkI ScanG Widget, 2D

Figure 10.5: The TkI ScanG Widget, 3D

The same applies to a2 and a3. But they don’t have to be supplied for 1D scans. For 2D scans we need also a2 and for 3D scan a3 has to be defined. The key description is also mandatory. The other keys of the hash are arbitrary. The have no meaning for Online. Putting them into this hash has the advantage that they can be displayed by selecting the menu option Info. This is the list of the functions:

• get position: Online invokes this function when it needs the position of an axis. • set position: This function is used to change the position of an axis. Notice that the new position can be reached by executing a command.

• exec before: This function is called once before the scan. It is used to allocate that data structures. • during before: Called for every stop. • after before: Called once after the scan. Used for writing data to disk, create a log file and do the cleanup.

That’s all. The general scan widget creates a framework for executing repeated measurements. It defines a minimal interface. Basically the name, the limits and some action buttons. All the rest is left to the user. Anything can be done in the before, during and after macros.

#!/usr/bin/perl -w use strict; package GS; # # An example for a General Scan Module # # The following symbols are defined by Online, they # may be used in this module # # $Spectra::SYM{ scan_name} # $Spectra::SYM{ np_total} # $Spectra::SYM{ sample_time} may change from point to point # $Spectra::SYM{ scan_offset_c1} # $Spectra::SYM{ scan_offset_c...} # $Spectra::SYM{ start} start, stop and delta are unknown, # $Spectra::SYM{ stop} if the positions are specified as # $Spectra::SYM{ delta} commands. # use vars qw( %h); %h = ( a1 => "MOT1", a2 => "MOT2", a3 => "MOT3", counters => [ qw( c3 c4 c5 c8)], timer => "t1", samples => { s1 => 12, s2 => 13}, description => "General Scan Demo Module", ); 1; # # set/get position # sub set_position { my ( $axis, $new_pos) = @_; my $status = 0;

if( ref( $new_pos) eq "CODE") { $status = &$new_pos; } else { $status = Spectra::move( $h{ $axis} => $new_pos); } finish: return $status; } sub get_position { my ( $axis) = @_; # ’a1’, ’a2’ or ’a3’

return Spectra::gmup( $h{ $axis}); } # # this function is called once when the scan starts # sub exec_before { my $status = 0;

Spectra::delete(); Spectra::cls();

my $scan_name = $Spectra::SYM{ scan_name}; my $np_total = $Spectra::SYM{ np_total}; # # the preparation: copy the offsets to %h, # thereby checking whether they exist # $h{ sample_time} = $Spectra::SYM{ sample_time};

foreach my $c ( @{ $h{ counters}}) { $h{ "offset_${c}"} = $Spectra::SYM{ "scan_offset_$c"}; if( !defined $h{ "offset_${c}"}) { Spectra::error( "before: failed to find scan_offset_${c}"); goto finish; } } $h{ start_time} = Spectra::date_and_time(); $h{ start_position} = GS::get_position( "a1"); $h{ np_total} = $np_total;

TEXT->create( name => 0, string => "T1 Scan ($scan_name) started at $h{ start_time}", y => 1.12, x => 1.0, v_aling => ’top’, h_align => ’right’);

TEXT->create( name => 0, string => $h{ a2} . " at " . Spectra::gmup( $h{a2}) , y => 1.05, x => 1.0, v_aling => ’top’, h_align => ’right’); # # it is important to create a SCAN named scan_name because # it helps Online to keeps track of the scan numbers # $h{ scan_name} = SCAN->create( name => $scan_name, np => $np_total); # # allocate space for the counter readings # foreach my $c ( @{ $h{ counters}}) { $h{ $c} = SCAN->create( name => $scan_name . "_" . $c, title => $c, colour => ’blue’, np => $np_total); } # # allocate space for the sample time # $h{ st} = SCAN-> create( name => $scan_name . "_sample_time", title => "Sample Time", colour => ’blue’, np => $np_total);

$h{ scan_name}->deactivate(); Spectra::display( vp => 1); $status = 1; finish: return $status; } # # this function is called for each stop # sub exec_during { my ( $index) = @_; my $status = 0; repeat: # # get the current position ... # my $pos = GS::get_position( "a1"); # # ... and store it # $h{ scan_name}->{ x}[ $index] = $pos; $h{ sample_time} = $Spectra::SYM{ sample_time}; if( $h{ sample_time} <= 0.) { Spectra::error( "exec-during: sample time: $h{ sample_time}"); goto finish; }

Spectra::reset_all_counters();

if( $Util::db_h{ flag_automatic_beamshutter}) { my $t = $Util::db_h{ timer_scan}; $Util::db_h{ timer_scan} = $h{ timer}; $status = Util::was_injection(); $Util::db_h{ timer_scan} = $t; if( !$status) { goto finish; } } else { if( !Spectra::start_and_wait_for_timer( $h{ timer}, $h{ sample_time})) { goto finish; } } # # loop over the counters # foreach my $c ( @{ $h{ counters}}) { $h{ $c}->{ x}[ $index] = $pos; $h{ $c}->{ y}[ $index] = Spectra::rc( $c)/$h{ sample_time} - $h{ "offset_$c"}; } # # store the sample time # $h{ st}->{x}[ $index] = $pos; $h{ st}->{y}[ $index] = $h{ sample_time};

Spectra::autoscale(); Spectra::display(); $status = 1; # # the after file needs to know the final scan position # $h{ stop_position} = GS::get_position( "a1"); finish: return $status; } # # this function is called once after the scan # sub exec_after { my $status; my $scan_name = $h{ scan_name}->get( "name"); # # prepare the command lines # $h{ scan_name}->set( com_1 => $h{ a1} . "-Scan started at " . $h{ start_time} . ", ended " . Spectra::time()); $h{ scan_name}->set( com_2 => "Name: $scan_name from " . $h{ start_position} . " to " . $h{ stop_position} . ", sampling " . $h{ sample_time} . "s"); $h{ scan_name}->set( com_3 => $h{ a2} . " at " . GS::get_position( "a2") . ", " . $h{ a3} . " at " . GS::get_position( "a3")); $h{ scan_name}->set( com_4 => "Counter reading are offset corrected, the offsets are"); my $line = ""; foreach my $c ( @{ $h{ counters}}) { $line .= "$c " . $Spectra::SYM{ "scan_offset_$c"} . " "; } $h{ scan_name}->set( com_5 => $line);

$status = Spectra::gra_command( "write/fio/scan/motors $Spectra::SYM{ scan_name}");

# # create log file # open( FH, ">${scan_name}.log"); print FH " Scan name ${scan_name}\n"; print FH " User $ENV{ USER} \n"; print FH " Start $Spectra::SYM{ start}\n"; print FH " Step $Spectra::SYM{ delta} \n"; print FH " Stop $Spectra::SYM{ stop} \n"; print FH " Sample time $Spectra::SYM{ sample_time} \n"; print FH " Started " . $Util::res_h{ start_time} . "\n"; print FH " Ended " . Spectra::date_and_time() . "\n"; print FH " Offset C3 " . $Spectra::SYM{ scan_offset_c3} . "\n"; print FH " Offset C4 " . $Spectra::SYM{ scan_offset_c4} . "\n"; print FH " Offset C5 " . $Spectra::SYM{ scan_offset_c5} . "\n"; print FH " Offset C8 " . $Spectra::SYM{ scan_offset_c8} . "\n"; if( defined( $Scan::menu_h{ w_comment})) { print FH " Comment " . $Scan::menu_h{ w_comment}->get() . "\n"; } close( FH); return $status; } Chapter 11

The Move Widget

Figure 11.1 shows the Move motor menu.

Figure 11.1: The Move Widget

The explanation of the elements: MOT1: A button that displays the currently selected motor. If pushed, a list of available motors pops up (fig. 11.2). Move to: New positions are specified in the adjacent entry widget. This button starts the move. Scale widget: The slider bar is one way to move the motor. Incr.: 100: A menu button that selects an increment, which is used by the << and >> buttons. Slew: 100%: A menu button for changing the slew rate temporarily. The original value is restored when the widget is exited. The temporary slew rate cannot exceed the original value. Range: 100%: A menu button for adjusting the range temporarily. The original value is restored when the widget is exited. The temporary range is limited by the original range. |<, >|: Starts a move to the left/right limit. <<, >>: Move the motor by one increment, no backlash. <, >: Move the motor by one step.

76 Stop: Stops the move.

Signal: A signal can be displayed while the motor is moving. The corresponding flag can be found in the Options menu. The signal frame displays the maximum and contains two buttons. One moves the motor to the maximum, the other to the current cursor position. The cursor position is available as long as the cursor window is open.

Sel. motor: Invokes the motor selector.

Sel. slit: Invokes the slit selector widget (??).

Sel. VM The available virtual motors are presented in a chooser.

Cursor Invokes the cursor widget for the signal SCAN GQE.

Figure 11.2: The Motor Selector

11.1 The Motor Properties Widget

This is the Motor Properties menu (11.3):

Position (Cal.): Calibrates a motor.

Acceleraton: Steps/s2

New parameter values are in effect after the user pressed Apply. Figure 11.3: The Motor Properties Widget

11.2 The Encoder Widget

The explanations for how to use this widget are given in our hardware manual.

Encoder position: calculated using the raw position, the home position and the encoder conversion factor. Encoder raw position: result of the RE command.

Home position: the home position (reference mark), in units. The motor is calibrated to this position after a homing procedure.

Encoder conversion: used to calculate the encoder position. This factor is also necessary for homing procedures and closed loop operations.

Encoder ratio: always 1 during open loop operations. For closed loop it is set to the ration Conversion/EncoderConversion.

FlagUseEncoderPosition: if set to 1, the server returns the encoder position when the position attribute is read.

ClosedLoop: if set to 1, the motor is in closed loop mode after the next move.

FlagInvertEncoderDir.: if set to 1, the encoder counts are inverted. Used, if steps and encoder counts are in opposite direction,

CorrectionGain: [1,32000], 1000 seems to be a good to get started. Figure 11.4: The Encoder Widget

DeadBand: in steps. SlewRateCorrection: the maximum slew rate used in corrections. SlipTolerance: a slip is signaled, if the encoder counts deviate more than this tolerance from the setpoint. WriteRead: debugging tool. Useful commands: RP request position, RE request encoder, ED? request invert encoder direction. Home: starts the homing procedure. Software limits are ignored when homing is active. Be sure to know what you are doing, if you press this button. Set FlagHomed: useful after a server restart, if the motor was homed and VME stayed powered. Cali Enc.: sets the encoder register using the unit position, the home position and the encoder conversion factor. Warning: The motor position must be well-defined (backlash-correct). This is always true after normally com- pleted moves, if the backlash correction is sufficiently large. But this is not necessarily true, if the last movement was interrupted. Things can be settled be executing a move.

New parameter values are in effect after the user pressed Apply.

11.3 Virtual Motors

Virtual motors are explained in the Perl-Spectra documentation.

11.4 Slits

Slits are introduced to Online by defining the symbol slit names in /online dir/exp ini.exp, e.g.: slit_names = (slt1, slt2) slt1_left = mot21 slt1_right = mot22 slt1_top = mot23 slt1_bottom = mot24 slt2_left = mot25 slt2_right = mot26 slt2_top = mot27 slt2_bottom = mot28

The symbol slit names holds the generic part of the slit names. In addition the jaws must be selected by: slt1 left = mot21, etc. After a slit is specified, the following degrees of freedom are available: cx, cy, dx, dy, left, right, top, bottom. They are presented in the slit selector, see 11.5. This widget can be called from the Scan GUI or the Move GUI. The coordinate system: z points in the direction of the photons, y points upwards, x completes the right-handed coordinate system. ’right’ points in the x-direction, like in school.

Figure 11.5: The Slit Selector Chapter 12

The MCA Widget

Figure 12.1 shows the MCA menu.

Figure 12.1: The MCA Widget

Here is an explanation of the elements:

Sample time: If set to -1, the sample time is unlimited. Update after: The time after which the MCAs are read-out and displayed. Total time: The total sample time. This value is resetted by a Clear command. The Devices frame MCA1: This menubutton specifies the device which parameters are displayed and changed by the widgets in this frame. It does not select an MCA for the measurement. This id done by the Select devices widget of the Options menu. 2048: The number of channels. Window: [0, 2047]: The windows limits. This parameter is used for the display only.

81 ROI-1: [650, 750]: The first region of interest. You find the total number of counts, the signal and the background in adjacent label widgets. The background is calculated from a linear interpolation of the first and last point of the region of interest.

The Counters frame

C1 (COUNTER I0): The counters are selected by Select Scan Devices of the Options menu of the toplevel widget. The counter contents are written to the output files. If counters are aliases of MONITOR MCA, MONITOR2 MCA or MONITOR3 MCA then Online makes sure that these symbols enter the output file, even if other aliases exist. Doris: The Doris current [mA]. Depending on the status of the flag Use digital Doris current the value is read from a server via the network or it is a converted analog signal.

The Output parameters frame

File name: The current file name. The generic part can be changed by pushing the adjacent button. Comment: The comment line is displayed in the graphics screen and written to the output file.

The Button line

Start: Starts a MCA run. The button changes to Stop as long as the run is active. Log: Switch between linear and logarithmic scales. Cursor: Invokes the cursor. It can be used to set the regions of interest. Clear: Resets a MCA spectrum. Changes the name of the output file. Write: Creates an output file. Display:

Options: The menu is displayed in figure 12.2. The items are:

Select devices: A widget for the selection of the MCA timer and the MCAs which are used. Include motors: A flag that determines whether the motor positions are written to the output files.

Use digital Doris current: If enabled, the Doris current is read from a server via the network. Otherwise an analog signal can be digitized. The associated counter is defined by the symbol DORIS MCA. The sym- bol C2C DORIS MCA stores the conversion factor which needed for the calculation counts to mA (I[mA] = Counts/C2C/SampleTime).

Calibration: Invokes a menu that relates channel numbers to energy values.

Figure 12.3 shows the widget that allows you specify the displayed devices. Figure 12.2: The MCA Options Menu

Figure 12.3: The MCA Select Devices Menu Chapter 13

The DSO Widget

Figure 13.1 shows the DSO menu. It is invoked by a button of the toplevel widget. This button is displayed, if a DSO has been defined.

Figure 13.1: The DSO Widget

Here is an explanation of the elements:

Update: The refresh interval.

Display: Selects the displayed channels.

The Trigger frame

NP: The number of points per trace. Sparse: A sparse factor of 5 means: read every 5th sample. Offset: A value of 1000 means: skip the first 1000 samples.

The Trigger frame

Channel: Selects the trigger channel.

84 Mode: AUTO, NORM, SINGLE or STOP. Level: The trigger level.

Time base: The DSO samples at a constant rate, depending on the module type. The time base is the time interval that corresponds to 1cm on the oscilloscope screen.

Auto-Setup: Sends the Auto-Setup command to the DSO. The time base, vertical gain, vertical offset and trigger conditions are automatically adjusted.

Trace C1: Enables channel 1, selectes the voltage range (vertical gain) and the offset.

Generic name: Specifies the generic part of the file name that is used when the data are written to a disk file. Chapter 14

Beamline Specific Code by Examples

Online widgets are designed to be useful at all beamlines or at least at several beamlines. However, there are experi- mental stations that need customized widgets for very specific purposes. Online has a general concept for integrating beamline specific code (BLSC). Each BLSC application generates a toplevel widget that may contain buttons, check- buttons, entries and labels. BLSCs are identified by a generic name. The variable $Spc::res_h{ blsc} stores all generic name. This way Online knows which widgets to create:

$Spc::res_h{ blsc} = "hello, energy, volts, k428, sltd, mc, hkl";

The variable is defined in the TkI startup file:

/online_dir/TkIrc.pl.

The BLSC code is also part of the startup file.

14.1 ’Hello world’, Button

The mandatory example:

$Spc::res_h{ blsc} = "hello"; $Spc::res_h{ hello_title} = { text => "Hello"}; $Spc::res_h{ hello_b1} = { name => "Press me", command => sub { Util::log( "hello world");}};

The BLSCs can be found in the Misc popup menu of the TkI toplevel widget. The GUI is displayed in figure 14.1. It displays a button, ’Press me’, which sends the string ’hello world’ to the log window of the TkI toplevel widget once it is pressed. Here are some details about the code:

Figure 14.1: Hello World

• $Spc::res_h{ blsc} = "hello"; There is only one BLSC widget, the generic name is hello.

• $Spc::res_h{ hello_title} = { text => "Hello"}; The title of the widget, it is introduced by setting a component of the %Spc::res_h hash. The indexing string is composed of the generic name (hello) and the keyword title.

86 • $Spc::res_h{ hello_b1} = { name => "Press me", command => sub {...}} Directs Online to create a button, ’Press me’ is displayed on the button. The command option specifies the callback routine for the button. hello_b1 is composed of the generic part, the letter ’b’, which selects the button widget, and the number 1. The purpose of appending a number is to distinguish between several buttons.

14.2 Energy

Another example: $Spc::res_h{ blsc} = "energy";

Figure 14.2: Energy energy is a keyword. A widget is created that changes the energy, nothing else.

14.3 Entry Widgets

The next example introduces entry widgets: $Spc::res_h{ blsc} = "volts"; $Spc::res_h{ volts_title} = { text => "Voltages"}; foreach my $i( qw( 1 2 3 4)) { $Spc::res_h{ "volts_io" . $i} = { label => { name => "U$i", width => 12, # optional get => sub { get_volts( "U$i");}, unit => "V"}, entry => { set => sub { set_volts( "U$i", $_[0]);}}}; } # # the callback functions # sub get_volts { my ( $u) = @_; my $ret = Util::P6( Spectra::random()); print " reading $u: $ret \n"; $ret; } sub set_volts { my ( $u, $value) = @_; print " setting $u to $value\n"; }

The widget is displayed in figure 14.3. Figure 14.3: The Voltages Interface

$Spc::res_h{ "volts_io" . $i} = { ...}; The letters ’io’ select the IO widget. An IO widget is a composite widget, which is optionally made of labels, checkbuttons, selectbuttons and entry widgets. label => { name => "U$i", get => sub { get_volts( "U$i");}} Creates a label widget, which has a name and an associated callback function that returns a value which is displayed by the widget. Notice that in this example 4 rows are created. Each has a different callback function. The functions differ by the values of $i. entry => { set => sub { set_volts( "U$i", $_[0]);}} Creates an entry widget. The contents is passed to the ’set’ function, once the ’Exec’ button is pressed.

14.4 Buttons, Keithley-428

Here it is demonstrated how check- and select-buttons are used:

$Spc::res_h{ blsc} = "k428"; $Spc::res_h{ k428_title} = { text => "Keithley-428"}; foreach my $i ( qw( 10 11 12)) { $Spc::res_h{ "k428_io" . $i} = { label => { name => "K428-$i", get => sub { get_K428( $i, "");}}, checkbutton => { name => "Zero check", set_on => sub { set_K428( $i, "C1X");}, set_off => sub { set_K428( $i, "C0X");}, get => sub { get_K428( $i, "C") =˜ /C1/i;}}, selectbutton => { name => "Range", items => {"R6", sub { set_K428( $i, "R6X");}, "R7", sub { set_K428( $i, "R7X");}, "R8", sub { set_K428( $i, "R8X");}, "R9", sub { set_K428( $i, "R9X");}}}}; } # # the callback functions # sub get_K428 { my ( $adr, $par) = @_; my $ret; # # read the status, e.g.: 428A0B0C0H05J0K0M000N0P1R08S07 # gpib_write( $adr, "U0X"); my $status = gpib_read( $adr, 30); if( $par =˜ /ˆr$/i) # range { $ret = substr( $status, 24, 3); } elsif( $par =˜ /ˆc$/i) # zero check { $ret = substr( $status, 7, 2); } $ret; } sub set_K428 { my ($adr, $value) = @_; gpib_write( $adr, $value); }

Figure 14.4 shows the resulting widget. Here are some explanations:

foreach my $i ( qw( 10 11 12)) The GPIB addresses of the Keithleys: 10, 11 and 12. checkbutton => { ...} The checkbutton widget has a name that describes it and 2 functions (get_on(), get_off()) that are invoked, if the button changes its state. In addition there is a function, get() that returns the current state. selectbutton => { ...} A selectbutton has a name which is displayed on top of a select button and it has a list of items. Each item consists of a name and a function that is invoked, if the name is selected. sub { get_K428( $i, "C") =˜ /C1/i;} This is an that returns 1, if the output of get_K428( $i, "C") contains C1. Otherwise 0 is returned. label => { ..., get => sub { get_K428( $i, "R");}

Figure 14.4: The K-428 Interface 14.5 Motors

This example shows how to create a widget for a group of motors.

$Spc::res_h{ blsc} = "sltd"; # # slits # $Spc::res_h{ sltd_title} = { text => "Sltd"}; $Spc::res_h{ sltd_m17} = { name => "Mot17", alias => "Left", unit => "mm"}; $Spc::res_h{ sltd_m18} = { name => "Mot18", alias => "Right", unit => "mm"}; $Spc::res_h{ sltd_m19} = { name => "Mot19", alias => "Top", unit => "mm"}; $Spc::res_h{ sltd_m20} = { name => "Mot20", alias => "Bottom", unit => "mm"}; $Spc::res_h{ sltd_single} = 1; # optional

If the ’single’ flag is defined and if it is set to 1, only single motor movements are allowed.

$Spc::res_h{ sltd_mt17} = { name => "Mot17", alias => "Left", unit => "mm"}; Specifies a motor, the line consists of a name, an alias and the unit. Online creates an entry widget for the motors which allows the user to specify a movement.

Figure 14.5: Motors

14.6 Monochromator

The next example shows part of the monochromator widget of X1:

$Spc::res_h{ blsc} = "mc"; $Spc::res_h{ mc_title} = { text => "Monochromator"}; $Spc::res_h{ mc_help} = sub { Util::display_text( "Help MC", ’ Si111 Si311 Si511 - Change MC setup ... ’ )};

$Spc::res_h{ mc_io1} = { label => { name => "Crystal spacing", get => sub {$Spectra::SYM{ d_crystal};}}}; $Spc::res_h{ mc_io2} = { label => { name => "Crystal type", get => \&type_crystal}}; # # the motors # $Spc::res_h{ mc_m1} = { name => "Mot1", alias => "Theta", unit => "Deg"}; $Spc::res_h{ mc_m2} = { name => "Mot2", alias => "Table", unit => "mm"}; $Spc::res_h{ mc_m3} = { name => "Mot3", alias => "C1_Theta", unit => "mm"}; $Spc::res_h{ mc_m4} = { name => "Mot4", alias => "Hor", unit => "mm"}; $Spc::res_h{ mc_m9} = { name => "Mot9", alias => "C2_trans", unit => "mm"}; $Spc::res_h{ mc_m10} = { name => "Mot10", alias => "C2_Rho", unit => "Deg."}; $Spc::res_h{ mc_m11} = { name => "Mot11", alias => "Top", unit => "mm"}; $Spc::res_h{ mc_m12} = { name => "Mot12", alias => "Bottom", unit => "mm"}; # # the buttons # $Spc::res_h{ mc_b1} = { name => "E to 9400 eV", command => sub { Spectra::move( energy => 9400);}}; $Spc::res_h{ mc_b2} = { name => "E to 18000 eV", command => sub { Spectra::move( energy => 18000);}}; $Spc::res_h{ mc_b3} = { name => "Si111", command => sub { change_crystal ( "Si111");}}; $Spc::res_h{ mc_b4} = { name => "Si311", command => sub { change_crystal ( "Si311");}}; $Spc::res_h{ mc_b5} = { name => "Si511", command => sub { change_crystal ( "Si511");}}; # # the options # $Spc::res_h{ mc_option1} = { name => "Calc Offset", command => \&new_hhe_offset}; # # a function which is executed after the calibration # $Spc::res_h{ mc_post_calibration} = \&new_hhe_offset; # # the callback functions # sub type_crystal { my $ret = "unknown"; my $temp = Spectra::gmup( $SYM{ mc_hor});

if( ($temp < 0.5) && ($temp > -0.5)) { $ret = "Si111"; } ... $ret; } sub change_crystal { my ( $type_new) = @_; print "change the crystal to $type_new\n"; } sub new_hhe_offset { print "calculated offset\n"; } The title and io widgets have already been explained. The new items are: $Spc::res_h{ mc_help} = sub { Util::display_text( ’title’, ’help text’);}; Creates an additional item in the Help popup menu. Figure 14.6: The MC Interface at X1

$Spc::res_h{ mc_option1} = { name => ’...’, command => ’...’}; Creates an entry in the Options pop-up menu. $Spc::res_h{ mc_post_calibration} = \&new_hhe_offset; This function is called after the calibration completed successfully. Here it means that a new encoder offset is calculated automatically.

14.7 hkl

This section shows how a widget that displays the components of the hkl vector and the diffractometer angles are displayed (14.7).

# # # $Spc::res_h{ blsc} = "hkl"; $Spc::res_h{ hkl_title} = { text => "hkl"}; $Spc::res_h{ hkl_io1} = { label => { name => "h", unit => " ", get => sub{ Spectra::h();}}, entry => { set => sub{ Spectra::hkl( h => $_[0]);}}}; $Spc::res_h{ hkl_io2} = { label => { name => "k", unit => " ", get => sub{ Spectra::k();}}, entry => { set => sub{ Spectra::hkl( k => $_[0]);}}}; $Spc::res_h{ hkl_io3} = { label => { name => "l", unit => " ", get => sub{ Spectra::l();}}, entry => { set => sub{ Spectra::hkl( l => $_[0]);}}}; $Spc::res_h{ hkl_io4} = { label => { name => "Psi", unit => "Deg.", get => sub{ Spectra::psi();}}, entry => { set => sub{ Spectra::hkl( psi => $_[0]);}}}; $Spc::res_h{ hkl_io5} = { label => { name => "TwoTheta", unit => "Deg.", get => sub{ Spectra::two_theta();}}, entry => { set => sub{ Spectra::angles( two_theta => $_[0]);}}}; $Spc::res_h{ hkl_io6} = { label => { name => "Omega", unit => "Deg.", get => sub{ Spectra::omega();}}, entry => { set => sub{ Spectra::angles( omega => $_[0]);}}}; $Spc::res_h{ hkl_io7} = { label => { name => "Chi", unit => "Deg.", get => sub{ Spectra::chi();}}, entry => { set => sub{ Spectra::angles( chi => $_[0]);}}}; $Spc::res_h{ hkl_io8} = { label => { name => "Phi", unit => "Deg.", get => sub{ Spectra::phi();}}, entry => { set => sub{ Spectra::angles( phi => $_[0]);}}};

Figure 14.7: The hkl Widget

14.8 Pilatus-300K, B1, BW4, P03, P09

# # the following lines are part of /online_dir/TkIrc.pl # $Spc::res_h{ blsc} = "pilatus"; # # # $Spc::res_h{ pilatus_title} = { text => "Pilatus-X300K"};

$Spc::res_h{ "pilatus_io1"} = { label => { name => "ExposureTime [s]", get => sub { Spectra::tng_attrDoubleRd( "pilatus", "ExposureTime");}, unit => ""}, entry => { set => sub { while(Spectra::tng_state( "pilatus") == 10) # Wait Pilatus to { Spectra::wait(0.1); } Spectra::tng_state( "pilatus"); Spectra::tng_attrDoubleWrt( "pilatus", "ExposureTime", $_[0]);}}}; $Spc::res_h{ "pilatus_io2"} = { label => { name => "ExposurePeriod [s]", get => sub { Spectra::tng_attrDoubleRd( "pilatus", "ExposurePeriod");}, unit => ""}, entry => { set => sub { while(Spectra::tng_state( "pilatus") == 10) # Wait Pilatus to { Spectra::wait(0.1); } Spectra::tng_state( "pilatus"); Spectra::tng_attrDoubleWrt( "pilatus", "ExposurePeriod", $_[0]);}}}; $Spc::res_h{ "pilatus_io3"} = { label => { name => "NbFrames", get => sub { Spectra::tng_attrLongRd( "pilatus", "NbFrames");}}}; $Spc::res_h{ "pilatus_io4"} = { label => { name => "FileDir", width => 30, get => sub { my $ret = Spectra::tng_attrStringRd( "pilatus", "FileDir");}}};

$Spc::res_h{ "pilatus_io5"} = { label => { name => "FilePrefix", get => sub { my $ret = Spectra::tng_attrStringRd( "pilatus", "FilePrefix"); return $ret;}, unit => ""}, entry => { set => sub { while(Spectra::tng_state( "pilatus") == 10) # Wait Pilatus to { Spectra::wait(0.1); } Spectra::tng_state( "pilatus"); Spectra::tng_attrStringWrt( "pilatus", "FilePrefix", $_[0]);}}}; $Spc::res_h{ "pilatus_io5"} = { label => { name => "FilePostfix", get => sub { my $ret = Spectra::tng_attrStringRd( "pilatus", "FilePostfix"); # $ret =˜ s/ˆ\s*(.*?)\s*$/$1/; return $ret;}, #}}; unit => ""}, entry => { set => sub { while(Spectra::tng_state( "pilatus") == 10) # Wait Pilatus to { Spectra::wait(0.1); } Spectra::tng_state( "pilatus"); Spectra::tng_attrStringWrt( "pilatus", "FilePostfix",$_[0] );}}}; $Spc::res_h{ "pilatus_io6"} = { label => { name => "FileStartNum", get => sub { my $ret = Spectra::tng_attrLongRd( "pilatus", "FileStartNum"); return $ret;}, unit => ""}, entry => { set => sub { while(Spectra::tng_state( "pilatus") == 10) # Wait Pilatus to { Spectra::wait(0.1); } Spectra::tng_state( "pilatus"); Spectra::tng_attrLongWrt( "pilatus", "FileStartNum", $_[0]);}}}; $Spc::res_h{ "pilatus_io7"} = { label => { name => "State", get => sub { my $ret = Spectra::tng_state( "pilatus");}}}; $Spc::res_h{ "pilatus_io8"} = { label => { name => "Threshold [eV]", get => sub { Spectra::tng_attrLongRd( "pilatus", "Threshold");}, unit => ""}, entry => { set => sub { while(Spectra::tng_state( "pilatus") == 10) # Wait Pilatus to { Spectra::wait(0.1); } Spectra::tng_state( "pilatus"); Spectra::tng_attrLongWrt( "pilatus", "Threshold", $_[0]);}}};

$Spc::res_h{ pilatus_b1} = { name => "Start", #Wait for pilatus to stop before starting command => sub { while(Spectra::tng_state( "pilatus") == 10) { Spectra::wait(0.1); } Spectra::tng_inout( "pilatus", "StartStandardAcq");}}; $Spc::res_h{ pilatus_b2} = { name => "Stop", command => sub { Spectra::tng_inout( "pilatus", "StopAcq");}}; $Spc::res_h{ pilatus_b3} = { name => "Reset", command => sub { Spectra::tng_inout( "pilatus", "Reset");}}; $Spc::res_h{ pilatus_b4} = { name => "Restart Server", command => sub { Util::log( "Restart Server");}};

Figure 14.8: Pilatus-300K, P03, P09

The virtual counter that operates the Pilatus needs the following lines:

if( $method =˜ /reset/i) { Spectra::tng_attrLongWrt( "pilatus", "NbFrames", 1); Spectra::pilatus_start( $Spectra::SYM{ scan_name}, $Spectra::SYM{ sample_time}, $Spectra::SYM{ sindex}, ".cbf"); return 1; }

if( $method =˜ /read/i) { while( Spectra::pilatus_state()) { Util::log( "waiting for Pilatus "); Spectra::wait( 0.5); } Util::log( "pilatus state " . Spectra::pilatus_state()); return 1; }

14.9 MAXV Encoder, Tango

The following code helps to operate a MAXV controller with an encoder axis. The widget is displayed below.

$Spc::res_h{ blsc} = "mot65encoder"; # # # $Spc::res_h{ mot65encoder_title} = { text => "Mot65-Encoder"};

$Spc::res_h{ mot65encoder_help} = sub { Util::display_text( "Help MOt65Encoder", ’ State 0 ON 6 MOVING

Home Starts the homing sequence

Toggle auto-refresh If enabled, the menu items are updated every 2 seconds. See current state of this flag is displayed in the log widget of the toplevel menu, if it is changed. ’ )}; $Spc::res_h{ "mot65encoder_io1"} = { label => { name => "Position", get => sub { Spectra::tng_attrDoubleRd( "mot65", "Position");}}, entry => { set => sub { Spectra::tng_inoutDoubleLong( "mot65", "Move", $_[0])}}};

$Spc::res_h{ "mot65encoder_io2"} = { label => { name => "Encoder Position", get => sub { if( Spectra::tng_attrLongRd( "mot65", "FlagEncoderHomed")) { Spectra::tng_attrDoubleRd( "mot65", "PositionEncoder"); } else { "not homed";}}}}; $Spc::res_h{ "mot65encoder_io3"} = { label => { name => "Encoder Home Position", get => sub { if( Spectra::tng_attrLongRd( "mot65", "FlagEncoderHomeDefined")) { Spectra::tng_attrDoubleRd( "mot65", "HomePosition"); } else { "home not defined";}}}, entry => { set => sub { Spectra::tng_attrDoubleWrt( "mot65", "HomePosition", $_[0])}}}; $Spc::res_h{ "mot65encoder_io4"} = { label => { name => "Encoder Conversion", get => sub { if( Spectra::tng_attrLongRd( "mot65", "FlagEncoderConversionDefined")) { Spectra::tng_attrDoubleRd( "mot65", "ConversionEncoder"); } else { "conversion not defined";}}}, entry => { set => sub { Spectra::tng_attrDoubleWrt( "mot65", "ConversionEncoder", $_[0])}}}; $Spc::res_h{ "mot65encoder_io5"} = { label => { name => "FlagHomed", get => sub { Spectra::tng_attrLongRd( "mot65", "FlagEncoderHomed");}}}; $Spc::res_h{ "mot65encoder_io6"} = { label => { name => "FlagUseEncoderPosition", get => sub { Spectra::tng_attrLongRd( "mot65", "FlagUseEncoderPosition");}}, entry => { set => sub { Spectra::tng_attrLongWrt( "mot65", "FlagUseEncoderPosition", $_[0])}}};

$Spc::res_h{ "mot65encoder_io7"} = { label => { name => "State", get => sub { Spectra::tng_state( "mot65");}}};

$Spc::res_h{ mot65encoder_b1} = { name => "Home", command => sub { Spectra::tng_inout( "mot65", "MoveHome");}};

$Spc::res_h{ mot65encoder_b2} = { name => "ResetMotor", command => sub { Spectra::tng_inout( "mot65", "ResetMotor");}};

$Spc::res_h{ mot65encoder_option1} = { name => "Toggle auto-refresh", command => sub { if( defined( $BLSC::h{ w_timer})) { $BLSC::h{ w_timer}->cancel(); delete $BLSC::h{ w_timer}; Util::log( "BLSC: timer cancelled"); } else { $BLSC::h{ w_timer} = $BLSC::h{ w_top}->after( 2000, \&BLSC::refresh); Util::log( "BLSC: timer started"); }}};

The following figure displays the widget just after the axis has been homed: the motor position, the encoder position and the home position are identical.

14.10 Spk/Slt, Tango

The following code creates a widget to operate Slt/Spk PLCs. In the meantime the features are available from online -tki itself ( to be invoked by a right-click on the motor name in the toplevel widget). However the code has been kept here to serve as an example.

$Spc::res_h{ blsc} = "spk1, other, devices"; $Spc::res_h{ spk1_title} = { text => "Spk1"};

$Spc::res_h{ spk1_help} = sub { Util::display_text( "Help Spk1", ’ Figure 14.9: An OMS MAXV controller with an encoder

State 0 ON 6 MOVING

Home Starts the homing sequence

Toggle auto-refresh If enabled, the menu items are updated every 2 seconds. See current state of this flag is displayed in the log widget of the toplevel menu, if it is changed. ’ )}; $Spc::res_h{ "spk1_io1"} = { label => { name => "Position", get => sub { sprintf "%g", Spectra::tng_attrDoubleRd( "spk1", "Position");}}, entry => { set => sub { Spectra::tng_attrDoubleWrt( "spk1", "Position", $_[0])}}};

$Spc::res_h{ "spk1_io2"} = { label => { name => "Encoder Home Position", get => sub { if( Spectra::tng_attrLongRd( "spk1", "FlagEncoderHomeDefined")) { sprintf "%g", Spectra::tng_attrDoubleRd( "spk1", "HomePosition"); } else { "home not defined";}}}, entry => { set => sub { Spectra::tng_attrDoubleWrt( "spk1", "HomePosition", $_[0])}}}; $Spc::res_h{ "spk1_io3"} = { label => { name => "FlagHomed", get => sub { Spectra::tng_attrLongRd( "spk1", "FlagEncoderHomed");}}}; $Spc::res_h{ "spk1_io4"} = { label => { name => "State", get => sub { Spectra::tng_state( "spk1");}}}; $Spc::res_h{ "spk1_io5"} = { label => { name => "Error code", get => sub { Spectra::tng_attrLongRd( "spk1", "ErrorCode");}}};

$Spc::res_h{ spk1_b1} = { name => "Home", command => sub { Spectra::tng_inout( "spk1", "MoveHome");}};

$Spc::res_h{ spk1_b2} = { name => "ResetMotor", command => sub { Spectra::tng_inout( "spk1", "ResetMotor");}};

$Spc::res_h{ spk1_b3} = { name => "ClearError", command => sub { Spectra::tng_inout( "spk1", "ClearError");}};

$Spc::res_h{ spk1_option1} = { name => "Toggle auto-refresh", command => sub { if( defined( $BLSC::h{ w_timer})) { $BLSC::h{ w_timer}->cancel(); delete $BLSC::h{ w_timer}; Util::log( "BLSC: timer cancelled"); } else { $BLSC::h{ w_timer} = $BLSC::h{ w_top}->after( 2000, \&BLSC::refresh); Util::log( "BLSC: timer started"); }}};

Figure 14.10: Spk

14.11 VHSC005N, HV PS, ISEG

THe following lines operate the VHSC005N HV power supply. The widget can be found below 14.11.

# # from /online_dir/TkIrc.pl # $Spc::res_h{ blsc} = "vhsc005n, otherItems"; # # # $Spc::res_h{ vhsc005n_title} = { text => "VHSC005N"}; $Spc::res_h{ vhsc005n_help} = sub { Util::display_text( "Help VHSC005N", ’ Ramp A parameter that applies to all channels of a module. The unit is per cent of -500 per second. The maximum is 20.

Exec Starts the ramp

Stop Changes the setpoint to the actual value. ’ )}; my @list = split ’ ’, Spectra::get_devices( "HV_PS"); my $i = 1; for my $hv ( @list) { $Spc::res_h{ "VHSC005N_io$i"} = { label => { name => "${hv} [V]", get => sub { sprintf "%g", Spectra::vhsc005n( $hv, "VoltageMeasure");}}, entry => { set => sub { Spectra::vhsc005n( $hv, "VoltageSet", $_[0]);}}}; $i++; }

$Spc::res_h{ "VHSC005N_io$i"} = { label => { name => "Ramp [1-20]", get => sub { sprintf "%g", Spectra::vhsc005n( $list[0], "VoltageRampSpeed");}}, entry => { set => sub { Spectra::vhsc005n( $list[0], "VoltageRampSpeed", $_[0]); }}};

14.12 Lom, Compound Device, P08, Tango

The following lines are part of /online dir/TkIrc.pl. They create a widget to operate the Large Offset Monochromator (Lom). It is an example of a compound device. Such devices export the attributes PositionSim and ResultSim (among other attributes). The are used as follows: if a value is written to PositionSim, the server sets the attribute ResultSim (a spectrum of strings), e.g.: Lom1Pitch = 24.2993, Lom2Pitch = 24.2993, Lom1Lin = -551.039, Lom2Lin = 551.039, emt = 0.123. Online parses these strings and fills the motor entry widgets accordingly, if the Test button is clicked. The Crystal Spacing is selected by the positions of Lom1Lat and Lom2Lat, the Si311 crystals are found at 73mm, the Si511 crystals at 2 mm. The motor lomenergy uses the TangoMotor interface. See our Tango manual for details.

$Spc::res_h{ blsc} = "lom";

$Spc::res_h{ lom_title} = { text => "Large Offset MC"}; $Spc::res_h{ lom_help} = sub { Util::display_text( "Help MC", ’ Some Help text ’ )}; # # the following line makes it a compound device # Figure 14.11: BLSC: VHSC005N

$Spc::res_h{ lom_cmpnd} = { name => "lomenergy", unit => "eV"};

# # the motors # $Spc::res_h{ lom_m1} = { name => "Lom1Pitch", unit => "Deg"}; $Spc::res_h{ lom_m2} = { name => "Lom1Lin", unit => "mm"}; $Spc::res_h{ lom_m3} = { name => "Lom1Lat", unit => "mm"}; $Spc::res_h{ lom_m4} = { name => "Lom2Pitch", unit => "Deg"}; $Spc::res_h{ lom_m5} = { name => "Lom2Lin", unit => "mm"}; $Spc::res_h{ lom_m6} = { name => "Lom2Lat", unit => "mm"};

$Spc::res_h{ lom_io1} = { label => { name => "Crystal spacing", get => sub {Spectra::tng_attrDoubleRd( "lomenergy", "D_Crystal");}}}; $Spc::res_h{ lom_io2} = { label => { name => "ConstantExit", get => sub { Spectra::tng_attrDoubleRd( "lomenergy", "ConstantExit");}, unit => "mm"}, entry => { set => sub { Spectra::tng_attrDoubleWrt( "lomenergy", "ConstantExit", $_[0])}}};

14.13 FMB Oxford DCM, CalibrationUnits, P01, P02, Tango

The following lines of code create a FMB widget including the calibration constants. A figure of the widget is displayed below.

# # part of /online_dir/TkIrc.pl # Figure 14.12: BLSC: Lom

$Spc::res_h{ blsc} = "fmb";

$Spc::res_h{ fmb_title} = { text => "FMB Monochromator"}; $Spc::res_h{ fmb_help} = sub { Util::display_text( "Help MC", ’ Some Help text ’ )};

$Spc::res_h{ fmb_cmpnd} = { name => "energyfmb", unit => "eV"};

# # the motors # $Spc::res_h{ fmb_m1} = { name => "Dcm_Bragg", unit => "Deg"}; $Spc::res_h{ fmb_m2} = { name => "Dcm_Parallel", unit => "mm"}; $Spc::res_h{ fmb_m3} = { name => "Dcm_Perp", unit => "mm"}; # # the calibration units # $Spc::res_h{ fmb_io1} = { label => { name => "CalBragg", get => sub { sprintf( "%g", Spectra::tng_attrDoubleRd( "dcm_bragg", "UnitCalibration"));}, unit => "Deg"}, entry => { set => sub { Spectra::tng_attrDoubleWrt( "dcm_bragg", "UnitCalibration", $_[0])}}}; $Spc::res_h{ fmb_io2} = { label => { name => "CalParallel", get => sub { sprintf( "%g", Spectra::tng_attrDoubleRd( "dcm_parallel", "UnitCalibration"));}, unit => "mm"}, entry => { set => sub { Spectra::tng_attrDoubleWrt( "dcm_parallel", "UnitCalibration", $_[0])}}}; $Spc::res_h{ fmb_io3} = { label => { name => "CalPerp", get => sub { sprintf( "%g", Spectra::tng_attrDoubleRd( "dcm_perp", "UnitCalibration"));}, unit => "mm"}, entry => { set => sub { Spectra::tng_attrDoubleWrt( "dcm_perp", "UnitCalibration", $_[0])}}};

Figure 14.13: BLSC: FMB, P01

The ’Test’ button works as follows. A value is inserted in the fmbenergy entry widget. If ’Test’ is pressed, the target positions of the axes are displayed in the log window of the toplevel widget. Calibration: the FMB is calibrated by supplying a value to the fmbenergy entry widget, followed by an ’Options’ - ’Calibrate’ action. Calibrations change the axes offsets. Consider to take a note of the old offsets before a new calibration is done. The FMB uses 4 motors (3 axes and the fmbenery) that need to be defined in /online dir/online.xml:

... energyfmb type_tango motor_tango pXX/dcmener/oh.01 tango hasppXXoh1:10000

dcm_bragg type_tango motor_tango pXX/dcmmotor/oh.01 tango hasppXXoh1:10000

dcm_parallel type_tango motor_tango pXX/dcmmotor/oh.04 tango hasppXXoh1:10000

dcm_perp type_tango motor_tango pXX/dcmmotor/oh.03 tango hasppXXoh1:10000 ...

14.14 MAR-CCD

The following lines which are part of /online dir/TkIrc.pl create a widget to operate the MARCCD.

$Spc::res_h{ marccd_title} = { text => "MAR-CCD"};

$Spc::res_h{ "marccd_io1"} = { label => { name => "File"}, entry => { set => sub { Spectra::marccd_writefile( $_[0]);}}}; $Spc::res_h{ "marccd_io2"} = { label => { name => "Get_state", get => sub { Spectra::marccd_get_state()}}};

$Spc::res_h{ marccd_b1} = { name => "Start", command => sub { Spectra::marccd_start();}}; $Spc::res_h{ marccd_b2} = { name => "Readout", command => sub { Spectra::marccd_readout();}}; $Spc::res_h{ marccd_b3} = { name => "Readout_bg", command => sub { Spectra::marccd_readout_bg();}}; $Spc::res_h{ marccd_b4} = { name => "Readout_mr", command => sub { Spectra::marccd_readout_mr();}}; $Spc::res_h{ marccd_b5} = { name => "Correct", command => sub { Spectra::marccd_correct();}}; $Spc::res_h{ marccd_b6} = { name => "Open Shutter", command => sub { Spectra::marccd_open_shutter();}}; $Spc::res_h{ marccd_b7} = { name => "Close Shutter", command => sub { Spectra::marccd_close_shutter();}}; $Spc::res_h{ marccd_b8} = { name => "Abort", command => sub { Spectra::marccd_abort(); Spectra::marccd_close_shutter(); }};

14.15 Hexapod, Tango, P03

The following lines which are part of /online dir/TkIrc.pl create a widget to operate Hexapod attributes.

$Spc::res_h{ blsc} = "hexa1";

$Spc::res_h{ hexa1_title} = { text => "Hexa1"};

$Spc::res_h{ hexa1_help} = sub { Util::display_text( "Help Hexa1", ’ n.n. ’ )}; $Spc::res_h{ "hexa1_io1"} = { label => { name => "PivotR", get => sub { sprintf "%g", Spectra::tng_attrDoubleRd( "hexa1conf", "PositionPivotR");}}, entry => { set => sub { Spectra::tng_attrDoubleWrt( "hexa1conf", "PositionPivotR", $_[0])}}}; $Spc::res_h{ "hexa1_io2"} = { label => { name => "PivotS", get => sub { sprintf "%g", Spectra::tng_attrDoubleRd( "hexa1conf", "PositionPivotS");}}, entry => { set => sub { Spectra::tng_attrDoubleWrt( "hexa1conf", "PositionPivotS", $_[0])}}}; $Spc::res_h{ "hexa1_io3"} = { label => { name => "PivotT", get => sub { sprintf "%g", Spectra::tng_attrDoubleRd( "hexa1conf", "PositionPivotT");}}, entry => { set => sub { Spectra::tng_attrDoubleWrt( "hexa1conf", "PositionPivotT", $_[0])}}}; my $cnt = 4; foreach my $ax ( qw( X Y Z U V W K M)) { $Spc::res_h{ "hexa1_io${cnt}"} = { label => { name => "Conv${ax}", get => sub { sprintf "%g", Spectra::tng_attrDoubleRd( "hexa1_mot${ax}", "Conversion");}}, entry => { set => sub { Spectra::tng_attrDoubleWrt( "hexa1_mot${ax}", "Conversion", $_[0])}}}; $cnt++; }

Figure 14.14: BLSC: Hexapod, P03

14.16 Analyzer, Tango, P09

The following lines which are part of /online dir/TkIrc.pl create a widget to operate analyzer at P09.

$Spc::res_h{ blsc} = "analyzer"; # # analyzer Figure 14.15: BLSC: Analyzer, P09

# $Spc::res_h{ analyzer_title} = { text => "Analyzer"}; $Spc::res_h{ analyzer_help} = sub { Util::display_text( "Help Analyzer", ’ n.n. ’ )};

$Spc::res_h{ analyzer_io1} = { label => { name => "Dhkl", unit => "u", get => sub { sprintf( "%g", Spectra::tng_attrDoubleRd( "analyzer", "Dhkl"));}}, entry => { set => sub { Spectra::tng_attrDoubleWrt( "analyzer", "Dhkl", $_[0]);}}}; $Spc::res_h{ analyzer_io2} = { label => { name => "ThanaOffset", unit => "u", get => sub { sprintf( "%g", Spectra::tng_attrDoubleRd( "analyzer", "ThanaOffset"));}}, entry => { set => sub { Spectra::tng_attrDoubleWrt( "analyzer", "ThanaOffset", $_[0]);}}}; $Spc::res_h{ analyzer_io3} = { label => { name => "UnitLimitMin", unit => "u", get => sub { sprintf( "%g", Spectra::tng_attrDoubleRd( "analyzer", "UnitLimitMin"));}}, entry => { set => sub { Spectra::tng_attrDoubleWrt( "analyzer", "UnitLimitMin", $_[0]);}}}; $Spc::res_h{ analyzer_io4} = { label => { name => "UnitLimitMax", unit => "u", get => sub { sprintf( "%g", Spectra::tng_attrDoubleRd( "analyzer", "UnitLimitMax"));}}, entry => { set => sub { Spectra::tng_attrDoubleWrt( "analyzer", "UnitLimitMax", $_[0]);}}};

14.17 MultipleMotors, Tango, P09

The following lines which are part of /online dir/TkIrc.pl create a widget to operate the MotorMask of a MultipleMotor.

$Spc::res_h{ blsc} = "momu";

# # # # $Spc::res_h{ mumo_title} = { text => "MultipleMotors"}; Figure 14.16: BLSC: MultipleMotor, P09

$Spc::res_h{ mumo_help} = sub { Util::display_text( "Help MC", ’ Some Help text ’ )};

$Spc::res_h{ mumo_cmpnd} = { name => "mnchrmtr", unit => "eV"};

$Spc::res_h{ mumo_io1} = { label => { name => "Analyzer"}, checkbutton => { name => "Enable", set_on => sub { my $msk = Spectra::tng_attrLongRd( "mnchrmtr", "MotorMask"); $msk |= 1; Spectra::tng_attrLongWrt( "mnchrmtr", "MotorMask", $msk);}, set_off => sub { my $msk = Spectra::tng_attrLongRd( "mnchrmtr", "MotorMask"); $msk &= ˜1; Spectra::tng_attrLongWrt( "mnchrmtr", "MotorMask", $msk);}, get => sub { my $msk = Spectra::tng_attrLongRd( "mnchrmtr", "MotorMask"); if( $msk & 1) { return 1; } else { return 0; }}}}; $Spc::res_h{ mumo_io2} = { label => { name => "Undulator"}, checkbutton => { name => "Enable", set_on => sub { my $msk = Spectra::tng_attrLongRd( "mnchrmtr", "MotorMask"); $msk |= 2; Spectra::tng_attrLongWrt( "mnchrmtr", "MotorMask", $msk);}, set_off => sub { my $msk = Spectra::tng_attrLongRd( "mnchrmtr", "MotorMask"); $msk &= ˜2; Spectra::tng_attrLongWrt( "mnchrmtr", "MotorMask", $msk);}, get => sub { my $msk = Spectra::tng_attrLongRd( "mnchrmtr", "MotorMask"); if( $msk & 2) { return 1; } else { return 0; }}}}; # # the motors # $Spc::res_h{ mumo_m1} = { name => "EnergyFMB", unit => "eV"}; $Spc::res_h{ mumo_m2} = { name => "Analyzer", unit => "eV"}; $Spc::res_h{ mumo_m3} = { name => "Undulator", unit => "eV"};

14.18 Lenses Box, Tango, P10

The following lines which are part of /online dir/TkIrc.pl create a widget to inspect the status of the lenses box.

Figure 14.17: BLSC: Lenses Box, P10

$Spc::res_h{ blsc} = "lbio"; # # LensesBox status in/out # # $Spc::res_h{ lbio_title} = { text => "LensesBox In/Out"}; $Spc::res_h{ lbio_help} = sub { Util::display_text( "Help MC", ’ Lenses in/out ’ )}; foreach my $i ( 1 .. 5) { $Spc::res_h{ "lbio_io$i"} = { label => { name => "Motor $i ", get => sub { my $in = Spectra::tng_attrLongArrRd( "lensesbox", "EndSwitchIN", $i my $out = Spectra::tng_attrLongArrRd( "lensesbox", "EndSwitchOUT",

if( $in && !$out) { return "In"; } elsif ( $out && !$in) { return "Out"; } else { return "Unknown";

}}}}; }

14.19 LCX, P10

The following lines which are part of /online dir/TkIrc.pl create a widget to operate the LCX camera.

$Spc::res_h{ blsc} = "lcx"; $Spc::res_h{ lcx_title } = { text => "LCX Camera"};

$Spc::res_h{ lcx_io1 } = { label => { name => "FileDirectory", get => sub {Spectra::tng_attrStringRd( "lcx", "FileDir");}}, entry => { set => sub {Spectra::tng_attrStringWrt( "lcx", "FileDir", $_[0]);}}}; $Spc::res_h{ lcx_io2 } = { label => { name => "FilePrefix", get => sub {Spectra::tng_attrStringRd( "lcx", "FilePrefix");}}, entry => { set => sub {Spectra::tng_attrStringWrt( "lcx", "FilePrefix", $_[0]);}}}; $Spc::res_h{ lcx_io3 } = { label => { name => "FileStartNum", get => sub {Spectra::tng_attrLongRd( "lcx", "FileStartNum");}}, entry => { set => sub {Spectra::tng_attrLongWrt( "lcx", "FileStartNum", $_[0]);}}}; $Spc::res_h{ lcx_io4 } = { label => { name => "ExposureTime", get => sub {Spectra::tng_attrDoubleRd( "lcx", "ExposureTime");}}, entry => { set => sub {Spectra::tng_attrDoubleWrt( "lcx", "ExposureTime", $_[0]);}}}; $Spc::res_h{ lcx_io5 } = { label => { name => "NbFrames", get => sub {Spectra::tng_attrLongRd( "lcx", "NbFrames");}}, entry => { set => sub {Spectra::tng_attrLongWrt( "lcx", "NbFrames", $_[0]);}}}; $Spc::res_h{ lcx_io6 } = { label => { name => "State", get => sub {Spectra::tng_state( "lcx");}}}; $Spc::res_h{ lcx_io7 } = { label => { name => "Status", get => sub {Spectra::tng_status( "lcx");}}}; $Spc::res_h{ lcx_b1} = { name => "StartAcq", command => sub { while(Spectra::tng_state( "lcx") == 10) { Spectra::wait(0.1); } Spectra::tng_inout( "lcx", "StartAcquisition"); while(Spectra::tng_state( "lcx") == 10) { Spectra::wait(0.10); }}}; $Spc::res_h{ lcx_b2} = { name => "Reset", command => sub { Spectra::tng_inout( "lcx", "Reset");}}; Figure 14.18: BLSC: LCX Camera, P10

14.20 Photonic Science Camera, P03

The following lines which are part of /online dir/TkIrc.pl create a widget to operate the Photonic Science Camera.

$Spc::res_h{ blsc} = "pscamera";

$Spc::res_h{ pscamera_title } = { text => "Photonic Science Camera"};

$Spc::res_h{ pscamera_io1 } = { label => { name => "FileDirectory", get => sub {Spectra::tng_attrStringRd( "pscamera", "FileDirectory");}}, entry => { set => sub {Spectra::tng_attrStringWrt( "pscamera", "FileDirectory", $_[0]);}}}; $Spc::res_h{ pscamera_io2 } = { label => { name => "FilePrefix", get => sub {Spectra::tng_attrStringRd( "pscamera", "FilePrefix");}}, entry => { set => sub {Spectra::tng_attrStringWrt( "pscamera", "FilePrefix", $_[0]);}}}; $Spc::res_h{ pscamera_io3 } = { label => { name => "FileRefNumber", get => sub {Spectra::tng_attrStringRd( "pscamera", "FileRefNumber");}}, entry => { set => sub {Spectra::tng_attrStringWrt( "pscamera", "FileRefNumber", $_[0]);}}}; $Spc::res_h{ pscamera_io4 } = { label => { name => "SubAreaBottom", get => sub {Spectra::tng_attrLongRd( "pscamera", "SubAreaBottom");}}, entry => { set => sub {Spectra::tng_attrLongWrt( "pscamera", "SubareaBottom", $_[0]);}}}; $Spc::res_h{ pscamera_io5 } = { label => { name => "SubAreaLeft", get => sub {Spectra::tng_attrLongRd( "pscamera", "SubAreaLeft");}}, entry => { set => sub {Spectra::tng_attrLongWrt( "pscamera", "SubareaLeft", $_[0]);}}}; $Spc::res_h{ pscamera_io6 } = { label => { name => "SubAreaRight", get => sub {Spectra::tng_attrLongRd( "pscamera", "SubAreaRight");}}, entry => { set => sub {Spectra::tng_attrLongWrt( "pscamera", "SubareaRight", $_[0]);}}}; $Spc::res_h{ pscamera_io7 } = { label => { name => "SubAreaTop", get => sub {Spectra::tng_attrLongRd( "pscamera", "SubAreaTop");}}, entry => { set => sub {Spectra::tng_attrLongWrt( "pscamera", "SubareaTop", $_[0]);}}}; $Spc::res_h{ pscamera_io8 } = { label => { name => "XBinning", get => sub {Spectra::tng_attrLongRd( "pscamera", "XBinning");}}, entry => { set => sub {Spectra::tng_attrLongWrt( "pscamera", "XBinning", $_[0]);}}}; $Spc::res_h{ pscamera_io9 } = { label => { name => "YBinning", get => sub {Spectra::tng_attrLongRd( "pscamera", "YBinning");}}, entry => { set => sub {Spectra::tng_attrLongWrt( "pscamera", "YBinning", $_[0]);}}}; Figure 14.19: BLSC: Photonic Science Camera, P03

14.21 VFCADC, gain, offset and polarity

The following lines which are part of /online dir/TkIrc.pl create a widget to change the gain and the offset of VF- CADCs.

$Spc::res_h{ blsc} = "vfc"; # # # $Spc::res_h{ vfc_title} = { text => "VFC"};

$Spc::res_h{ vfc_help} = sub { Util::display_text( "Help VFC", ’ n.n. ’ )}; my $i = 1; for my $j ( 1 .. 8) { my $vfc = "VFC$j"; $Spc::res_h{ "VFC_io$i"} = { label => { name => "${vfc} Gain", get => sub { sprintf "%g", Spectra::get_adc_gain( $vfc);}}, entry => { set => sub { Spectra::set_adc_gain( $vfc, $_[0]);}}}; $i++; $Spc::res_h{ "VFC_io$i"} = { label => { name => "${vfc} Offset", get => sub { sprintf "%g", Spectra::get_adc_offset( $vfc);}}, entry => { set => sub { Spectra::set_adc_offset( $vfc, $_[0]);}}}; $i++; $Spc::res_h{ "VFC_io$i"} = { label => { name => "${vfc} Polarity", get => sub { sprintf "%g", Spectra::get_adc_polarity( $vfc);}}, entry => { set => sub { Spectra::set_adc_polarity( $vfc, $_[0]);}}}; $i++; }

14.22 Perkin Elmer Detector

The following lines, which a part of /online dir/TkIrc.pl, create a widget to operate the Perkin ELmer detector:

$Spc::res_h{ blsc} = "pe"; $Spc::res_h{ pe_help} = sub { Util::display_text( "Help Perkin Elmer", ’ SummedSavedImages set by perkinElmer_start(), is a function of sampleTime (scan parameter), ExposureTime and FilesAfterTrigger

ExposureTime used by perkinElmer_start() to calculate ExposureTime

FilesAfterTrigger used by perkinElmer_start() to calculate ExposureTime eval [Spectra::perkinElmer_singleShot( "pe_detector", "fname", 1, 2)] executes a PE sequence. The SampleTime is 1s, the image index is 2.

sets the attribute SummedSavedImages

SummedSavedImages = ceil(sampleTime/ExposureTime/FilesAfterTrigger)

executes the command AcquireSubtractedImagesAndSave

’ )};

$Spc::res_h{ pe_title } = { text => "Perkin Elmer Detector"};

$Spc::res_h{ pe_io1 } = { label => { name => "OutputDirectory", get => sub {Spectra::tng_attrStringRd( "pe_detector", "OutputDirectory");}}, entry => { set => sub {Spectra::tng_attrStringWrt( "pe_detector", "OutputDirectory", $_[0]);}}}; $Spc::res_h{ pe_io2 } = { label => { name => "FilePattern", get => sub {Spectra::tng_attrStringRd( "pe_detector", "FilePattern");}}, entry => { set => sub {Spectra::tng_attrStringWrt( "pe_detector", "FilePattern", $_[0]);}}}; $Spc::res_h{ pe_io3 } = { label => { name => "FileIndex", get => sub {Spectra::tng_attrLongRd( "pe_detector", "FileIndex");}}, entry => { set => sub {Spectra::tng_attrLongWrt( "pe_detector", "FileIndex", $_[0]);}}}; $Spc::res_h{ pe_io4 } = { label => { name => "SummedDarkImages", get => sub {Spectra::tng_attrLongRd( "pe_detector", "SummedDarkImages");}}, entry => { set => sub {Spectra::tng_attrLongWrt( "pe_detector", "SummedDarkImages", $_[0]);}}}; $Spc::res_h{ pe_io5 } = { label => { name => "SummedSavedImages", get => sub {Spectra::tng_attrLongRd( "pe_detector", "SummedSaveImages");}}, entry => { set => sub {Spectra::tng_attrLongWrt( "pe_detector", "SummedSaveImages", $_[0]);}}}; $Spc::res_h{ pe_io6 } = { label => { name => "BinningMode", get => sub {Spectra::tng_attrLongRd( "pe_detector", "BinningMode");}}, entry => { set => sub {Spectra::tng_attrLongWrt( "pe_detector", "BinningMode", $_[0]);}}}; $Spc::res_h{ pe_io7 } = { label => { name => "CameraGain", get => sub {Spectra::tng_attrFloatRd( "pe_detector", "CameraGain");}}, entry => { set => sub {Spectra::tng_attrFloatWrt( "pe_detector", "CameraGain", $_[0]);}}}; $Spc::res_h{ pe_io8 } = { label => { name => "ExposureTime", get => sub { sprintf( "%g", Spectra::tng_attrFloatRd( "pe_detector", "ExposureTime"));}}, entry => { set => sub {Spectra::tng_attrFloatWrt( "pe_detector", "ExposureTime", $_[0]);}}}; $Spc::res_h{ pe_io9 } = { label => { name => "FilesBeforeTrigger", get => sub {Spectra::tng_attrLongRd( "pe_detector", "FilesBeforeTrigger");}}, entry => { set => sub {Spectra::tng_attrLongWrt( "pe_detector", "FilesBeforeTrigger", $_[0]);}}}; $Spc::res_h{ pe_io10 } = { label => { name => "FilesAfterTrigger", get => sub {Spectra::tng_attrLongRd( "pe_detector", "FilesAfterTrigger");}}, entry => { set => sub {Spectra::tng_attrLongWrt( "pe_detector", "FilesAfterTrigger", $_[0]);}}}; $Spc::res_h{ pe_io11 } = { label => { name => "State", get => sub {Spectra::tng_state( "pe_detector");}}}; $Spc::res_h{ pe_b1} = { name => "AcqDark", command => sub { Spectra::tng_inout( "pe_detector", "AcquireDarkImages");}}; $Spc::res_h{ pe_b2} = { name => "AcqDarkSave", command => sub { Spectra::tng_inout( "pe_detector", "AcquireDarkImagesAndSave");}}; $Spc::res_h{ pe_b3} = { name => "AcqRaw", command => sub { Spectra::tng_inout( "pe_detector", "AcquireRawImages");}}; $Spc::res_h{ pe_b4} = { name => "AcqRawSave", command => sub { Spectra::tng_inout( "pe_detector", "AcquireRawImagesAndSave");}}; $Spc::res_h{ pe_b5} = { name => "AcqSub", command => sub { Spectra::tng_inout( "pe_detector", "AcquireSubtractedImages");}}; $Spc::res_h{ pe_b6} = { name => "AcqSubSave", command => sub { Spectra::tng_inout( "pe_detector", "AcquireSubtractedImagesAndSave");}}; $Spc::res_h{ pe_b7} = { name => "UpdRdOutSttngs", command => sub { Spectra::tng_inout( "pe_detector", "UpdateReadoutSettings");}}; $Spc::res_h{ pe_b8} = { name => "OSH", command => sub { Util::log( "open the shutter");}}; $Spc::res_h{ pe_b9} = { name => "CSH", command => sub { Util::log( "close the shutter");}}; $Spc::res_h{ pe_b10} = { name => "Measure", command => sub { Util::log( "This is a measurment sequence");}};

Figure 14.20: BLSC: Perkin Elmer Detector, P02 14.23 Prosilica Camera

$Spc::res_h{ blsc} = "prosilica";

$Spc::res_h{ prosilica_title } = { text => "Prosilica Camera"}; $Spc::res_h{ prosilica_help} = sub { Util::display_text( "Help Prosilica", ’ n.n. ’ )}; $Spc::res_h{ prosilica_io1 } = { label => { name => "FileDir", get => sub {Spectra::tng_attrStringRd( "prosilica", "FileDir");}}, entry => { set => sub {Spectra::tng_attrStringWrt( "prosilica", "FileDir", $_[0]);}}}; $Spc::res_h{ prosilica_io2 } = { label => { name => "FilePrefix", get => sub {Spectra::tng_attrStringRd( "prosilica", "FilePrefix");}}, entry => { set => sub {Spectra::tng_attrStringWrt( "prosilica", "FilePrefix", $_[0]);}}}; $Spc::res_h{ prosilica_io3 } = { label => { name => "FilePostfix", get => sub {Spectra::tng_attrStringRd( "prosilica", "FilePostfix");}}, entry => { set => sub {Spectra::tng_attrStringWrt( "prosilica", "FilePostfix", $_[0]);}}}; $Spc::res_h{ prosilica_io4 } = { label => { name => "FileStartNum", get => sub {Spectra::tng_attrLongRd( "prosilica", "FileStartNum");}}, entry => { set => sub {Spectra::tng_attrLongWrt( "prosilica", "FileStartNum", $_[0]);}}}; $Spc::res_h{ prosilica_io4 } = { label => { name => "AcquisitionMode", get => sub {Spectra::tng_attrLongRd( "prosilica", "AcquisitionMode");}}, entry => { set => sub {Spectra::tng_attrLongWrt( "prosilica", "AcquisitionMode", $_[0]);}}}; $Spc::res_h{ prosilica_io4 } = { label => { name => "Exposure", get => sub {Spectra::tng_attrLongRd( "prosilica", "Exposure");}}, entry => { set => sub {Spectra::tng_attrLongWrt( "prosilica", "Exposure", $_[0]);}}}; $Spc::res_h{ prosilica_io5 } = { label => { name => "BinningX", get => sub {Spectra::tng_attrLongRd( "prosilica", "BinningX");}}, entry => { set => sub {Spectra::tng_attrLongWrt( "prosilica", "BinningX", $_[0]);}}}; $Spc::res_h{ prosilica_io6 } = { label => { name => "BinningY", get => sub {Spectra::tng_attrLongRd( "prosilica", "BinningY");}}, entry => { set => sub {Spectra::tng_attrLongWrt( "prosilica ", "BinningY", $_[0]);}}}; $Spc::res_h{ prosilica_io7 } = { label => { name => "State", get => sub {Spectra::tng_state( "prosilica");}}}; $Spc::res_h{ prosilica_b1} = { name => "Start", command => sub { while(Spectra::tng_state( "Prosilica") != 0) { Spectra::wait(0.1); } Spectra::tng_inout( "Prosilica", "StartAcquisition");}}; $Spc::res_h{ prosilica_b2} = { name => "Stop", command => sub {Spectra::tng_inout( "Prosilica", "StopAcquisition");}}; $Spc::res_h{ prosilica_b3} = { name => "Cleanup", command => sub {Spectra::tng_inout( "Prosilica", "CleanupCamera");}}; $Spc::res_h{ prosilica_b4} = { name => "Init", command => sub {Spectra::tng_inout( "Prosilica", "InitCamera");}};

14.24 Mythen Detector

$Spc::res_h{ blsc} = "mythen";

$Spc::res_h{ mythen_title } = { text => "Mythen Detector"}; $Spc::res_h{ mythen_help} = sub { Util::display_text( "Help Mythen", ’ n.n. ’ )}; $Spc::res_h{ mythen_io1 } = { label => { name => "OutDir", get => sub {Spectra::tng_attrStringRd( "mythen", "OutDir");}}, entry => { set => sub {Spectra::tng_attrStringWrt( "mythen", "OutDir", $_[0]);}}}; $Spc::res_h{ mythen_io2 } = { label => { name => "Threshold", get => sub {Spectra::tng_attrShortRd( "mythen", "Threshold");}}, entry => { set => sub {Spectra::tng_attrShortWrt( "mythen", $Spc::res_h{ mythen_io3 } = { label => { name => "Setting", get => sub {Spectra::tng_attrShortRd( "mythen", "Settings");}}, entry => { set => sub {Spectra::tng_attrShortWrt( "mythen", $Spc::res_h{ mythen_io4 } = { label => { name => "NCycles", get => sub {Spectra::tng_attrShortRd( "mythen", "NCycles");}}, entry => { set => sub {Spectra::tng_attrShortWrt( "mythen", $Spc::res_h{ mythen_io5 } = { label => { name => "FramesPerCycle", get => sub {Spectra::tng_attrShortRd( "mythen", "FramesPerCycle");}}, entry => { set => sub {Spectra::tng_attrShortWrt( "mythen", $Spc::res_h{ mythen_io6 } = { label => { name => "ExposureTime", get => sub {Spectra::tng_attrFloatRd( "mythen", "ExposureTime");}}, entry => { set => sub {Spectra::tng_attrFloatWrt( "mythen",

$Spc::res_h{ mythen_b1} = { name => "Start", command => sub { while(Spectra::tng_state( "mythen") != 0) { Spectra::wait(0.1); } Spectra::tng_inout( "mythen", "StartAcquisition");}}; $Spc::res_h{ mythen_b2} = { name => "Stop", command => sub {Spectra::tng_inout( "mythen", "StopAcquisition");}}; $Spc::res_h{ mythen_b3} = { name => "Init", command => sub {Spectra::tng_inout( "mythen", "Init");}};

Figure 14.21: BLSC: Mythen 14.25 TwoThetaP07

$Spc::res_h{ blsc} = "tth"; # # If an isAlive function is defined, it is called. If it # returns 0, the widget is not opened. # $Spc::res_h{ tth_isalive} = sub { return Spectra::tng_isAlive( "tth");};

$Spc::res_h{ tth_cmpnd} = { name => "tth", unit => "Deg."};

$Spc::res_h{ tth_help} = sub { Util::display_text( "Help Mythen", ’ UseAnalyzer 0 - neither the collimator nor the analyzer are rotated

EFromAttribute 0 - energy from the Energy attribute 1 - energy from the Position attribute of the AxisMonochromator (this is a ) ’ )};

# # the motors # $Spc::res_h{ tth_m1} = { name => "RDT", unit => "Deg"}; $Spc::res_h{ tth_m2} = { name => "XDT", unit => "mm"}; $Spc::res_h{ tth_m3} = { name => "RCOLL", unit => "Deg"}; $Spc::res_h{ tth_m4} = { name => "OMAN", unit => "Deg"}; $Spc::res_h{ tth_m5} = { name => "YDT", unit => "mm"};

$Spc::res_h{ tth_io1 } = { label => { name => "tthMin", get => sub {Spectra::tng_attrDoubleRd( "tth", "UnitLimitMin");}}, entry => { set => sub {Spectra::tng_attrDoubleWrt( "tth", "UnitLimitMin", $_[0]);}}};

$Spc::res_h{ tth_io2 } = { label => { name => "tthMax", get => sub {Spectra::tng_attrDoubleRd( "tth", "UnitLimitMax");}}, entry => { set => sub {Spectra::tng_attrDoubleWrt( "tth", "UnitLimitMax", $_[0]);}}}; $Spc::res_h{ tth_io3 } = { label => { name => "UseAnalyzer", get => sub {Spectra::tng_attrLongRd( "tth", "FlagUseAnalyzer");}}, entry => { set => sub {Spectra::tng_attrLongWrt( "tth", "FlagUseAnalyzer", $_[0]);}}}; $Spc::res_h{ tth_io4 } = { label => { name => "EFromAttribute", get => sub {Spectra::tng_attrLongRd( "tth", "FlagEnergyFromAttribute");}}, entry => { set => sub {Spectra::tng_attrLongWrt( "tth", "FlagEnergyFromAttribute", $_[0]);}}};

14.26 PCO4000 Detector

This section displays the beamline spefici code for the PCO4000 and the resulting widget. $Spc::res_h{ blsc} = "pco4000"; $Spc::res_h{ pco4000_title} = { text => "PCO4000"};

$Spc::res_h{ "pco4000_io1"} = { label => { name => "ExposureTime [s]", get => sub { Spectra::tng_attrDoubleRd( "pco4000", "ExposureTime");}, unit => ""}, entry => { set => sub { while(Spectra::tng_state( "pco4000") == 10) # Wait Pco4000 to Figure 14.22: BLSC: TwoThetaP07

{ Spectra::wait(0.1); } Spectra::tng_state( "pco4000"); Spectra::tng_attrDoubleWrt( "pco4000", "ExposureTime", $_[0]);}}}; $Spc::res_h{ "pco4000_io2"} = { label => { name => "FilePrefix", get => sub { my $ret = Spectra::tng_attrStringRd( "pco4000", "FilePrefix"); return $ret;}, unit => ""}, entry => { set => sub { while(Spectra::tng_state( "pco4000") == 10) # Wait Pco4000 to { Spectra::wait(0.1); } Spectra::tng_state( "pco4000"); Spectra::tng_attrStringWrt( "pco4000", "FilePrefix", $_[0]);}}}; $Spc::res_h{ "pco4000_io3"} = { label => { name => "FilePostfix", get => sub { my $ret = Spectra::tng_attrStringRd( "pco4000", "FilePostfix"); return $ret;}, unit => ""}, entry => { set => sub { while(Spectra::tng_state( "pco4000") == 10) # Wait Pco4000 to { Spectra::wait(0.1); } Spectra::tng_state( "pco4000"); Spectra::tng_attrStringWrt( "pco4000", "FilePostfix",$_[0] );}}}; $Spc::res_h{ "pco4000_io4"} = { label => { name => "FileStartNum", get => sub { my $ret = Spectra::tng_attrLongRd( "pco4000", "FileStartNum"); return $ret;}, unit => ""}, entry => { set => sub { while(Spectra::tng_state( "pco4000") == 10) # Wait Pco4000 to { Spectra::wait(0.1); } Spectra::tng_state( "pco4000"); Spectra::tng_attrLongWrt( "pco4000", "FileStartNum", $_[0]);}}}; $Spc::res_h{ "pco4000_io5"} = { label => { name => "State", get => sub { my $ret = Spectra::tng_state( "pco4000");}}};

$Spc::res_h{ "pco4000_io6"} = { label => { name => "TriggerMode", get => sub { Spectra::tng_attrShortRd( "pco4000", "Triggermode");}, unit => ""}, entry => { set => sub { while(Spectra::tng_state( "pco4000") == 10) # Wait Pco4000 to { Spectra::wait(0.1); } Spectra::tng_state( "pco4000"); Spectra::tng_attrShortWrt( "pco4000", "Triggermode", $_[0]);}}}; $Spc::res_h{ "pco4000_io7"} = { label => { name => "FileDir", width => 30, get => sub { Spectra::tng_state( "pco4000"); Spectra::tng_attrStringRd( "pco4000", "FileDir");}, unit => ""}, entry => { set => sub { while(Spectra::tng_state( "pco4000") == 10) # Wait Pco4000 to { Spectra::wait(0.1); } Spectra::tng_state( "pco4000"); Spectra::tng_attrStringWrt( "pco4000", "FileDir", $_[0]);}}}; $Spc::res_h{ "pco4000_io8"} = { label => { name => "FileSaving", get => sub { Spectra::tng_state( "pco4000"); Spectra::tng_attrBoolRd( "pco4000", "FileSaving");}, unit => ""}, entry => { set => sub { while(Spectra::tng_state( "pco4000") == 10) # Wait Pco4000 to { Spectra::wait(0.1); } Spectra::tng_state( "pco4000"); Spectra::tng_attrBoolWrt( "pco4000", "FileSaving", $_[0]);}}}; $Spc::res_h{ "pco4000_io9"} = { label => { name => "Binning_x", get => sub { my $ret = Spectra::tng_attrShortRd( "pco4000", "Binning_x"); return $ret;}, unit => ""}, entry => { set => sub { while(Spectra::tng_state( "pco4000") == 10) # Wait Pco4000 to { Spectra::wait(0.1); } Spectra::tng_state( "pco4000"); Spectra::tng_attrShortWrt( "pco4000", "Binning_x", $_[0]);}}}; $Spc::res_h{ "pco4000_io10"} = { label => { name => "Binning_y", get => sub { my $ret = Spectra::tng_attrShortRd( "pco4000", "Binning_y"); return $ret;}, unit => ""}, entry => { set => sub { while(Spectra::tng_state( "pco4000") == 10) # Wait Pco4000 to { Spectra::wait(0.1); } Spectra::tng_state( "pco4000"); Spectra::tng_attrShortWrt( "pco4000", "Binning_y", $_[0]);}}}; $Spc::res_h{ "pco4000_io11"} = { label => { name => "ADCs", get => sub { my $ret = Spectra::tng_attrShortRd( "pco4000", "ADCs"); return $ret;}, unit => ""}, entry => { set => sub { while(Spectra::tng_state( "pco4000") == 10) # Wait Pco4000 to { Spectra::wait(0.1); } Spectra::tng_state( "pco4000"); Spectra::tng_attrShortWrt( "pco4000", "ADCs", $_[0]);}}};

$Spc::res_h{ pco4000_b1} = { name => "Start", #Wait for pco4000 to stop before starting command => sub { while(Spectra::tng_state( "pco4000") == 10) { Spectra::wait(0.1); } Spectra::tng_inout( "pco4000", "StartStandardAcq");}}; $Spc::res_h{ pco4000_b2} = { name => "Stop", command => sub { Spectra::tng_inout( "pco4000", "StopAcq");}}; $Spc::res_h{ pco4000_b3} = { name => "Reset", command => sub { Spectra::tng_inout( "pco4000", "Reset");}}; $Spc::res_h{ pco4000_b4} = { name => "Live", command => sub { Spectra::tng_inout( "pco4000", "Live");}};

Figure 14.23: BLSC: Pco4000

14.27 Roper QuadRO

This section displays the beamline specific code for the Roper QuadRO and the resulting widget.

$Spc::res_h{ blsc} = "roper"; # # Start of Roper package # # title $Spc::res_h{ roper_title} = { text => "Roper"}; $Spc::res_h{ roper_help} = sub { Util::display_text( "Help MC", ’ Some Help text’) };

# io1 $Spc::res_h{ "roper_io1"} = { label => { name => "ExposureTime [s]", get => sub { Spectra::tng_attrDoubleRd( "roper", "ExposureTime");}, unit => ""}, entry => { set => sub { while(Spectra::tng_state( "roper") == 10) # Wait Roper to finish { Spectra::wait(0.1); } Spectra::tng_state( "roper"); Spectra::tng_attrDoubleWrt( "roper", "ExposureTime", $_[0]);}}};

# io2 $Spc::res_h{ "roper_io2"} = { label => { name => "NbFrames", get => sub { Spectra::tng_attrLongRd( "roper", "NbFrames");}, #}}; unit => ""}, entry => { set => sub { while(Spectra::tng_state( "roper") == 10) # Wait Roper to finish { Spectra::wait(0.1); } Spectra::tng_state( "roper"); Spectra::tng_attrLongWrt( "roper", "NbFrames", $_[0]);}}};

# io3 $Spc::res_h{ "roper_io3"} = { label => { name => "FilePrefix", get => sub { my $ret = Spectra::tng_attrStringRd( "roper", "FilePrefix"); # $ret =˜ s/ˆ\s*(.*?)\s*$/$1/; return $ret;}, unit => ""}, entry => { set => sub { while(Spectra::tng_state( "roper") == 10) # Wait Roper to finish { Spectra::wait(0.1); } Spectra::tng_state( "roper"); Spectra::tng_attrStringWrt( "roper", "FilePrefix", $_[0]);}}};

# io4 $Spc::res_h{ "roper_io4"} = { label => { name => "FileStartNum", get => sub { my $ret = Spectra::tng_attrLongRd( "roper", "FileStartNum"); return $ret;}, unit => ""}, entry => { set => sub { while(Spectra::tng_state( "roper") == 10) # Wait Roper to finish { Spectra::wait(0.10); } Spectra::tng_state( "roper"); Spectra::tng_attrLongWrt( "roper","FileStartNum", $_[0]);}}};

# io5 $Spc::res_h{ "roper_io5"} = { label => { name => "Gain (1/2/3)", get => sub { Spectra::tng_attrLongRd( "roper", "Gain");}, unit => ""}, entry => { set => sub { while(Spectra::tng_state( "roper") == 10) # Wait Roper to finish { Spectra::wait(0.1); } Spectra::tng_state( "roper"); Spectra::tng_attrLongWrt( "roper", "Gain", $_[0]);}}};

# io6 $Spc::res_h{ "roper_io6"} = { label => { name => "Temperature", get => sub { Spectra::tng_attrFloatRd( "roper", "Temperature");}, unit => ""}}; # io7 $Spc::res_h{ "roper_io7"} = { label => { name => "ImageCounter", get => sub { my $ret = Spectra::tng_attrLongRd( "roper", "ImageCounter"); return $ret;}, unit => ""}};

# io8 $Spc::res_h{ "roper_io8"} = { label => { name => "FileDir", width => 40, get => sub { Spectra::tng_state( "roper"); Spectra::tng_attrStringRd( "roper", "FileDir"); }, unit => ""}, entry => { set => sub { while(Spectra::tng_state( "roper") == 10) # Wait Roper to finish { Spectra::wait(0.10); } Spectra::tng_state( "roper"); Spectra::tng_attrStringWrt( "roper", "FileDir", $_[0]);}}}; # io9 $Spc::res_h{ "roper_io9"} = { label => { name => "UseFullFrame [0/1]", get => sub { my $ret = Spectra::tng_attrLongRd( "roper", "UseFullFrame"); return $ret;}, unit => ""}, entry => { set => sub { while(Spectra::tng_state( "roper") == 10) # Wait Roper to finish { Spectra::wait(0.10); } Spectra::tng_state( "roper"); Spectra::tng_attrLongWrt( "roper","UseFullFrame", $_[0]);}}};

# io10 $Spc::res_h{ "roper_io10"} = { label => { name => "ROIStartParallelDir [UFF == 1, 1-4096]", get => sub { my $ret = Spectra::tng_attrUShortRd( "roper", "ROIp1"); return $ret;}, unit => ""}, entry => { set => sub { while(Spectra::tng_state( "roper") == 10) # Wait Roper to finish { Spectra::wait(0.10); } Spectra::tng_state( "roper"); Spectra::tng_attrUShortWrt( "roper","ROIp1", $_[0]);}}}; # io11 $Spc::res_h{ "roper_io11"} = { label => { name => "ROIEndParallelDir [UFF == 1, 1-4096]", get => sub { my $ret = Spectra::tng_attrUShortRd( "roper", "ROIp2"); return $ret;}, unit => ""}, entry => { set => sub { while(Spectra::tng_state( "roper") == 10) # Wait Roper to finish { Spectra::wait(0.10); } Spectra::tng_state( "roper"); Spectra::tng_attrUShortWrt( "roper","ROIp2", $_[0]);}}};

# io12 $Spc::res_h{ "roper_io12"} = { label => { name => "ROIParallelDirBin [UFF == 1]", get => sub { my $ret = Spectra::tng_attrUShortRd( "roper", "ROIpbin"); return $ret;}, unit => ""}, entry => { set => sub { while(Spectra::tng_state( "roper") == 10) # Wait Roper to finish { Spectra::wait(0.10); } Spectra::tng_state( "roper"); Spectra::tng_attrUShortWrt( "roper","ROIpbin", $_[0]);}}};

# io13 $Spc::res_h{ "roper_io13"} = { label => { name => "ROIStartSerialDir [UFF == 1, 1-4096]", get => sub { my $ret = Spectra::tng_attrUShortRd( "roper", "ROIs1"); return $ret;}, unit => ""}, entry => { set => sub { while(Spectra::tng_state( "roper") == 10) # Wait Roper to finish { Spectra::wait(0.10); } Spectra::tng_state( "roper"); Spectra::tng_attrUShortWrt( "roper","ROIs1", $_[0]);}}}; # io14 $Spc::res_h{ "roper_io14"} = { label => { name => "ROIEndSerialDir [UFF == 1, 1-4096]", get => sub { my $ret = Spectra::tng_attrUShortRd( "roper", "ROIs2"); return $ret;}, unit => ""}, entry => { set => sub { while(Spectra::tng_state( "roper") == 10) # Wait Roper to finish { Spectra::wait(0.10); } Spectra::tng_state( "roper"); Spectra::tng_attrUShortWrt( "roper","ROIs2", $_[0]);}}};

# io15 $Spc::res_h{ "roper_io15"} = { label => { name => "ROISerialDirBin [UFF == 1]", get => sub { my $ret = Spectra::tng_attrUShortRd( "roper", "ROIsbin"); return $ret;}, unit => ""}, entry => { set => sub { while(Spectra::tng_state( "roper") == 10) # Wait Roper to finish { Spectra::wait(0.10); } Spectra::tng_state( "roper"); Spectra::tng_attrUShortWrt( "roper","ROIsbin", $_[0]);}}};

# # Define Roper functionality buttons (’Start’ & ’Transfer’) # $Spc::res_h{ roper_b1} = { name => "Start", #Wait for roper to stop before starting command => sub { while(Spectra::tng_state( "roper") == 10) { Spectra::wait(0.1); } Gra_command("roperon"); Gra_command("osh"); Spectra::wait(0.05); Spectra::tng_inout( "roper", "StartStandardAcq"); while(Spectra::tng_state( "roper") == 10) { Spectra::wait(0.10); } Gra_command("csh"); Gra_command("roperoff"); }}; # # End of Roper #

Figure 14.24: BLSC: Roper QuadRO 14.28 MarCCD

This section displays the beamline specific code for the MarCCD.

$Spc::res_h{ blsc} = "marccd"; ######################## ### MarCCD widget ######################## $Spc::res_h{ marccd_title} = { text => "MarCCD"};

$Spc::res_h{ "marccd_io1"} = { label => { name => "SavingDirectory", get => sub { Spectra::tng_attrStringRd( "marccd", "SavingDirectory");}, unit => ""}, entry => { set => sub { Spectra::tng_attrStringWrt( "marccd", "SavingDirectory", $_[0]);}}}; $Spc::res_h{ "marccd_io2"} = { label => { name => "SavingPrefix", get => sub { Spectra::tng_attrStringRd( "marccd", "SavingPrefix");}, unit => ""}, entry => { set => sub { Spectra::tng_attrStringWrt( "marccd", "SavingPrefix", $_[0]);}}}; $Spc::res_h{ "marccd_io3"} = { label => { name => "SavingPostfix", get => sub { Spectra::tng_attrStringRd( "marccd", "SavingPostfix");}, unit => ""}, entry => { set => sub { Spectra::tng_attrStringWrt( "marccd", "SavingPostfix", $_[0]);}}}; $Spc::res_h{ "marccd_io4"} = { label => { name => "BinXandY", get => sub { Spectra::tng_attrLongRd( "marccd", "BinXandY");}, unit => ""}, entry => { set => sub { Spectra::tng_attrLongWrt( "marccd", "BinXandY", $_[0]);}}}; $Spc::res_h{ "marccd_io5"} = { label => { name => "FrameShift", get => sub { Spectra::tng_attrLongRd( "marccd", "FrameShift");}, unit => ""}, entry => { set => sub { Spectra::tng_attrLongWrt( "marccd", "FrameShift", $_[0]);}}}; $Spc::res_h{ "marccd_io6"} = { label => { name => "SizeX", get => sub { Spectra::tng_attrLongRd( "marccd", "SizeX");}, unit => ""}, entry => { set => sub { Spectra::tng_attrLongWrt( "marccd", "SizeX", $_[0]);}}}; $Spc::res_h{ "marccd_io7"} = { label => { name => "SizeY", get => sub { Spectra::tng_attrLongRd( "marccd", "SizeY");}, unit => ""}, entry => { set => sub { Spectra::tng_attrLongWrt( "marccd", "SizeY", $_[0]);}}}; $Spc::res_h{ marccd_b1} = { name => "StartExposing", command => sub { Spectra::tng_inout( "marccd", "StartExposing");}}; $Spc::res_h{ marccd_b2} = { name => "StopExposing", command => sub { Spectra::tng_inout( "marccd", "StopExposing");}};

14.29 PiezoPiE712

This section displays the beamline specific code for the PiezoPiE712.

# # E712 code # Figure 14.25: BLSC: MarCCD

$Spc::res_h{ e712_title } = { text => "E712 Detector"}; $Spc::res_h{ e712_help} = sub { Util::display_text( "Help E712", ’

WAV axis X LIN SegLength Ampl Offset WaveLength StartPoint SpeedUpDown

SegLength the length of the wave table segment in points, def. 5000

Amp the amplitude of the scan line, e.g. 100 move from the current position relative +100

Offset the offset of the scan line, e.g. 0

Wavelength the length of the single scan line curve in points, e.g. 4980

StartPoint the index of the starting point of the scan line in the segment, e.g. 0

SpeedUpDown the number of points for speed-up or low-down, e.g. 10

TableRate the duration of the output, e.g. 10

OutputCycles 1

WOS wave generator output offset, reflects the position

Position Move using waveform, if distance > 2 PositionRaw Move by command, not by WF ’ )};

$Spc::res_h{ e712_io1 } = { label => { name => "SegLength", get => sub {Spectra::tng_attrLongRd( "mi_pi1", "WaveSegmentLength");}}, entry => { set => sub {Spectra::tng_attrLongWrt( "mi_pi1", "WaveSegmentLength", $_[0]);}}}; $Spc::res_h{ e712_io2 } = { label => { name => "Amp", get => sub {Spectra::tng_attrLongRd( "mi_pi1", "WaveAmplitude");}}, entry => { set => sub {Spectra::tng_attrLongWrt( "mi_pi1", "WaveAmplitude", $_[0]);}}}; $Spc::res_h{ e712_io3 } = { label => { name => "Offset", get => sub {Spectra::tng_attrLongRd( "mi_pi1", "WaveOffset");}}, entry => { set => sub {Spectra::tng_attrLongWrt( "mi_pi1", "WaveOffset", $_[0]);}}}; $Spc::res_h{ e712_io4 } = { label => { name => "WaveLength", get => sub {Spectra::tng_attrLongRd( "mi_pi1", "WaveWaveLength");}}, entry => { set => sub {Spectra::tng_attrLongWrt( "mi_pi1", "WaveWaveLength", $_[0]);}}}; $Spc::res_h{ e712_io5 } = { label => { name => "StartPoint", get => sub {Spectra::tng_attrLongRd( "mi_pi1", "WaveStartPoint");}}, entry => { set => sub {Spectra::tng_attrLongWrt( "mi_pi1", "WaveStartPoint", $_[0]);}}}; $Spc::res_h{ e712_io6 } = { label => { name => "SpeedUpDown", get => sub {Spectra::tng_attrLongRd( "mi_pi1", "WaveSpeedUpDown");}}, entry => { set => sub {Spectra::tng_attrLongWrt( "mi_pi1", "WaveSpeedUpDown", $_[0]);}}}; $Spc::res_h{ e712_io7 } = { label => { name => "TableRate", get => sub {Spectra::tng_attrLongRd( "mi_pi1", "WaveTableRate");}}, entry => { set => sub {Spectra::tng_attrLongWrt( "mi_pi1", "WaveTableRate", $_[0]);}}}; $Spc::res_h{ e712_io8 } = { label => { name => "OutputCycles", get => sub {Spectra::tng_attrLongRd( "mi_pi1", "WaveOutputCycles");}}, entry => { set => sub {Spectra::tng_attrLongWrt( "mi_pi1", "WaveOutputCycles", $_[0]);}}}; $Spc::res_h{ e712_io9 } = { label => { name => "WOS", get => sub {Spectra::tng_attrDoubleRd( "mi_pi1", "WOS");}}, entry => { set => sub {Spectra::tng_attrDoubleWrt( "mi_pi1", "WOS", $_[0]);}}}; $Spc::res_h{ e712_io10 } = { label => { name => "ServoUpdateRate", get => sub {Spectra::tng_attrDoubleRd( "mi_pi1", "ServoUpdateRate");}}}; $Spc::res_h{ e712_io11 } = { label => { name => "State", get => sub {Spectra::tng_state( "mi_pi1");}}}; $Spc::res_h{ e712_io12 } = { label => { name => "Position (WF)", get => sub {Spectra::tng_attrDoubleRd( "mi_pi1", "Position");}}, entry => { set => sub {Spectra::tng_attrDoubleWrt( "mi_pi1", "Position", $_[0]);}}}; $Spc::res_h{ e712_io13 } = { label => { name => "PositionRaw", get => sub {Spectra::tng_attrDoubleRd( "mi_pi1", "PositionRaw");}}, entry => { set => sub {Spectra::tng_attrDoubleWrt( "mi_pi1", "PositionRaw", $_[0]);}}};

$Spc::res_h{ e712_b1} = { name => "DefineWF", command => sub { Spectra::tng_inout( "mi_pi1", "DefineWaveform");}}; $Spc::res_h{ e712_b2} = { name => "StartWaveGen.", command => sub { Spectra::tng_inout( "mi_pi1", "StartWaveGenerator");}}; $Spc::res_h{ e712_b3} = { name => "StopWaveGen.", command => sub { Spectra::tng_inout( "mi_pi1", "StopWaveGenerator");}};

14.30 Galil Slit

The following lines create a widget that operates the jaws of a Galil slit.

$Spc::res_h{ blsc} = "Galil";

# # galil slit Figure 14.26: BLSC: PiezoPiE712

# $Spc::res_h{ galil_title} = { text => "Galil"};

$Spc::res_h{ galil_m1} = { name => "ga_t", unit => "mm"}; $Spc::res_h{ galil_m2} = { name => "ga_b", unit => "mm"}; $Spc::res_h{ galil_m3} = { name => "ga_l", unit => "mm"}; $Spc::res_h{ galil_m4} = { name => "ga_r", unit => "mm"}; $Spc::res_h{ galil_m5} = { name => "ga_cx", unit => "mm"}; $Spc::res_h{ galil_m6} = { name => "ga_cy", unit => "mm"}; $Spc::res_h{ galil_m7} = { name => "ga_dx", unit => "mm"}; $Spc::res_h{ galil_m8} = { name => "ga_dy", unit => "mm"}; Figure 14.27: BLSC: Galil Chapter 15

Symbols

15.1 Introduction

The Perl interface to symbols is the %SYM hash. That means the expression s1 = 12 in .gra-speak is equivalent to $Spectra::SYM{ s1} = 12 in Perl. The symbol name is not case sensitive.

15.2 DORIS MCA

DORIS_MCA Defines the counter for the measurement of the Doris current, use by MCA.pm. The symbol C2C_DORIS_MCA is a conversion factor: I[mA] = Counts/C2C/SampleTime.

15.3 FLAG TKI STOP flag_tki_stop This flag is set by Util::stop_moves() which is called by the toplevel stop button. It has to be reset by the user.

$Spectra::SYM{ FLAG_TKI_STOP} = 0; while(1) { ... last if( $Spectra::SYM{ FLAG_TKI_STOP}); ... }

15.4 INTERRUPT SCAN

INTERRUPT_SCAN If set to 1, the scan is interrupted. This symbol is set by various functions, also by the stop button of the toplevel widget.

15.5 RETURN VALUE

RETURN_VALUE Used to return values from virtual motor scripts, e.g.: $Spectra::SYM::{ return_value} = Spectra::gmup(mot1).

15.6 SCAN NAME DONE

SCAN_NAME_DONE Contains the name of last completed scans. It is used e.g. for output file names (.ps and .fio). It is deleted before a scan is started and created after a scan completed successfully by: Scan.pm, ScanQ.pm, exp general scan.c, exp scan::exp scan q(), exp general scan::exp general scan().

129 Chapter 16

Functions

The module Util.pm makes the following functions available. Notice that optional parameters are inclosed in square .

16.1 Util::display text()

Util::display_text( "title", "some text"); Util::display_text( "title", "some other text"); Opens a window and puts some lines of text in it. If the line is empty, the window is cleared.

16.2 Util::edit file() edit_file( name => "fname"[, cb_func => \&some_function]) fname is opened in an editor window. If the user choses to write changes to the disk, a new version of the file is created. The optional callback function is invoked after apply. e.g.: Util::edit_file( "test.lis");

16.3 FileSelector

FileSelector() opens a widget that allows the specification of a file name: my $fname = Spectra::FileSelector( -defaultextension => ’.pl’, -initialfile => "$filename"); -initialdir => "$dirname");

All parameters are optional.

16.4 Util::log() log( "text"[, $w_log]) Writes a text string, preceded by a time stamp, to $w_log or to the log widget of the TkI toplevel widget. e.g.: Util::log( "Mirrored beam setup");

16.5 Util::prompt() prompt( "label", $variable[, "description"]) The user is prompted to enter a variables value. The widget inhibits further program execution until the user pressed Exit or Cancel. $variable is used as a default. If the widget is terminated by Exit, the function returns the supplied value or undef, in case the user deleted the default value. If the widget is terminated by Cancel, it returns the default. e.g.: $pos = Util::prompt( "Pos", "1.234", "Select a target position");

130 16.6 Util::refresh()

Util::refresh() Refreshes the motor positions and calls the update function of the toplevel widget. Here is a typical example: a loop that executes some commands calls refresh() to update the widgets and allow the mainloop() to handle pending events. The button Stop, which might have been pressed by the user, generates an event. The corresponding call- back function sets the symbol $Spectra::SYM{ flag_tki_stop} to notify any running program that the user requested a stop. The line last if( $Spectra::SYM{ flag_tki_stop}) senses the flag and terminates the loop, if necessary.

$Spectra::SYM{ flag_tki_stop} = 0; while(1) { ... Util::refresh(); last if( $Spectra::SYM{ flag_tki_stop}); ... }

16.7 Util::yesno() yesno( "text"[, $w_popover]), noyes() Opens a toplevel widget and prompts the user for yes or no. It returns 1, if the user clicked the Yes button. The function yesno() has 0 as the default, noyes() has 1 as default. Th optional parameter w popover specifies the position of the widget. e.g.: Util::yesno( "Do you really want it");

16.8 Util::zoom() zoom( [name => "gqe_name"] [, cb_func => \&some_function]) Zooms the spefified GQE or all active GQEs. If supplied, the callback function is called after each display of the data. That happens, after the user pressed a button to zoom-in/zoom-out or to move the window left/right. The callback function is intended to be used to display some text on the screen. The current zoom window limits can be found at $Spectra::SYM{ zoom_x_min} and $Spectra::SYM{ zoom_x_max}. e.g.: Util::zoom( name => "scan_c1"); Chapter 17

Examples

17.1 Access device selection in before-code, P03, Lambda

To check whether e.g. VC1 has been selected for a scan: if( $Util::db_h{ flag_use_scan_VC1} == 1) { print "VC1 has been selected\n"; } else { print "VC1 has NOT been selected\n"; }

17.2 Sweep with outer loop motor, P10

#!/bin/env perl # # this script executes sweeps at different positions # of an outer loop motor. It switches an output # register when the sweep motor passes the start point # use Spectra; use strict; my $status = 1; my ($sweepTime) = @ARGV; if( !defined( $sweepTime)) { print "Usage: contScan.pl \n"; $status = 0; goto finish; } my $sweepStart = 0; my $sweepDistance = 1.; my $sweepMotor = "exp_mot65"; my $outerStart = 0; my $outerStop = 1; my $outerDelta = 0.5; my $outerMotor = "exp_mot66"; my $oldSlew = Spectra::gms( $sweepMotor); my $moveTime = Spectra::get_move_time( $sweepMotor, $sweepDistance);

132 # ramp units for default slew rate my $rampUnits = Spectra::get_motor_ramp_units( $sweepMotor); my $sweepSlew = $oldSlew*$moveTime/$sweepTime; # ramp units for sweep slew rate my $rampSweepUnits = $rampUnits*$sweepSlew/$oldSlew; if( $sweepSlew > $oldSlew || $sweepSlew < Spectra::gmb( $sweepMotor)) { Util::log( sprintf( "contScan: slew rate out of range [%d, %d]", Spectra::gmb( $sweepMotor), Spectra::gms( $sweepMotor))); } Util::log( "contScan: slew $oldSlew"); Util::log( "contScan: sweepSlew $sweepSlew"); Util::log( "contScan: rampUnits $rampUnits"); Util::log( "contScan: moveTime $moveTime");

$Spectra::SYM{ flag_tki_stop} = 0;

Spectra::move( $outerMotor => $outerStart); my $count = 0; # # use ’sweep’ as a prefix # my $logFileName = Spectra::create_scan_name( "sweep") . ".log"; if( !open( LOG, ">$logFileName")) { Util::log( "contScan: failed to open $logFileName"); goto finish; } Util::log( "contScan: opened $logFileName"); print LOG "sequence started at " . Spectra::date_and_time() . "\n"; print LOG "sweepMotor $sweepMotor, start $sweepStart, distance $sweepDistance, sweep time print LOG "outerMotor $outerMotor, start $outerStart, stop $outerStop, delta $outerDelta\n"; while(1) { Spectra::set_motor_slew( $sweepMotor, $oldSlew); if( !Spectra::move( $sweepMotor => ($sweepStart - $rampSweepUnits))) { goto finish; }

Spectra::sms( $sweepMotor, $sweepSlew); Util::log( sprintf( "contScan: starting sweep, $outerMotor at %g", Spectra::gmup( $outerMotor))); Spectra::amove( $sweepMotor => ($sweepStart + $sweepDistance)); my $startTime = Spectra::secnds(); print LOG "sweep starts with $outerMotor at " . Spectra::gmup( $outerMotor) . "\n"; my $flag = 0; while( Spectra::check_move( $sweepMotor)) { if( !$flag && (Spectra::gmup( $sweepMotor) > $sweepStart)) { $flag = 1; print LOG "raise trigger at " . Spectra::date_and_time() . " $sweepMotor at " . Spectra::gmup( $sweepMotor) . "\n"; Util::log( "switching OREG to ON "); # Spectra::wor( $oreg, 1); }

Spectra::start_and_wait_for_timer( "exp_t01", 0.1); # # space bar and STOP button terminate move # if( $Spectra::SYM{ flag_tki_stop} || Spectra::key() == 32) { $Spectra::SYM{ flag_tki_stop} = 0; Util::log( "contScan.pl interrupted"); Spectra::stop_move( $sweepMotor); while( Spectra::check_move( $sweepMotor)) { Spectra::wait( 0.1); } goto finish; } } Util::log( "switching OREG to OFF"); print LOG "disable trigger at " . Spectra::date_and_time() . " $sweepMotor at " . Spectra::gmup( $sweepMotor) . "\n"; # Spectra::wor( $oreg, 0); Util::log( sprintf( "%s at %g dT %g ", $sweepMotor, Spectra::gmup( $sweepMotor), (Spectra::secnds() -

$count++; if( ($outerStart + $count*$outerDelta) > $outerStop) { last; } if( !Spectra::move( $outerMotor => ($outerStart + $count*$outerDelta))) { goto finish; }

} finish: close( LOG); Spectra::set_motor_slew( $sweepMotor, $oldSlew); $status;

17.3 PE image series, incl. loop over SDD positions, P02

#!/bin/env perl use strict; use Spectra; sub test_abort { my $status = 0; my $k = Spectra::key(); if( $k == 32) { $status = 1; goto finish; } if( Spectra::flag( "perltk")) { # # ... we call the refresh routine to look whether # the user pressed the Stop button # Util::refresh(); # # Util::refresh() take some time, if many motor positions are updated. # The following call is fast because it updates the Stop button # of the toplevel widget only. # Util::update_toplevel_stop_button(); } if( $Spectra::SYM{ flag_tki_stop}) { $status = 1; goto finish; } $Spectra::SYM{ flag_tki_stop} = 0; return $status; } sub _mylog { my ( $string) = @_; Util::log( $string); Spectra::log( $string); } my $sample_time = 2; my @capillary_pos = ( 0.01, -0.13); my @sdd_positions_x = ( 270, 260, 250); my @sdd_positions_z = ( 2600, 2500, 2400);

_mylog( ">>> p02_demo START"); my $total = scalar( @sdd_positions_x); foreach my $i ( 0 .. ( $total - 1)) { my $sdd_pos_x = $sdd_positions_x[$i]; my $sdd_pos_z = $sdd_positions_z[$i]; my $j = $i + 1; _mylog( "> sdd to x $sdd_pos_x, z $sdd_pos_z, $j/$total"); if( !Spectra::move( "eh1b_mot16" => $sdd_pos_x)) { goto finish; } Spectra::gra_command( "sdd $sdd_pos_z"); _mylog( "collect $sample_time (Dark)"); Spectra::gra_command( "collect_pe $sample_time 1"); if( !Spectra::wait( 1.)) { _mylog( " script aborted"); goto finish; } foreach my $pos ( @capillary_pos) { _mylog( "moving eh1a_mot13 to $pos "); if( !Spectra::move( "eh1a_mot13" => $pos)) { goto finish; } if( !Spectra::wait( 1.)) { _mylog( " script aborted"); goto finish; } _mylog( "collect $sample_time"); Spectra::gra_command( "collect_pe $sample_time"); if( !Spectra::wait( 1.)) { _mylog( " script aborted"); goto finish; } if( test_abort()) { _mylog( " script aborted"); goto finish; } } } _mylog( "<<< p02_demo DONE"); finish: $Spectra::SYM{ flag_tki_stop} = 0; 1;

17.4 Interrupting Perl code that was started from online -tki (P10)

The following piece of code demonstrates how a Perl application that was started from the online -tki command line can be interrupted, either by pressing the space bar or by pressing the Stop button at the toplevel widget. Notice that the function Spectra::key() works only, if the xterm that started online -tki is brought to the front. Notice also that the function Util::refresh() is useful in general. It should be called repeatedly from long running Perl programs in order to prevent widgets to be ’frozen’. If Util::refresh() is called, the motor positions are updated and control is transfered to the PerlTk manager which handles button events and invokes callback functions, if necessary.

#!/usr/bin/env perl use Spectra; while( 1) { my $k = Spectra::key(); # # if we run online -tki, ... # if( Spectra::flag( "perltk")) { # # ... we call the refresh routine to look whether # the user pressed the Stop button # Util::refresh(); # # Util::refresh() take some time, if many motor positions are updated. # The following call is fast because it updates the Stop button # of the toplevel widget only. # Util::update_toplevel_stop_button(); } print " key $k, stop-flag $Spectra::SYM{ flag_tki_stop} \n"; if( $k == 32) { last; } if( $Spectra::SYM{ flag_tki_stop}) { last; } Spectra::wait( 0.2); } # # clear the stop button flag # $Spectra::SYM{ flag_tki_stop} = 0; print " DONE \n"; 1;

17.5 Optimizing a motor position, while the MCA menu is active (P01)

Suppose the MCA widget is active and a motor position needs to be optimized regularily. The following script serves this purpose. Here are some explanations. The tags, e.g. (1), can be found in the code.

(1) The MCA toplevel widget is stored in $MCA::h{ w_top}. The Tk::Exists() function does what it says. (2) The symbol SIGNAL is evaluated to find a new maximum. (3) The function $MCA::h{ w_start}->invoke() acts, as if somebode pressed the Start button. Calling $MCA::h{ w_top}->update() updates the MCA widget (switches from Busy to Idle). (4) The loop over the motor positions. (5) This loop waits for wait time seconds. The function Util::refresh() updates all Online -tki widgets and processes events. If the used pressed Stop, the symbol $Spectra::SYM{ flag_tki_stop} is set.

#!/bin/env perl use Spectra; use Tk 800.000 (’Exists’); use strict; my $range = 0.002; my $np = 11; my $mot = "exp_mot65"; my $delta = $range/($np - 1); my $wait_time = 10; delete $Spectra::SYM{ flag_tki_stop}; my $flagWasBusy = 0; my $posOld = Spectra::gmup( $mot); my $status = 1;

Spectra::log( "McaOpt.pl: starting");

# (1) # is the MCA menu active? # if( !Tk::Exists( $MCA::h{ w_top})) { Spectra::error( "McaOpt.pl: MCA toplevel widget does not exist"); goto finish; } # (2) # we need the symbol signal (definition in exp_ini.exp): # # signal = [vfc( EXP_C32, EXP_T01, 0.1)] # if( !defined( $Spectra::SYM{ signal})) { Spectra::error( "McaOpt.pl: symbol SIGNAl is not defined"); $status = 0; goto finish; }

# # the loop # restart: my $signalMax = -1; my $flagFoundMax = 0; my $posMax = $posOld;

# (3) # w_start is a toggle widget # if( $MCA::status_mca =˜ /busy/i) { Util::log("McaOpt.pl: pausing MCA operation"); $MCA::h{ w_start}->invoke(); $MCA::h{ w_top}->update(); $MCA::h{ w_write}->invoke(); $flagWasBusy = 1; }

# (4) foreach my $i ( 0 .. $np) { my $pos = $posOld - $range/2. + $i*$delta; if( !Spectra::move( $mot => $pos)) { Spectra::error(" McaOpt.pl: move was interrupted"); $status = 0; goto finish; } my $signal = Spectra::gra_decode_float( "signal"); Util::log( "McaOpt.pl: pos $pos, signal $signal"); if( $signal > $signalMax) { Util::log( "McaOpt.pl: new max signal at $pos, value $signal"); $signalMax = $signal; $posMax = $pos; $flagFoundMax = 1; } } if( $flagFoundMax) { Spectra::log( "McaOpt.pl: moving to max $posMax"); if( !Spectra::move( $mot => $posMax)) { $status = 0; goto finish; } my $signal = Spectra::gra_decode_float( "signal"); Util::log( "McaOpt.pl: signal $signal"); } else { Spectra::log( "McaOpt.pl: no max found, moving to old position $posOld"); if( !Spectra::move( $mot => $posOld)) { $status = 0; goto finish; } } if( $flagWasBusy) { $MCA::h{ w_start}->invoke(); }

Util::log( "McaOpt.pl: waiting $wait_time s");

# (5) for( my $t = 0; $t < $wait_time; $t += 0.5) { select undef, undef, undef, 0.5; Util::refresh(); if( $Spectra::SYM{ flag_tki_stop}) { Util::log( "McaOpt.pl: interrupted, goto finish"); goto finish; } } goto restart; finish: Spectra::log( "McaOpt.pl: DONE"); $status; Bibliography

[1] et al., , O’Reilly

[2] Steve Lidie, Nancy Walsh, Mastering Perl/Tk, O’Reilly

140 Index

%Spectra::data scan , 42

FileSelector, 130 absorber, 36

Compound device, 100 continuous scans, 43 coordinate system, 80 examples, 132 extra code, 43

Files.lis, 63 Files temp.lis, 63 filter, 36 Function, 130 Util::display text(), 130 Util::edit file(), 130 Util::log(), 130 Util::prompt(), 130 Util::refresh(), 131 Util::yesno(), 131 Util::zoom(), 131

Galil, 11 heatup time, 41

Lom, 100

MOSTAB, 17

Nexus files, 45 online.xml, 11, 12 online galil.xml, 11 performance, 46 slits, 79 Sweep, 63 SweepList.pl, 65 Symbol, 129 DORIS MCA, 129 FLAG TKI STOP, 129 INTERRUPT SCAN, 129 RETURN VALUE, 129 SCAN NAME DONE, 129 tags, 12 virtual counters, 42

WAIT TIME PRESET MAX, 41

141