### XLD/XMCD Analysis HOWTO

#### Contents

1. Usage
2. Description
2.1 Top row
2.2 Options window
2.2.1 Normalization
2.2.2 Interpolation
2.2.3 Motor selection
2.3 Table
2.4 Analysis window
3. Extend the automatic assignment
3.1 Edit the experiments dictionary
3.2 Edit the drop down menu
3.3 Edit the selectExperiment function

#### Synopsis

Xray linear dichroism (XLD) and Xray magnetic circular dichroism (XMCD) measurements as performed at Beamlines ID08 and ID12 of the ESRF probe the sample with x-rays of two different polarizations. From two spectra with different polarizations, one calculates the difference spectrum (the XLD/XMCD spectrum) as well as the average spectrum (XAS spectrum). The present plug-in aims to ease the evaluation process.
To assign the recorded spectra into two groups (labeled 'A' and 'B') depending on their polarization, the plug-in displays meta data obtained from the spec file and provides methods to automate the assignment process. A separate plot window allows a preview on calculated XLD/XMCD spectra. Several options relevant to the treatment of the data can be specified and saved. The results of an analysis can be exported into spec-files.
up

### 1. Usage

From the open spec-File, select the relevant scans in the scan selection window on the left side of your PyMca session. Assign the relevant counters to the respective axes and load the scans in the plot window on the right. Load the plug-in from the plug-in menu (gearbox item in the top row of the plot window). Notice that if one selects a section of the data by zooming in before starting the plug-in, only the data within that energy range is used for the analysis.
The selected spectra now appears in the table of the plug-in. Per default, the spectra remain unassigned as indicated by the drop down menu showing the entry 'Generic dichroism'. Either one selects an existing experiment from the drop down menu (which also provides automatic division of spectra into groups) or does all settings by hand using the options menu. The options menu also allows to determine if and when a normalization is applied to the spectra and the specifics of the interpolation carried out during the calculation.
If all necessary information is displayed in the table, the assignment of spectra to either group 'A' or 'B' can be done by right-clicking on the table. A context menu appears offering several ways to assign a selected spectrum a group.
Once a selection is made, the result of calculations is displayed immediately in the analysis window. An average is calculated on the spectra that belong to groups 'A' and 'B' (curves labeled avg_A resp. avg_B). The difference spectrum (curve labeled XMCD) is calculated as Avg(B)- Avg(A). The XAS spectrum is calculated as the average of both groups: (Avg(A) + Avg(B))/2
The finished analysis can be saved in a spec file using the Save Button in the top button row of the analysis window.
up

### 2. Description

The plug-in consists of four elements: the top row of buttons, the table listing the spectra and the analysis window. Another important element is the options window.

#### 2.1 Top row

The top row contains the following buttons in order from left to right: the Update Button, the Options Button and the Experiment Selection.
Update Button
Loads plots from the main window of the PyMca session into the plug-in. Notice: If the plot window of the main application is zoomed in or out, only the data within the zoomed in energy range is considered for analysis. After zooming in or out in the main application, the spectra in the plug-in should be updated.
Options Button
Allows to specify the plug-in behavior during the analysis. For information in can be found in section 2.2.
Experiment Selection:
The options for the experiments carried out at beamlines ID08 and ID12 are embedded in the plug-in. Selecting one of the experiments sets these options and divides the spectra automatically into groups 'A' and 'B'. A new experimental configuration can be added using the 'Add new configuration' option. A window will open and ask the user to name the configuration. Once accepted, an option window is opened and can be used to define the experimental configuration. This can be done by either loading an existing configuration or by specifying it by hand. The new experimental configuration can now be selected in the drop down menu and remains there until the end of the PyMca session. It sets all options as specified, however the spectra assignment into groups has still to be done by hand.
up

#### 2.2 Options Window

