4 Commits

Author SHA1 Message Date
80a01f2bdb updates: pshell import, angle-scans, elog
- pshell import: fix units and data scaling.
- pshell import: support new multi-region scans.
- angle scans: add trim function.
- angle scans: update import_tpi_scan function.
- angle scans: fix scales of check waves in normalization.
- area display: new cursor mode for background selection.
- elog: bugfixes (attachment list, check existing logbook).
2017-07-04 11:06:49 +02:00
9a65d26984 updates: scaling of pshell data, matrix preview, elog panel
- elog panel supports multiple attachments
- matrix (omicron STM) data file preview in data explorer
- various improvements for the scaling of pshell data
2017-02-02 15:31:13 +01:00
c8a69460bc updates: igor 7, map projections, hemi cuts, longitudinal section
- pearl procedures compile under igor 7.
  some features may not work, e.g. 3D graphics with gizmo.
- add orthographic map projection to angle scans.
- add functions for azimuthal and polar cuts through hemispherical scan.
- add function to load longitudinal section from pshell data file.
2016-10-14 16:56:20 +02:00
600061f684 bugfixes in pshell import and preview
changes:
- fix null string exception in preview
- fix transposition of two-dimensional datasets
2016-09-23 19:11:07 +02:00
12 changed files with 2625 additions and 371 deletions

View File

@ -11,10 +11,12 @@ PEARL Procedures should be installed according to the regular Igor Pro guideline
- Make a `pearl-procs` directory in your private or shared `User Procedures` folder, and copy the PEARL Procedures distribution there.
- Create shortcuts of the `pearl-arpes.ipf` and `pearl-menu.ipf` files, and move them to the `Igor Procedures` folder next to your `User Procedures` folder.
- Find the `HDF5.XOP` extension in the `Igor Pro Folder` under `More Extensions/File Loaders`, create a shortcut, and move the shortcut to the `Igor Extensions` folder next to your `User Procedures` folder.
- Find the `HDF5.XOP` (`HDF5-64.xop` for Igor 7 64-bit) extension in the `Igor Pro Folder` under `More Extensions/File Loaders` (`More Extensions (64-bit)/File Loaders`), create a shortcut, and move the shortcut to the `Igor Extensions` folder next to your `User Procedures` folder.
- Find the `HDF5 Help.ihf` next to `HDF5.XOP`, create a shortcut, and move the shortcut to the `Igor Help Files` folder next to your `User Procedures` folder.
PEARL Procedures has been tested under Igor Pro version 6.37 (32-bit). Older versions (particularly prior to 6.34) may not be compatible. Please update to the latest Igor Pro version before reporting any problems.
PEARL Procedures has been tested under Igor Pro version 6.37 (32-bit). Older versions prior to 6.36 are not be compatible. Please update to the latest Igor Pro 6 version before reporting any problems.
PEARL Procedures compiles under Igor 7.00. Some features, in particular 3D graphics, may not work properly.
License

View File

