minor updates and bug fixes in angle scan processing and data explorer
This commit is contained in:
parent
b2f4816629
commit
3235d52212
368
doc/src/anglescan-processing.dox
Normal file
368
doc/src/anglescan-processing.dox
Normal file
@ -0,0 +1,368 @@
|
||||
/*! @page pag_anglescan_processing Angle-scan processing
|
||||
|
||||
@tableofcontents
|
||||
|
||||
\section sec_intro Introduction
|
||||
|
||||
This page describes the data processing steps of angle-scans using the PEARL Procedures.
|
||||
The description relies on using the command line regardless of available GUIs.
|
||||
|
||||
\section sec_import Data reduction
|
||||
|
||||
The goal of this step is to import raw data and at the same time eliminate the energy dimension.
|
||||
We want a two-dimensional wave
|
||||
where the first dimension is the angle axis of the detector
|
||||
and the second dimension is the sequence of measurements,
|
||||
scanning one or multiple manipulator angles.
|
||||
The second dimension requires additional one-dimensional waves
|
||||
that describe the polar, tilt and azimuthal angle setting of the manipulator
|
||||
for each dimension index.
|
||||
|
||||
The processing steps depend on the complexity of the measured spectrum.
|
||||
The user may have to adopt one of the predefined or a custom procedure accordingly.
|
||||
Here, we describe two procedures that may cover many generic cases
|
||||
or that can serve as a starting point for a refined, customized procedure.
|
||||
However, any procedure that produces the datasets mentioned above is, of course, a valid approach.
|
||||
For instance, you could load the complete three-dimensional ScientaImage dataset,
|
||||
and generate the two-dimensional dataset using your own procedures.
|
||||
|
||||
\subsection sec_import_basics Basic steps
|
||||
|
||||
The central import functions are @ref psh5_load_reduced and @ref psh5_load_dataset_reduced.
|
||||
The first form is sufficient if the file contains just one scan and region.
|
||||
Further regions/scans need to be loaded using the second form.
|
||||
The first form is also exposed in the PEARL data explorer window.
|
||||
|
||||
The functions require a data reduction function and processing parameters as arguments.
|
||||
Some particular reduction functions are described further below.
|
||||
More can be found in the source code (or obtained from other users).
|
||||
A list of functions that look like reduction functions can be got from @ref adh5_list_reduction_funcs.
|
||||
|
||||
The basic call sequence looks as follows.
|
||||
Substitute the arguments in angle brackets as necessary.
|
||||
You may have to analyse a reference spectrum or the complete ScientaImage
|
||||
to figure out the processing parameters beforehand.
|
||||
|
||||
First form:
|
||||
|
||||
@code{.ipf}
|
||||
setdatafolder root:
|
||||
string sparam
|
||||
sparam = "<param1=1.5;param2=test;>"
|
||||
psh5_load_reduced("<igor-datafolder>", "<igor-filepath>", "<filename>", <reduction_function>, sparam)
|
||||
@endcode
|
||||
|
||||
Second form:
|
||||
|
||||
@code{.ipf}
|
||||
// open the file
|
||||
setdatafolder root: // or other parent folder
|
||||
variable fid
|
||||
string sparam
|
||||
fid = psh5_open_file("<igor-datafolder>", "<igor-filepath>", "<filename>")
|
||||
|
||||
// load metadata for scaling
|
||||
psh5_load_scan_meta(fileID, "<scan 1>")
|
||||
newdatafolder /s /o attr
|
||||
psh5_load_scan_attrs(fileID, "<scan 1>")
|
||||
setdatafolder ::
|
||||
|
||||
// load and reduce dataset
|
||||
sparam = "<param1=1.5;param2=test;>"
|
||||
psh5_load_dataset_reduced(fid, "<scan 1/region1>", "<ScientaImage>", <reduction_function>, sparam)
|
||||
|
||||
// close the file
|
||||
psh5_close_file(fid)
|
||||
fid = 0
|
||||
@endcode
|
||||
|
||||
\subsection sec_import_intlinbg Peak integration over linear background
|
||||
|
||||
The @ref int_linbg_reduction function converts a two-dimensional Scienta image I(angle, energy)
|
||||
into a one-dimensional angle distribution I(angle).
|
||||
For each angle slice, it calculates a linear background.
|
||||
Then, it integrates the difference between the original data and the background over a specified interval.
|
||||
|
||||
The function requires the following, fixed parameters:
|
||||
|
||||
Parameter | Description | Typical value
|
||||
----------|-------------|--------------
|
||||
Lcrop | size of the low-energy cropping region | 0.11 (fixed mode)
|
||||
Lsize | size of the low-energy background region | 0.2
|
||||
Hcrop | size of the high-energy cropping region | 0.11
|
||||
Hsize | size of the high-energy background region | 0.2
|
||||
Cpos | position of the peak center | 0.5
|
||||
Csize | size of the center region | 0.3
|
||||
|
||||
All parameters are relative to the size of the image (length of the energy interval)
|
||||
and must be in the range from 0 to 1.
|
||||
|
||||
The cropping region is cut away from the image for the rest of the processing.
|
||||
This is necessary to remove the dark corners in fixed mode
|
||||
but can be neglected in swept mode (cropping size = 0).
|
||||
|
||||
The low and high background regions are adjacent to the cropping regions on either side.
|
||||
The function calculates two fix points of the linear background in the center of each background region.
|
||||
The intensity value of each fix point is the average intensity in the background region.
|
||||
|
||||
The peak region is integrated over the integral given by the Csize parameter centered at Cpos.
|
||||
|
||||
The background-subtracted peak integral is returned in ReducedData1.
|
||||
ReducedData2 receives the error estimate of the peak integral (assuming Poisson statistics).
|
||||
|
||||
\subsection sec_import_peakfit Peak fitting
|
||||
|
||||
The @ref gauss4_reduction function converts a two-dimensional Scienta image I(angle, energy)
|
||||
into a one-dimensional angle distribution I(angle).
|
||||
For each angle slice, it performs a Gaussian curve fit with up to four components on a linear background.
|
||||
|
||||
To improve the stability of the fit, the peak positions and widths are kept fixed
|
||||
while the amplitudes of the peaks and the background parameters are variable
|
||||
but constrained to reasonable values (positive amplitude).
|
||||
Furthermore, the function can optionally do a box averaging over three slices.
|
||||
|
||||
The function requires the following, fixed parameters:
|
||||
|
||||
Parameter | Description
|
||||
----------|------------
|
||||
rngl | lower limit of the fit interval
|
||||
rngh | upper limit of the fit interval
|
||||
npeaks | number of components
|
||||
pos1 | center energy of peak 1
|
||||
wid1 | width of peak 1
|
||||
pos2 | center energy of peak 2
|
||||
wid2 | width of peak 2
|
||||
pos3 | center energy of peak 3
|
||||
wid3 | width of peak 3
|
||||
pos4 | center energy of peak 3
|
||||
wid4 | width of peak 3
|
||||
ybox | box size of slice averaging (1 or 3)
|
||||
|
||||
The peak parameters should be determined beforehand from fitting a reference spectrum,
|
||||
or the angle-scan integrated over all angles.
|
||||
Peak positions and widths have to be specified only up to the given number of peaks.
|
||||
|
||||
The data reduction procedure returns the peak integrals
|
||||
(amplitude times width times square root of 2) in waves
|
||||
named ReducedDataN where N is a numeric index from 1 to npeaks.
|
||||
The waves starting with an index of npeaks+1
|
||||
contain the corresponding error estimate of the peak integral.
|
||||
|
||||
\subsection sec_import_custom Custom reduction functions
|
||||
|
||||
See the documentation and source code of @ref int_linbg_reduction, @ref gauss4_reduction and
|
||||
@ref adh5_default_reduction for help on writing custom reduction functions.
|
||||
To integrate your function with the PEARL data explorer,
|
||||
you have to provide an additional function that prompts for reduction parameters
|
||||
such as @ref prompt_int_linbg_reduction, for example.
|
||||
Since reduction functions cannot be called from the command line,
|
||||
it is redommended to also write an adapter function for testing.
|
||||
|
||||
\section sec_norm Normalization
|
||||
|
||||
The goal of the data normalization is to get a (still two-dimensional) dataset
|
||||
that ideally contains intensity variations due to diffraction features and statistical fluctuations only.
|
||||
In particular, instrumental variations should be removed.
|
||||
In some cases, it may be necessary to preserve the overall polar dependence of the intensity.
|
||||
Note that this latter case is not properly treated with the methods described here.
|
||||
|
||||
Depending on the quality of the measured data,
|
||||
only some of the following processing steps are necessary.
|
||||
Use your own judgement.
|
||||
|
||||
\subsection sec_norm_prep Preparations
|
||||
|
||||
Start by creating a new copy of the data and inspecting it:
|
||||
@code{.ipf}
|
||||
duplicate ReducedData1, NormData1
|
||||
ad_display_profiles(NormData1)
|
||||
@endcode
|
||||
|
||||
To update the display after changes to NormData1:
|
||||
@code{.ipf}
|
||||
ad_update_profiles(NormData1)
|
||||
@endcode
|
||||
|
||||
\subsection sec_norm_crop Detector angle range
|
||||
|
||||
Crop the detector angle axis to a useful range (usually about -25 to +25 degrees):
|
||||
@code{.ipf}
|
||||
crop_strip(NormData1, -25, 25)
|
||||
@endcode
|
||||
|
||||
\subsection sec_norm_angle Normalize detector angle
|
||||
|
||||
Remove inhomogeneity of the detector in the detector angle axis.
|
||||
This component may also include a contribution from the sample.
|
||||
If your raw data shows a flat distribution, this step is not necessary.
|
||||
|
||||
@code{.ipf}
|
||||
normalize_strip_x(NormData1, smooth_method=4, smooth_factor=0.15, check=2)
|
||||
@endcode
|
||||
|
||||
Note that the argument <code>check=2</code> causes the function to generate
|
||||
two check waves but not to modify the original data.
|
||||
To inspect the check waves:
|
||||
@code{.ipf}
|
||||
display check_dist, check_smoo
|
||||
ModifyGraph rgb(check_dist)=(0,0,0)
|
||||
@endcode
|
||||
|
||||
Vary the <code>smooth_factor</code> (between 0.1 and 1.0)
|
||||
until it follows the instrumental curve
|
||||
but does not affect diffraction features.
|
||||
Then set <code>check=1</code> to apply the normalization to <code>NormData1</code>.
|
||||
|
||||
\subsection sec_norm_wobble Azimuthal variation (wobble)
|
||||
|
||||
Reduce the effect of azimuthal wobble (misaligned surface) on intensity.
|
||||
A misaligned surface may cause a sinusoidal variation of the intensity as a function of azimuthal angle with a 360°ree; period.
|
||||
A strong azimuthal variation may affect the polar normalization in the next step.
|
||||
The azimuthal normalization can be based on a restricted range of polar angles (theta range).
|
||||
You have to find out which value works best for your sample.
|
||||
|
||||
@code{.ipf}
|
||||
normalize_strip_phi(NormData1, :attr:ManipulatorTheta, :attr:ManipulatorPhi, theta_offset=-8.8, theta_range=10, check=2)
|
||||
@endcode
|
||||
|
||||
Note, however, that his function does not correct for angle shifts induced by the misalignment!
|
||||
|
||||
\subsection sec_norm_theta Polar dependence
|
||||
|
||||
Remove the polar angle dependence (matrix element and excitation/detection geometry).
|
||||
|
||||
@code{.ipf}
|
||||
normalize_strip_theta(NormData1, :attr:ManipulatorTheta, theta_offset=-8.8, smooth_method=4, smooth_factor=0.5, check=2)
|
||||
@endcode
|
||||
|
||||
Use the check waves and the <code>check</code> argument as described above.
|
||||
|
||||
|
||||
\section sec_plot Binning and plotting
|
||||
|
||||
\subsection sec_plot_basics Basic steps
|
||||
|
||||
You can bin and plot the data in one step:
|
||||
|
||||
@code{.ipf}
|
||||
pizza_service(NormData1, "Nickname1", -8.8, 0.5, 6)
|
||||
@endcode
|
||||
|
||||
or two steps:
|
||||
|
||||
@code{.ipf}
|
||||
pizza_service(NormData1, "Nickname2", -8.8, 0.5, 6, nograph=1)
|
||||
display_hemi_scan("Nickname2")
|
||||
@endcode
|
||||
|
||||
The benefit of the latter is that you have more control over the graph through optional arguments.
|
||||
In particular, you can select the projection or hide the ticks and grids.
|
||||
See @ref display_hemi_scan for details.
|
||||
|
||||
The @ref pizza_service function requires the waves with manipulator positions
|
||||
in a specific place, namely <code>:attr:ManipulatorTheta</code> (for the polar angle),
|
||||
and the normal emission values as function arguments.
|
||||
If you have moved the waves, or if you have subtracted the offsets yourself,
|
||||
use the alternative @ref pizza_service_2 function.
|
||||
|
||||
Additional parameters of the @ref pizza_service function allow for rotational averaging,
|
||||
larger angle steps (default 1 degree),
|
||||
or the creation of metadata including a notebook for xpdPlot.
|
||||
|
||||
Note there is currently a bug in the nick name argument of some of the following functions.
|
||||
If the lines shown below do not work,
|
||||
try to switch to the data folder that contains the generated polar plot data,
|
||||
and call the function with an empty nickname <code>""</code>.
|
||||
|
||||
\subsection sec_plot_refine Refinements
|
||||
|
||||
To remove high polar angles above θ = 80 from the plot (and data):
|
||||
|
||||
@code{.ipf}
|
||||
trim_hemi_scan("Nickname1", 80)
|
||||
@endcode
|
||||
|
||||
Modify the pseudocolor scale by changing the <code>polarY0</code> trace:
|
||||
|
||||
@code{.ipf}
|
||||
ModifyGraph zColor(polarY0)={mod_values, *, *, BlueGreenOrange, 0}
|
||||
ModifyGraph zColor(polarY0)={mod_values, -0.2, 0.2, BlueGreenOrange, 0}
|
||||
@endcode
|
||||
|
||||
To set the contrast to clip specified percentiles of the data points,
|
||||
use the @arg set_contrast function:
|
||||
|
||||
@code{.ipf}
|
||||
set_contrast(2, 2, graphname="graph_Nickname1", colortable="BlueGreenOrange")
|
||||
@endcode
|
||||
|
||||
|
||||
\subsection sec_plot_interp Interpolation
|
||||
|
||||
Polar plots can also be interpolated to a rectangular matrix,
|
||||
which may in some cases produce nicer images:
|
||||
|
||||
@code{.ipf}
|
||||
interpolate_hemi_scan("Nickname1")
|
||||
display_hemi_scan("Nickname1", graphtype=3, graphname="intp")
|
||||
matrix = sqrt(x^2 + y^2) <= calc_graph_radius(80) ? matrix : nan
|
||||
ModifyImage matrix ctab= {*,*,BlueGreenOrange,0}
|
||||
@endcode
|
||||
|
||||
The <code>matrix =</code> line optionally removes artefacts at high polar angles.
|
||||
Replace the cut-off angle with your own.
|
||||
|
||||
|
||||
\subsection sec_modulation Modulation function
|
||||
|
||||
To calculate the modulation function and substitute it in the graph:
|
||||
|
||||
@code{.ipf}
|
||||
setdatafolder Nickname1
|
||||
calc_modulation(values, factor1=pol, factor2=az)
|
||||
ModifyGraph zColor(polarY0)={mod_values,-0.2,0.2,BlueGreenOrange,0}
|
||||
@endcode
|
||||
|
||||
|
||||
\section sec_export Data export
|
||||
|
||||
\subsection sec_export_plot Export picture
|
||||
|
||||
The following line is an example of how to export a graph window.
|
||||
Click on the desired graph window, then issue the following command,
|
||||
substituting the file path and file name as appropriate.
|
||||
|
||||
@code{.ipf}
|
||||
SavePICT/P=home/E=-5/B=144/O as "some_filename.png"
|
||||
@endcode
|
||||
|
||||
\subsection sec_export_data Export processed data
|
||||
|
||||
The following line saves the dataset to an Igor text file.
|
||||
The file contains all data necessary to recreate a polar plot without further processing.
|
||||
|
||||
@code{.ipf}
|
||||
save_hemi_scan("Nickname1", "home", "some_filename")
|
||||
@endcode
|
||||
|
||||
For structural optimization using the PMSCO software,
|
||||
it is necessary to generate an ETPI file.
|
||||
There is currently no special function for this.
|
||||
Instead, you have to create and set an energy wave,
|
||||
|
||||
@code{.ipf}
|
||||
duplicate pol, en
|
||||
en = 123.4 // kinetic energy of the photoelectron
|
||||
@endcode
|
||||
|
||||
and write the four waves <code>en, pol, az, values</code> to a general text file.
|
||||
Be careful about the ordering of the waves!
|
||||
You will also have to rename the file to the <code>.etpi</code> extension
|
||||
because Igor always saves with <code>.txt</code> extension.
|
||||
If you have a wave with statistical errors, add a fifth column and use the <code>.etpis</code> extension.
|
||||
|
||||
@code{.ipf}
|
||||
Save /G /M="\n" /O /P=home en, pol, az, values, sig as "Nickname1.etpis.txt"
|
||||
@endcode
|
||||
|
||||
*/
|
@ -1,4 +1,7 @@
|
||||
/*! @mainpage Introduction
|
||||
|
||||
@tableofcontents
|
||||
|
||||
\section sec_intro Introduction
|
||||
|
||||
PEARL Procedures is a suite of Igor Pro procedures developed for data acquisition and data processing at the PEARL beamline at the Swiss Light Source.
|
||||
|
@ -537,7 +537,7 @@ end
|
||||
|
||||
/// calculate the output using all enabled processing filters.
|
||||
///
|
||||
/// the diffractogram is calculated, to display the graph, call @ref asp_display_graph.
|
||||
/// the diffractogram is calculated, to display the graph, call @ref asp_display_output.
|
||||
///
|
||||
function asp_calculate_output()
|
||||
dfref saveDF = GetDataFolderDFR()
|
||||
@ -552,6 +552,7 @@ function asp_calculate_output()
|
||||
|
||||
nvar folding=output_folding
|
||||
nvar horizon=output_horizon
|
||||
nvar graph_mode
|
||||
|
||||
do_init_process(0)
|
||||
do_crop_alpha(0)
|
||||
@ -569,25 +570,57 @@ function asp_calculate_output()
|
||||
values = pol <= horizon ? values : nan
|
||||
endif
|
||||
|
||||
interpolate_hemi_scan("")
|
||||
|
||||
SetDataFolder saveDF
|
||||
end
|
||||
|
||||
/// display the output diffractogram in a new graph
|
||||
/// display the output diffractogram
|
||||
///
|
||||
function asp_display_output()
|
||||
dfref df = $(package_path)
|
||||
/// this function either displays the current working data from the angle scan panel data folder,
|
||||
/// or hologram data from a specified other data folder.
|
||||
/// in either case, the graph is displayed using the current projection, mode, color table and contrast settings of the angle scan panel.
|
||||
///
|
||||
/// @param data_df data folder where the diffractogram data is located.
|
||||
/// default: the folder of the angle scan panel package.
|
||||
///
|
||||
/// @param data_name name of the diffractogram data.
|
||||
/// this is normally the name of a sub-folder that contains the data.
|
||||
/// default: the name specified in the output_name variable in the package data folder.
|
||||
///
|
||||
function /s asp_display_output([data_df, data_name])
|
||||
dfref data_df
|
||||
string data_name
|
||||
|
||||
dfref pkg_df = $(package_path)
|
||||
svar /sdfr=pkg_df output_name
|
||||
svar /sdfr=pkg_df output_graphname
|
||||
nvar /sdfr=pkg_df graph_projection
|
||||
nvar /sdfr=pkg_df graph_mode
|
||||
svar /sdfr=pkg_df graph_colortable
|
||||
nvar /sdfr=pkg_df graph_contrast
|
||||
|
||||
svar /sdfr=df output_name
|
||||
svar /sdfr=df output_graphname
|
||||
nvar /sdfr=df graph_projection
|
||||
nvar /sdfr=df graph_mode
|
||||
if (ParamIsDefault(data_df))
|
||||
dfref data_df = pkg_df
|
||||
endif
|
||||
if (ParamIsDefault(data_name))
|
||||
data_name = output_name
|
||||
endif
|
||||
|
||||
dfref saveDF = GetDataFolderDFR()
|
||||
setdatafolder $(package_path)
|
||||
output_graphname = output_name
|
||||
output_graphname = display_hemi_scan(output_name, projection=graph_projection, graphtype=graph_mode, graphname=output_graphname)
|
||||
setdatafolder data_df
|
||||
string graphname = data_name
|
||||
graphname = display_hemi_scan(data_name, projection=graph_projection, graphtype=graph_mode, graphname=graphname)
|
||||
if (ParamIsDefault(data_df))
|
||||
output_graphname = graphname
|
||||
endif
|
||||
SetDataFolder saveDF
|
||||
asp_update_graph()
|
||||
|
||||
if (strlen(graphname) && (wintype(graphname) == 1))
|
||||
set_contrast(graph_contrast, graph_contrast, graphname=graphname, colortable=graph_colortable)
|
||||
endif
|
||||
|
||||
return graphname
|
||||
end
|
||||
|
||||
/// update graphs with new color table or contrast
|
||||
@ -647,9 +680,19 @@ end
|
||||
/// the destination folder does not need to exist.
|
||||
/// existing data in the destination folder is overwritten.
|
||||
///
|
||||
function asp_duplicate_output(dest_name)
|
||||
/// @param do_graph switch to duplicate the graph window as well (1).
|
||||
/// default: 0 (do not create a graph)
|
||||
///
|
||||
/// @return name of the graph window
|
||||
///
|
||||
function /s asp_duplicate_output(dest_name, [do_graph])
|
||||
string dest_name
|
||||
variable do_graph
|
||||
|
||||
if (ParamIsDefault(do_graph))
|
||||
do_graph = 0
|
||||
endif
|
||||
|
||||
dfref df = $(package_path)
|
||||
svar /sdfr=df source_path
|
||||
svar /sdfr=df output_name
|
||||
@ -657,14 +700,20 @@ function asp_duplicate_output(dest_name)
|
||||
wave raw_data = $source_path
|
||||
|
||||
dfref saveDF = GetDataFolderDFR()
|
||||
dfref dest_df = GetWavesDataFolderDFR(raw_data)
|
||||
setdatafolder dest_df
|
||||
dfref raw_df = GetWavesDataFolderDFR(raw_data)
|
||||
setdatafolder raw_df
|
||||
newdatafolder /o /s $dest_name
|
||||
dfref dest_df = GetDataFolderDFR()
|
||||
setdatafolder df
|
||||
duplicate_hemi_scan(output_name, dest_df, "")
|
||||
|
||||
string graphname = ""
|
||||
if (do_graph)
|
||||
graphname = asp_display_output(data_df=raw_df, data_name=dest_name)
|
||||
endif
|
||||
|
||||
SetDataFolder saveDF
|
||||
return graphname
|
||||
end
|
||||
|
||||
/// save the output diffractogram to an igor text file
|
||||
@ -777,12 +826,14 @@ function asp_show_panel()
|
||||
return 0
|
||||
endif
|
||||
|
||||
NewPanel /K=1 /N=anglescan_panel /W=(200,100,479,1027) as "angle scan processing"
|
||||
NewPanel /K=1 /N=anglescan_panel /W=(200,100,479,854) as "angle scan processing"
|
||||
panel_name = s_name
|
||||
|
||||
GroupBox gb_source, title="data source"
|
||||
Button b_source_select, size={50,20},proc=PearlAnglescanPanel#bp_source_select,title="select..."
|
||||
Button b_source_select, help={"select the source wave, e.g. ReducedData1. it must be in the original scan data folder along with the attr folder and the manipulator positions."}
|
||||
Button b_source_select, help={"select the source wave, e.g. ReducedData1. it must be in the scan or region data folder. the attr folder with the manipulator waves must be in the same folder or one level up."}
|
||||
Button b_source_update, size={50,20},proc=PearlAnglescanPanel#bp_source_update,title="update"
|
||||
Button b_source_update, help={"reload the process data from the previous source (link displayed below)"}
|
||||
TitleBox tb_source_path, size={240,21}
|
||||
TitleBox tb_source_path,variable= root:packages:pearl_anglescan_panel:source_path
|
||||
|
||||
@ -799,6 +850,10 @@ function asp_show_panel()
|
||||
SetVariable sv_alpha_offset, size={90,16},bodyWidth=60,title="alpha"
|
||||
SetVariable sv_alpha_offset,value= root:packages:pearl_anglescan_panel:alpha_offset
|
||||
SetVariable sv_alpha_offset, help={"alpha value that corresponds to normal emission (if the sample normal is properly aligned)."}
|
||||
Button b_save_prefs, size={80,20},proc=PearlAnglescanPanel#bp_save_prefs,title="save prefs"
|
||||
Button b_save_prefs, help={"save settings as preferences."}
|
||||
Button b_load_prefs, size={80,20},proc=PearlAnglescanPanel#bp_load_prefs,title="load prefs"
|
||||
Button b_load_prefs, help={"load settings from preferences."}
|
||||
|
||||
GroupBox gb_crop_alpha, title="crop alpha"
|
||||
CheckBox cb_crop_alpha_enable, size={50,14}, title="enable"
|
||||
@ -878,8 +933,8 @@ function asp_show_panel()
|
||||
PopupMenu pm_graph_projection, mode=2, popvalue="stereographic", value= #"\"equidistant;stereographic;equal area;gnomonic;orthographic;\""
|
||||
PopupMenu pm_graph_projection, help={"projection (theta mapping) mode"}
|
||||
PopupMenu pm_graph_mode, size={129,21}, bodyWidth=100, proc=PearlAnglescanPanel#pmp_graph_mode,title="mode"
|
||||
PopupMenu pm_graph_mode, mode=2, popvalue="polar plot", value= #"\"none;polar plot;none;image;\""
|
||||
PopupMenu pm_graph_mode, help={"graph mode"}
|
||||
PopupMenu pm_graph_mode, mode=2, popvalue="dots", value= #"\"none;dots;none;image;\""
|
||||
PopupMenu pm_graph_mode, help={"graph type: dots = coloured dots on circles; image = interpolated matrix"}
|
||||
Button b_output_calc, size={80,20}, proc=PearlAnglescanPanel#bp_output_calc, title="calc + display"
|
||||
Button b_output_calc, help={"execute data processing with the enabled filters and display the diffractogram."}
|
||||
Button b_output_duplicate, size={80,20}, proc=PearlAnglescanPanel#bp_output_duplicate, title="duplicate ..."
|
||||
@ -910,9 +965,9 @@ static function arrange_controls()
|
||||
svar /sdfr=df panel_name
|
||||
|
||||
variable gb_space = 2
|
||||
variable gb_internal_top = 20
|
||||
variable gb_internal_bot = 8
|
||||
variable line_space = 26
|
||||
variable gb_internal_top = 16
|
||||
variable gb_internal_bot = 4
|
||||
variable line_space = 22
|
||||
|
||||
variable cb_adj = 2
|
||||
variable sv_adj = 2
|
||||
@ -933,6 +988,7 @@ static function arrange_controls()
|
||||
GroupBox gb_source,pos={4,gb_top}
|
||||
gb_ht = gb_internal_top
|
||||
Button b_source_select,pos={17, gb_top + gb_ht + b_adj},size={50,20}
|
||||
Button b_source_update, pos={67, gb_top + gb_ht + b_adj},size={50,20}
|
||||
gb_ht += line_space
|
||||
TitleBox tb_source_path,pos={18, gb_top + gb_ht + tb_adj},size={240,21}
|
||||
gb_ht += line_space
|
||||
@ -943,8 +999,10 @@ static function arrange_controls()
|
||||
GroupBox gb_offsets,pos={4,gb_top}
|
||||
gb_ht = gb_internal_top
|
||||
SetVariable sv_theta_offset,pos={46, gb_top + gb_ht + sv_adj},size={88,16}
|
||||
Button b_save_prefs,pos={186, gb_top + gb_ht + b_adj},size={80,20}
|
||||
gb_ht += line_space
|
||||
SetVariable sv_tilt_offset,pos={60, gb_top + gb_ht + sv_adj},size={74,16}
|
||||
Button b_load_prefs,pos={186, gb_top + gb_ht + b_adj},size={80,20}
|
||||
gb_ht += line_space
|
||||
SetVariable sv_phi_offset,pos={56, gb_top + gb_ht + sv_adj},size={78,16}
|
||||
gb_ht += line_space
|
||||
@ -1047,6 +1105,9 @@ static function arrange_controls()
|
||||
gb_ht += line_space
|
||||
gb_ht += gb_internal_bot
|
||||
GroupBox gb_graph, size={272,gb_ht}
|
||||
|
||||
gb_top += gb_ht + gb_space
|
||||
//MoveWindow 200, 100, 479, 100 + gb_top
|
||||
end
|
||||
|
||||
/// update the popup menus to reflect the values of the global variables
|
||||
@ -1077,6 +1138,34 @@ static function update_menus()
|
||||
endif
|
||||
end
|
||||
|
||||
static function bp_load_prefs(ba) : ButtonControl
|
||||
STRUCT WMButtonAction &ba
|
||||
|
||||
switch( ba.eventCode )
|
||||
case 2: // mouse up
|
||||
load_prefs()
|
||||
break
|
||||
case -1: // control being killed
|
||||
break
|
||||
endswitch
|
||||
|
||||
return 0
|
||||
End
|
||||
|
||||
static function bp_save_prefs(ba) : ButtonControl
|
||||
STRUCT WMButtonAction &ba
|
||||
|
||||
switch( ba.eventCode )
|
||||
case 2: // mouse up
|
||||
save_prefs()
|
||||
break
|
||||
case -1: // control being killed
|
||||
break
|
||||
endswitch
|
||||
|
||||
return 0
|
||||
End
|
||||
|
||||
static function bp_source_select(ba) : ButtonControl
|
||||
STRUCT WMButtonAction &ba
|
||||
|
||||
@ -1103,6 +1192,27 @@ static function bp_source_select(ba) : ButtonControl
|
||||
return 0
|
||||
End
|
||||
|
||||
static function bp_source_update(ba) : ButtonControl
|
||||
STRUCT WMButtonAction &ba
|
||||
|
||||
switch( ba.eventCode )
|
||||
case 2: // mouse up
|
||||
dfref packdf = $package_path
|
||||
svar /sdfr=packdf source_path
|
||||
wave /z w = $source_path
|
||||
if (waveexists(w))
|
||||
asp_import_raw(w)
|
||||
else
|
||||
DoAlert 0, "can't find source data."
|
||||
endif
|
||||
break
|
||||
case -1: // control being killed
|
||||
break
|
||||
endswitch
|
||||
|
||||
return 0
|
||||
End
|
||||
|
||||
static function bp_norm_alpha_check(ba) : ButtonControl
|
||||
STRUCT WMButtonAction &ba
|
||||
|
||||
@ -1250,10 +1360,12 @@ static function bp_output_duplicate(ba) : ButtonControl
|
||||
switch( ba.eventCode )
|
||||
case 2: // mouse up
|
||||
string dest_folder
|
||||
variable do_graph = 1
|
||||
prompt dest_folder, "destination folder name (relative to data source)"
|
||||
doprompt "duplicate", dest_folder
|
||||
prompt do_graph, "duplicate graph (yes = 1, no = 0)"
|
||||
doprompt "duplicate", dest_folder, do_graph
|
||||
if (!v_flag)
|
||||
asp_duplicate_output(dest_folder)
|
||||
asp_duplicate_output(dest_folder, do_graph=do_graph)
|
||||
endif
|
||||
break
|
||||
case -1: // control being killed
|
||||
|
@ -160,6 +160,8 @@ end
|
||||
/// this is a simple way to remove the effect of the angle-dependence of the analyser transmission function.
|
||||
/// the strip is normalized in place, previous data is overwritten.
|
||||
///
|
||||
/// the function can handle sparse NaNs.
|
||||
///
|
||||
/// @param[in,out] strip 2D data, X-axis = analyser angle, Y-axis = arbitrary manipulator scan
|
||||
///
|
||||
/// @param[in] smooth_method smoothing method
|
||||
@ -205,12 +207,20 @@ function normalize_strip_x(strip, [smooth_method, smooth_factor, check])
|
||||
endif
|
||||
|
||||
// average over all scan positions
|
||||
wave dist = ad_profile_x(strip, -inf, inf, "")
|
||||
wave raw_dist = ad_profile_x(strip, -inf, inf, "")
|
||||
|
||||
// remove nans
|
||||
extract /free /indx raw_dist, clean_index, numtype(raw_dist) == 0
|
||||
duplicate /free raw_dist, dist, dist_x
|
||||
redimension /n=(numpnts(clean_index)) dist, dist_x
|
||||
dist = raw_dist[clean_index[p]]
|
||||
dist_x = pnt2x(raw_dist, clean_index[p])
|
||||
variable div = mean(dist)
|
||||
dist /= div
|
||||
|
||||
if (check)
|
||||
duplicate /o dist, check_dist
|
||||
duplicate /o raw_dist, check_dist
|
||||
check_dist = numtype(raw_dist) == 0 ? interp(x, dist_x, dist) : nan
|
||||
endif
|
||||
|
||||
// smooth distribution function
|
||||
@ -223,21 +233,24 @@ function normalize_strip_x(strip, [smooth_method, smooth_factor, check])
|
||||
break
|
||||
case 3:
|
||||
make /n=1 /d /free fit_params
|
||||
fit_scienta_ang_transm(dist, fit_params)
|
||||
fit_scienta_ang_transm(raw_dist, fit_params)
|
||||
duplicate /free raw_dist, dist, dist_x
|
||||
dist_x = x
|
||||
dist = scienta_ang_transm(fit_params, x)
|
||||
break
|
||||
case 4:
|
||||
loess /smth=(smooth_factor) srcWave=dist
|
||||
loess /smth=(smooth_factor) srcWave=dist, factors={dist_x}
|
||||
break
|
||||
endswitch
|
||||
|
||||
if (check)
|
||||
duplicate /o dist, check_smoo
|
||||
duplicate /o raw_dist, check_smoo
|
||||
check_smoo = interp(x, dist_x, dist)
|
||||
endif
|
||||
|
||||
// divide
|
||||
if (check != 2)
|
||||
strip /= dist[p]
|
||||
strip /= interp(x, dist_x, dist)
|
||||
endif
|
||||
end
|
||||
|
||||
@ -1660,6 +1673,17 @@ function /s display_hemi_scan(nickname, [projection, graphtype, do_ticks, do_gri
|
||||
endif
|
||||
|
||||
string s_trace
|
||||
DoWindow $graphname
|
||||
if (v_flag)
|
||||
if (str2num(GetUserData(graphname, "", "graphtype")) == graphtype)
|
||||
// graph exists and will update automatically - do not recreate
|
||||
graphtype = 0
|
||||
else
|
||||
// graph exists - but needs recreating
|
||||
killwindow $graphname
|
||||
endif
|
||||
endif
|
||||
|
||||
switch(graphtype)
|
||||
case 1:
|
||||
graphname = display_polar_graph(graphname, angle_offset=azim_offset, do_ticks=do_ticks)
|
||||
@ -1673,6 +1697,7 @@ function /s display_hemi_scan(nickname, [projection, graphtype, do_ticks, do_gri
|
||||
ColorScale /W=$graphname /C /N=text0 nticks=2, minor=1, tickLen=4.00, tickThick=0.50
|
||||
|
||||
SetWindow $graphname, userdata(projection)=num2str(projection)
|
||||
SetWindow $graphname, userdata(graphtype)=num2str(graphtype)
|
||||
draw_hemi_axes(graphname, do_grids=do_grids)
|
||||
break
|
||||
case 3:
|
||||
@ -1687,6 +1712,7 @@ function /s display_hemi_scan(nickname, [projection, graphtype, do_ticks, do_gri
|
||||
ColorScale /W=$graphname /C /N=text0 nticks=2, minor=1, tickLen=4.00, tickThick=0.50
|
||||
|
||||
SetWindow $graphname, userdata(projection)=num2str(projection)
|
||||
SetWindow $graphname, userdata(graphtype)=num2str(graphtype)
|
||||
draw_hemi_axes(graphname, do_grids=do_grids)
|
||||
break
|
||||
endswitch
|
||||
|
@ -79,7 +79,7 @@ static function init_package()
|
||||
string /g s_reduction_params = "" // recently used reduction parameters
|
||||
string /g s_preview_pvs = "" // semicolon-separated list of EPICS PVs to display in preview.
|
||||
// the list items can contain wildcards for StringMatch
|
||||
s_preview_pvs = "*OP:CURRENT*;*Stats*Total*;*CADC*"
|
||||
s_preview_pvs = "*OP:CURRENT*;*Stats*Total*;*KEITHLEY*READOUT;*CADC*"
|
||||
|
||||
// non-persistent strings and variables
|
||||
string /g s_preview_file = "" // file or folder name of the current preview
|
||||
@ -392,6 +392,25 @@ static function /wave preview_hdf_file(filename)
|
||||
return preview_image
|
||||
end
|
||||
|
||||
/// load the preview of a general ITX file.
|
||||
///
|
||||
/// the function is designed for PEARL OTF and EPICS scan data converted from MDA files.
|
||||
/// the function picks the first wave whose PV note matches one from the global string s_preview_pvs
|
||||
/// (see @ref preview_datafolder and @ref init_package).
|
||||
///
|
||||
/// the preview is loaded to the preview_image wave in the pearl_explorer data folder.
|
||||
/// the s_file_info string is updated with information about the scan dimensions.
|
||||
///
|
||||
/// @note: the ITX files should load their waves into the current data folder (a "free" data folder).
|
||||
/// some early versions of PEARL ITX data files created a data folder of their own.
|
||||
/// both ways are allowed, while the first one is preferred.
|
||||
/// on return, the current data folder must point to either the original free folder or the newly created one.
|
||||
///
|
||||
/// @param filename name of a file in the directory specified by the pearl_explorer_filepath path object.
|
||||
///
|
||||
/// @return wave reference of the preview trace.
|
||||
/// empty wave reference if the function failed.
|
||||
///
|
||||
static function /wave preview_itx_file(filename)
|
||||
string filename
|
||||
|
||||
@ -401,10 +420,6 @@ static function /wave preview_itx_file(filename)
|
||||
svar s_preview_source
|
||||
wave preview_image
|
||||
|
||||
// note: some versions of PEARL data files save data to a new data folder,
|
||||
// and leave the newly created folder as the current folder.
|
||||
// the free data folder is used by those files which don't create their own data folder.
|
||||
// this is the new recommended behaviour
|
||||
dfref dataDF = newfreedatafolder()
|
||||
setdatafolder dataDF
|
||||
LoadWave /t/p=pearl_explorer_filepath/q filename
|
||||
|
@ -90,6 +90,40 @@ threadsafe function MultiGaussLinBG_AO(pw, yw, xw) : FitFunc
|
||||
endfor
|
||||
end
|
||||
|
||||
/// doublet gaussian peaks on a linear background fit function (all at once).
|
||||
///
|
||||
/// this fits two gaussian peaks.
|
||||
/// peak positions are specified by center and distance rather than individually.
|
||||
/// amplitude and width are specified as absolute values for the upper peak (in x),
|
||||
/// and relative values for the lower peak.
|
||||
///
|
||||
/// @note FWHM = width * 2 * sqrt(ln(2)) = width * 1.665
|
||||
///
|
||||
/// @param pw shape parameters.
|
||||
/// the length of the wave defines the number of peaks.
|
||||
/// @arg pw[0] = constant coefficient of background
|
||||
/// @arg pw[1] = linear coefficient of background
|
||||
/// @arg pw[2] = amplitude of peak 1 (higher x)
|
||||
/// @arg pw[3] = amplitude of peak 2 relative to peak 1
|
||||
/// @arg pw[4] = center position
|
||||
/// @arg pw[5] = distance between peaks (splitting)
|
||||
/// @arg pw[6] = width of peak 1 (see note)
|
||||
/// @arg pw[7] = width of peak 2 relative to peak 1
|
||||
///
|
||||
/// @param yw y (dependent) values.
|
||||
///
|
||||
/// @param xw x (independent) independent values.
|
||||
///
|
||||
threadsafe function DoubletGaussLinBG_AO(pw, yw, xw) : FitFunc
|
||||
wave pw
|
||||
wave yw
|
||||
wave xw
|
||||
|
||||
yw = pw[0] + xw[p] * pw[1]
|
||||
yw += pw[2] * exp( -( (xw[p] - pw[4] - pw[5] /2) / pw[6] )^2 )
|
||||
yw += pw[2] * pw[3] * exp( -( (xw[p] - pw[4] + pw[5] /2) / pw[6] / pw[7] )^2 )
|
||||
end
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Voigt shapes
|
||||
//------------------------------------------------------------------------------
|
||||
@ -581,7 +615,7 @@ function Au4f(w, x): fitfunc
|
||||
// otherwise only the constant background.
|
||||
variable x
|
||||
|
||||
variable np = 15
|
||||
variable np = numpnts(w)
|
||||
variable ip, ip0
|
||||
|
||||
variable bg = w[0]
|
||||
|
Loading…
x
Reference in New Issue
Block a user