With the Options Window, the user can control the details of the analysis and determine the information shown in the table. A configuration made in the Options Window can be saved and an existing configuration can be loaded. Notice that once the 'OK' button is clicked, the analysis is immediately recalculated.
The saved options are stored in a config file. If the result of a XLD/XMCD analysis is saved a spec file, the current configuration is automatically saved in a separate file.
up

#### 2.2.1 Normalization

One can select if and when a normalization is applied, the normalization method can be specified. Either no normalization is applied at all or it is applied before performing the averages over groups 'A' and 'B'. The third option is to perform the normalization after averaging over both groups.
The following table explains the various normalization methods in detail.

Option | Explanation
--- | ---
(y-min(y)) /trapz(max(y)-min(y),x) | Default selection. Subtracts the minimum value as offset from the spectrum and normalizes it to its integral
y/max(y) | Normalizes the curve to its maximum value
(y-min(y)) /(max(y)-min(y)) | Subtracts the minimum value as offset from the spectrum and normalizes to the resulting maximum, effectively putting all spectral values between zero and one
(y-min(y)) /sum(max(y)-min(y)) | Similar to the default options, but uses the summation over all spectral values instead of the integral

up

#### 2.2.2 Interpolation

The plug-in performs an interpolation of the spectra selected to be used in the analysis before calculation averages and differences. In the "Interpolation x-range" section the user can select, which energy range is used for interpolation. To guarantee numerical stability of the interpolation, the spectra are cleaned up before being copied from the main application to the plug-in. The clean up process consists of sorting the data with respect to the energy (i.e. x) range as well as removing energies that have been measured twice.
One can chose between selecting one of the energy ranges that actually have been measured or let the plug-in determine a equidistant energy range, which might be beneficial for further analysis such as Savitzky-Golay smoothing. Options that conserve at least one measured energy range are 'First curve in sequence' or 'Active curve' (i.e. taking the active curve in the plot window of the main application).
up

#### 2.2.3 Motor Selection

The drop down menus allow to select the motors positions to be shown in the plug-in table. Notice that all motors in the drop down menu are not hard coded in the plug-in but are obtained dynamically from meta data in the spec file. Motor names are treated case sensitive by the plug-in.
Motors for ID08 are:
phaseD, PhaseD, oxPS, magnet
Motors for ID12 are:
Phase, PhaseA, BRUKER, CRYO, OXFORD
Notice that ID12 also uses different counters to differ between polarizations.
up

#### 2.3 Table

The table, positioned beneath the top row, shows the spectra that are included in the XLD/XMCD analysis. The table shows the group to which a curve is assigned, the curves' legend, the scan number and the counter of a spectrum. The remaining columns display settings of various physical or virtual motors that were recorded during the course of the measurement and stored in the meta data of the spec file. Every column of the table can be used to sort it with respect to the values in this column by double clicking the right top corner of the respective header section.
Right click on the table provides the user with a context menu with the following options:
Perform Analysis
Although most calculation is triggered automatically upon selection of a set of scans, selecting this option forces the plug-in to recalculate the XLD/XMCD spectrum.
Set as A resp. Set as B
Assigns a scan selected in the table to the respective group and triggers a recalculation of the XLD/XMCD Analysis.
Enter sequence
Opens a window and allows to enter a sequence of letters ('A', 'B', 'D'). The spectra in the table are sorted after their scan number and assigned into groups 'A' and 'B' based on the sequence, 'D' leaves a spectrum unselected. If no scan number is present, the spectra remain unsorted. The length of the sequence does not need to match the number of spectra. If the length of the sequence is smaller than the number of spectra, the plug-in assumes the entered sequence as a pattern and repeats it.
Remove selection
Removes a scan from the selection, effectively setting its group to 'D'
Invert selection
Selects scans in the table that are not selected yet and deselects the selected scans.
Remove curves
Removes curves from the table and the plot window in the main application.
up

#### 2.4 Analysis Window

