distro release 2.1.1

This commit is contained in:
2020-06-09 12:31:05 +02:00
parent b7390cb46f
commit ef9d08e5f5
168 changed files with 3286 additions and 1205 deletions

View File

@ -1,11 +1,11 @@
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
#pragma version = 1.7
#pragma version = 1.8
#pragma IgorVersion = 6.2
#pragma ModuleName = PearlAnglescanPanel
#include "pearl-anglescan-process"
#include "pearl-pmsco-import"
// copyright (c) 2018 Paul Scherrer Institut
// copyright (c) 2018-20 Paul Scherrer Institut
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -29,7 +29,7 @@
///
/// @author matthias muntwiler, matthias.muntwiler@psi.ch
///
/// @copyright 2018 Paul Scherrer Institut @n
/// @copyright 2018-20 Paul Scherrer Institut @n
/// Licensed under the Apache License, Version 2.0 (the "License"); @n
/// you may not use this file except in compliance with the License. @n
/// You may obtain a copy of the License at
@ -45,8 +45,6 @@
static strconstant package_name = "pearl_anglescan_panel"
/// data folder path
static strconstant package_path = "root:packages:pearl_anglescan_panel:"
/// semicolon-separated list of persistent variable, string, and wave names
static strconstant prefs_objects = "theta_offset;tilt_offset;phi_offset;alpha_offset;crop_alpha_enable;crop_alpha_value;norm_alpha_enable;norm_alpha_mode;norm_alpha_smoothing;norm_phi_enable;norm_phi_mode;norm_phi_thetarange;norm_theta_enable;norm_theta_mode;norm_theta_smoothing;norm_thetaphi_enable;norm_thetaphi_mode;norm_theta_smoothing;output_folding;output_horizon;graph_mode;graph_projection;graph_colortable;graph_contrast;"
/// initialize package data once when the procedure is first loaded
static function AfterCompiledHook()
@ -82,19 +80,26 @@ static function init_package()
// configuration (persistent)
string /g graphname = "graph_anglescan_panel"
string /g prefs_objects = "prefs_objects;theta_offset;tilt_offset;phi_offset;alpha_offset;crop_enable;crop_alpha;crop_theta;"
prefs_objects += "norm_alpha_enable;norm_alpha_mode;norm_alpha_smoothing;norm_phi_enable;norm_phi_mode;norm_phi_thetarange;"
prefs_objects += "norm_theta_enable;norm_theta_mode;norm_theta_domain;norm_theta_smoothing;norm_thetaphi_enable;norm_thetaphi_mode;norm_thetaphi_smoothing;"
prefs_objects += "output_folding;output_horizon;graph_mode;graph_projection;graph_colortable;graph_contrast;"
// recently used (persistent)
variable /g theta_offset = 0
variable /g tilt_offset = 0
variable /g phi_offset = 0
variable /g alpha_offset = 0
variable /g crop_alpha_enable = 0
variable /g crop_alpha_value = 25
variable /g crop_enable = 0
variable /g crop_alpha = 25
variable /g crop_theta = 88
string /g crop_rows = ""
variable /g norm_alpha_enable = 0
variable /g norm_alpha_mode = 4
variable /g norm_alpha_smoothing = 0.25
variable /g norm_theta_enable = 0
variable /g norm_theta_mode = 4
variable /g norm_theta_domain = 0
variable /g norm_theta_smoothing = 0.25
variable /g norm_thetaphi_enable = 0
variable /g norm_thetaphi_mode = 4
@ -136,6 +141,8 @@ end
///
static function save_prefs()
dfref saveDF = GetDataFolderDFR()
dfref df = $(package_path)
svar /sdfr=df prefs_objects
string fullPath = SpecialDirPath("Packages", 0, 0, 0)
fullPath += package_name
@ -337,7 +344,7 @@ static function do_init_process(check)
setscale /p x dimoffset(raw, 0) - alpha_offset, dimdelta(raw, 0), waveunits(raw, 0), process_data
end
/// alpha-crop the process data.
/// crop the process data.
///
/// @param[in] check select which output to generate (currently not used).
/// @arg 0 (default) process data, don't calculate check waves.
@ -348,7 +355,7 @@ end
/// @arg 0 (default) apply this filter only if its global enable flag is set.
/// @arg 1 apply this filter even if it is not enabled.
///
static function do_crop_alpha(check, [force])
static function do_crop(check, [force])
variable check
variable force
@ -358,14 +365,80 @@ static function do_crop_alpha(check, [force])
dfref df = $(package_path)
wave /sdfr=df process_data
nvar /sdfr=df crop_alpha_enable
nvar /sdfr=df crop_alpha_value
wave /sdfr=df process_theta
wave /sdfr=df process_tilt
wave /sdfr=df process_phi
nvar /sdfr=df crop_enable
nvar /sdfr=df crop_alpha
nvar /sdfr=df crop_theta
svar /sdfr=df crop_rows
if ((force || crop_alpha_enable) && (crop_alpha_value > abs(dimdelta(process_data, 0))))
crop_strip(process_data, -crop_alpha_value, +crop_alpha_value)
if (force || crop_enable)
if (crop_alpha > abs(dimdelta(process_data, 0)))
crop_strip(process_data, -crop_alpha, +crop_alpha)
endif
if ((crop_theta >= 10) && (crop_theta < 90))
crop_strip_theta(process_data, 0, crop_theta, process_theta, process_tilt, process_phi)
endif
if (strlen(crop_rows) > 0)
delete_rows(crop_rows, process_data, process_theta, process_tilt, process_phi)
endif
endif
end
/// delete individual rows from the data strip
///
/// @param[in] rows comma-separated list of row indices or ranges.
/// ranges are specified by joining the start and end index with a hyphen, e.g. 24-46.
/// the list does not need to be ordered.
/// @param[in,out] data 2D data
/// the original wave is modified.
/// @param[in,out] theta theta positions along Y dimension of data.
/// the original wave is modified.
/// @param[in,out] tilt tilt positions along Y dimension of data
/// the original wave is modified.
/// @param[in,out] phi phi positions along Y dimension of data
/// the original wave is modified.
///
static function delete_rows(rows, data, theta, tilt, phi)
string rows
wave data
wave theta
wave tilt
wave phi
make /n=(numpnts(theta)) /i /free idx
idx = p
variable nrows = ItemsInList(rows, ",")
variable irow
string srow
variable q1, q2
for (irow = 0; irow < nrows; irow += 1)
srow = StringFromList(irow, rows, ",")
q1 = str2num(StringFromList(0, srow, "-"))
q2 = str2num(StringFromList(1, srow, "-"))
if (numtype(q2))
q2 = q1
endif
if (q1 <= q2)
idx[q1,q2] = -1
endif
endfor
extract /free idx, idx, idx >= 0
variable nx = dimsize(data, 0)
variable ny = numpnts(idx)
theta = theta[idx]
tilt = tilt[idx]
phi = phi[idx]
redimension /n=(ny) theta, tilt, phi
duplicate /free data, data_copy
redimension /n=(nx,ny) data
data = data_copy[p][idx[q]]
end
/// alpha-normalize the process data.
///
/// @param[in] check select which output to generate.
@ -475,12 +548,17 @@ static function do_norm_theta(check, [force])
wave /sdfr=df process_theta
nvar /sdfr=df norm_theta_enable
nvar /sdfr=df norm_theta_mode
nvar /sdfr=df norm_theta_domain
nvar /sdfr=df norm_theta_smoothing
if (force || norm_theta_enable)
dfref temp_df = newfreedatafolder()
setdatafolder temp_df
normalize_strip_theta(process_data, process_theta, smooth_method=norm_theta_mode, smooth_factor=norm_theta_smoothing, check=check)
if (norm_theta_domain==1)
normalize_strip_theta_scans(process_data, process_theta, smooth_method=norm_theta_mode, smooth_factor=norm_theta_smoothing, check=check)
else
normalize_strip_theta(process_data, process_theta, smooth_method=norm_theta_mode, smooth_factor=norm_theta_smoothing, check=check)
endif
if (check)
wave check_dist
wave check_smoo
@ -554,7 +632,7 @@ function asp_calculate_output()
nvar horizon=output_horizon
do_init_process(0)
do_crop_alpha(0)
do_crop(0)
do_norm_alpha(0)
do_norm_phi(0)
do_norm_theta(0)
@ -757,62 +835,62 @@ end
static function check_norm_alpha()
do_init_process(0)
do_crop_alpha(0)
do_crop(0)
do_norm_alpha(2, force=1)
asp_display_dist_check(1, 0)
end
static function check_norm_phi()
do_init_process(0)
do_crop_alpha(0)
do_crop(0)
do_norm_phi(2, force=1)
asp_display_dist_check(0, 1)
end
static function check_norm_theta()
do_init_process(0)
do_crop_alpha(0)
do_crop(0)
do_norm_theta(2, force=1)
asp_display_dist_check(0, 1)
end
static function check_norm_thetaphi()
do_init_process(0)
do_crop_alpha(0)
do_crop(0)
do_norm_thetaphi(2, force=1)
asp_display_dist_check(0, 1)
end
static function preview_crop_alpha()
static function preview_crop()
do_init_process(0)
do_crop_alpha(0, force=1)
do_crop(0, force=1)
asp_display_previews()
end
static function preview_norm_alpha()
do_init_process(0)
do_crop_alpha(0)
do_crop(0)
do_norm_alpha(1, force=1)
asp_display_previews()
end
static function preview_norm_phi()
do_init_process(0)
do_crop_alpha(0)
do_crop(0)
do_norm_phi(1, force=1)
asp_display_previews()
end
static function preview_norm_theta()
do_init_process(0)
do_crop_alpha(0)
do_crop(0)
do_norm_theta(1, force=1)
asp_display_previews()
end
static function preview_norm_thetaphi()
do_init_process(0)
do_crop_alpha(0)
do_crop(0)
do_norm_thetaphi(1, force=1)
asp_display_previews()
end
@ -828,7 +906,7 @@ function asp_show_panel()
return 0
endif
NewPanel /K=1 /N=anglescan_panel /W=(200,100,479,854) as "angle scan processing"
NewPanel /K=1 /N=anglescan_panel /W=(200,50,480,874) as "angle scan processing"
panel_name = s_name
GroupBox gb_source, title="data source"
@ -857,15 +935,21 @@ function asp_show_panel()
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"
CheckBox cb_crop_alpha_enable, help={"enable cropping at +/- alpha"}
CheckBox cb_crop_alpha_enable,variable= root:packages:pearl_anglescan_panel:crop_alpha_enable
SetVariable sv_crop_alpha_value, size={90,16},bodyWidth=60,title="angle"
SetVariable sv_crop_alpha_value,limits={0,30,1},value= root:packages:pearl_anglescan_panel:crop_alpha_value
SetVariable sv_crop_alpha_value, help={"alpha (detection angle) cropping angle"}
Button b_crop_alpha_preview, size={80,20},proc=PearlAnglescanPanel#bp_crop_alpha_preview,title="preview"
Button b_crop_alpha_preview, help={"show a preview of the cropped dataset."}
GroupBox gb_crop, title="crop and delete"
CheckBox cb_crop_enable, size={50,14}, title="enable"
CheckBox cb_crop_enable, help={"crop at +/-alpha and +theta, delete arbitrary rows"}
CheckBox cb_crop_enable, variable= root:packages:pearl_anglescan_panel:crop_enable
SetVariable sv_crop_alpha, size={90,16},bodyWidth=60,title="alpha"
SetVariable sv_crop_alpha, limits={0,30,1},value= root:packages:pearl_anglescan_panel:crop_alpha
SetVariable sv_crop_alpha, help={"alpha (detection angle) cropping angle (positive boundary), relative to normal emission"}
SetVariable sv_crop_theta, size={90,16},bodyWidth=60,title="theta"
SetVariable sv_crop_theta, limits={10,90,1},value= root:packages:pearl_anglescan_panel:crop_theta
SetVariable sv_crop_theta, help={"theta (polar angle) upper limit, relative to normal emission"}
SetVariable sv_crop_rows, size={200,16},bodyWidth=160,title="rows"
SetVariable sv_crop_rows, limits={10,90,1},value= root:packages:pearl_anglescan_panel:crop_rows
SetVariable sv_crop_rows, help={"rows to delete from the raw data. comma-separated point indices, hyphen for range."}
Button b_crop_preview, size={80,20},proc=PearlAnglescanPanel#bp_crop_preview,title="preview"
Button b_crop_preview, help={"show a preview of the cropped dataset."}
GroupBox gb_norm_alpha, title="normalize alpha"
CheckBox cb_norm_alpha_enable, size={50,14}, title="enable"
@ -898,6 +982,9 @@ function asp_show_panel()
CheckBox cb_norm_theta_enable, size={50,14},title="enable"
CheckBox cb_norm_theta_enable, variable= root:packages:pearl_anglescan_panel:norm_theta_enable
CheckBox cb_norm_theta_enable, help={"enable normalization of the theta distribution (integrated over phi)"}
PopupMenu pm_norm_theta_domain, size={138,21}, bodyWidth=100, proc=PearlAnglescanPanel#pmp_norm_theta_domain, title="domain"
PopupMenu pm_norm_theta_domain, mode=5, popvalue="loess", value= #"\"global;scans;\""
PopupMenu pm_norm_theta_domain, help={"smoothing domain: global or individual scans. use global unless there is a stronga or irregular phi variation."}
PopupMenu pm_norm_theta_mode, size={138,21},bodyWidth=100,proc=PearlAnglescanPanel#pmp_norm_theta_mode,title="method"
PopupMenu pm_norm_theta_mode,mode=5,popvalue="loess",value= #"\"none;binomial;boxcar;polynomial;loess;\""
PopupMenu pm_norm_theta_mode, help={"theta normalization method. recommended: loess"}
@ -1014,15 +1101,19 @@ static function arrange_controls()
GroupBox gb_offsets, size={272,gb_ht}
gb_top += gb_ht + gb_space
GroupBox gb_crop_alpha,pos={4,gb_top}
GroupBox gb_crop,pos={4,gb_top}
gb_ht = gb_internal_top
CheckBox cb_crop_alpha_enable,pos={73, gb_top + gb_ht + cb_adj},size={50,14}
CheckBox cb_crop_enable,pos={73, gb_top + gb_ht + cb_adj},size={50,14}
gb_ht += line_space
SetVariable sv_crop_alpha_value,pos={44, gb_top + gb_ht + sv_adj},size={90,16}
Button b_crop_alpha_preview,pos={186, gb_top + gb_ht + b_adj},size={80,20}
SetVariable sv_crop_alpha, pos={44, gb_top + gb_ht + sv_adj}, size={90,16}
Button b_crop_preview,pos={186, gb_top + gb_ht + b_adj},size={80,20}
gb_ht += line_space
SetVariable sv_crop_theta, pos={44, gb_top + gb_ht + sv_adj}, size={90,16}
gb_ht += line_space
SetVariable sv_crop_rows, pos={44, gb_top + gb_ht + sv_adj}, size={190,16}
gb_ht += line_space
gb_ht += gb_internal_bot
GroupBox gb_crop_alpha, size={272,gb_ht}
GroupBox gb_crop, size={272,gb_ht}
gb_top += gb_ht + gb_space
GroupBox gb_norm_alpha,pos={4,gb_top}
@ -1055,12 +1146,14 @@ static function arrange_controls()
gb_ht = gb_internal_top
CheckBox cb_norm_theta_enable,pos={73, gb_top + gb_ht + cb_adj},size={50,14}
gb_ht += line_space
PopupMenu pm_norm_theta_mode,pos={35, gb_top + gb_ht + pm_adj},size={138,21}
PopupMenu pm_norm_theta_domain, pos={35, gb_top + gb_ht + pm_adj}, size={138,21}
Button b_norm_theta_check,pos={186, gb_top + gb_ht + b_adj},size={80,20}
gb_ht += line_space
SetVariable sv_norm_theta_smoothing,pos={21, gb_top + gb_ht + sv_adj},size={112,16}
PopupMenu pm_norm_theta_mode,pos={35, gb_top + gb_ht + pm_adj},size={138,21}
Button b_norm_theta_preview,pos={186, gb_top + gb_ht + b_adj},size={80,20}
gb_ht += line_space
SetVariable sv_norm_theta_smoothing,pos={21, gb_top + gb_ht + sv_adj},size={112,16}
gb_ht += line_space
gb_ht += gb_internal_bot
GroupBox gb_norm_theta, size={272,gb_ht}
@ -1122,6 +1215,9 @@ static function update_menus()
nvar /sdfr=df norm_alpha_mode
m = norm_alpha_mode + 1
PopupMenu pm_norm_alpha_mode win=$panel_name, mode=m
nvar /sdfr=df norm_theta_domain
m = norm_theta_domain + 1
PopupMenu pm_norm_theta_domain win=$panel_name, mode=m
nvar /sdfr=df norm_theta_mode
m = norm_theta_mode + 1
PopupMenu pm_norm_theta_mode win=$panel_name, mode=m
@ -1271,12 +1367,12 @@ static function bp_norm_thetaphi_check(ba) : ButtonControl
return 0
End
static function bp_crop_alpha_preview(ba) : ButtonControl
static function bp_crop_preview(ba) : ButtonControl
STRUCT WMButtonAction &ba
switch( ba.eventCode )
case 2: // mouse up
preview_crop_alpha()
preview_crop()
break
case -1: // control being killed
break
@ -1462,6 +1558,22 @@ static function pmp_norm_alpha_mode(pa) : PopupMenuControl
return 0
End
static function pmp_norm_theta_domain(pa) : PopupMenuControl
STRUCT WMPopupAction &pa
switch( pa.eventCode )
case 2: // mouse up
dfref df = $(package_path)
nvar /sdfr=df norm_theta_domain
norm_theta_domain = pa.popNum - 1
break
case -1: // control being killed
break
endswitch
return 0
End
static function pmp_norm_theta_mode(pa) : PopupMenuControl
STRUCT WMPopupAction &pa