@ -300,6 +300,7 @@ function normalize_strip_theta(strip, theta, [theta_offset, smooth_method, smoot
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
variable nx = dimsize(strip, 0)
variable ix
@ -336,6 +337,7 @@ function normalize_strip_theta(strip, theta, [theta_offset, smooth_method, smoot
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
@ -808,9 +810,9 @@ function convert_angles_ttpa2polar(theta, tilt, phi, analyser, polar, azi)
// this is simply a polar-cartesian mapping, independent of the manipulator
// phi=0 is in the polar rotation plane
make /n=(3,na) /d /free w_orig_polar, w_orig_cart, w_rot_cart, w_rot_polar
w_orig_polar[0] = radius
w_orig_polar[1] = analyser[q]
w_orig_polar[2] = 0
w_orig_polar[0][] = radius
w_orig_polar[1][] = analyser[q]
w_orig_polar[2][] = 0
polar2cart_wave(w_orig_polar, w_orig_cart)
// if the angle-dispersive axis was horizontal, we'd need to rotate the detector
//rotate_z_wave(w_orig_cart, 90)
@ -1861,7 +1863,7 @@ function /s display_scanlines(nickname, alpha_lo, alpha_hi, m_theta, m_tilt, m_p
make /n=1 /d /free d_polar, d_azi
variable n_alpha = round(alpha_hi - alpha_lo) + 1
make /n=(n_alpha) /d /free analyser
setscale /i x alpha_lo, alpha_hi, "deg", analyser
setscale /i x alpha_lo, alpha_hi, "<EFBFBD>", analyser
analyser = x
convert_angles_ttpa2polar(m_theta, loc_m_tilt, m_phi, analyser, d_polar, d_azi)
@ -1905,21 +1907,46 @@ function /s display_scanlines(nickname, alpha_lo, alpha_hi, m_theta, m_tilt, m_p
return graphname
end
static constant kProjScaleLinear = 2
/// @page PageProjections Projections
///
/// the functions of the anglescan package support the following map projections.
/// for a description of the different projections, see, for example,
/// https://en.wikipedia.org/wiki/Map_projection
///
/// | Selector | Projection | Function | Properties |
/// | :----: | :----: | :----: | :---- |
/// | kProjDist = 0 | azimuthal equidistant | r = c * theta | radius is proportional to polar angle. |
/// | kProjStereo = 1 | stereographic | r = c * tan theta/2 | circles on sphere map to circles. |
/// | kProjArea = 2 | azimuthal equal-area | r = c * sin theta/2 | preserves area measure. |
/// | kProjGnom = 3 | gnomonic | r = c * tan theta | great circles map to straight lines. |
/// | kProjOrtho = 4 | orthographic | r = c * sin theta | k-space mapping in ARPES and LEED. |
///
/// the projections in this package are defined for 0 <= theta < 90.
///
constant kProjDist = 0
constant kProjStereo = 1
constant kProjArea = 2
constant kProjGnom = 3
constant kProjOrtho = 4
static constant kProjScaleDist = 2
static constant kProjScaleStereo = 2
static constant kProjScaleAzim = 2
static constant kProjScaleArea = 2
// scaled so that radius(gnom) = radius(stereo) for polar = 88
static constant kProjScaleGnomonic = 0.06744519021
static constant kProjScaleGnom = 0.06744519021
static constant kProjScaleOrtho = 2
/// calculate the projected polar angle
///
/// @param polar polar angle in degrees
///
/// @param projection mapping function from polar to cartesian coordinates
/// @arg 0 linear
/// @arg 1 stereographic (default)
/// @arg 2 azimuthal
/// @arg 3 gnomonic (0 <= polar < 90)
/// @param projection mapping function from polar to cartesian coordinates.
/// see @ref PageProjections for details.
/// @arg kProjDist = 0 azimuthal equidistant
/// @arg kProjStereo = 1 stereographic (default)
/// @arg kProjArea = 2 azimuthal equal-area
/// @arg kProjGnom = 3 gnomonic (0 <= polar < 90)
/// @arg kProjOrtho = 4 orthographic
///
/// @return projected radius.
/// the radius is scaled such that grazing emission maps to 2.
@ -1933,17 +1960,20 @@ threadsafe function calc_graph_radius(polar, [projection])
variable radius
switch(projection)
case 1: // stereographic
case kProjStereo: // stereographic
radius = kProjScaleStereo * tan(polar / 2 * pi / 180)
break
case 2: // azimuthal
radius = kProjScaleAzim * cos((180 - polar) / 2 * pi / 180)
case kProjArea: // equal area
radius = kProjScaleArea * sin(polar / 2 * pi / 180)
break
case 3: // gnomonic
radius = polar < 90 ? kProjScaleGnomonic * tan(polar * pi / 180) : inf
case kProjGnom: // gnomonic
radius = polar < 90 ? kProjScaleGnom * tan(polar * pi / 180) : inf
break
default: // linear
radius = kProjScaleLinear * polar / 90
case kProjOrtho: // orthographic
radius = kProjScaleOrtho * sin(polar * pi / 180)
break
default: // equidistant
radius = kProjScaleDist * polar / 90
endswitch
return radius
@ -1955,10 +1985,13 @@ end
///
/// @param x, y projected Cartesian coordinate
///
/// @param projection mapping function from polar to cartesian coordinates
/// @arg 0 linear
/// @arg 1 stereographic (default)
/// @arg 2 azimuthal
/// @param projection mapping function from polar to cartesian coordinates.
/// see @ref PageProjections for details.
/// @arg kProjDist = 0 azimuthal equidistant
/// @arg kProjStereo = 1 stereographic (default)
/// @arg kProjArea = 2 azimuthal equal-area
/// @arg kProjGnom = 3 gnomonic (0 <= polar < 90)
/// @arg kProjOrtho = 4 orthographic
///
/// @returns polar angle in degrees
///
@ -1976,17 +2009,20 @@ threadsafe function calc_graph_polar(x, y, [projection])
radius = sqrt(x^2 + y^2)
switch(projection)
case 1: // stereographic
case kProjStereo: // stereographic
polar = 2 * atan(radius / kProjScaleStereo) * 180 / pi
break
case 2: // azimuthal
polar = 180 - 2 * acos(radius / kProjScaleAzim) * 180 / pi
case kProjArea: // equal area
polar = 2 * asin(radius / kProjScaleArea) * 180 / pi
break
case 3: // gnomonic
polar = atan(radius / kProjScaleGnomonic) * 180 / pi
case kProjGnom: // gnomonic
polar = atan(radius / kProjScaleGnom) * 180 / pi
break
default: // linear
polar = 90 * radius / kProjScaleLinear
case kProjOrtho: // orthographic
polar = asin(radius / kProjScaleOrtho) * 180 / pi
break
default: // equidistant
polar = 90 * radius / kProjScaleDist
endswitch
return polar
@ -1997,10 +2033,13 @@ end
/// @param x, y projected Cartesian coordinate
///
/// @param projection mapping function from polar to cartesian coordinates.
/// projections 0-2 have no effect on the azimuthal coordinate.
/// @arg 0 linear
/// @arg 1 stereographic (default)
/// @arg 2 azimuthal
/// all supported projections are azimuthal, they have no effect on the azimuthal coordinate.
/// see @ref PageProjections for details.
/// @arg kProjDist = 0 azimuthal equidistant
/// @arg kProjStereo = 1 stereographic (default)
/// @arg kProjArea = 2 azimuthal equal-area
/// @arg kProjGnom = 3 gnomonic (0 <= polar < 90)
/// @arg kProjOrtho = 4 orthographic
///
/// @param zeroAngle zeroAngleWhere parameter of polar graphs
/// @arg 0 (default) zero is at the 3 o'clock position
@ -2549,8 +2588,35 @@ end
/// import a hemispherical scan from theta-phi-intensity waves and display it
///
/// @warning EXPERIMENTAL
/// the interface and behaviour of this function may change
/// in the tpi format, the hemi scan data is represented
/// by a triple of flat one-dimensional waves
/// corresponding to the polar angle (theta), azimuthal angle (phi) and intensity.
/// no specific sort order is required.
///
/// @param nickname nick name for output data
/// @arg in default mode, this will become the name of a child folder containing the output.
/// @arg in XPDplot mode, this will become a prefix of the generated data in the root folder.
///
/// @param theta theta angles, 0 = normal emission.
///
/// @param phi phi angles, 0 = azimuthal origin. size = dimsize(data, 1)
///
/// @param intensity intensity wave, see requirements above.
///
/// @param npolar number of polar angles, determines polar and azimuthal step size.
/// default = 91 (1 degree steps)
///
/// @param folding rotational averaging.
/// example: 3 = average to 3-fold symmetry.
/// default = 1.
///
/// @param nograph display a new graph window?
/// @arg 0 (default) display a new polar graph
/// @arg 1 don't display a new graph
///
/// @param xpdplot XPDplot compatibility
/// @arg 0 (default) create waves in child folder $nickname
/// @arg 1 create waves in root folder (compatible with XPDplot)
///
function import_tpi_scan(nickname, theta, phi, intensity, [folding, npolar, nograph, xpdplot])
string nickname
@ -2585,5 +2651,195 @@ function import_tpi_scan(nickname, theta, phi, intensity, [folding, npolar, nogr
fold_phi = fold_phi >= 180 ? fold_phi + 360 / folding - fold_phi : fold_phi + 360 / folding
endfor
if (nograph==0)
display_hemi_scan(nickname)
endif
end
/// trim a hemispherical scan at grazing angle
///
/// the function recalaculates the values wave from totals and weights
/// but sets elements above a given polar angle to nan.
///
/// @param nickname name of the scan dataset.
/// can be empty if no prefix is used.
/// the dataset must be in the current datafolder.
///
/// @param theta_max highest polar angle to keep (0...90 degrees).
///
function trim_hemi_scan(nickname, theta_max)
string nickname
variable theta_max
if (strlen(nickname))
string s_prefix = nickname + "_"
string s_int = s_prefix + "i"
else
s_prefix = ""
s_int = "values"
endif
string s_totals = s_prefix + "tot"
string s_weights = s_prefix + "wt"
string s_polar = s_prefix + "pol"
wave w_polar = $s_polar
wave w_values = $s_int
wave w_totals = $s_totals
wave w_weights = $s_weights
w_values = w_polar <= theta_max ? w_totals / w_weights : nan
end
/// extract a polar cut from a hemispherical scan.
///
/// for each polar angle, the function first extracts all azimuthal angles.
/// the intensity is then interpolated between the nearest neighbours of the given azimuth.
///
/// the hemi grid must have been created in the current data folder by the make_hemi_grid function.
/// correct ordering is required.
///
/// @param nickname name of the scan dataset.
/// can be empty if no prefix is used.
/// the dataset must be in the current datafolder.
///
/// @param azim azimuthal angle in degrees
///
/// @return reference of the created wave.
/// the wave has the same name as the intensity wave of the dataset
/// with the suffix "_azi" and the azimuthal angle rounded to integer.
/// it is created in the same datafolder as the original data.
///
function /wave hemi_polar_cut(nickname, azim)
string nickname
variable azim
if (strlen(nickname))
string s_prefix = nickname + "_"
string s_int = s_prefix + "i"
else
s_prefix = ""
s_int = "values"
endif
string s_totals = s_prefix + "tot"
string s_weights = s_prefix + "wt"
string s_polar = s_prefix + "pol"
string s_azim = s_prefix + "az"
string s_index = s_prefix + "index"
string s_theta = s_prefix + "th"
string s_dphi = s_prefix + "dphi"
string s_nphis = s_prefix + "nphis"
string s_cut
sprintf s_cut, "%s_azi%03u", s_int, round(azim)
wave w_polar = $s_polar
wave w_azim = $s_azim
wave w_values = $s_int
wave w_totals = $s_totals
wave w_weights = $s_weights
wave w_index = $s_index
wave w_theta = $s_theta
wave w_dphi = $s_dphi
wave w_nphis = $s_nphis
variable npol = numpnts(w_theta)
variable ipol
variable pol_st = abs(w_theta[1] - w_theta[0])
variable pol
variable pol1, pol2
variable nsel
make /n=(npol) /o $s_cut
wave w_cut = $s_cut
setscale /i x w_theta[0], w_theta[numpnts(w_theta)-1], "deg", w_cut
make /n=1 /free azi_slice
make /n=1 /free values_slice
for (ipol = 0; ipol < npol; ipol += 1)
pol = w_theta[ipol]
pol1 = pol - pol_st / 2
pol2 = pol + pol_st / 2
extract /free /indx w_polar, sel, (pol1 < w_polar) && (w_polar <= pol2)
nsel = numpnts(sel)
if (nsel > 0)
redimension /n=(nsel+2) azi_slice, values_slice
azi_slice[1, nsel] = w_azim[sel[p-1]]
azi_slice[0] = azi_slice[nsel] - 360
azi_slice[nsel+1] = azi_slice[1] + 360
values_slice[1, nsel] = w_values[sel[p-1]]
values_slice[0] = values_slice[nsel]
values_slice[nsel+1] = values_slice[1]
w_cut[ipol] = interp(azim, azi_slice, values_slice)
else
w_cut[ipol] = nan
endif
endfor
return w_cut
end
/// extract an azimuthal cut from a hemispherical scan
///
/// the function extracts all azimuthal angles that are present for the given polar angle.
///
/// the hemi grid must have been created in the current data folder by the make_hemi_grid function.
/// correct ordering is required.
///
/// @param nickname name of the scan dataset.
/// can be empty if no prefix is used.
/// the dataset must be in the current datafolder.
///
/// @param pol polar angle in degrees
///
/// @return reference of the created wave.
/// the wave has the same name as the intensity wave of the dataset
/// with the suffix "_azi" and the azimuthal angle rounded to integer.
/// it is created in the same datafolder as the original data.
///
function /wave hemi_azi_cut(nickname, pol)
string nickname
variable pol
if (strlen(nickname))
string s_prefix = nickname + "_"
string s_int = s_prefix + "i"
else
s_prefix = ""
s_int = "values"
endif
string s_totals = s_prefix + "tot"
string s_weights = s_prefix + "wt"
string s_polar = s_prefix + "pol"
string s_azim = s_prefix + "az"
string s_index = s_prefix + "index"
string s_theta = s_prefix + "th"
string s_dphi = s_prefix + "dphi"
string s_nphis = s_prefix + "nphis"
string s_cut
sprintf s_cut, "%s_pol%03u", s_int, round(pol)
wave w_polar = $s_polar
wave w_azim = $s_azim
wave w_values = $s_int
wave w_totals = $s_totals
wave w_weights = $s_weights
wave w_index = $s_index
wave w_theta = $s_theta
wave w_dphi = $s_dphi
wave w_nphis = $s_nphis
variable pol_st = abs(w_theta[1] - w_theta[0])
variable pol1, pol2
variable nsel
pol1 = pol - pol_st / 2
pol2 = pol + pol_st / 2
extract /free /indx w_polar, sel, (pol1 < w_polar) && (w_polar <= pol2)
nsel = numpnts(sel)
if (nsel > 0)
make /n=(nsel) /o $s_cut
wave w_cut = $s_cut
w_cut = w_values[sel]
setscale /i x w_azim[sel[0]], w_azim[sel[nsel-1]], "<22>", w_cut
return w_cut
else
return $""
endif
end

View File

@ -436,7 +436,7 @@ static function setup_detector()
setdatafolder $(package_path)
make /n=31 /o detector_angle, detector_pol, detector_az, detector_rad
setscale /i x -30, 30, "deg", detector_angle, detector_pol, detector_az, detector_rad
setscale /i x -30, 30, "°", detector_angle, detector_pol, detector_az, detector_rad
detector_angle = x
setdatafolder saveDF
@ -573,7 +573,7 @@ static function update_detector(theta, tilt, phi, range)
//m_phi *= -1 // checked 140702
wave detector_angle, detector_pol, detector_az, detector_rad
setscale /i x -range/2, +range/2, "deg", detector_angle
setscale /i x -range/2, +range/2, "°", detector_angle
detector_angle = x
convert_angles_ttpa2polar(m_theta, m_tilt, m_phi, detector_angle, detector_pol, detector_az)

View File

@ -196,6 +196,7 @@ function /s ad_display_profiles(image, [filter])
view_filter_options = ""
variable /g view_filter_smoothing_x = 1
variable /g view_filter_smoothing_y = 1
variable /g view_cursor_mode = 0
string dfname = ReplaceString("root:", GetDataFolder(1, imagedf), "")
string graphtitle = dfname + NameOfWave(image) + " Profiles"
string /g prof_graphname = graphname_from_dfref(imagedf, "prof_")
@ -348,15 +349,88 @@ function ad_update_profiles(image)
return 0
end
/// switch cursors on a profiles graph
///
/// the standard cursors allow to select the profiles to display in the profiles panes.
/// additional cursors are shown in the profiles panes.
///
/// in the background selection mode, additional cursors allow the user to select
/// the limits of the background and peak integration regions.
/// the meaning of the cursors depends on the particular processing function.
///
/// @param mode cursor mode.
/// @arg 0 (default) standard profile selection. cursors C-F on profile panes.
/// @arg 1 background selection. cursors A-F on image.
///
/// @param image image displayed in the graph.
/// this is the original image, not the one in the view data folder.
///
function ad_profiles_cursor_mode(image, mode)
wave image
variable mode
dfref savedf = GetDataFolderDFR()
wave view_image = get_view_image(image)
dfref viewdf = GetWavesDataFolderDFR(view_image)
svar /sdfr=viewdf graphname = prof_graphname
nvar /sdfr=viewdf cursor_mode = view_cursor_mode
wave /sdfr=viewdf xprofiles, yprofiles
variable dx = DimSize(view_image, 0)
variable dy = DimSize(view_image, 1)
switch(mode)
case 1: // background selection
Cursor /w=$graphname /A=0 /P /I /S=2 /H=1 /L=1 A view_image 0, 0
Cursor /w=$graphname /A=0 /P /I /S=2 /H=1 /L=1 B view_image dx-1, dy-1
Cursor /w=$graphname /A=0 /P /I /S=2 /H=2 /L=1 C view_image round(0.2 * dx) -1, 0
Cursor /w=$graphname /A=0 /P /I /S=2 /H=2 /L=1 D view_image round(0.8 * dx) -1, 0
Cursor /w=$graphname /A=0 /P /I /S=2 /H=2 /L=1 E view_image round(0.4 * dx) -1, 0
Cursor /w=$graphname /A=0 /P /I /S=2 /H=2 /L=1 F view_image round(0.6 * dx) -1, 0
ShowInfo /w=$graphname /CP=0
cursor_mode = mode
break
default:
Cursor /w=$graphname /A=1 /P /I /S=2 /H=1 /L=1 A view_image 0,0
Cursor /w=$graphname /A=1 /P /I /S=2 /H=1 /L=1 B view_image dx-1, dy-1
variable pcurs
pcurs = floor(DimSize(xprofiles, 0) / 3)
Cursor /w=$graphname /A=0 /P /S=1 /H=0 C xprofiles#2 pcurs
pcurs = floor(DimSize(xprofiles, 0) * 2 / 3)
Cursor /w=$graphname /A=0 /P /S=1 /H=0 D xprofiles#2 pcurs
pcurs = floor(DimSize(yprofiles, 0) / 3)
Cursor /w=$graphname /A=0 /P /S=1 /H=0 E yprofiles#2 pcurs
pcurs = floor(DimSize(yprofiles, 0) * 2 / 3)
Cursor /w=$graphname /A=0 /P /S=1 /H=0 F yprofiles#2 pcurs
ShowInfo /w=$graphname /CP=0
cursor_mode = 0
endswitch
setdatafolder savedf
return 0
end
/// move a cursor to the specified position in a profiles graph.
///
/// this function can only set cursors in the image part of the profiles graph.
///
/// @param image image displayed in the graph.
/// this is the original image, not the one in the view data folder.
/// @param cursorname name of the cursor, e.g. "A" or "B".
/// other cursors are allowed but need to be activated separately.
/// @param xa x-coordinate to move the cursor to.
/// the position is coerced to the image scale. +/-inf is allowed.
/// @param ya y-coordinate to move the cursor to.
/// the position is coerced to the image scale. +/-inf is allowed.
/// @param pscale scaling of the position argument
/// @arg 0 (default) wave scaling
/// @arg 1 point scaling
///
function ad_profiles_set_cursor(image, cursorname, xa, ya, [pscale])
wave image // image displayed in the graph. this is the original image, not the one in the view data folder.
string cursorname // name of the cursor. must be "A" or "B".
variable xa, ya // position to move the cursor to.
// the position is coerced to the image scale. +/-inf is allowed.
variable pscale // scaling of the position argument
// 0 (default) = wave scaling
// 1 = point scaling
wave image
string cursorname
variable xa, ya
variable pscale
if (ParamIsDefault(pscale))
pscale = 0

View File

@ -1667,12 +1667,12 @@ function adh5_scale_scienta(data)
case 1: // Angular45
ALow = -45/2
AHigh = +45/2
AUnit = "deg"
AUnit = "°"
break
case 2: // Angular60
ALow = -60/2
AHigh = +60/2
AUnit = "deg"
AUnit = "°"
break
endswitch
endif

View File

@ -1,11 +1,14 @@
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
#pragma IgorVersion = 6.1
#pragma ModuleName = PearlDataExplorer
#pragma version = 1.43
#pragma version = 1.50
#include "pearl-area-import"
#include "pearl-area-profiles"
#include "pearl-area-display"
#include "pearl-pshell-import"
#if exists("MFR_OpenResultFile")
#include "pearl-matrix-import"
#endif
// copyright (c) 2013-16 Paul Scherrer Institut
//
@ -20,7 +23,10 @@
///
///
/// preview and import panel for PEARL data:
/// scienta analyser, prosilica cameras, s-scans, otf-scans
/// @arg area detector (HDF5) files from scienta analyser and prosilica cameras (if HDF5.xop is installed).
/// @arg igor text files from s-scans and otf-scans.
/// @arg pshell (HDF5) data files (if HDF5.xop is installed).
/// @arg matrix STM files (if MatrixFileReader.xop is installed).
/// @namespace PearlDataExplorer
/// @brief preview and import panel for PEARL data
@ -33,6 +39,7 @@ static strconstant package_path = "root:packages:pearl_explorer:"
static strconstant ks_filematch_adh5 = "*.h5"
static strconstant ks_filematch_pshell = "psh*.h5"
static strconstant ks_filematch_itx = "*.itx"
static strconstant ks_filematch_mtrx = "*_mtrx"
function pearl_data_explorer()
init_package()
@ -140,31 +147,64 @@ static function load_prefs()
return result
end
/// check whether a file can be imported by this module.
///
/// the file type is determined by the extension of the file name.
///
/// @return file type
/// @arg 0 not a recognized file type
/// @arg 1 PShell file (HDF5, name starts with psh_)
/// @arg 2 area detector HDF5 file
/// @arg 3 Igor text (itx) file
/// @arg 4 Matrix STM file (*_mtrx)
///
static function pearl_file_type(filename)
string filename
if (StringMatch(filename, ks_filematch_pshell))
return 1
elseif (StringMatch(filename, ks_filematch_adh5))
return 2
elseif (StringMatch(filename, ks_filematch_itx))
return 3
#if exists("MFR_OpenResultFile")
elseif (StringMatch(filename, ks_filematch_mtrx))
return 4
#endif
else
return 0
endif
end
/// read a list of PEARL files from the file system
///
/// wtFiles and wSelectedFiles in the package data folder are updated.
/// only files for which pearl_file_type() returns non-zero are listed.
///
static function update_filelist()
dfref saveDF = GetDataFolderDFR()
string hdf_files, itx_files, all_files
string all_files
wave /t wtFiles = $(package_path + "wtFiles")
wave wSelectedFiles = $(package_path + "wSelectedFiles")
variable nn
PathInfo pearl_explorer_filepath
if (v_flag == 1)
hdf_files = IndexedFile(pearl_explorer_filepath, -1, ".h5")
itx_files = IndexedFile(pearl_explorer_filepath, -1, ".itx")
all_files = hdf_files + itx_files
all_files = SortList(hdf_files + itx_files, ";", 4)
all_files = IndexedFile(pearl_explorer_filepath, -1, "????")
nn = ItemsInList(all_files)
else
all_files = ""
nn = 0
endif
redimension /n=(nn) wtFiles, wSelectedFiles
if (nn > 0)
wtFiles = StringFromList(p, all_files)
make /n=(nn) /t /free wtAllFiles
wtAllFiles = StringFromList(p, all_files)
Extract /o /t wtAllFiles, wtFiles, pearl_file_type(wtAllFiles[p])
Sort /A /R wtFiles, wtFiles
redimension /n=(numpnts(wtFiles)) wSelectedFiles
wSelectedFiles = 0
endif
setdatafolder saveDF
end
@ -217,13 +257,23 @@ static function preview_file(filename)
dfref saveDF = GetDataFolderDFR()
if (StringMatch(filename, ks_filematch_pshell))
variable ft = pearl_file_type(filename)
switch(ft)
case 1:
wave /z image = preview_pshell_file(filename)
elseif (StringMatch(filename, ks_filematch_adh5))
break
case 2:
wave /z image = preview_hdf_file(filename)
elseif (StringMatch(filename, ks_filematch_itx))
break
case 3:
wave /z image = preview_itx_file(filename)
endif
break
case 4:
wave /z image = preview_mtrx_file(filename)
break
default:
wave /z image = $""
endswitch
if (WaveExists(image))
string graphname = show_preview_graph(image)
@ -240,9 +290,10 @@ static function preview_file(filename)
endif
setdatafolder saveDF
return 0
end
/// load the preview of a PShell HDF5 file (not implemented).
/// load the preview of a PShell HDF5 file.
///
/// the preview is an arbitrary detector image extracted from the file, see adh5_load_preview().
/// the preview is loaded to the preview_image wave in the pear_explorer data folder.
@ -354,6 +405,63 @@ static function /wave preview_itx_file(filename)
return preview_image
end
/// load the preview of a Matrix STM file.
///
/// 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.
///
/// this function requires the MatrixFileReader.xop and pearl-matrix-import.ipf to be loaded.
/// otherwise it will return an empty wave reference.
///
/// @param filename name of a file in the directory specified by the pearl_explorer_filepath path object.
///
/// @return wave reference of the preview image.
/// empty wave reference if the function failed.
///
static function /wave preview_mtrx_file(filename)
string filename
#if exists("MFR_OpenResultFile")
dfref saveDF = GetDataFolderDFR()
setdatafolder $package_path
variable /g V_MatrixFileReaderOverwrite = 1
variable /g V_MatrixFileReaderFolder = 0
variable /g V_MatrixFileReaderDouble = 0
svar s_preview_file
svar s_preview_source
string datanames
string dataname
datanames = mtrx_load_preview("preview", "pearl_explorer_filepath", filename)
if (strlen(datanames) > 0)
s_preview_file = filename
dataname = StringFromList(0, datanames)
wave data = $dataname
duplicate /o $dataname, preview_image
s_preview_source = StringByKey("Dataset", note(data), "=", "\r")
svar /z s_file_info
if (svar_exists(s_file_info))
s_file_info = ""
endif
variable i
variable n = ItemsInList(datanames)
string s
for (i = 0; i < n; i += 1)
s = StringFromList(i, datanames)
killwaves /z $s
endfor
endif
wave /z preview_image
setdatafolder saveDF
#else
wave /z preview_image = $""
#endif
return preview_image
end
static function extract_preview_image(data, preview)
// extracts a preview image from a wave of arbitrary dimension
wave data
@ -862,21 +970,31 @@ static function load_file(filename, [options])
dfref saveDF = GetDataFolderDFR()
if (StringMatch(filename, ks_filematch_pshell))
variable ft = pearl_file_type(filename)
switch(ft)
case 1:
if (ParamIsDefault(options))
load_pshell_file(filename)
else
load_pshell_file(filename, options=options)
endif
elseif (StringMatch(filename, ks_filematch_adh5))
break
case 2:
if (ParamIsDefault(options))
load_hdf_file(filename)
else
load_hdf_file(filename, options=options)
endif
elseif (StringMatch(filename, ks_filematch_itx))
break
case 3:
load_itx_file(filename)
endif
break
case 4:
load_mtrx_file(filename)
break
default:
break
endswitch
setdatafolder saveDF
end
@ -972,6 +1090,7 @@ static function /df load_pshell_file(filename, [options])
string reduction_params = pref_params
if (prompt_func_params(reduction_func, reduction_params) == 0)
pref_params = reduction_params
print reduction_func, reduction_params
psh5_load_reduced(nickname, "pearl_explorer_filepath", filename, $reduction_func, reduction_params)
svar s_filepath
loaded_filename = s_filepath
@ -1023,6 +1142,7 @@ static function /df load_hdf_file(filename, [options])
string reduction_params = pref_params
if (prompt_func_params(reduction_func, reduction_params) == 0)
pref_params = reduction_params
print reduction_func, reduction_params
loaded_filename = adh5_load_reduced(nickname, "pearl_explorer_filepath", filename, $reduction_func, reduction_params)
endif
break
@ -1080,6 +1200,32 @@ static function /df load_itx_file(filename, [options])
return actDF
end
/// load a matrix (STM) data file
///
///
static function /df load_mtrx_file(filename, [options])
string filename
string options
dfref saveDF = GetDataFolderDFR()
dfref dataDF = $""
#if exists("MFR_OpenResultFile")
setdatafolder root:
string datasets = ""
datasets = mtrx_load_file("pearl_explorer_filepath", filename)
if (strlen(datasets) > 0)
string /g pearl_explorer_import = "load_mtrx_file"
string s1 = StringFromList(0, datasets)
wave w1 = $s1
dataDF = GetWavesDataFolderDFR(w1)
endif
#endif
setdatafolder saveDF
return dataDF
end
function /s itx_suggest_foldername(filename, [ignoredate,sourcename,unique])
// suggests the name of a data folder based on a file name
// if the file name follows the naming convention source-date-index.extension,

View File

@ -1,5 +1,5 @@
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
#pragma version = 1.31
#pragma version = 1.40
#pragma IgorVersion = 6.2
#pragma ModuleName = PearlElog
@ -16,14 +16,39 @@
/// @ingroup ArpesPackage
///
///
/// the functions in this module support the following work flows:
/// 1. send a preview of a selected measurement to ELOG.
/// 2. send any Igor graph to ELOG. (CLI and GUI)
/// 3. direct access to all ELOG parameters. (CLI only)
///
/// the configuration of the ELOG server and logbooks (except user name and password)
/// the functions in this module support the following ELOG features:
/// - submit new entries and replies to existing entries.
/// - text field, list box, and check box attributes.
/// - attach any Igor graph to ELOG.
/// - configurable logbook templates for logbooks that share the same configuration.
/// - common server configurations available on the ELOG command line
/// (hostname, port, SSL, username, password, sub-directory).
/// - not specific to the configuration at PEARL.
/// PEARL code is concentrated in the elog_init_pearl_templates() function.
/// - the configuration of the ELOG server and logbooks
/// as well as the most recently used attributes are persisted in the preference file.
///
/// usage:
/// 1. the administrator of the ELOG server creates logbook templates
/// according to the configuration of the logbooks.
/// the templates are written in Igor code.
/// 2. the user opens logbooks via the _Open ELOG panel_ menu item.
/// before first use, select a template and enter a name for the logbook.
/// the new logbook is written to the preference file,
/// and can afterwards be opened directly.
/// 3. if the server requires a user name and password,
/// click the login button.
/// 4. edit the message, attributes and attachments as necessary, and submit to ELOG.
/// 5. log out before saving the experiment to clear the password.
///
/// @attention the user name and password are stored in the global data tree of an experiment.
/// it is not possible to handle passwords safely in Igor.
/// they can be read by anyone having access to an open Igor experiment or a saved experiment file
/// (unless the password is reset before saving).
/// therefore:
/// - use a password for the ELOG server which is different from your other passwords.
/// - clear the password (logout button in the panel) before saving an experiment.
///
/// elog command line
///@verbatim
/// elog -h <hostname> [-p port] [-d subdir]
@ -43,12 +68,6 @@
/// -m <textfile>] | <text>
///@endverbatim
///
/// user name and password are used if configured in the package data folder.
/// there is currently no separate user interface.
///
/// @attention some functions in this module refer specifically to the ELOG configuration at PEARL.
///
/// @todo ask for logbook, username and password before opening the panel.
///
/// @author matthias muntwiler, matthias.muntwiler@psi.ch
///
@ -82,7 +101,7 @@ function pearl_elog(logbook)
load_prefs()
string templates = list_logbooks(templates=1)
if (ItemsInList(templates) < 1)
init_pearl_templates()
elog_init_pearl_templates()
endif
endif
@ -95,7 +114,11 @@ function pearl_elog(logbook)
if (strlen(WinList(win_name, ";", "")) > 0)
DoWindow /F $win_name
else
PearlElogPanel(logbook)
win_name = PearlElogPanel(logbook)
STRUCT WMWinHookStruct s
s.eventCode = 0
s.winName = win_name
elog_panel_hook(s)
endif
endif
end
@ -104,6 +127,7 @@ end
static function IgorBeforeNewHook(igorApplicationNameStr)
string igorApplicationNameStr
save_prefs()
cleanup_temp_files()
return 0
end
@ -111,6 +135,7 @@ end
static function IgorQuitHook(igorApplicationNameStr)
string igorApplicationNameStr
save_prefs()
cleanup_temp_files()
return 0
end
@ -234,7 +259,7 @@ end
///
/// @remark this function is specific to the setup at PEARL.
///
static function init_pearl_templates()
function elog_init_pearl_templates()
dfref savedf = getdatafolderdfr()
dfref df_root = get_elog_df("", kdfRoot)
@ -247,10 +272,10 @@ static function init_pearl_templates()
// attributes (persistent)
// available attributes
string /g attributes = "author;project;sample;source;task;technique;valid;file"
string /g attributes = "author;project;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;cb_valid;sv_file"
string /g controls = "sv_author;sv_project;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
@ -258,8 +283,8 @@ static function init_pearl_templates()
// 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"
string /g tasks = "Measurement;Sample Preparation;Sample Storage;Optimization;Analysis;Development;Maintenance;Test;Comment;Other"
string /g techniques = "XPS;UPS;XPD;XAS;XMCD;PhD;ARUPS;LEED;AES;STM;STS;QMS;MBE;Test;Other"
string /g tasks = "Measurement;Optimization;Analysis;Sample Preparation;Sample Storage;Comment;Development;Maintenance;Test;Other"
string /g techniques = "XPS;UPS;XPD;XAS;XMCD;PhD;ARUPS;STM;STS;LEED;AES;QMS;MBE;Sputter/Anneal;Test;Other"
// Calculations template
setdatafolder df_templates
@ -267,18 +292,38 @@ static function init_pearl_templates()
// attributes (persistent)
// available attributes
string /g attributes = "author;project;sample;program;revision;machine;job;source path;result path;valid"
string /g attributes = "author;project;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_sourcepath;sv_resultpath;cb_valid"
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"
// attributes with fixed options, value item declares the options string
string /g options = "program=programs;machine=machines"
// attributes which must be defined
string /g required_attributes = "author;project;sample"
// option lists
string /g programs = "DMSUP;EDAC;MSC;MUFPOT;SSC"
string /g machines = "llcx;Merlin;PC"
string /g programs = "PMSCO;EDAC;MSC;SSC;MUFPOT;DMSUP;Other"
string /g machines = "PC;VM;Ra;Merlin;llcx;Other"
// System template
setdatafolder df_templates
newdatafolder /o/s System
// attributes (persistent)
// available attributes
string /g attributes = "author;type;system;source;file"
// controls corresponding to attributes
// prefix determines the control type: sv_ = setvariable (string), pm_ = popup menu, cb = check box
string /g controls = "sv_author;pm_type;pm_system;pm_source;sv_file"
// attributes with fixed options, value item declares the options string
string /g options = "type=types;system=systems;source=sources"
// attributes which must be defined
string /g required_attributes = "author;type;system"
// 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 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
return 0
@ -303,6 +348,11 @@ static function init_volatile_vars()
variable nlb = ItemsInList(logbooks)
variable ilb
SetDataFolder df_volatile_root
if (exists("temp_graph_files") != 2)
string /g temp_graph_files = ""
endif
for (ilb = 0; ilb < nlb; ilb += 1)
logbook = StringFromList(ilb, logbooks)
@ -322,6 +372,13 @@ static function init_volatile_vars()
if (exists("msg_id") != 2)
variable /g msg_id = 0
endif
if (exists("att_list") != 1)
make /n=(0,3) /t /o attach_list
make /n=(0,3) /i /o attach_sel
endif
if (exists("url") != 2)
string /g url = ""
endif
endfor
SetDataFolder savedf
@ -347,6 +404,9 @@ end
/// create a new empty logbook or duplicate from a template.
///
/// @param name name of the new logbook.
/// if the logbook exists, the existing logbook folder is killed
/// and replaced by a new one.
/// this may fail if a window is still open.
///
/// @param template name of the template.
/// if empty string, a new empty logbook is created.
@ -366,8 +426,19 @@ function elog_create_logbook(name, [template])
dfref df_volatile_root = get_elog_df("", kdfVolatile)
dfref df_volatile_parent = df_volatile_root:logbooks
setdatafolder df_persistent_parent
if (CheckName(name, 11) != 0)
setdatafolder savedf
Abort "invalid logbook name"
return -1
endif
if (strlen(template) > 0)
dfref df_template = get_elog_df(template, kdfTemplates)
dfref df_existing = get_elog_df(name, kdfPersistent)
if (DataFolderRefStatus(df_existing))
KillDataFolder /Z df_existing
endif
DuplicateDataFolder df_template, df_persistent_parent:$name
else
NewDataFolder /o/s df_persistent_parent:$name
@ -695,7 +766,6 @@ function elog_create_entry(logbook, attributes, message, [encoding, graphs, repl
endif
result = -4
endif
cleanup_temp_files()
else
if (loglevel >= 2)
print "ELOG: failed to create temporary message file."
@ -759,7 +829,6 @@ function elog_add_attachment(logbook, id, graphs)
endif
result = -4 // error: elog returned error
endif
cleanup_temp_files()
endif
setdatafolder savedf
@ -817,6 +886,39 @@ static function /s prepare_command_line(logbook)
return cmd
end
/// format the URL for display to the user
///
///
/// @param logbook name of the target logbook
///
static function /s format_url(logbook)
string logbook
dfref df_general = get_elog_df("", kdfPersistent)
svar /sdfr=df_general hostname
nvar /sdfr=df_general port
nvar /sdfr=df_general ssl
svar /sdfr=df_general subdir
string cmd = ""
if ((nvar_exists(ssl)) && (ssl != 0))
cmd += "https://"
else
cmd += "http://"
endif
cmd += hostname
if ((nvar_exists(port)) && (port > 0))
cmd += ":" + num2str(port)
endif
if ((svar_exists(subdir)) && (strlen(subdir) > 0))
cmd += "/" + subdir
endif
cmd += "/" + logbook
return cmd
end
/// prepare screenshots of graph windows for attachments
///
/// prepares the attachment files from Igor graph windows
@ -875,13 +977,18 @@ static function /s create_graph_file(graphname, fileindex)
string graphname
variable fileindex
dfref df_volatile_root = get_elog_df("", kdfVolatile)
svar /sdfr=df_volatile_root temp_graph_files
string path = SpecialDirPath("Temporary", 0, 1, 0)
string ts = get_timestamp("_")
variable len = strlen(path)
if (numtype(len) == 0)
path += "elog_" + ts + "_" + num2str(fileindex) + ".png"
SavePICT /B=72 /E=-5 /M /O /W=(0,0,8,6) /WIN=$graphname /Z as path
if (v_flag != 0)
if (v_flag == 0)
temp_graph_files = AddListItem(path, temp_graph_files, ";", inf)
else
path = ""
endif
else
@ -921,12 +1028,30 @@ static function /s get_log_path()
return path
end
static function /s cleanup_temp_files()
string path = SpecialDirPath("Temporary", 0, 1, 0)
string cmd
sprintf cmd, "del \"%s\elog*.*\"", path
//ExecuteScriptText cmd
return path
/// delete temporary files created by the ELOG module.
///
/// this deletes all temporary graph files that are referenced by the volatile temp_graph_files list.
/// temp_graph_files is a semicolon-delimited string.
/// items are added by create_graph_file().
///
/// this function should be called before a new experiment is loaded or igor quits.
///
static function cleanup_temp_files()
dfref df_volatile_root = get_elog_df("", kdfVolatile)
if (DataFolderRefStatus(df_volatile_root))
svar /sdfr=df_volatile_root /z temp_graph_files
if (SVAR_Exists(temp_graph_files))
variable nfi = ItemsInList(temp_graph_files)
variable ifi
string sfi
for (ifi = 0; ifi < nfi; ifi += 1)
sfi = StringFromList(ifi, temp_graph_files)
DeleteFile /Z sfi
endfor
temp_graph_files = ""
endif
endif
return 0
end
static strconstant elog_success_msg = "Message successfully transmitted"
@ -1048,13 +1173,16 @@ function /s PearlElogPanel(logbook)
string win_name = logbook + "ElogPanel"
string win_title = "ELOG " + logbook
NewPanel /K=1 /N=$win_name /W=(600,200,926,494) as win_title
NewPanel /K=1 /N=$win_name /W=(600,200,1200,700) as win_title
win_name = s_name
ModifyPanel /w=$win_name cbRGB=(52224,52224,65280)
svar /sdfr=df_persistent attributes
svar /sdfr=df_persistent controls
svar /sdfr=df_persistent options
wave /t /sdfr=df_volatile attach_list
wave /sdfr=df_volatile attach_sel
svar /sdfr=df_volatile url
variable iattr
variable nattr = ItemsInList(attributes, ";")
@ -1066,35 +1194,28 @@ function /s PearlElogPanel(logbook)
string options_path
string variable_path
variable ypos = 2
Button b_login,win=$win_name, pos={264,ypos},size={46,20},proc=PearlElog#bp_login,title="Login"
Button b_login,win=$win_name, help={"Enter user name and password."}
Button b_login,win=$win_name, fcolor=(56576,60928,47872)
Button b_logout,win=$win_name, pos={264,ypos},size={46,20},proc=PearlElog#bp_logout,title="Logout"
Button b_logout,win=$win_name, help={"Clear user name and password."}
Button b_logout,win=$win_name, fcolor=(56576,60928,47872), disable=3
variable height = 0
for (iattr = 0; iattr < nattr; iattr += 1)
s_attr = StringFromList(iattr, attributes, ";")
s_control = StringFromList(iattr, controls, ";")
strswitch(s_control[0,1])
case "sv":
SetVariable $s_control, win=$win_name, pos={0,ypos}, size={260,16}, bodyWidth=200
SetVariable $s_control, win=$win_name, pos={0,ypos}, size={300,16}, bodyWidth=230
SetVariable $s_control, win=$win_name, title=s_attr, value= _STR:""
SetVariable $s_control, win=$win_name, userdata(attribute)=s_attr
ypos += 18
break
case "pm":
options_path = persistent_path + StringByKey(s_attr, options, "=", ";")
PopupMenu $s_control, win=$win_name, pos={0,ypos}, size={260,21}, bodyWidth=200
PopupMenu $s_control, win=$win_name, pos={0,ypos}, size={300,21}, bodyWidth=230
PopupMenu $s_control, win=$win_name, title=s_attr
PopupMenu $s_control, win=$win_name, mode=1, popvalue="Test", value= #options_path
PopupMenu $s_control, win=$win_name, userdata(attribute)=s_attr
ypos += 23
break
case "cb":
CheckBox $s_control, win=$win_name, pos={60,ypos}, size={260,14}
CheckBox $s_control, win=$win_name, pos={70,ypos}, size={300,14}
CheckBox $s_control, win=$win_name, title=s_attr, value= 1
CheckBox $s_control, win=$win_name, userdata(attribute)=s_attr
ypos += 17
@ -1102,48 +1223,81 @@ function /s PearlElogPanel(logbook)
endswitch
endfor
PopupMenu pm_attach,win=$win_name, pos={0,ypos},size={260,21},bodyWidth=200,title="Attachment"
PopupMenu pm_attach,win=$win_name, mode=1,popvalue="(none)",value=PearlElog#pm_list_attach_items()
PopupMenu pm_attach,win=$win_name, help={"Choose any visible Igor graph for attachment."}
Button b_select_attach_top,win=$win_name, pos={264,ypos},size={60,20},proc=PearlElog#bp_select_attach_top,title="Top Graph"
Button b_select_attach_top,win=$win_name, help={"Select top graph window."}
Button b_select_attach_top,win=$win_name, fcolor=(56576,60928,47872)
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}
ListBox lb_attach, win=$win_name, listWave=attach_list
ListBox lb_attach, win=$win_name, mode=1, selWave=attach_sel, selRow=-1
ListBox lb_attach, win=$win_name, widths={20,160,80}
ListBox lb_attach, win=$win_name, help={"Choose graphs to attach to the message."}
Button b_attach_top, win=$win_name, pos={420,2}, size={40,18}, title="top"
Button b_attach_top, win=$win_name, fcolor=(56576,60928,47872)
Button b_attach_top, win=$win_name, proc=PearlElog#bp_attach_top
Button b_attach_top, win=$win_name, help={"Select top graph for attachment."}
Button b_attach_all, win=$win_name, pos={460,2}, size={40,18}, title="all"
Button b_attach_all, win=$win_name, fcolor=(56576,60928,47872)
Button b_attach_all, win=$win_name, proc=PearlElog#bp_attach_allnone
Button b_attach_all, win=$win_name, help={"Select all graphs for attachment."}
Button b_attach_none, win=$win_name, pos={500,2}, size={40,18}, title="none"
Button b_attach_none, win=$win_name, fcolor=(56576,60928,47872)
Button b_attach_none, win=$win_name, proc=PearlElog#bp_attach_allnone
Button b_attach_none, win=$win_name, help={"Deselect all attachments."}
Button b_save_graphs, win=$win_name, pos={540,2}, size={40,18}, title="save"
Button b_save_graphs, win=$win_name, fcolor=(56576,60928,47872)
Button b_save_graphs, win=$win_name, proc=PearlElog#bp_save_graphs
Button b_save_graphs, win=$win_name, help={"Save selected graphs as PNG bitmap files."}
Button b_attach_up, win=$win_name, pos={576,20}, size={20,20}, title="\\W517"
Button b_attach_up, win=$win_name, fcolor=(56576,60928,47872)
Button b_attach_up, win=$win_name, proc=PearlElog#bp_attach_updown
Button b_attach_up, win=$win_name, help={"Move selected graph up."}
Button b_attach_dw, win=$win_name, pos={576,40}, size={20,20}, title="\\W523"
Button b_attach_dw, win=$win_name, fcolor=(56576,60928,47872)
Button b_attach_dw, win=$win_name, proc=PearlElog#bp_attach_updown
Button b_attach_dw, win=$win_name, help={"Move selected graph down."}
ypos += 246-160
Button b_submit,win=$win_name, pos={60,ypos},size={46,20},proc=PearlElog#bp_submit,title="Submit"
Button b_submit,win=$win_name, pos={70,ypos},size={46,20},proc=PearlElog#bp_submit,title="Submit"
Button b_submit,win=$win_name, help={"Submit form data to ELOG (new entry)."}
Button b_submit,win=$win_name, fcolor=(56576,60928,47872)
Button b_clear,win=$win_name, pos={110,ypos},size={46,20},proc=PearlElog#bp_clear,title="Clear"
Button b_clear,win=$win_name, pos={120,ypos},size={46,20},proc=PearlElog#bp_clear,title="Clear"
Button b_clear,win=$win_name, help={"Clear the form fields"}
Button b_clear,win=$win_name, fcolor=(56576,60928,47872)
ypos += 272-246
variable_path = volatile_path + "msg_id"
SetVariable sv_id,win=$win_name, pos={46,ypos},size={109,16},bodyWidth=94
SetVariable sv_id,win=$win_name, pos={51,ypos},size={119,16},bodyWidth=77
SetVariable sv_id,win=$win_name, title="ID",value=$variable_path
SetVariable sv_id,win=$win_name, help={"ID of last submitted message, or message to attach or reply to."}
TitleBox t_host, win=$win_name, pos={170,ypos+4}, size={112.00,14.00}, frame=0
TitleBox t_host, win=$win_name, variable=url
ypos += 270-272
Button b_attach,win=$win_name, pos={160,ypos},size={48,20},proc=PearlElog#bp_attach,title="Attach"
Button b_attach,win=$win_name, pos={170,ypos},size={48,20},proc=PearlElog#bp_attach,title="Attach"
Button b_attach,win=$win_name, help={"Attach the selected graph to an existing ELOG entry (correct ID required)."}
Button b_attach,win=$win_name, fcolor=(56576,60928,47872)
Button b_reply,win=$win_name, pos={210,ypos},size={48,20},proc=PearlElog#bp_submit,title="Reply"
Button b_reply,win=$win_name, pos={220,ypos},size={48,20},proc=PearlElog#bp_submit,title="Reply"
Button b_reply,win=$win_name, help={"Submit form data to ELOG as a reply to an existing message (correct ID required)."}
Button b_reply,win=$win_name, fcolor=(56576,60928,47872)
ypos += 184-270
TitleBox t_message,win=$win_name, pos={0,ypos},size={58,16},fixedSize=1,frame=0,anchor=RT,title="Message"
Button b_login,win=$win_name, pos={550,ypos},size={46,20},proc=PearlElog#bp_login,title="Login"
Button b_login,win=$win_name, help={"Enter user name and password."}
Button b_login,win=$win_name, fcolor=(56576,60928,47872)
Button b_logout,win=$win_name, pos={550,ypos},size={46,20},proc=PearlElog#bp_logout,title="Logout"
Button b_logout,win=$win_name, help={"Clear user name and password."}
Button b_logout,win=$win_name, fcolor=(56576,60928,47872), disable=3
SetWindow $win_name, hook(elogPanelHook)=PearlElog#elog_panel_hook
SetWindow $win_name, userdata(logbook)=logbook
DefineGuide UGH0={FT,ypos},UGV0={FL,60},UGH1={FB,-52},UGV1={FR,-2}
ypos += 160-270
TitleBox t_message,win=$win_name, pos={10,ypos},size={58,16},fixedSize=1,frame=0,anchor=RT,title="Message"
DefineGuide UGH0={FT,ypos},UGV0={FL,70},UGH1={FB,-52},UGV1={FR,-2}
NewNotebook /F=0 /N=Message /OPTS=3 /W=(115,404,345,341)/FG=(UGV0,UGH0,UGV1,UGH1) /HOST=#
Notebook kwTopWin, defaultTab=20, statusWidth=0, autoSave=0
Notebook kwTopWin font="Arial", fSize=10, fStyle=0, textRGB=(0,0,0)
Notebook kwTopWin fSize=10, fStyle=0, textRGB=(0,0,0)
RenameWindow #,Message
string nb_name = win_name + "#Message"
SetActiveSubwindow ##
// restore recently used attributes and message
@ -1155,6 +1309,7 @@ function /s PearlElogPanel(logbook)
if (svar_exists(recent_message) && (strlen(recent_message) > 0))
set_panel_message(win_name, recent_message)
endif
Notebook $nb_name selection={startOfFile,startOfFile}, findText={"",1}
setdatafolder savedf
return win_name
@ -1166,49 +1321,153 @@ static function elog_panel_hook(s)
Variable hookResult = 0
switch(s.eventCode)
case 0: // activate
string logbook = GetUserData(s.winName, "", "logbook")
if (strlen(logbook) > 0)
dfref df_volatile = get_elog_df(logbook, kdfVolatile)
svar /sdfr=df_volatile url
url = format_url(logbook)
update_attach_items(logbook)
endif
break
case 6: // resize
// move bottom-aligned controls when the window is resized
variable b_top = s.winRect.bottom + 4
Button b_submit,pos={60,b_top}
Button b_clear,pos={110,b_top}
Button b_submit,pos={70,b_top}
Button b_clear,pos={120,b_top}
TitleBox t_host, pos={170,b_top+4}
b_top += 24
Button b_attach,pos={160,b_top}
Button b_reply,pos={210,b_top}
Button b_attach,pos={170,b_top}
Button b_reply,pos={220,b_top}
Button b_login, pos={550,b_top}
Button b_logout, pos={550,b_top}
b_top += 2
SetVariable sv_id,pos={46,b_top}
SetVariable sv_id,pos={51,b_top}
break
endswitch
return hookResult // 0 if nothing done, else 1
end
/// get a list of graph windows for a popup menu.
static function /s pm_list_attach_items()
static constant kAttachColSel = 0
static constant kAttachColTitle = 1
static constant kAttachColName = 2
// get graph names
/// update the list of attachments
static function update_attach_items(logbook)
string logbook
dfref savedf = getdatafolderdfr()
dfref df_volatile = get_elog_df(logbook, kdfVolatile)
wave /t /sdfr=df_volatile attach_list
wave /sdfr=df_volatile attach_sel
if (!waveexists(attach_list))
return -1
endif
string names = WinList("*", ";", "WIN:1;VISIBLE:1")
names = SortList(names, ";", 16)
// get corresponding graph titles
variable nnames = ItemsInList(names, ";")
variable iname
string name
string item
string items = ""
// format each entry like "name: title"
for (iname = 0; iname < nnames; iname += 1)
name = StringFromList(iname, names, ";")
getwindow /z $name, wtitle
if (v_flag == 0)
item = ReplaceString(";", s_value, ", ") // title
item = item + " (" + name + ")"
items = AddListItem(item, items, ";", inf)
// remove closed graphs
variable i
variable k
variable n = DimSize(attach_list, 0)
string s
for (i = n-1; i >= 0; i -= 1)
s = attach_list[i][kAttachColName]
if (WhichListItem(s, names) < 0)
DeletePoints /M=0 i, 1, attach_list, attach_sel
endif
endfor
items = AddListItem("(none)", items, ";")
return items
// add new graphs
n = ItemsInList(names)
for (i = 0; i < n; i += 1)
s = StringFromList(i, names)
FindValue /text=s /txop=4 /z attach_list
if (v_value < 0)
k = DimSize(attach_list, 0)
Redimension /n=(k+1,3) attach_list, attach_sel
//InsertPoints /M=0 k, 1, attach_list, attach_sel
attach_list[k][kAttachColSel] = ""
attach_list[k][kAttachColTitle] = ""
attach_list[k][kAttachColName] = s
attach_sel[k][kAttachColSel] = 32
attach_sel[k][kAttachColTitle] = 0
attach_sel[k][kAttachColName] = 0
endif
endfor
// update titles
n = DimSize(attach_list, 0)
for (i = n-1; i >= 0; i -= 1)
s = attach_list[i][kAttachColName]
getwindow /z $s, wtitle
if (v_flag == 0)
attach_list[i][kAttachColTitle] = s_value
else
attach_list[i][kAttachColTitle] = s
endif
endfor
setdatafolder savedf
return 0
end
/// move an attachment item in the list of attachments
static function move_attach_item(logbook, item, distance)
string logbook
variable item
variable distance
dfref savedf = getdatafolderdfr()
dfref df_volatile = get_elog_df(logbook, kdfVolatile)
wave /t /sdfr=df_volatile attach_list
wave /sdfr=df_volatile attach_sel
variable n = DimSize(attach_list, 0)
variable dest = item + distance
if ((item >= 0) && (item < n) && (dest >= 0) && (dest < n))
string name = attach_list[item][kAttachColName]
variable sel = attach_sel[item][kAttachColSel]
DeletePoints /M=0 item, 1, attach_list, attach_sel
InsertPoints /M=0 dest, 1, attach_list, attach_sel
attach_list[dest][kAttachColName] = name
update_attach_items(logbook)
attach_sel[dest][kAttachColSel] = sel
endif
end
/// button procedure for the attachment up and down buttons
static function bp_attach_updown(ba) : ButtonControl
STRUCT WMButtonAction &ba
switch( ba.eventCode )
case 2: // mouse up
string logbook = GetUserData(ba.win, "", "logbook")
ControlInfo /w=$ba.win lb_attach
variable row = v_value
dfref df = $s_datafolder
wave /t /sdfr=df attach_list = $s_value
if (cmpstr(ba.ctrlName, "b_attach_up") == 0)
// up button
if (row >= 1)
move_attach_item(logbook, row, -1)
ListBox lb_attach, win=$ba.win, selRow=(row-1)
endif
else
// down button
if (row < DimSize(attach_list, 0) - 1)
move_attach_item(logbook, row, +1)
ListBox lb_attach, win=$ba.win, selRow=(row+1)
endif
endif
break
case -1: // control being killed
break
endswitch
return 0
end
/// button procedure for the Submit and Reply buttons
@ -1259,7 +1518,7 @@ static function bp_submit(ba) : ButtonControl
end
/// select top graph window for attachment
static function bp_select_attach_top(ba) : ButtonControl
static function bp_attach_top(ba) : ButtonControl
STRUCT WMButtonAction &ba
switch( ba.eventCode )
@ -1274,6 +1533,28 @@ static function bp_select_attach_top(ba) : ButtonControl
return 0
end
/// select/deselect all graph windows for attachment
static function bp_attach_allnone(ba) : ButtonControl
STRUCT WMButtonAction &ba
switch( ba.eventCode )
case 2: // mouse up
string logbook = GetUserData(ba.win, "", "logbook")
dfref df_volatile = get_elog_df(logbook, kdfVolatile)
wave /sdfr=df_volatile attach_sel
if (cmpstr(ba.ctrlName, "b_attach_all") == 0)
attach_sel[][kAttachColSel] = attach_sel[p][kAttachColSel] | 16
else
attach_sel[][kAttachColSel] = attach_sel[p][kAttachColSel] & ~16
endif
break
case -1: // control being killed
break
endswitch
return 0
end
static function bp_attach(ba) : ButtonControl
STRUCT WMButtonAction &ba
@ -1307,6 +1588,34 @@ static function bp_attach(ba) : ButtonControl
return 0
end
static function bp_save_graphs(ba) : ButtonControl
STRUCT WMButtonAction &ba
switch( ba.eventCode )
case 2: // mouse up
string logbook = GetUserData(ba.win, "", "logbook")
string graphs = get_panel_graphs(ba.win)
variable ngraphs = ItemsInList(graphs, ";")
variable igraph
string sgraph
string graph_path
for (igraph = 0; igraph < ngraphs; igraph += 1)
sgraph = StringFromList(igraph, graphs, ";")
graph_path = create_graph_file(sgraph, igraph)
if (strlen(graph_path) > 0)
print graph_path
endif
endfor
break
case -1: // control being killed
break
endswitch
return 0
end
static function bp_clear(ba) : ButtonControl
STRUCT WMButtonAction &ba
@ -1522,15 +1831,14 @@ end
/// get the names of the graphs selected for attachment
///
/// @param windowname panel window name
/// @returns a semicolon-separated list,
/// or the empty string if the selection is not valid.
///
/// in the current version, the function returns at most one graph.
/// in future versions, the function may return more than one graph.
///
static function /s get_panel_graphs(windowname)
string windowname // panel window name
dfref savedf = getdatafolderdfr()
if (strlen(windowname) == 0)
windowname = get_default_panel_name()
endif
@ -1538,24 +1846,38 @@ static function /s get_panel_graphs(windowname)
return ""
endif
ControlInfo /W=$windowname pm_attach
// menu item has the form: "title (name)"
string graphname = ReplaceString(")", StringFromList(ItemsInList(s_value, "(") - 1, s_value, "("), "")
string logbook = GetUserData(windowname, "", "logbook")
dfref df_volatile = get_elog_df(logbook, kdfVolatile)
wave /t /sdfr=df_volatile attach_list
wave /sdfr=df_volatile attach_sel
string graphs = ""
string windows = WinList(graphname, ";", "WIN:1")
string windows = ""
string graphname
variable n = DimSize(attach_sel, 0)
variable i
for (i = 0; i < n; i += 1)
if (attach_sel[i][kAttachColSel] & 16)
graphname = attach_list[i][kAttachColName]
windows = WinList(graphname, ";", "WIN:1")
if (ItemsInList(windows) == 1)
graphs = graphname
else
graphs = ""
graphs = AddListItem(graphname, graphs, ";", inf)
endif
endif
endfor
return graphs
end
/// update selection of graphs for attachment
///
/// @param windowname panel window name. looks for default panel if empty.
///
/// @param graphs semicolon-separated list of names of graph windows to select for attachment.
///
static function /s set_panel_graphs(windowname, graphs)
string windowname // panel window name. looks for default panel if empty.
string graphs // name of graph window to select for attachment.
string windowname
string graphs
if (strlen(windowname) == 0)
windowname = get_default_panel_name()
@ -1564,23 +1886,21 @@ static function /s set_panel_graphs(windowname, graphs)
return ""
endif
// the panel supports only one graph
string graph = StringFromList(0, graphs, ";")
string logbook = GetUserData(windowname, "", "logbook")
update_attach_items(logbook)
dfref df_volatile = get_elog_df(logbook, kdfVolatile)
wave /t /sdfr=df_volatile attach_list
wave /sdfr=df_volatile attach_sel
string items = pm_list_attach_items()
string item
string itemname
variable nitems = ItemsInList(items, ";")
variable iitem
for (iitem = 0; iitem < nitems; iitem += 1)
item = StringFromList(iitem, items, ";")
itemname = ReplaceString(")", StringFromList(ItemsInList(item, "(") - 1, item, "("), "")
if (cmpstr(graph, itemname) == 0)
iitem += 1
PopupMenu pm_attach mode=iitem, win=$windowname
break
variable n = DimSize(attach_sel, 0)
variable i
string graphname
for (i = 0; i < n; i += 1)
graphname = attach_list[i][kAttachColName]
if (WhichListItem(graphname, graphs)>= 0)
attach_sel[i][kAttachColSel] = 48
else
attach_sel[i][kAttachColSel] = 32
endif
endfor
return graph
end

View File

@ -454,7 +454,7 @@ function Au4f(w, x): fitfunc
vc1 = w[ip] / sqrt(pi) * vc2
vc3 = w[ip+1]
vc4 = vc2 * w[ip+2] / 2
v += vc1 * Voigt(vc2 * (x - vc3), vc4)
v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
endfor
return v
@ -491,25 +491,25 @@ function Au4f_2p2(w, x): fitfunc
vc1 = w[3] / sqrt(pi) * vc2
vc3 = w[4]
vc4 = vc2 * w[5] / 2
v += vc1 * Voigt(vc2 * (x - vc3), vc4)
v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
// 5/2 surface
vc1 = w[3] / sqrt(pi) * vc2 * w[9]
vc3 = w[4] + w[10]
vc4 = vc2 * w[5] / 2
v += vc1 * Voigt(vc2 * (x - vc3), vc4)
v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
// 7/2 bulk
vc1 = w[6] / sqrt(pi) * vc2
vc3 = w[7]
vc4 = vc2 * w[8] / 2
v += vc1 * Voigt(vc2 * (x - vc3), vc4)
v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
// 7/2 surface
vc1 = w[6] / sqrt(pi) * vc2 * w[9]
vc3 = w[7] + w[10]
vc4 = vc2 * w[8] / 2
v += vc1 * Voigt(vc2 * (x - vc3), vc4)
v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
return v
@ -578,37 +578,37 @@ function Au4f_2p3(w, x): fitfunc
vc1 = w[3] / sqrt(pi) * vc2
vc3 = w[4]
vc4 = vc2 * w[5] / 2
v += vc1 * Voigt(vc2 * (x - vc3), vc4)
v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
// 5/2 surface
vc1 = w[3] / sqrt(pi) * vc2 * w[9]
vc3 = w[4] + w[10]
vc4 = vc2 * w[5] / 2
v += vc1 * Voigt(vc2 * (x - vc3), vc4)
v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
// 5/2 2nd layer
vc1 = w[3] / sqrt(pi) * vc2 * w[11]
vc3 = w[4] + w[12]
vc4 = vc2 * w[5] / 2
v += vc1 * Voigt(vc2 * (x - vc3), vc4)
v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
// 7/2 bulk
vc1 = w[6] / sqrt(pi) * vc2
vc3 = w[7]
vc4 = vc2 * w[8] / 2
v += vc1 * Voigt(vc2 * (x - vc3), vc4)
v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
// 7/2 surface
vc1 = w[6] / sqrt(pi) * vc2 * w[9]
vc3 = w[7] + w[10]
vc4 = vc2 * w[8] / 2
v += vc1 * Voigt(vc2 * (x - vc3), vc4)
v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
// 7/2 2nd layer
vc1 = w[6] / sqrt(pi) * vc2 * w[11]
vc3 = w[7] + w[12]
vc4 = vc2 * w[8] / 2
v += vc1 * Voigt(vc2 * (x - vc3), vc4)
v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
return v

View File

@ -0,0 +1,900 @@
#pragma rtGlobals=3
#pragma version = 1.00
#pragma IgorVersion = 6.36
#pragma ModuleName = PearlMatrixImport
// author: matthias.muntwiler@psi.ch
// Copyright (c) 2016 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 data file import for omicron matrix (STM) files
///
/// the matrix file import requires the matrix file reader XOP by thomas braun
/// (http://www.igorexchange.com/project/matrixFileReader)
/// which in turn requires an installation of vernissage by omicron nanotechnology.
///
/// @warning EXPERIMENTAL
/// the matrix import module and its interface may change radically in future revisions!
///
/// @author matthias muntwiler, matthias.muntwiler@psi.ch
///
/// @copyright 2016 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 PearlMatrixImport
/// @brief data file import for omicron matrix (STM) files
///
/// PearlMatrixImport is declared in @ref pearl-matrix-import.ipf.
static strconstant package_name = "pearl_matrix_import"
static strconstant package_path = "root:packages:pearl_matrix_import:"
static strconstant ks_filematch_mtrx = "*_mtrx"
/// initialize the package data folder.
///
///
static function init_package()
dfref savedf = getdatafolderdfr()
setdatafolder root:
newdatafolder /o/s packages
newdatafolder /o/s $package_name
variable /g loglevel = 3
string /g dataFilePath = ""
string /g resultFilePath = ""
variable /g runCycle = 0
variable /g scanCycle = 0
string /g channelName = ""
variable /g brickletID = 0
variable /g V_MatrixFileReaderOverwrite = 1
variable /g V_MatrixFileReaderFolder = 0
variable /g V_MatrixFileReaderDouble = 0
setdatafolder savedf
return 0
end
/// check that the package data folder exists
///
/// initialize the package if the folder does not exist.
///
static function check_package_folder()
dfref df_pack = $(package_path)
if (DataFolderRefStatus(df_pack))
svar /sdfr=df_pack /z resultFilePath
if (!svar_exists(resultFilePath))
init_package()
endif
else
init_package()
endif
end
/// initialize the package and reload preferences after an experiment is loaded.
static function AfterFileOpenHook(refNum,file,pathName,type,creator,kind)
Variable refNum,kind
String file,pathName,type,creator
if( (kind >= 1) && (kind <= 2))
init_package()
//load_prefs()
endif
return 0
end
/// open a matrix file that was dropped into Igor.
///
/// preliminary implementation.
/// this should rather load the entire file and display a preview.
/// graph windows should be reused by subsequent loads.
/// also decide on a data saving location.
///
static function BeforeFileOpenHook(refNum,fileName,path,type,creator,kind)
Variable refNum,kind
String fileName,path,type,creator
Variable handledOpen = 0
if (StringMatch(fileName, ks_filematch_mtrx))
setdatafolder root:
newdatafolder /o /s matrix
mtrx_load_preview("matrix", path, fileName)
handledOpen = 1
endif
return handledOpen
End
/// generate elog message from bricklet metadata
///
/// @param metadata two-column text wave
///
function /s matrix_format_elog_message(metadata)
wave /t metadata
string key
string value
variable nkeys = dimsize(metadata, 0)
variable ikey
string message_keys
message_keys = "resultFileName;sampleName;channelName;"
message_keys += "XYScanner.Points.value;XYScanner.Raster_Time.value;XYScanner.Raster_Time.unit;XYScanner.Width.value;XYScanner.Width.unit;XYScanner.Height.value;XYScanner.Height.unit;"
message_keys += "GapVoltageControl.Voltage.value;GapVoltageControl.Voltage.unit;"
message_keys += "Regulator.Loop_Gain_1_I.value;Regulator.Loop_Gain_1_I.unit;Regulator.Setpoint_1.value;Regulator.Setpoint_1.unit;"
message_keys += "Spectroscopy.Device_1_Start.value;Spectroscopy.Device_1_Start.unit;Spectroscopy.Spectroscopy_Mode.value;"
string message
message_keys = ""
for (ikey = 0; ikey < nkeys; ikey += 1)
key = metadata[ikey][0]
value = metadata[ikey][1]
if (WhichListItem(key, message_keys) >= 0)
message += key + " = " + value + "\r"
endif
endfor
end
function matrix_preview_2d(data, metadata)
wave data
wave /t metadata
Display
AppendImage data
ModifyImage data ctab= {*,*,Mud,0}
ModifyGraph margin(left)=30,margin(bottom)=30,margin(top)=5,margin(right)=5,height={Plan,1,left,bottom}
ModifyGraph mirror=2
ModifyGraph nticks=3
ModifyGraph axThick=0.5
ModifyGraph btLen=4
end
/// load the preview of a Matrix data file
///
/// 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.
///
/// @param filename name of a file in the directory specified by the pearl_explorer_filepath path object.
///
/// @return wave reference of the preview image
///
static function /wave preview_matrix_file(filename)
string filename
dfref saveDF = GetDataFolderDFR()
setdatafolder $package_path
svar s_preview_file
svar s_preview_source
mtrx_load_preview("preview_image", "pearl_explorer_filepath", filename)
s_preview_file = filename
s_preview_source = ""
wave /z preview_image
svar /z s_file_info
if (! svar_exists(s_file_info))
string /g s_file_info
endif
if (strlen(s_preview_file) > 0)
s_file_info = mtrx_load_info("pearl_explorer_filepath", filename)
else
s_file_info = ""
endif
setdatafolder saveDF
return preview_image
end
/// from matrixfilereader help
Structure errorCode
int32 SUCCESS
int32 UNKNOWN_ERROR
int32 ALREADY_FILE_OPEN
int32 EMPTY_RESULTFILE
int32 FILE_NOT_READABLE
int32 NO_NEW_BRICKLETS
int32 WRONG_PARAMETER
int32 INTERNAL_ERROR_CONVERTING_DATA
int32 NO_FILE_OPEN
int32 INVALID_RANGE
int32 WAVE_EXIST
EndStructure
/// from matrixfilereader help
static Function initStruct(errorCode)
Struct errorCode &errorCode
errorCode.SUCCESS =0
errorCode.UNKNOWN_ERROR=10001
errorCode.ALREADY_FILE_OPEN=10002
errorCode.EMPTY_RESULTFILE=10004
errorCode.FILE_NOT_READABLE=10008
errorCode.NO_NEW_BRICKLETS=10016
errorCode.WRONG_PARAMETER=10032
errorCode.INTERNAL_ERROR_CONVERTING_DATA=10064
errorCode.NO_FILE_OPEN=10128
errorCode.INVALID_RANGE=10256
errorCode.WAVE_EXIST=10512
end
/// load all data from a Matrix data file.
///
function mtrx_load_all()
struct errorCode errorCode
initStruct(errorCode)
#if exists("MFR_OpenResultFile")
MFR_OpenResultFile
if(V_flag != errorCode.SUCCESS)
MFR_GetXOPErrorMessage
return -1
endif
MFR_GetBrickletData
if(V_flag != errorCode.SUCCESS)
MFR_GetXOPErrorMessage
return -1
endif
MFR_GetBrickletMetaData
if(V_flag != errorCode.SUCCESS)
MFR_GetXOPErrorMessage
return -1
endif
return 0
#else
return -1
#endif
end
/// parse matrix file names
///
/// parse matrix file names for result name, run cycle, scan cycle, and channel.
///
/// @param fileName matrix result or data file name (without path).
///
/// @param resultFile (out) base name of the result file.
/// append "_%04u.mtrx" to get the actual result file.
/// we do not know the chain link number at this stage.
///
/// @param runCycle (out) run cycle number. necessary to look up the bricklet ID.
///
/// @param scanCycle (out) scan cycle number. necessary to look up the bricklet ID.
///
/// @param channel (out) channel name.
///
/// @return file type
/// @arg 0 result file (logbook)
/// @arg 1 result data file (bricklet)
///
/// result file names look like:
/// default_2015Apr20-124353_STM-STM_AtomManipulation_0001.mtrx,
/// default_2015Apr20-124353_STM-STM_AtomManipulation_0002.mtrx, etc.
/// the function returns the first part up to the experiment name ("AtomManipulation" in the examples).
/// all other return values set to defaults and must not be regarded.
///
/// result data files look like:
/// default_2015Apr20-124353_STM-STM_AtomManipulation--136_1.Aux1(V)_mtrx,
/// default_2015Apr20-124353_STM-STM_AtomManipulation--136_1.I(V)_mtrx,
/// default_2015Apr20-124353_STM-STM_AtomManipulation--14_1.I_mtrx,
/// default_2015Apr20-124353_STM-STM_AtomManipulation--14_1.Z_mtrx, etc.
/// the function returns all results as described in the parameter list.
///
function mtrx_parse_filename(fileName, resultFile, runCycle, scanCycle, channel)
string fileName
string &resultFile
variable &runCycle
variable &scanCycle
string &channel
variable fileType = 0
resultFile = ""
channel = ""
runCycle = 0
scanCycle = 0
string regexp = ""
string index1 = ""
string index2 = ""
string extension = ""
if (StringMatch(fileName, "*.mtrx"))
regexp = "(.+)_([[:digit:]]+)\.(.+)"
SplitString /E=regexp fileName, resultFile, index1, extension
fileType = 0
else
regexp = "(.+)--([[:digit:]]+)_([[:digit:]]+)\.((.+)_mtrx)"
SplitString /E=regexp fileName, resultFile, index1, index2, extension, channel
fileType = 1
runCycle = str2num(index1)
scanCycle = str2num(index2)
endif
return fileType
end
/// split a matrix filename and return the first three parts
///
/// we assume that the second (third) part contains the date (time).
/// the parts are separated by dash or underscore.
///
function /s mtrx_split_filename(fileName, prefix, datepart, timepart)
string fileName
string &prefix
string &datepart
string &timepart
string regexp
regexp = "([[:alpha:][:digit:]]+)[-_]([[:alpha:][:digit:]]+)[-_]([[:alpha:][:digit:]]+)[-_].+"
SplitString /E=regexp fileName, prefix, datepart, timepart
return datepart
end
/// create or look up a data folder based on a matrix file name.
///
/// the name of the folder is mtrx_date_time, where date and time are parsed from the file name.
/// for this to work, the file name must consist of at least three parts that are separated by dash or underscore.
/// the second (third) part contains the date (time).
/// date and time are copied as strings.
///
/// if the data folder exists, a reference to the existing folder is returned.
///
/// @param fileName name of the result or data file.
///
/// @param df_base (optional) base data folder.
/// default: current folder.
///
/// @return reference of the newly created or existing data folder.
///
function /df mtrx_create_folder(fileName, [df_base])
string fileName
dfref df_base
if (ParamIsDefault(df_base))
df_base = GetDataFolderDFR()
endif
string prefix
string datepart
string timepart
string folderName
mtrx_split_filename(fileName, prefix, datepart, timepart)
folderName = "mtrx_" + datepart + "_" + timepart
folderName = CleanupName(folderName, 0)
dfref df_save = GetDataFolderDFR()
setdatafolder root:
newdatafolder /o /s $foldername
dfref df = GetDataFolderDFR()
setdatafolder df_save
return df
end
/// create a data folder for bricklet data.
///
/// the name of the folder is, for example "r23s2" where the first (second) number is the run (scan) cycle.
/// run cycle and scan cycle numbers are taken from the open matrix file unless overridden by optional arguments.
///
/// if the data folder exists, a reference to the existing folder is returned.
/// if one of the run or scan cycle numbers is lower than 1, the base folder is returned.
///
/// @param df_base (optional) base data folder.
/// default: current folder.
///
/// @param runCycle (optional) run cycle number. must be >= 1.
/// default: from last mtrx_open_file call.
///
/// @param scanCycle (optional) scan cycle number. must be >= 1.
/// default: from last mtrx_open_file call.
///
/// @return reference of the newly created or existing data folder.
///
function /df mtrx_get_cycle_folder([df_base, runCycle, scanCycle])
dfref df_base
variable runCycle
variable scanCycle
dfref df_save = GetDataFolderDFR()
dfref df_pack = $(package_path)
if (ParamIsDefault(df_base))
df_base = GetDataFolderDFR()
endif
if (ParamIsDefault(runCycle))
nvar /sdfr=df_pack defRunCycle = runCycle
runCycle = defRunCycle
endif
if (ParamIsDefault(scanCycle))
nvar /sdfr=df_pack defScanCycle = scanCycle
scanCycle = defScanCycle
endif
string dfname
if ((runCycle >= 1) && (scanCycle >= 1))
sprintf dfname, "r%us%u", runCycle, scanCycle
setdatafolder df_base
dfref df = $dfname
if (DataFolderRefStatus(df) == 0)
newdatafolder $dfname
dfref df = $dfname
endif
else
dfref df = df_base
endif
setdatafolder df_save
return df
end
/// find out bricklet ID of a file
///
/// @warning EXPERIMENTAL
/// the code of this function is inefficient.
/// the function may be removed in a later version.
///
/// @param resultFile base name of result file without chain link number and extension.
/// as returned by mtrx_parse_filename.
///
/// @param runCycle requested run cycle.
/// 0 = first available.
///
/// @param scanCycle requested scan cycle.
/// 0 = first available.
///
/// @param channel channel name. for example: "I", "Z", "Aux(V)", etc.
/// empty string: first available.
///
/// @return bricklet ID, or -1 if an error occurred.
///
function mtrx_file_brickletID(resultFile, runCycle, scanCycle, channel)
string resultFile
variable runCycle
variable scanCycle
string channel
dfref df_overview = NewFreeDataFolder()
variable link = 1
variable id = -1
variable idx = 0
string resultFileName
#if exists("MFR_OpenResultFile")
struct errorCode errorCode
initStruct(errorCode)
do
sprintf resultFileName, "%s_%04u.mtrx", resultFile, link
MFR_OpenResultFile /K resultFileName
if(V_flag != errorCode.SUCCESS)
return -1
endif
MFR_CreateOverviewTable /DEST=df_overview
// dimension labels are: brickletID, scanCycleCount, runCycleCount, sequenceID, dimension, channelName
wave /t /sdfr=df_overview overviewTable
make /n=(dimsize(overviewTable, 0)) /i /u /free runcycles, scancycles, ids, match
make /n=(dimsize(overviewTable, 0)) /t /free channels
ids = str2num(overviewtable[p][%brickletID])
if (runcycle > 0)
runcycles = str2num(overviewtable[p][%runCycleCount])
else
runcycles = runcycle
endif
if (scancycle > 0)
scancycles = str2num(overviewtable[p][%scanCycleCount])
else
scancycles = scancycle
endif
if (strlen(channel) > 0)
channels = overviewTable[p][%channelName]
else
channels = channel
endif
Extract /FREE ids, match_ids, (scancycles == scanCycle) && (runcycles == runCycle) && (cmpstr(channels, channel) == 0)
if (numpnts(match_ids) > 0)
id = match_ids[0]
else
link += 1
endif
while (id < 0)
#endif
return id
end
/// open a matrix result or data file
///
/// this function opens a matrix result file (.mtrx) or data file (.*_mtrx).
///
/// if a data file is selected, the function locates the corresponding result file, opens it,
/// and looks up the bricklet ID of the data file.
/// if a result file is selected, the function opens it but does not look up bricklet IDs.
///
/// the result file remains open and can be accessed using the mtrx_ functions or MFR_ operations.
/// once a result file is open, you can easily access any bricklets linked to it,
/// i.e., any run cycle, scan cycle, and channel.
///
/// the function stores information about the opened file in a global package data folder.
/// if the same result file is opened again later, the information is reused and the file not read again.
/// this may cause problems if the file has been modified in the meantime,
/// or if the cached data become corrupt for some reason.
/// the function detects if a data file is not linked in the open result file, and updates the cache.
/// in other situations it may be necessary to force a reload.
///
/// @todo fix possible cache issues, add an option to override the cache.
///
/// @param pathName igor path name or empty string.
///
/// @param fileName file name, with or without path, or empty string.
///
/// @return file type
/// @arg 0 result file (logbook)
/// @arg 1 result data file (bricklet)
/// @arg -1 error, no data loaded
/// @arg -2 matrixfilereader.xop not installed
///
function mtrx_open_file(pathName, fileNameOrPath)
string pathName
string fileNameOrPath
check_package_folder()
dfref df_save = GetDataFolderDFR()
dfref df_pack = $(package_path)
svar /sdfr=df_pack dataFilePath
svar /sdfr=df_pack resultFilePath
nvar /sdfr=df_pack runCycle
nvar /sdfr=df_pack scanCycle
svar /sdfr=df_pack channelName
nvar /sdfr=df_pack brickletID
string loc_resultFileName
string loc_resultFilePath
variable loc_runCycle
variable loc_scanCycle
string loc_channelName
// make sure we have a valid and complete file path
GetFileFolderInfo /P=$pathName /Q /Z=2 fileNameOrPath
string filePath
if ((v_flag == 0) && (v_isFile))
filePath = s_path
else
return -1
endif
// get base file name
string fileName
string fileDir
string baseFileName
variable fileType
fileName = ParseFilePath(0, filePath, ":", 1, 0)
fileDir = ParseFilePath(1, filePath, ":", 1, 0)
fileType = mtrx_parse_filename(fileName, baseFileName, loc_runCycle, loc_scanCycle, loc_channelName)
variable link = 1
variable id = -1
variable result = -1
variable using_cache = 0
struct errorCode errorCode
initStruct(errorCode)
do
sprintf loc_resultFileName, "%s_%04u.mtrx", baseFileName, link
loc_resultFilePath = fileDir + loc_resultFileName
#if exists("MFR_OpenResultFile")
if ((strlen(resultFilePath) == 0) || (cmpstr(loc_resultFilePath, resultFilePath) != 0))
MFR_OpenResultFile /K loc_resultFilePath
if(V_flag != errorCode.SUCCESS)
MFR_GetXOPErrorMessage
result = -1
break
endif
resultFilePath = loc_resultFilePath
if (fileType == 1)
dataFilePath = filePath
else
dataFilePath = ""
endif
runCycle = 0
scanCycle = 0
channelName = ""
brickletID = 0
MFR_CreateOverviewTable /DEST=df_pack
if(V_flag != errorCode.SUCCESS)
MFR_GetXOPErrorMessage
result = -1
break
endif
using_cache = 0
else
using_cache = 1
endif
#else
print "matrixfilereader.xop not installed"
result = -2
break
#endif
// dimension labels are: brickletID, scanCycleCount, runCycleCount, sequenceID, dimension, channelName
wave /t /sdfr=df_pack overviewTable
make /n=(dimsize(overviewTable, 0)) /i /u /o df_pack:runCycles, df_pack:scanCycles, df_pack:ids
make /n=(dimsize(overviewTable, 0)) /t /o df_pack:channels
wave /sdfr=df_pack ids, runCycles, scanCycles
wave /t /sdfr=df_pack channels
ids = str2num(overviewtable[p][%brickletID])
runCycles = str2num(overviewtable[p][%runCycleCount])
scanCycles = str2num(overviewtable[p][%scanCycleCount])
channels = overviewTable[p][%channelName]
result = fileType
// if a data file is opened, make sure we found the right result file
if ((loc_runCycle > 0) && (loc_scanCycle > 0))
Extract /FREE ids, match_ids, (runCycles == loc_runCycle) && (scanCycles == loc_scanCycle) && (cmpstr(channels, loc_channelName) == 0)
if (numpnts(match_ids) > 0)
id = match_ids[0]
runCycle = loc_runCycle
scanCycle = loc_scanCycle
channelName = loc_channelName
brickletID = id
break
elseif (using_cache)
resultFilePath = ""
else
link += 1
endif
else
break
endif
while (id < 0)
return result
end
/// load a preview image from a Matrix data file.
///
/// the data wave is loaded into the current data folder.
///
/// @param destName destination wave name. the wave is created in the current data folder.
///
/// @param pathName igor symbolic path name. can be empty if the path is specified in FileName or a dialog box should be displayed
///
/// @param fileName if empty a dialog box shows up
/// the file name must adhere to the format
/// "{prefix}-{date}-{time}-{anything}--{run_cycle}_{scan_cycle}.{extension}".
/// the first three seperators can alternatively be underscores.
/// it may be necessary to change the configuration of the Matrix application.
///
/// @param traces (currently not used) semicolon-separated list of preferred traces.
/// the items of the list are match strings for the Igor StringMatch function.
/// only the first matching trace is loaded from the file.
/// default: "*Up;*Down;*ReUp;*ReDown;"
///
/// @return semicolon-separated list of loaded waves including partial path from current data folder.
///
function /s mtrx_load_preview(destName, pathName, fileName, [traces])
string destName
string pathName
string fileName
string traces
if (ParamIsDefault(traces))
traces = "*Up;*Down;*ReUp;*ReDown;"
endif
dfref df_save = GetDataFolderDFR()
string datanames = ""
string datapaths = ""
variable filestatus = mtrx_open_file(pathName, fileName)
if (filestatus != 1)
return ""
endif
dfref df_pack = $(package_path)
svar /sdfr=df_pack dataFilePath
svar /sdfr=df_pack resultFilePath
nvar /sdfr=df_pack runCycle
nvar /sdfr=df_pack scanCycle
svar /sdfr=df_pack channelName
nvar /sdfr=df_pack brickletID
#if exists("MFR_OpenResultFile")
dfref df_data = df_save
variable /g df_data:V_MatrixFileReaderOverwrite = 1
variable /g df_data:V_MatrixFileReaderFolder = 0
variable /g df_data:V_MatrixFileReaderDouble = 0
struct errorCode errorCode
initStruct(errorCode)
MFR_GetBrickletData /N=destName /R=(brickletID) /S=2 /DEST=df_data
if(V_flag == errorCode.SUCCESS)
datanames = S_waveNames
variable i
variable n = ItemsInList(datanames)
string s
s = StringFromList(0, datanames)
wave data = $s
mtrx_scale_dataset(data)
if (WaveDims(data) == 2)
subtract_line_bg(data)
endif
datapaths = AddListItem(GetWavesDataFolder(data, 4), datapaths, ";", inf)
for (i = 1; i < n; i += 1)
s = StringFromList(i, datanames)
killwaves /z $s
endfor
else
MFR_GetXOPErrorMessage
endif
//MFR_GetBrickletMetaData /N=ANickName /R=(brickletID) // /DEST=dfref
#else
print "matrixfilereader.xop not installed"
#endif
setdatafolder df_save
return datapaths
end
/// load all data from a Matrix data file.
///
/// the data wave is loaded into a sub-subfolder the current data folder.
/// the relative path has the format ":mtrx_{date}_{time}:r{run_cycle}s{scan_cycle}",
/// where the parameters {date}, {time}, {run_cycle} and {scan_cycle} are copied from the file name.
/// the file name must be formatted according to the specifications set out below.
///
/// @param pathName igor symbolic path name. can be empty if the path is specified in FileName or a dialog box should be displayed
///
/// @param fileName if empty a dialog box shows up
/// the file name must adhere to the format
/// "{prefix}-{date}-{time}-{anything}--{run_cycle}_{scan_cycle}.{extension}".
/// the first three seperators can alternatively be underscores.
/// it may be necessary to change the configuration of the Matrix application.
///
/// @param traces (currently not used) semicolon-separated list of preferred traces.
/// the items of the list are match strings for the Igor StringMatch function.
/// only matching traces are loaded from the file.
/// default: "*Up;*Down;*ReUp;*ReDown;"
///
/// @return semicolon-separated list of loaded waves including partial path from current data folder.
///
function /s mtrx_load_file(pathName, fileName, [traces])
string pathName
string fileName
string traces
if (ParamIsDefault(traces))
traces = "*Up;*Down;*ReUp;*ReDown;"
endif
dfref df_save = GetDataFolderDFR()
string datanames = ""
string datapaths = ""
variable filestatus = mtrx_open_file(pathName, fileName)
if (filestatus != 1)
return ""
endif
dfref df_pack = $(package_path)
svar /sdfr=df_pack dataFilePath
svar /sdfr=df_pack resultFilePath
nvar /sdfr=df_pack runCycle
nvar /sdfr=df_pack scanCycle
svar /sdfr=df_pack channelName
nvar /sdfr=df_pack brickletID
#if exists("MFR_OpenResultFile")
string resultFileName = ParseFilePath(0, resultFilePath, ":", 1, 0)
dfref df_result = mtrx_create_folder(resultFileName, df_base=df_save)
dfref df_data = mtrx_get_cycle_folder(df_base = df_result)
variable /g df_data:V_MatrixFileReaderOverwrite = 1
variable /g df_data:V_MatrixFileReaderFolder = 0
variable /g df_data:V_MatrixFileReaderDouble = 0
struct errorCode errorCode
initStruct(errorCode)
string name
name = CleanupName(channelName, 0)
MFR_GetBrickletData /N=name /R=(brickletID) /DEST=df_data
if(V_flag == errorCode.SUCCESS)
datanames = S_waveNames
variable i
variable n = ItemsInList(datanames)
string s
for (i = 0; i < n; i += 1)
s = StringFromList(i, datanames)
wave /sdfr=df_data data = $s
mtrx_scale_dataset(data)
datapaths = AddListItem(GetWavesDataFolder(data, 4), datapaths, ";", inf)
endfor
else
MFR_GetXOPErrorMessage
endif
//MFR_GetBrickletMetaData /N=ANickName /R=(brickletID) // /DEST=dfref
#else
print "matrixfilereader.xop not installed"
#endif
setdatafolder df_save
return datapaths
end
function mtrx_scale_dataset(data)
wave data
dfref df_pack = $(package_path)
nvar /sdfr=df_pack runCycle
nvar /sdfr=df_pack scanCycle
svar /sdfr=df_pack channelName
nvar /sdfr=df_pack brickletID
string scanDir = StringFromList(2, NameOfWave(data), "_")
if (WaveDims(data) == 2)
Note data, "AxisLabelX=X"
Note data, "AxisLabelY=Y"
endif
Note data, "AxisLabelD=" + channelName
string title
sprintf title, "%u-%u %s %s", runCycle, scanCycle, channelName, scanDir
Note data, "Dataset=" + title
end
/// load descriptive info from a Matrix data file.
///
/// the info string lists the following information for each scan contained in the file:
/// - path of the scan group inside the file.
/// - number of scan positions.
/// - dataset names of scan positioners.
/// - dataset names of detectors.
///
/// @param APathName igor symbolic path name. can be empty if the path is specified in AFileName or a dialog box should be displayed
///
/// @param AFileName if empty a dialog box shows up
///
/// @return newline terminated string.
///
function /s mtrx_load_info(APathName, AFileName)
string APathName
string AFileName
dfref saveDF = GetDataFolderDFR()
dfref fileDF = NewFreeDataFolder()
setdatafolder fileDF
variable fileID
string filepath
string scanpaths
variable nscans
variable iscan
string scanpath
string info = ""
setdatafolder saveDF
return info
end
/// remove linear background line-by-line
///
function subtract_line_bg(img)
wave img
variable nx = dimsize(img, 0)
variable ny = dimsize(img, 1)
variable iy
make /n=(nx) /free line, fit
for (iy = 0; iy < ny; iy += 1)
line = img[p][iy]
if (numtype(sum(line)) == 0)
CurveFit /N /Q /NTHR=0 line line /D=fit
img[][iy] = line[p] - fit[p]
endif
endfor
end

File diff suppressed because it is too large Load Diff

View File

@ -703,3 +703,99 @@ function scienta_poly_bg(w, e, a): fitfunc
return bg * (base + pk1 + pk2 + pk3)
end
/// parameter dialog for the redim_linbg_reduction() function
///
/// @param param parameter string in a key1=value1;key2=value2;... list.
/// the parameter string is passed by reference.
/// see redim_linbg_reduction() for a description of parameters.
///
/// @return zero if the user clicked OK, non-zero if the user clicked Cancel.
///
function prompt_redim_linbg_reduction(param)
string &param
variable Lcrop = NumberByKey("Lcrop", param, "=", ";")
variable Lsize = NumberByKey("Lsize", param, "=", ";")
variable Hcrop = NumberByKey("Hcrop", param, "=", ";")
variable Hsize = NumberByKey("Hsize", param, "=", ";")
variable Cpos = NumberByKey("Cpos", param, "=", ";")
variable Csize = NumberByKey("Csize", param, "=", ";")
prompt Lcrop, "Lower cropping region"
prompt Hcrop, "Upper cropping region"
prompt Lsize, "Lower background region"
prompt Hsize, "Upper background region"
prompt Cpos, "Center position"
prompt Csize, "Center integration region"
doprompt "redim_linbg_reduction Parameters", lcrop, hcrop, lsize, hsize, cpos, csize
if (v_flag == 0)
param = ReplaceNumberByKey("Lcrop", param, Lcrop, "=", ";")
param = ReplaceNumberByKey("Lsize", param, Lsize, "=", ";")
param = ReplaceNumberByKey("Hcrop", param, Hcrop, "=", ";")
param = ReplaceNumberByKey("Hsize", param, Hsize, "=", ";")
param = ReplaceNumberByKey("Cpos", param, Cpos, "=", ";")
param = ReplaceNumberByKey("Csize", param, Csize, "=", ";")
endif
return v_flag
end
/// linear background reduction function for incorrectly dimensioned scienta image
///
/// if the energy step size does not divide the energy range to an integer number,
/// the scienta image is exported with the wrong array size.
/// this can be fixed by redimensioning the array.
///
/// the current implementation works in the case where dimension 0 needs to be incremented.
/// the function may be generalized to dimension 1 and/or decrementing by additional parameters.
/// it is not known yet whether a generalization is needed or whether it can cover all cases.
///
/// background subtraction and peak integration is the same as by the int_linbg_reduction() function.
///
/// @param source source wave
/// Scienta detector image, energy axis along X, angle axis along Y
///
/// @param dest1 destination wave 1
///
/// @param dest2 destination wave 2
/// each wave is a one-dimensional intensity distribution
/// the function may redimension these waves to one of the image dimensions
/// (it must be clear to the user which dimension this is).
/// the meaning of dest1 and dest2 is up to the particular function,
/// e.g. dest1 could hold the mean value and dest2 the one-sigma error,
/// or dest1 could hold the X-profile, and dest2 the Y-profile.
///
/// @param param parameter string in a key1=value1;key2=value2;... list.
/// the parameter string is passed by reference.
///
/// all region parameters are relative to the image size (0...1).
/// @arg Lcrop size of the lower cropping region
/// @arg Hcrop size of the upper cropping region
/// @arg Lsize size of the lower background integration region
/// @arg Hsize size of the upper background integration region
/// @arg Cpos center position of the of the peak integration region
/// @arg Csize size of the peak integration region
///
/// typical values (peak centered on detector, FWHM ~ 20 % of image)
/// Lcrop=0.11;Hcrop=0.11;Lsize=0.2;Hsize=0.2;Cpos=0.5;Csize=0.2
///
/// @return zero if successful, non-zero if an error occurs.
///
threadsafe function redim_linbg_reduction(source, dest1, dest2, param)
wave source
wave dest1, dest2
string &param
variable nx = dimsize(source, 0)
variable ny = dimsize(source, 1)
duplicate /free source, source_redim
redimension /n=(nx * ny) source_redim
nx += 1
redimension /n=(nx, ny) source_redim
return int_linbg_reduction(source_redim, dest1, dest2, param)
end