The analysis window beneath the table shows the result of the XLD/XMCD analysis. Four curves are displayed: the arithmetic averages over groups A and B, the XAS spectrum (an arithmetic average over the averages of groups A and B) and the difference spectrum (group B - group A) called the XMCD spectrum.
Notice that the XMCD spectrum usually is not in the same order of magnitude as the average spectra and the XAS spectrum. Thus, the XMCD spectrum is plotted to the secondary y axis on the right. In order to hide individual spectra, one can right-click on the legend and select 'Hide curve'.
In the analysis window behaves exactly like the plot window of the main application. The plot can be zoomed and the spectra can be manipulated using the usual tools of PyMca. Only the save routine has been modified to the specific demands of XLD/XMCD analysis.
Save routine
The save icon in the analysis window allows the users to save all results of the XLD/XMCD analysis at once in a single spec file. The data is divided into multiple columns. The first column contains the energy range over which the analysis is carried out, followed by the averages over groups 'A' and 'B'. The last two columns are occupied by the XLD/XMCD spectra.
The save dialog also allows to enter a comment that will be written in the spec file. If multiple datasets are analyzed consecutively, the results can be still saved in a single spec file by selecting the 'Append to existing file' option. Every individual scan is saved in a separate file, too. Therefore, the original file name is extended by an underscore and the number of scans already present in the file to which the analysis is appended to.
Along with the data, the configuration from the options menu is also saved under the same file name, but with the extension 'cfg'.
Buttons Add, Add all, Replace and Replace All
Allow to push the resulting spectra from the plug-in window to the plot window of the main application. While 'Add' and 'Replace' only affect the active curve in the plug-in plot window, 'Add all' and 'Replace all' copy all curves from the analysis to the main application. Notice: If one plans to compare two or more analyzed spectra by consecutively pushing them to the main window, the spectra should be renamed beforehand. The name for each analyzed spectrum remains the same (avg_A, avg_B, XMCD, XAS) and moving spectra of the same name to the plot window in the main application just replaces them there.
up

#### 3. Extend the automatic assignment

The scope of this paragraph is to explain the additions to the source code necessary to make to define a new experiment. The paragraph assumes entry level knowledge of the Python programming language.
Data measured on beamline ID08 or ID12 of the ESRF can automatically be assigned to one of groups 'A' or 'B', as long as it is saved in spec files. By selecting one of the experiments from the drop down menu in the top row, the XLD/XMCD plug-in sets the motors resp. counters controlling the polarization in the options menu. This displays the respective values in the plug-ins table. To achieve the automatic assignment, the plug-in reads the displayed values and guesses the affiliation of a spectrum based on a set of rules.
up

#### 3.1 Edit the experiments dictionary

The experiments dictionary contains the settings specific to an experiments. The options concern the normalization settings and method, the interpolation settings and most importantly the motors on which the assignment depends.
The following code fragment shows the exemplary entry 'Generic Dichroism' in the experiments dictionary.

    self.experimentsDict = {
        'Generic Dichroism': {
              'xrange': 0,
              'normalization': 0,
              'normalizationMethod': 'offsetAndArea',
              'motor0': '',
              'motor1': '',
              'motor2': '',
              'motor3': '',
              'motor4': ''
        },
        ...
    }

Notice that every experiment is represented by a dictionary itself, with the different options as keys and the respective settings as values. Valid values for each option, as well as the necessary types are shown in the following table.

Option | Type | Values: Explanation
--- | --- | ---
xrange | Int | 0: First curve in sequence 1: Active curve 2: Equidistant x-range
normalization | Int | 0: No normalization 1: Normalize after average 2: Normalize before average
normalizationMethod | String | OffsetAndArea: Subtracts minimum and normalizes to the integral, OffsetAndCounts: Subtracts minimum and normalizes to the sum, OffsetAndMaximum: Subtracts minimum and normalizes to the maximum NormToMaximum: Normalizes to the maximum
motor0, motor1, motor2, motor3, motor4 | String | Assumes knowledge of the motor settings in the experimental apparatus. If unsure, consult the Motor Info plug-in or a Beamline Scientist.