View File

@ -515,6 +515,88 @@ function normalize_strip_thetaphi(strip, theta, phi, [theta_offset, smooth_metho
endif
end
/// divide the strip piecewise by a smooth polar distribution.
///
/// @warning experimental. this function is under development.
///
///
function normalize_strip_theta_scans(strip, theta, [theta_offset, smooth_method, smooth_factor, check])
wave strip
wave theta
variable theta_offset
variable smooth_method
variable smooth_factor
variable check
if (ParamIsDefault(check))
check = 0
endif
if (ParamIsDefault(theta_offset))
theta_offset = 0
endif
if (ParamIsDefault(smooth_method))
smooth_method = 4
endif
if (ParamIsDefault(smooth_factor))
smooth_factor = 0.5
endif
// average over analyser angles
wave dist = ad_profile_y(strip, -inf, inf, "")
// smooth distribution function
duplicate /free dist, dist_smoo
duplicate /free theta, theta_int
theta_int = theta - theta_offset
setscale /p x theta_int[0], theta_int[1] - theta_int[0], waveunits(theta,-1), dist, dist_smoo
// analyse scanning scheme
duplicate /free theta_int, d1_theta, d2_theta
Differentiate /METH=2 theta_int /D=d1_theta
Differentiate /METH=2 d1_theta /D=d2_theta
d2_theta = abs(d2_theta)
make /free w_levels
FindLevels /edge=1 /p /q /d=w_levels d2_theta, 0.1
if (v_flag != 1)
abort "unrecognized scanning scheme"
endif
w_levels = ceil(w_levels)
InsertPoints 0, 1, w_levels
w_levels[0] = 0
InsertPoints numpnts(w_levels), 1, w_levels
w_levels[numpnts(w_levels)-1] = numpnts(theta_int)
variable n_scans = numpnts(w_levels) - 1
variable i_scan
variable p1, p2
for (i_scan = 0; i_scan < n_scans; i_scan += 1)
p1 = w_levels[i_scan]
p2 = w_levels[i_scan+1] - 1
duplicate /free /r=[p1, p2] dist, dist_piece, smooth_piece
duplicate /free /r=[p1, p2] theta_int, theta_piece
switch(smooth_method)
case 4:
loess /dest=smooth_piece /smth=(smooth_factor) srcWave=dist_piece, factors={theta_piece}
break
default:
abort "smooth method not supported"
endswitch
dist_smoo[p1, p2] = smooth_piece[p - p1]
endfor
// divide
if (check != 2)
strip /= dist_smoo[q]
endif
// check
if (check)
duplicate /o dist, check_dist
duplicate /o dist_smoo, check_smoo
setscale /p x dimoffset(dist,0), dimdelta(dist,0), waveunits(dist,0), check_dist, check_smoo
endif
end
/// divide the strip by a two-dimensional normalization function.
///
/// @warning experimental. this function is under development.
@ -606,6 +688,42 @@ function crop_strip(strip, xlo, xhi)
setscale /i x xlo, xhi, waveunits(strip, 0), strip
end
/// crop a strip in theta.
///
/// the strip is cropped in place, data outside the region of interest is lost.
///
/// @param[in,out] strip 2D data, X-axis = analyser angle, Y-axis = arbitrary manipulator scan
/// @param[in] ylo lowest polar angle to keep (will be rounded to nearest existing point)
/// @param[in] yhi highest polar angle to keep (will be rounded to nearest existing point)
/// @param[in,out] theta polar angle along the Y dimension of strip.
/// this wave is modified: cropped rows are deleted.
/// @param[in,out] tilt tilt angle along the Y dimension of strip.
/// this wave is modified: cropped rows are deleted.
/// @param[in,out] phi azimuthal angle along the Y dimension of strip.
/// this wave is modified: cropped rows are deleted.
///
function crop_strip_theta(strip, theta_lo, theta_hi, theta, tilt, phi)
wave strip
variable theta_lo
variable theta_hi
wave theta
wave tilt
wave phi
extract /indx /free theta, idx, (theta >= theta_lo) && (theta <= theta_hi)
variable nx = dimsize(strip, 0)
variable ny = numpnts(idx)
theta = theta[idx]
tilt = tilt[idx]
phi = phi[idx]
redimension /n=(ny) theta, tilt, phi
duplicate /free strip, strip_copy
redimension /n=(nx,ny) strip
strip = strip_copy[p][idx[q]]
end
/// create a pizza plot from a measured (energy-integrated) data strip
///
/// accepts angle-scan data as returned by adh5_load_reduced(),
@ -3198,3 +3316,37 @@ function set_contrast(pcmin, pcmax, [graphname, colortable])
setdatafolder save_df
end
/// k-space mapping of 2D angle-energy distribution (scienta image)
///
/// courtesy of F. Matsui
///
/// @param inwave 2D wave, x = kinetic energy (eV), y = polar angle (deg)
/// note: the kinetic energy is with reference to the vacuum level at the sample.
/// if the work functions of the analyser and the sample differ:
/// Ekin,sample = Ekin,analyser + WFanalyser - WFsample
/// where WFanalyser = Ephot - EFermi
///
/// @return the output wave has the name of the input wave with the suffix "_k".
///
Function AngleToK(inwave)
Wave inwave
String newname = NameofWave(inwave)+"_k"
Duplicate/O inwave, $newname
Wave outwave = $newname
Variable rows,columns,xdelta,xoffset,ydelta,yoffset,kmin,kmax,Emax
// inwave parameters
rows = DimSize(inwave,0)
columns = DimSize(inwave,1)
xdelta = DimDelta(inwave,0)
xoffset = DimOffset(inwave,0)
ydelta = DimDelta(inwave,1)
yoffset = DimOffset(inwave,1)
Emax= xoffset + xdelta*(rows-1)
kmin = 0.5123*sqrt(Emax)*sin(pi/180*(yoffset)) // calculate the k boundaries
kmax = 0.5123*sqrt(Emax)*sin(pi/180*(yoffset+(columns-1)*ydelta))
SetScale/I y kmin,kmax,"Ang^-1", outwave
// scale the y axis
outwave = interp2D(inwave, x, 180/pi*asin(y/ (0.5123*sqrt(x)))) // recalculate to k
outwave = (NumType(outwave)==2) ? 0 : outwave // replace NaNs (optional)
End

View File

@ -805,8 +805,13 @@ end
static function epics_disconnect()
dfref savedf = GetDataFolderDFR()
setdatafolder $(package_path)
if (DataFolderExists(package_path))
SetDataFolder $(package_path)
else
return nan
endif
nvar connected
if (connected)
connected = 0

View File

@ -314,6 +314,59 @@ function /s ad_display_profiles(image, [filter])
return graphname
end
/// add an overlay on top of the displayed image
///
/// the function creates the overlay wave and returns it as function result.
/// the name of the wave is "view_overlay" and is created in the same folder as the "view_image" wave.
///
/// @param image image wave that identifies the profiles window.
///
/// @return overlay overlay wave.
/// same dimensions and scales as image, but unsigned binary.
/// pixels that are 0 are overlaid with semi-transparent color.
/// other pixels should be 64 (igor's mask convention).
///
function /wave ad_add_overlay(image, [rgba])
wave image
string rgba
if (ParamIsDefault(rgba))
rgba = "65535,65532,16385,32767"
elseif (ItemsInList(rgba, ",") == 3)
rgba += ",32767"
endif
dfref savedf = GetDataFolderDFR()
wave view_image = get_view_image(image)
dfref viewdf = GetWavesDataFolderDFR(view_image)
svar /sdfr=viewdf graphname = prof_graphname
setdatafolder viewdf
string overlayname = "view_overlay"
duplicate /o image, $overlayname /wave=overlay
redimension /b/u overlay
overlay = 64
string imagenames = ImageNameList(graphname, ";")
if (whichlistItem(overlayname, imagenames, ";") < 0)
AppendImage /w=$graphname $overlayname
rgba = replacestring("(", rgba, "")
rgba = replacestring(")", rgba, "")
variable rr = str2num(StringFromList(0, rgba, ","))
variable gg = str2num(StringFromList(1, rgba, ","))
variable bb = str2num(StringFromList(2, rgba, ","))
variable aa = str2num(StringFromList(3, rgba, ","))
#if IgorVersion() >= 8
ModifyImage /w=$graphname $overlayname explicit=1,eval={0,rr,gg,bb,aa},eval={255,-1,-1,-1}
#else
ModifyImage /w=$graphname $overlayname explicit=1,eval={0,rr,gg,bb},eval={255,-1,-1,-1}
#endif
endif
setdatafolder savedf
return overlay
end
/// update a profiles graph with new data.
///
/// @param image wave which contains the image data.
@ -333,7 +386,12 @@ function ad_update_profiles(image)
// data structures
string viewname = "view_image"
duplicate /o image, $viewname /wave=view
string overlayname = "view_overlay"
wave /z overlay = $overlayname
if (waveexists(overlay))
redimension /n=(dimsize(view,0), dimsize(view,1)) overlay
endif
// data processing
svar view_filter
svar view_filter_options

View File

@ -18,6 +18,7 @@
#include "pearl-epics" // EPICS access under Igor
#include "pearl-arpes-scans" // run ARPES scans under Igor
#include "pearl-sample-tracker" // live tracking and adjustment of sample position
#include "pearl-scienta-countrate"
#endif
/// @file

View File

@ -94,24 +94,25 @@ static function init_package()
SetDataFolder savefolder
end
/// save persistent package data to the preferences file.
///
/// this function is called when the user clicks the corresponding button.
/// the data saved in the file are: data file path, attributes filter
///
static function save_prefs()
// saves persistent package data to the preferences file
// the data saved in the file are: data file path, attributes filter
dfref saveDF = GetDataFolderDFR()
string fullPath = SpecialDirPath("Packages", 0, 0, 0)
fullPath += package_name
NewPath/O/C/Q tempPackagePrefsPath, fullPath
fullPath += ":preferences.pxp"
SetDataFolder root:packages
SetDataFolder $package_name
string objects = "attr_filter;attr_filter_summary;s_filepath;s_hdf_options;s_reduction_params;s_preview_pvs"
SaveData /O /Q /J=objects fullPath
KillPath/Z tempPackagePrefsPath
SetDataFolder saveDF
dfref df = $package_path
if (DataFolderRefStatus(df) == 1)
string fullPath = SpecialDirPath("Packages", 0, 0, 0)
fullPath += package_name
NewPath/O/C/Q tempPackagePrefsPath, fullPath
fullPath += ":preferences.pxp"
SetDataFolder df
string objects = "attr_filter;attr_filter_summary;s_filepath;s_hdf_options;s_reduction_params;s_preview_pvs"
SaveData /O /Q /J=objects fullPath
KillPath/Z tempPackagePrefsPath
endif
SetDataFolder saveDF
end
static function load_prefs()

View File

@ -272,14 +272,14 @@ function elog_init_pearl_templates()
// attributes (persistent)
// available attributes
string /g attributes = "author;project;sample;source;task;technique;file;valid;"
string /g attributes = "author;project;p-group;sample;source;task;technique;file;valid;"
// controls corresponding to attributes
// prefix determines the control type: sv_ = setvariable (string), pm_ = popup menu, cb = check box
string /g controls = "sv_author;sv_project;sv_sample;pm_source;pm_task;pm_technique;sv_file;cb_valid;"
string /g controls = "sv_author;sv_project;sv_pgroup;sv_sample;pm_source;pm_task;pm_technique;sv_file;cb_valid;"
// attributes with fixed options, value item declares the options string
string /g options = "source=sources;task=tasks;technique=techniques"
// attributes which must be defined
string /g required_attributes = "author;project;sample;source;task;technique;valid"
string /g required_attributes = "author;project;p-group;sample;source;task;technique;valid"
// option lists
string /g sources = "Manual Entry;PShell;Scienta Data;SScan Data;Prosilica Data;OTF Data;Beamline Status;LEED Data;QMS Data;Matrix Data;Igor Pro;Other"
@ -292,10 +292,10 @@ function elog_init_pearl_templates()
// attributes (persistent)
// available attributes
string /g attributes = "author;project;sample;program;revision;machine;job;experiment;source path;result path;valid"
string /g attributes = "author;project;p-group;sample;program;revision;machine;job;experiment;source path;result path;valid"
// controls corresponding to attributes
// prefix determines the control type: sv_ = setvariable (string), pm_ = popup menu, cb = check box
string /g controls = "sv_author;sv_project;sv_sample;pm_program;sv_revision;pm_machine;sv_job;sv_experiment;sv_sourcepath;sv_resultpath;cb_valid"
string /g controls = "sv_author;sv_project;sv_pgroup;sv_sample;pm_program;sv_revision;pm_machine;sv_job;sv_experiment;sv_sourcepath;sv_resultpath;cb_valid"
// attributes with fixed options, value item declares the options string
string /g options = "program=programs;machine=machines"
// attributes which must be defined
@ -322,7 +322,7 @@ function elog_init_pearl_templates()
// option lists
string /g types = "Installation;Repair;Maintenance;Test;Commissioning;Bakeout;Incident;Cool-down;Warm-up;Storage;Other"
string /g systems = "Vacuum;Control System;BL;XA;XP;SA;SP;T;LL;Monochromator;Carving;Scienta;STM;PC-Scienta;PC-Matrix;PC-Console;PC-Console-Win;PC-XP;EPS;LAC;Desiccator"
string /g systems = "Vacuum;Control System;BL;XA;XP;SA;SP;T;LL;Monochromator;Carving;Scienta;STM;PC-Scienta;PC-Matrix;PC-Console;PC-Console-Win;PC-XP;EPS;LAC;Desiccator;Other"
string /g sources = "Manual Entry;PShell;Scienta Data;SScan Data;Prosilica Data;OTF Data;Beamline Status;LEED Data;QMS Data;Matrix Data;Igor Pro;Other"
setdatafolder savedf
@ -1298,7 +1298,8 @@ function /s PearlElogPanel(logbook)
break
endswitch
endfor
ypos = max(ypos, 80)
TitleBox t_attach, win=$win_name, pos={308,5}, size={70,14}, title="Attachments", frame=0
height = ypos - 21 - 4
ListBox lb_attach, win=$win_name, pos={308,21}, size={264,height}
@ -1819,6 +1820,12 @@ static function /s set_panel_attributes(windowname, attributes, [clear])
endif
string path
string logbook = GetUserData(windowname, "", "logbook")
dfref df_persistent = get_elog_df(logbook, kdfPersistent)
string persistent_path = GetDataFolder(1, df_persistent)
svar /sdfr=df_persistent options
string options_path
string controls = ControlNameList(windowname, ";")
string control
@ -1845,7 +1852,12 @@ static function /s set_panel_attributes(windowname, attributes, [clear])
endif
break
case 3: // popupmenu
PopupMenu $control, popvalue=value, win=$windowname
options_path = persistent_path + StringByKey(attribute, options, "=", ";")
svar values = $options_path
numval = WhichListItem(value, values, ";") + 1
if (numval >= 1)
PopupMenu $control, mode=numval, win=$windowname
endif
break
case 5: // setvariable
SetVariable /z $control, value= _STR:value, win=$windowname

View File

@ -893,3 +893,23 @@ function FermiGaussConv(pw, yw, xw) : FitFunc
yw = pw[2] * resultwave(xw[p] - pw[3]) + pw[0] + pw[1] * xw[p]
end
/// calculate the shirley background
///
///
function ShirleyBG(w, bg, p1, p2)
wave w
wave bg
variable p1, p2
duplicate /o w, bg
integrate /meth=1 w /d=bg
variable bg1 = bg[p1]
variable bg2 = bg[p2]
bg -= bg1
bg /= bg2 - bg1
bg *= w[p2] - w[p1]
bg += w[p1]
end

View File

@ -36,12 +36,14 @@ menu "PEARL"
help = {"Display preview panel with latest image from Scienta", "Requires ARPES package and EPICS XOP"}
PearlMenuEnableFunc("ast_setup") + "Angle Scan Tracker", /Q, PearlAnglescanTracker("X03DA-SCIENTA:", "(65280,54528,48896)")
help = {"Preview of acquired angle scan data and current detection angles.", "Requires ARPES package and EPICS XOP"}
PearlMenuEnableFunc("sample_tracker") + "Sample Tracker", /Q, PearlSampleTracker(1)
help = {"Live tracking and adjustment of sample position.", "Requires ARPES package and EPICS XOP"}
end
submenu "Cameras"
PearlMenuEnableFunc("ad_display_profiles") + "Exit Slit Live View", /Q, PearlLiveDisplay("X03DA-OP-PS1:", "OP", "(65280,54528,48896)")
PearlMenuEnableFunc("ad_display_profiles") + "Exit Slit Camera", /Q, PearlLiveDisplay("X03DA-OP-PS1:", "OP", "(65280,54528,48896)")
help = {"Display preview panel with latest image from Scienta", "Requires ARPES package and EPICS XOP"}
PearlMenuEnableFunc("ad_display_profiles") + "Manipulator Live View", /Q, PearlLiveDisplay("X03DA-ES-PS1:", "ES", "(65280,54528,48896)")
PearlMenuEnableFunc("ad_display_profiles") + "Manipulator Camera", /Q, PearlCameraDisplay("X03DA-ES-PS1:", "ES", "(32767,32767,32767)")
help = {"Display live panel of the exit slit camera", "Requires ARPES package and EPICS XOP"}
end
@ -65,7 +67,7 @@ menu "PEARL"
end
submenu "Sample Preparation"
PearlMenuEnableFunc("ann_ramp_start") + "Annealing Ramp", /Q, panel_ramp_gen()
PearlMenuEnableFunc("ramp_generator") + "Annealing Ramp", /Q, ramp_generator()
help = {"Sample annealing ramp generator"}
end
@ -79,10 +81,12 @@ menu "PEARL"
end
end
/// check whether a function name exists
///
/// return a prefix which disables the menu item
/// if the function does not exist
///
function /s PearlMenuEnableFunc(funcname)
// checks whether a function name exists
// and conditionally returns a prefix which disables the menu item
// if the function does not exist
string funcname
if (exists(funcname) >= 3)
return ""
@ -94,7 +98,6 @@ end
function LoadPearlOptics()
execute /p/q/z "INSERTINCLUDE \"pearl-optics\""
execute /p/q/z "COMPILEPROCEDURES "
execute /p/q/z "PearlOpticsPanel#po_InitPanel()"
execute /p/q/z "BuildMenu \"PEARL\""
end
@ -165,33 +168,100 @@ function DisplayGizmoSlicer()
endif
end
/// area detector live display
///
/// display an area detector channel in an ad_display_profiles() window.
///
/// @param epicsname base name of the detector, e.g. X03DA-SCIENTA:
/// image1: and cam1: are appended by the function.
/// see ad_connect().
///
/// @param nickname nick name under which this detector is referred to in Igor.
/// must be a valid name for a data folder.
/// see ad_connect().
///
/// @param wbRGB window background color, e.g. "(32768,49152,55296)"
///
function PearlLiveDisplay(epicsname, nickname, wbRGB)
string epicsname // base name of the detector, e.g. X03DA-SCIENTA:
// image1: and cam1: are appended by the function
// see ad_connect
string nickname // nick name under which this detector is referred to in Igor
// must be a valid data folder name
// see ad_connect
string wbRGB // window background color, e.g. "(32768,49152,55296)"
string epicsname
string nickname
string wbRGB
string cmd
sprintf cmd, "ad_connect(\"%s\", \"%s\")", epicsname, nickname
execute /q/z cmd
sprintf cmd, "ad_display_profiles(root:pearl_epics:%s:image)", nickname
execute /q/z cmd
//sprintf cmd, "ad_add_overlay(root:pearl_epics:%s:image)", nickname
//execute /q/z cmd
sprintf cmd, "ModifyGraph wbRGB=%s", wbRGB
execute /q/z cmd
sprintf cmd, "add_roi_controls()"
execute /q/z cmd
end
/// area detector surveillance camera display
///
/// display an area detector channel in a simple image window
/// without any interactive controls.
///
/// @param epicsname base name of the detector, e.g. X03DA-SCIENTA:
/// image1: and cam1: are appended by the function.
/// see ad_connect().
///
/// @param nickname nick name under which this detector is referred to in Igor.
/// must be a valid name for a data folder.
/// see ad_connect().
///
/// @param wbRGB window background color, e.g. "(32768,49152,55296)"
///
function PearlCameraDisplay(epicsname, nickname, wbRGB)
string epicsname
string nickname
string wbRGB
string cmd
sprintf cmd, "ad_connect(\"%s\", \"%s\")", epicsname, nickname
execute /q/z cmd
sprintf cmd, "display; appendimage root:pearl_epics:%s:image", nickname
execute /q/z cmd
sprintf cmd, "ModifyGraph wbRGB=%s", wbRGB
execute /q/z cmd
cmd = "ModifyGraph height={Plan,1,left,bottom}"
execute /q/z cmd
end
/// display the angle scan tracker window
///
/// @param epicsname base name of the detector, e.g. X03DA-SCIENTA:
/// image1: and cam1: are appended by the function.
/// see ad_connect().
///
/// @param wbRGB window background color, e.g. "(32768,49152,55296)"
///
function PearlAnglescanTracker(epicsname, wbRGB)
string epicsname // base name of the detector, e.g. X03DA-SCIENTA:
// image1: and cam1: are appended by the function
// see ast_setup
string wbRGB // window background color, e.g. "(32768,49152,55296)"
string epicsname
string wbRGB
string cmd
sprintf cmd, "ast_setup()"
execute /q/z cmd
sprintf cmd, "ModifyGraph wbRGB=%s", wbRGB
execute /q/z cmd
end
/// display the sample tracker window
///
/// @param epicsname base name of the detector, e.g. X03DA-SCIENTA:
/// image1: and cam1: are appended by the function.
/// see ad_connect().
///
/// @param wbRGB window background color, e.g. "(32768,49152,55296)"
///
function PearlSampleTracker(action)
variable action
string cmd
sprintf cmd, "sample_tracker(%u)", action
execute /q/z cmd
end

View File

@ -0,0 +1,213 @@
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
#pragma IgorVersion = 6.35
#pragma ModuleName = PearlScientaCountrate
#include "pearl-area-display"
// Copyright (c) 2019 Paul Scherrer Institut
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
/// @file
/// @brief count rate functions for Scienta detector images.
/// @ingroup ArpesPackage
///
/// this procedure contains functions for working with true count rates.
///
/// @author matthias muntwiler, matthias.muntwiler@psi.ch
///
/// @copyright 2019 Paul Scherrer Institut @n
/// Licensed under the Apache License, Version 2.0 (the "License"); @n
/// you may not use this file except in compliance with the License. @n
/// You may obtain a copy of the License at
/// http://www.apache.org/licenses/LICENSE-2.0
/// @namespace PearlScientaCountrate
/// @brief count rate functions for Scienta detector images.
///
/// PearlScientaCountrate is declared in @ref pearl-scienta-countrate.ipf.
/// open live display of most recent scienta measurement
///
///
/// @param epicsname base name of the detector, e.g. X03DA-SCIENTA:
/// image1: and cam1: are appended by the function.
/// see @ref ad_connect.
/// @param nickname nick name under which this detector is referred to in Igor.
/// must be a valid data folder name.
/// see @ref ad_connect.
/// @param wbRGB window background color, e.g. "32768,49152,55296"
///
function ScientaLiveDisplay(epicsname, nickname, wbRGB)
string epicsname
string nickname
string wbRGB
ad_connect(epicsname, nickname)
string df_name
sprintf df_name, "ad_display_profiles(root:pearl_epics:%s)", nickname
dfref df = $df_name
wave /sdfr=df img = image
string graphname = ad_display(img)
wbRGB = replacestring("(", wbRGB, "")
wbRGB = replacestring(")", wbRGB, "")
variable rr = str2num(StringFromList(0, wbRGB, ","))
variable gg = str2num(StringFromList(1, wbRGB, ","))
variable bb = str2num(StringFromList(2, wbRGB, ","))
ModifyGraph /w=$graphname wbRGB=(rr,gg,bb)
add_roi_controls()
ad_add_overlay(img)
end
#if igorVersion() >= 8
/// check exposure and calculate overexposure indicator mask
///
/// calculate the local count rate density and return a mask
/// to indicate where the maximum count rate is exceeded.
/// the raw image is filtered by FFT with a gaussian kernel.
///
/// the raw image must have been acquired in fixed mode.
/// slicing and dwell time are accounted for.
///
/// all intermediate waves are created ad-hoc as free waves.
/// this function requires igor 8.
///
/// @param[i] image raw image from scienta in fixed mode.
///
/// @param[o] outmask mask wave.
/// must have same dimensions as image.
/// suggested data type /b/u.
/// the mask value in overexposed regions is 0,
/// in regular regions 64.
///
/// @param[i] dwelltime in seconds.
///
function check_exposure(image, outmask, dwelltime)
wave image
wave outmask
variable dwelltime
variable xbin = 1
variable ybin = 902 / dimsize(image, 1)
variable thresh = 1e5 / 900 / 900
duplicate /free image, filt
setscale /p x -dimsize(image, 0)/2, 1, "", filt // energy
setscale /p y -dimsize(image, 1)/2, 1, "", filt // angle
variable wx = sqrt(500) / xbin
variable wy = sqrt(500) / ybin
filt = exp(-((x/wx)^2 + (y/wy)^2))
variable nfilt = sum(filt)
filt /= nfilt
fft /free /dest=filt_fft filt
duplicate /free image, img
img /= dwelltime
setscale /p x -dimsize(image, 0)/2, 1, "", img
setscale /p y -dimsize(image, 1)/2, 1, "", img
fft /free /dest=img_fft img
img_fft *= filt_fft
ifft /free /dest=img_ifft img_fft
imagetransform swap img_ifft
outmask = (img_ifft < thresh) * 64
end
#endif
/// optimized check exposure and calculate overexposure indicator mask
///
/// calculate the local count rate density and return a mask
/// to indicate where the maximum count rate is exceeded.
/// the raw image is filtered by FFT with a gaussian kernel.
///
/// the raw image must have been acquired in fixed mode.
/// slicing and dwell time are accounted for.
///
/// this function does the same as check_exposure()
/// but keeps intermediate waves for time-optimized processing.
/// moreover it is compatible with igor 6.
///
/// @param[i] image raw image from scienta in fixed mode.
///
/// @param[o] outmask mask wave.
/// must have same dimensions as image.
/// suggested data type /b/u.
/// the mask value in overexposed regions is 0, in regular regions 64.
///
/// @param[i] dwelltime in seconds.
///
/// @param[i] calc_df (optional) data folder reference where intermediate and cached waves should be stored.
/// by default, the data folder is named "psc_" plus the name of the image wave
/// and inserted in the folder where the image wave is stored.
///
/// the possible gain can be estimated from the following test data:
/// - total execution time 510 ms
/// - gain from re-using (but recalculating) waves: 20 ms
/// - gain from re-using co_filt_fft: 220 ms
///
function check_exposure_opt(image, outmask, dwelltime, [calc_df])
wave image
wave outmask
variable dwelltime
dfref calc_df
variable xbin = 1
variable ybin = 902 / dimsize(image, 1)
variable thresh = 1e5 / 900 / 900
dfref save_df = GetDataFolderDFR()
if (ParamIsDefault(calc_df))
dfref source_df = GetWavesDataFolderDFR(image)
string calc_df_name = PearlCleanupName("psc_" + NameOfWave(image))
dfref calc_df = source_df:$calc_df_name
endif
NewDataFolder /o /s calc_df
wave /z co_filt
wave /z /c co_filt_fft
wave /z co_img
wave /z /c co_img_fft
wave /z co_img_ifft
nvar /z co_img_size_x
nvar /z co_img_size_y
variable cache = 0
if (waveexists(co_filt))
cache = (dimsize(image, 0) == co_img_size_x) && (dimsize(image, 1) == co_img_size_y)
if (!cache)
redimension /n=(dimsize(image, 0), dimsize(image, 1)) co_filt, co_filt_fft, co_img, co_img_fft, co_img_ifft
endif
else
duplicate /o image, co_filt, co_img, co_img_ifft
make /n=(dimsize(image, 0), dimsize(image, 1)) /c co_filt_fft, co_img_fft
variable /g co_img_size_x
variable /g co_img_size_y
endif
co_img_size_x = dimsize(image, 0)
co_img_size_y = dimsize(image, 1)
setscale /p x -co_img_size_x/2, 1, "", co_filt, co_filt_fft, co_img, co_img_fft, co_img_ifft
setscale /p y -co_img_size_y/2, 1, "", co_filt, co_filt_fft, co_img, co_img_fft, co_img_ifft
if (!cache)
variable wx = sqrt(500) / xbin
variable wy = sqrt(500) / ybin
co_filt = exp(-((x/wx)^2 + (y/wy)^2))
variable nfilt = sum(co_filt)
co_filt /= nfilt
fft /dest=co_filt_fft co_filt
endif
co_img /= dwelltime
fft /dest=co_img_fft co_img
co_img_fft *= co_filt_fft
ifft /dest=co_img_ifft co_img_fft
imagetransform swap co_img_ifft
redimension /n=(dimsize(co_img_ifft, 0), dimsize(co_img_ifft, 1)) outmask
outmask = (co_img_ifft < thresh) * 64
SetDataFolder save_df
end

View File

@ -62,7 +62,33 @@ function prompt_int_linbg_reduction(param)
return v_flag
end
/// this function is for testing only, until we implement a proper interface
/// capture linear background reduction parameters from cursors in a graph.
///
/// PRELIMINARY - function arguments may change
///
/// sets reduction parameters from cursors in a graph.
/// the resulting parameters are copied to the global `s_reduction_params` string
/// used by the data explorer.
///
/// an even number of cursors (2 or more) must be set on the image.
/// cursor names and order do not matter,
/// except that the alphabetically first cursor which is attached to an image selects the image.
/// the cursors mark the following positions, from innermost to outermost pair:
///
/// 1. low and high limits of peak region.
/// if no cursors are present, the limits are set at 40% and 60% of the x-scale.
/// 2. peak-side boundary of lower and upper background region.
/// if two or less cursors are present, the default background region applies,
/// which extends from the peak limits up to the default cropping region.
/// the background region extends up to the cropping region defined by the third pair.
/// 3. lower and upper cropping region.
/// if four or less cursors are present, the default cropping region applies,
/// which is 11% on either side of the image in fixed mode, and 0% otherwise.
/// fixed mode is detected by the number of pixels (>= 992).
///
/// @note on profile graphs, the necessary cursors can be configured easily
/// by calling the ad_profile_cursor_mode() function, e.g.
/// `ad_profiles_cursor_mode(root:packages:pearl_explorer:preview_image, 1)`.
///
function /s capture_int_linbg_cursors()
string param = csr_int_linbg_reduction("")
@ -73,18 +99,36 @@ function /s capture_int_linbg_cursors()
return param
end
/// set reduction parameters from cursors in a graph.
/// calculate linear background reduction parameters from cursors in a graph.
///
/// PRELIMINARY - function arguments may change
///
/// sets reduction parameters from cursors in a graph.
/// calculates reduction parameters from cursors in a graph.
/// the resulting parameters are returned in a string.
///
/// an even number of cursors (2 or more) must be set on the image.
/// cursor names and order do not matter,
/// except that the alphabetically first cursor which is attached to an image selects the image.
/// the cursors mark the following positions, from innermost to outermost pair:
/// 1) low and high limits of peak region.
/// 2) peak-side boundary of lower and upper background region.
/// 3) lower and upper cropping region.
///
/// 1. low and high limits of peak region.
/// if no cursors are present, the limits are set at 40% and 60% of the x-scale.
/// 2. peak-side boundary of lower and upper background region.
/// if two or less cursors are present, the default background region applies,
/// which extends from the peak limits up to the default cropping region.
/// the background region extends up to the cropping region defined by the third pair.
/// 3. lower and upper cropping region.
/// if four or less cursors are present, the default cropping region applies,
/// which is 11% on either side of the image in fixed mode, and 0% otherwise.
/// fixed mode is detected by the number of pixels (>= 992).
///
/// @note on profile graphs, the necessary cursors can be configured easily
/// by calling the ad_profile_cursor_mode() function, e.g.
/// `ad_profiles_cursor_mode(root:packages:pearl_explorer:preview_image, 1)`.
///
/// @param win graph window name or empty string for top window.
///
/// @return parameter string for linear background subtraction
///
function /s csr_int_linbg_reduction(win)
string win
@ -127,8 +171,8 @@ function /s csr_int_linbg_reduction(win)
// map innermost cursor pair to peak center and size
variable ip2 = np / 2
variable ip1 = ip2 - 1
variable Cpos = (positions[ip1] + positions[ip2]) / 2
variable Csize = positions[ip2] - positions[ip1]
variable Cpos
variable Csize
if (ip1 >= 0)
Cpos = (positions[ip1] + positions[ip2]) / 2
Csize = positions[ip2] - positions[ip1]
@ -155,15 +199,17 @@ function /s csr_int_linbg_reduction(win)
// crop region
ip1 -= 1
ip2 += 1
variable Lcrop
variable Hcrop
variable Lcrop = 0
variable Hcrop = 0
if (ip1 >= 0)
Lcrop = positions[ip1]
Hcrop = 1 - positions[ip2]
else
// default: dead corners of the EW4000 at PEARL
Lcrop = 0.11
Hcrop = 0.11
// default: in fixed mode: dark corners of the EW4000 at PEARL, 0 otherwise
if (dimsize(image, 0) >= 992)
Lcrop = 0.11
Hcrop = 0.11
endif
endif
Lsize = max(Lsize - Lcrop, 0)
Hsize = max(Hsize - Hcrop, 0)

View File

@ -1,41 +1,97 @@
#pragma rtGlobals=3
#pragma version = 2.0
#pragma version = 2.1
#pragma IgorVersion = 6.1
#pragma ModuleName = PearlVectorOperations
// author: matthias.muntwiler@psi.ch
// Copyright (c) 2011-13 Paul Scherrer Institut
// $Id$
// copyright (c) 2011-17 Paul Scherrer Institut
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http:///www.apache.org/licenses/LICENSE-2.0
//
// Please acknowledge the use of this code.
/// @file
/// @brief basic vector geometry operations.
/// @ingroup ArpesPackage
///
/// this procedure file contains basic vector geometry functions,
/// such as rotations.
///
/// @author matthias muntwiler, matthias.muntwiler@psi.ch
///
/// @copyright 2011-17 Paul Scherrer Institut @n
/// Licensed under the Apache License, Version 2.0 (the "License"); @n
/// you may not use this file except in compliance with the License. @n
/// You may obtain a copy of the License at
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// @namespace PearlVectorOperations
/// @brief basic vector geometry operations.
///
/// PearlVectorOperations is declared in @ref pearl-vector-operations.ipf.
/// rotate a 2D cartesian vector and returns its x component.
///
/// @param xx x coordinate.
/// @param yy y coordinate.
/// @param angle rotation angle in degrees.
///
/// @return x coordinate of the rotated vector.
///
function rotate2d_x(xx, yy, angle)
// rotates a 2D cartesian vector and returns its x component
variable xx, yy
variable angle // rotation angle in degrees
variable angle
return xx * cos(angle * pi / 180) - yy * sin(angle * pi / 180)
end
/// rotate a 2D cartesian vector and returns its y component.
///
/// @param xx x coordinate.
/// @param yy y coordinate.
/// @param angle rotation angle in degrees.
///
/// @return y coordinate of the rotated vector.
///
function rotate2d_y(xx, yy, angle)
// rotates a 2D cartesian vector and returns its y component
variable xx, yy
variable angle // rotation angle in degrees
variable angle
return xx * sin(angle * pi / 180) + yy * cos(angle * pi / 180)
end
/// create a free matrix wave which represents the 3-vector identity.
///
/// the matrix is initialized as identity.
///
/// @return 3x3 identity matrix in a free wave.
///
function /wave create_rotation_matrix_free()
// creates a matrix which represents a 3-vector rotation
// the matrix is initialized as identity
make /n=(3,3)/free matrix
matrix = p == q // identity
return matrix
end
/// calculate a matrix representing a 3-vector rotation around the x axis.
///
/// the function calculates the matrix elements of a rotation about the x axis.
///
/// @param[in,out] matrix 3x3 wave to receive the rotation matrix elements.
/// the function calculates only the 2x2 block of the rotation.
/// the other elements must be initialized by the caller,
/// e.g. set to the identity matrix.
/// @param[in] angle rotation angle in degrees.
///
/// @return rotation matrix.
/// this is the same wave instance as the matrix input.
///
function /wave set_rotation_x(matrix, angle)
// calculates a matrix representing a 3-vector rotation around the x axis
wave matrix // rotation matrix
variable angle // rotation angle in degrees
wave matrix
variable angle
variable si = sin(angle * pi / 180)
variable co = cos(angle * pi / 180)
@ -48,10 +104,22 @@ function /wave set_rotation_x(matrix, angle)
return matrix
end
/// calculate a matrix representing a 3-vector rotation around the y axis
///
/// the function calculates the matrix elements of a rotation about the y axis.
///
/// @param[in,out] matrix 3x3 wave to receive the rotation matrix elements.
/// the function calculates only the 2x2 block of the rotation.
/// the other elements must be initialized by the caller,
/// e.g. set to the identity matrix.
/// @param[in] angle rotation angle in degrees.
///
/// @return rotation matrix.
/// this is the same wave instance as the matrix input.
///
function /wave set_rotation_y(matrix, angle)
// calculates a matrix representing a 3-vector rotation around the y axis
wave matrix // rotation matrix
variable angle // rotation angle in degrees
wave matrix
variable angle
variable si = sin(angle * pi / 180)
variable co = cos(angle * pi / 180)
@ -64,10 +132,22 @@ function /wave set_rotation_y(matrix, angle)
return matrix
end
/// calculate a matrix representing a 3-vector rotation around the z axis
///
/// the function calculates the matrix elements of a rotation about the z axis.
///
/// @param[in,out] matrix 3x3 wave to receive the rotation matrix elements.
/// the function calculates only the 2x2 block of the rotation.
/// the other elements must be initialized by the caller,
/// e.g. set to the identity matrix.
/// @param[in] angle rotation angle in degrees.
///
/// @return rotation matrix.
/// this is the same wave instance as the matrix input.
///
function /wave set_rotation_z(matrix, angle)
// calculates a matrix representing a 3-vector rotation around the z axis
wave matrix // rotation matrix
variable angle // rotation angle in degrees
wave matrix
variable angle
variable si = sin(angle * pi / 180)
variable co = cos(angle * pi / 180)
@ -80,11 +160,21 @@ function /wave set_rotation_z(matrix, angle)
return matrix
end
/// rotate a wave of 3-vectors about the x axis.
///
/// this function rotates multiple vectors.
///
/// @param[in,out] inout wave with dimensions (M, N), M >= 3 (x, y, z), N >= 1.
/// the result will be in same wave.
/// only the first three rows of dimension 0 are used,
/// extra rows are left unchanged.
/// @param[in] angle rotation angle in degrees.
///
/// @return none
///
function rotate_x_wave(inout, angle)
// rotates a wave of 3-vectors about the x axis
wave inout // wave with dimensions (3, N), N >= 1, (x, y, z)
// result will be in same wave
variable angle // rotation angle in degrees
wave inout
variable angle
wave m_rotation_x = create_rotation_matrix_free()
make /n=3/d/free w_temp_rotate_x
@ -94,15 +184,25 @@ function rotate_x_wave(inout, angle)
set_rotation_x(m_rotation_x, angle)
w_temp_rotate_x = inout[p][ivec]
matrixop /free w_temp_rotate_x_result = m_rotation_x x w_temp_rotate_x
inout[][ivec] = w_temp_rotate_x_result[p]
endfor
inout[0,2][ivec] = w_temp_rotate_x_result[p]
endfor
end
/// rotates a wave of 3-vectors about the y axis
///
/// this function rotates multiple vectors.
///
/// @param[in,out] inout wave with dimensions (M, N), M >= 3 (x, y, z), N >= 1.
/// the result will be in same wave.
/// only the first three rows of dimension 0 are used,
/// extra rows are left unchanged.
/// @param[in] angle rotation angle in degrees.
///
/// @return none
///
function rotate_y_wave(inout, angle)
// rotates a wave of 3-vectors about the y axis
wave inout // wave with dimensions (3, N), N >= 1, (x, y, z)
// result will be in same wave
variable angle // rotation angle in degrees
wave inout
variable angle
wave m_rotation_y = create_rotation_matrix_free()
make /n=3/d/free w_temp_rotate_y
@ -112,15 +212,25 @@ function rotate_y_wave(inout, angle)
set_rotation_y(m_rotation_y, angle)
w_temp_rotate_y = inout[p][ivec]
matrixop /free w_temp_rotate_y_result = m_rotation_y x w_temp_rotate_y
inout[][ivec] = w_temp_rotate_y_result[p]
inout[0,2][ivec] = w_temp_rotate_y_result[p]
endfor
end
/// rotates a wave of 3-vectors about the z axis
///
/// this function rotates multiple vectors.
///
/// @param[in,out] inout wave with dimensions (M, N), M >= 3 (x, y, z), N >= 1.
/// the result will be in same wave.
/// only the first three rows of dimension 0 are used,
/// extra rows are left unchanged.
/// @param[in] angle rotation angle in degrees.
///
/// @return none
///
function rotate_z_wave(inout, angle)
// rotates a wave of 3-vectors about the z axis
wave inout // wave with dimensions (3, N), N >= 1, (x, y, z)
// result will be in same wave
variable angle // rotation angle in degrees
wave inout
variable angle
wave m_rotation_z = create_rotation_matrix_free()
make /n=3/d/free w_temp_rotate_z
@ -130,6 +240,6 @@ function rotate_z_wave(inout, angle)
set_rotation_z(m_rotation_z, angle)
w_temp_rotate_z = inout[p][ivec]
matrixop /free w_temp_rotate_z_result = m_rotation_z x w_temp_rotate_z
inout[][ivec] = w_temp_rotate_z_result[p]
inout[0,2][ivec] = w_temp_rotate_z_result[p]
endfor
end