Notice that up to five motors can be specified, however no motor must be specified. If a motor is not needed, just set the variable to an empty string.
up

#### 3.2 Edit the drop down menu

Now that a new experiment is present in the experiments dictionary, it can be added into the selection of the drop down menu. The drop down menu itself is a QComboBox whose items are added using the addItem member function. The explicit code to do so (at least in the initial version of this program) looks as follows:

    self.expCBox.addItems(
        ['Generic Dichroism',
        'ID08: XLD 9 Tesla Magnet',
        'ID08: XLD 5 Tesla Magnet',
        'ID08: XMCD 9 Tesla Magnet',
        'ID08: XMCD 5 Tesla Magnet',
        'ID12: XLD (quater wave plate)',
        'ID12: XMCD (Flipper)',
        'ID12: XMCD',
        'Add new configuration'])

It is important, that the registered string is the exact key of the experiment in the experiments dictionary. New experiments should be added above the 'Add new configuration' option.
up

#### 3.3 Edit the selectExperiment function

The selectExperiment function is called every time a item from the drop down menu is selected. In the process, the selected option is passed on to the function as a string. Based on this string, the function then sets the options as defined in the experiments dictionary. This triggers the table of the plug-in to display the information, especially if motors are present in the options.
In a second step, the function reads all values shown in the tables motor columns (that is columns 4 to 8). If needed (as in case of two of the ID12 experiments), the counter column (no. 3) might as well be read out. The code fragment below shows the updating of the table and the readout.

    self.updateTree()
    values0 = numpy.array(
        self.list.getColumn(4, convertType=float))
    values1 = numpy.array(
        self.list.getColumn(5, convertType=float))
    values2 = numpy.array(
        self.list.getColumn(6, convertType=float))
    values3 = numpy.array(
        self.list.getColumn(7, convertType=float))
    values4 = numpy.array(
        self.list.getColumn(8, convertType=float))

The table function getColumn returns the entries of a table column as a list while conserving the current order of the table rows. The type of the list elements can be specified using the convertType option. The numpy Arrays values0 to values4 now contain different motor positions, each values array has the length of the number of scans in question
The next section consists of a succession of if/else statements to determine the specific experiment. Within such a statement, the values from the table are reduced to a single vector named 'values' that determines the affiliation of a spectrum to groups 'A' or 'B'. This array contains numerical values for every spectrum. The second step here is to set a pivot element (or threshold value), so that if the value for a spectrum is above this value, the spectrum belongs to group 'A' and below to group 'B'. New assignment routines must be implemented here as a new elif block.
In case of the XLD experiment of ID08, the decision process is shown in the code fragment below.

    if exp.startswith('ID08: XLD'):
        values = values0
        mask = numpy.where(numpy.isfinite(values))[0]
        minmax = values.take(mask)
        if len(minmax):
            vmin = minmax.min()
            vmax = minmax.max()
            vpivot = .5 * (vmax + vmin)
        else:
            values = numpy.array(
                [float('NaN')]*numOfSpectra)

In this case, the motor 'PhaseD' (or 'phaseD', depending on the magnet) determines the polarization on the sample and is thus set in the options dictionary. All motor positions are then contained in numpy array 'values0'. Since no further calculations are needed, we can directly assign 'values0' to 'values'. The pivot element in this case is calculated as the average between maximal and minimal values in 'values'.
The last step of the assignment processes is to loop though the 'values' array and check if the element is above or below threshold, as shown in the next code fragement.

    seq = ''
    for x in values:
        if str(x) == 'nan':
            seq += 'D'
        elif x>vpivot:
            seq += 'A'
        else:
            seq += 'B'
    self.list.setSelectionToSequence(seq)

Notice that not-a-number float values in the 'values' array are set to the dummy identifier 'D' and thus are ignored in the selection. The resulting sequence of this procedure is then passed on to the table function setToSequence, which assigns the selection. Once a selection is made, a recalculation is triggered automatically.
up