8 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
0dc6ca820b bugfix release: pshell import and preview
changes:
- catch runtime errors due to empty datasets
- improve window titles and graph names
- fix scaling of scienta image from XPSSpectrum script
- remove unnecessary spaces and underscores from folder names
2016-09-22 14:15:09 +02:00
a87975d1e6 update data explorer: axis scale and labels in preview 2016-08-17 12:12:52 +02:00
86cf328961 README.md: fix heading levels 2016-06-06 16:07:19 +02:00
2479582c08 README.md: add release notes 2016-06-06 16:04:56 +02:00
13 changed files with 3108 additions and 476 deletions

View File

@ -11,16 +11,20 @@ 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. - 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. - 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. - 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 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 License
======= =======
The source code of PEARL Procedures is available under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) at <https://git.psi.ch/pearl-public/igor-procs>. The source code of PEARL Procedures is available under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) at <https://git.psi.ch/pearl-public/igor-procs>.
Users of PEARL Procedures are requested to coordinate and share the development of the code with the original author.
Please read and respect the respective license agreements. Please read and respect the respective license agreements.
Please share your extensions of the code with the original author.
Author Author
------ ------
@ -32,3 +36,12 @@ Copyright
Copyright 2009-2016 by [Paul Scherrer Institut](http://www.psi.ch) Copyright 2009-2016 by [Paul Scherrer Institut](http://www.psi.ch)
Release Notes
=============
## rev-distro-1.1.1
- If you have upgraded PEARL Procedures from pre-1.1.1 and Igor breaks in pearl-elog.ipf while opening an experiment, please delete the ELOG preferences file `pearl-elog/preferences.pxp`. (Check the Igor Help to find the package preferences folder on your system.)

View File

@ -6,14 +6,14 @@
#include "pearl-polar-coordinates" #include "pearl-polar-coordinates"
#include <New Polar Graphs> #include <New Polar Graphs>
// $Id$ // copyright (c) 2013-16 Paul Scherrer Institut
//
// copyright (c) 2013-15 Paul Scherrer Institut
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// http:///www.apache.org/licenses/LICENSE-2.0 // http:///www.apache.org/licenses/LICENSE-2.0
//
// Please acknowledge the use of this code.
/// @file /// @file
/// @brief processing and holographic mapping of angle scanned XPD data. /// @brief processing and holographic mapping of angle scanned XPD data.
@ -64,7 +64,7 @@
/// ///
/// @author matthias muntwiler, matthias.muntwiler@psi.ch /// @author matthias muntwiler, matthias.muntwiler@psi.ch
/// ///
/// @copyright 2013-15 Paul Scherrer Institut @n /// @copyright 2013-16 Paul Scherrer Institut @n
/// Licensed under the Apache License, Version 2.0 (the "License"); @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 not use this file except in compliance with the License. @n
/// You may obtain a copy of the License at /// You may obtain a copy of the License at
@ -79,15 +79,38 @@
/// ///
/// PearlAnglescanProcess is declared in @ref pearl-anglescan-process.ipf. /// PearlAnglescanProcess is declared in @ref pearl-anglescan-process.ipf.
/// @warning experimental
function strip_remove_frames(strip, yscale, ylo, yhi) /// delete a contiguous range of frames from a strip.
///
/// this can be used to remove a region of bad frames due to, e.g., measurement problems.
/// the function operates on 2D intensity data and manipulator coordinates at the same time.
///
/// @param[in,out] strip 2D data, X-axis = analyser angle, Y-axis = arbitrary manipulator scan.
/// the result is written to the original wave.
///
/// @param[in,out] theta 1D data, manipulator scan.
/// the result is written to the original wave.
///
/// @param[in,out] tilt 1D data, manipulator scan.
/// the result is written to the original wave.
///
/// @param[in,out] phi 1D data, manipulator scan.
/// the result is written to the original wave.
///
/// @param[in] qlo point index of first frame to delete.
///
/// @param[in] qhi point index of last frame to delete.
/// qhi must be greater or equal than qlo.
///
function strip_delete_frames(strip, qlo, qhi, theta, tilt, phi)
wave strip // 2D data, X-axis = analyser angle, Y-axis = arbitrary manipulator scan wave strip // 2D data, X-axis = analyser angle, Y-axis = arbitrary manipulator scan
wave /z yscale // Y scaling, e.g. ManipulatorPhi variable qlo
// if unassigned, point scaling is assumed variable qhi
variable ylo wave theta
variable yhi wave tilt
wave phi
if (ylo > yhi) if (qlo > qhi)
return -1 return -1
endif endif
@ -95,8 +118,8 @@ function strip_remove_frames(strip, yscale, ylo, yhi)
variable snx = dimsize(strip, 0) variable snx = dimsize(strip, 0)
variable sny = dimsize(strip, 1) variable sny = dimsize(strip, 1)
variable sq1lo = 0 variable sq1lo = 0
variable sq1hi = max(round((ylo - dimoffset(strip, 1)) / dimdelta(strip, 1)), 0) variable sq1hi = max(qlo-1, 0)
variable sq2lo = min(round((ylo - dimoffset(strip, 1)) / dimdelta(strip, 1)), sny - 1) variable sq2lo = min(qhi+1, sny - 1)
variable sq2hi = dimsize(strip, 1) - 1 variable sq2hi = dimsize(strip, 1) - 1
// dest indices // dest indices
@ -111,10 +134,24 @@ function strip_remove_frames(strip, yscale, ylo, yhi)
duplicate /free strip, strip_copy duplicate /free strip, strip_copy
redimension /n=(dnx,dny) strip redimension /n=(dnx,dny) strip
strip[][dq1lo,dq1hi] = strip_copy[p][q + q1ofs] strip[][dq1lo,dq1hi] = strip_copy[p][q + q1ofs]
strip[][dq2lo,dq2hi] = strip_copy[p][q + q2ofs] strip[][dq2lo,dq2hi] = strip_copy[p][q + q2ofs]
duplicate /free theta, theta_copy
redimension /n=(dny) theta
theta[dq1lo,dq1hi] = theta_copy[p + q1ofs]
theta[dq2lo,dq2hi] = theta_copy[p + q2ofs]
duplicate /free tilt, tilt_copy
redimension /n=(dny) tilt
tilt[dq1lo,dq1hi] = tilt_copy[p + q1ofs]
tilt[dq2lo,dq2hi] = tilt_copy[p + q2ofs]
duplicate /free phi, phi_copy
redimension /n=(dny) phi
phi[dq1lo,dq1hi] = phi_copy[p + q1ofs]
phi[dq2lo,dq2hi] = phi_copy[p + q2ofs]
return 0 return 0
end end
@ -144,6 +181,7 @@ end
/// @return if check waves are enabled, the following waves are created (overwritten if existing): /// @return if check waves are enabled, the following waves are created (overwritten if existing):
/// @arg check_dist average X distribution /// @arg check_dist average X distribution
/// @arg check_smoo smoothed distribution used to normalize the strip /// @arg check_smoo smoothed distribution used to normalize the strip
///
function normalize_strip_x(strip, [smooth_method, smooth_factor, check]) function normalize_strip_x(strip, [smooth_method, smooth_factor, check])
wave strip wave strip
variable smooth_method variable smooth_method
@ -233,6 +271,7 @@ end
/// @return if check waves are enabled, the following waves are created (overwritten if existing): /// @return if check waves are enabled, the following waves are created (overwritten if existing):
/// @arg check_dist average theta distribution /// @arg check_dist average theta distribution
/// @arg check_smoo smoothed distribution used to normalize the strip /// @arg check_smoo smoothed distribution used to normalize the strip
///
function normalize_strip_theta(strip, theta, [theta_offset, smooth_method, smooth_factor, check]) function normalize_strip_theta(strip, theta, [theta_offset, smooth_method, smooth_factor, check])
wave strip wave strip
wave theta wave theta
@ -261,6 +300,7 @@ function normalize_strip_theta(strip, theta, [theta_offset, smooth_method, smoot
duplicate /free dist, dist_smoo duplicate /free dist, dist_smoo
duplicate /free theta, theta_int duplicate /free theta, theta_int
theta_int = theta - theta_offset 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 nx = dimsize(strip, 0)
variable ix variable ix
@ -297,6 +337,71 @@ function normalize_strip_theta(strip, theta, [theta_offset, smooth_method, smoot
if (check) if (check)
duplicate /o dist, check_dist duplicate /o dist, check_dist
duplicate /o dist_smoo, check_smoo duplicate /o dist_smoo, check_smoo
setscale /p x dimoffset(dist,0), dimdelta(dist,0), waveunits(dist,0), check_dist, check_smoo
endif
end
/// divide the strip by a two-dimensional normalization function.
///
/// @warning experimental. this function is under development.
///
/// @param check enable output of intermediate results
/// @arg 0 (default) don't create additional waves
/// @arg 1 create check waves in the current folder
/// @arg 2 calculate check waves only, do not modify strip
///
/// @return if check waves are enabled, the following waves are created (overwritten if existing):
/// @arg check_dist average theta distribution
/// @arg check_smoo smoothed distribution used to normalize the strip
///
function normalize_strip_2d(strip, theta, [theta_offset, smooth_method, smooth_factor, check])
wave strip
wave theta
variable theta_offset
variable smooth_method
variable smooth_factor
variable check
if (ParamIsDefault(check))
check = 0
endif
if (ParamIsDefault(theta_offset))
theta_offset = 0
endif
if (ParamIsDefault(smooth_method))
smooth_method = 4
endif
if (ParamIsDefault(smooth_factor))
smooth_factor = 0.5
endif
variable nx = dimsize(strip, 0)
variable ny = dimsize(strip, 1)
duplicate /free strip, dist, alpha_int, theta_int
theta_int = theta[q] - theta_offset
alpha_int = dimoffset(strip, 0) + p * dimdelta(strip, 0)
redimension /n=(nx * ny) dist, alpha_int, theta_int
switch(smooth_method)
case 4:
loess /dest=dist_smoo /smth=(smooth_factor) srcWave=dist, factors={alpha_int, theta_int}
redimension /n=(nx, ny) dist_smoo
break
default:
Abort "undefined smooth method"
break
endswitch
// divide
if (check != 2)
strip /= dist_smoo
endif
// check
if (check)
//duplicate /o dist, check_dist
duplicate /o dist_smoo, check_smoo
endif endif
end end
@ -705,9 +810,9 @@ function convert_angles_ttpa2polar(theta, tilt, phi, analyser, polar, azi)
// this is simply a polar-cartesian mapping, independent of the manipulator // this is simply a polar-cartesian mapping, independent of the manipulator
// phi=0 is in the polar rotation plane // 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 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[0][] = radius
w_orig_polar[1] = analyser[q] w_orig_polar[1][] = analyser[q]
w_orig_polar[2] = 0 w_orig_polar[2][] = 0
polar2cart_wave(w_orig_polar, w_orig_cart) polar2cart_wave(w_orig_polar, w_orig_cart)
// if the angle-dispersive axis was horizontal, we'd need to rotate the detector // if the angle-dispersive axis was horizontal, we'd need to rotate the detector
//rotate_z_wave(w_orig_cart, 90) //rotate_z_wave(w_orig_cart, 90)
@ -1758,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 make /n=1 /d /free d_polar, d_azi
variable n_alpha = round(alpha_hi - alpha_lo) + 1 variable n_alpha = round(alpha_hi - alpha_lo) + 1
make /n=(n_alpha) /d /free analyser 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 analyser = x
convert_angles_ttpa2polar(m_theta, loc_m_tilt, m_phi, analyser, d_polar, d_azi) convert_angles_ttpa2polar(m_theta, loc_m_tilt, m_phi, analyser, d_polar, d_azi)
@ -1802,21 +1907,46 @@ function /s display_scanlines(nickname, alpha_lo, alpha_hi, m_theta, m_tilt, m_p
return graphname return graphname
end 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 kProjScaleStereo = 2
static constant kProjScaleAzim = 2 static constant kProjScaleArea = 2
// scaled so that radius(gnom) = radius(stereo) for polar = 88 // 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 /// calculate the projected polar angle
/// ///
/// @param polar polar angle in degrees /// @param polar polar angle in degrees
/// ///
/// @param projection mapping function from polar to cartesian coordinates /// @param projection mapping function from polar to cartesian coordinates.
/// @arg 0 linear /// see @ref PageProjections for details.
/// @arg 1 stereographic (default) /// @arg kProjDist = 0 azimuthal equidistant
/// @arg 2 azimuthal /// @arg kProjStereo = 1 stereographic (default)
/// @arg 3 gnomonic (0 <= polar < 90) /// @arg kProjArea = 2 azimuthal equal-area
/// @arg kProjGnom = 3 gnomonic (0 <= polar < 90)
/// @arg kProjOrtho = 4 orthographic
/// ///
/// @return projected radius. /// @return projected radius.
/// the radius is scaled such that grazing emission maps to 2. /// the radius is scaled such that grazing emission maps to 2.
@ -1830,17 +1960,20 @@ threadsafe function calc_graph_radius(polar, [projection])
variable radius variable radius
switch(projection) switch(projection)
case 1: // stereographic case kProjStereo: // stereographic
radius = kProjScaleStereo * tan(polar / 2 * pi / 180) radius = kProjScaleStereo * tan(polar / 2 * pi / 180)
break break
case 2: // azimuthal case kProjArea: // equal area
radius = kProjScaleAzim * cos((180 - polar) / 2 * pi / 180) radius = kProjScaleArea * sin(polar / 2 * pi / 180)
break break
case 3: // gnomonic case kProjGnom: // gnomonic
radius = polar < 90 ? kProjScaleGnomonic * tan(polar * pi / 180) : inf radius = polar < 90 ? kProjScaleGnom * tan(polar * pi / 180) : inf
break break
default: // linear case kProjOrtho: // orthographic
radius = kProjScaleLinear * polar / 90 radius = kProjScaleOrtho * sin(polar * pi / 180)
break
default: // equidistant
radius = kProjScaleDist * polar / 90
endswitch endswitch
return radius return radius
@ -1852,10 +1985,13 @@ end
/// ///
/// @param x, y projected Cartesian coordinate /// @param x, y projected Cartesian coordinate
/// ///
/// @param projection mapping function from polar to cartesian coordinates /// @param projection mapping function from polar to cartesian coordinates.
/// @arg 0 linear /// see @ref PageProjections for details.
/// @arg 1 stereographic (default) /// @arg kProjDist = 0 azimuthal equidistant
/// @arg 2 azimuthal /// @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 /// @returns polar angle in degrees
/// ///
@ -1873,17 +2009,20 @@ threadsafe function calc_graph_polar(x, y, [projection])
radius = sqrt(x^2 + y^2) radius = sqrt(x^2 + y^2)
switch(projection) switch(projection)
case 1: // stereographic case kProjStereo: // stereographic
polar = 2 * atan(radius / kProjScaleStereo) * 180 / pi polar = 2 * atan(radius / kProjScaleStereo) * 180 / pi
break break
case 2: // azimuthal case kProjArea: // equal area
polar = 180 - 2 * acos(radius / kProjScaleAzim) * 180 / pi polar = 2 * asin(radius / kProjScaleArea) * 180 / pi
break break
case 3: // gnomonic case kProjGnom: // gnomonic
polar = atan(radius / kProjScaleGnomonic) * 180 / pi polar = atan(radius / kProjScaleGnom) * 180 / pi
break break
default: // linear case kProjOrtho: // orthographic
polar = 90 * radius / kProjScaleLinear polar = asin(radius / kProjScaleOrtho) * 180 / pi
break
default: // equidistant
polar = 90 * radius / kProjScaleDist
endswitch endswitch
return polar return polar
@ -1894,10 +2033,13 @@ end
/// @param x, y projected Cartesian coordinate /// @param x, y projected Cartesian coordinate
/// ///
/// @param projection mapping function from polar to cartesian coordinates. /// @param projection mapping function from polar to cartesian coordinates.
/// projections 0-2 have no effect on the azimuthal coordinate. /// all supported projections are azimuthal, they have no effect on the azimuthal coordinate.
/// @arg 0 linear /// see @ref PageProjections for details.
/// @arg 1 stereographic (default) /// @arg kProjDist = 0 azimuthal equidistant
/// @arg 2 azimuthal /// @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 /// @param zeroAngle zeroAngleWhere parameter of polar graphs
/// @arg 0 (default) zero is at the 3 o'clock position /// @arg 0 (default) zero is at the 3 o'clock position
@ -2446,8 +2588,35 @@ end
/// import a hemispherical scan from theta-phi-intensity waves and display it /// import a hemispherical scan from theta-phi-intensity waves and display it
/// ///
/// @warning EXPERIMENTAL /// in the tpi format, the hemi scan data is represented
/// the interface and behaviour of this function may change /// 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]) function import_tpi_scan(nickname, theta, phi, intensity, [folding, npolar, nograph, xpdplot])
string nickname string nickname
@ -2482,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 fold_phi = fold_phi >= 180 ? fold_phi + 360 / folding - fold_phi : fold_phi + 360 / folding
endfor endfor
display_hemi_scan(nickname) if (nograph==0)
end 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) setdatafolder $(package_path)
make /n=31 /o detector_angle, detector_pol, detector_az, detector_rad 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 detector_angle = x
setdatafolder saveDF setdatafolder saveDF
@ -573,7 +573,7 @@ static function update_detector(theta, tilt, phi, range)
//m_phi *= -1 // checked 140702 //m_phi *= -1 // checked 140702
wave detector_angle, detector_pol, detector_az, detector_rad 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 detector_angle = x
convert_angles_ttpa2polar(m_theta, m_tilt, m_phi, detector_angle, detector_pol, detector_az) convert_angles_ttpa2polar(m_theta, m_tilt, m_phi, detector_angle, detector_pol, detector_az)

View File

@ -52,6 +52,25 @@
/// PearlAreaDisplay is declared in @ref pearl-area-display.ipf. /// PearlAreaDisplay is declared in @ref pearl-area-display.ipf.
/// ///
/// compose a valid and unique graph name from a data folder reference
static function /s graphname_from_dfref(df, prefix)
dfref df
string prefix
string name
name = GetDataFolder(1, df)
name = ReplaceString("root:", name, "")
name = name[0, strlen(name) - 2]
name = ReplaceString(" ", name, "")
name = CleanupName(prefix + name, 0)
if (CheckName(name, 6))
name = UniqueName(name, 6, 0)
endif
return name
end
/// open a new graph window with a 2D image. /// open a new graph window with a 2D image.
/// ///
/// this is essentially <code>display; appendimage</code>. /// this is essentially <code>display; appendimage</code>.
@ -72,7 +91,7 @@ function /s ad_display(image)
string dfname = ReplaceString("root:", GetDataFolder(1, imagedf), "") string dfname = ReplaceString("root:", GetDataFolder(1, imagedf), "")
string graphtitle = dfname + " View" string graphtitle = dfname + " View"
string /g view_graphname = CleanupName("view_" + dfname, 0) string /g view_graphname = graphname_from_dfref(imagedf, "view_")
svar graphname = view_graphname svar graphname = view_graphname
display /k=1/n=$graphname as graphtitle display /k=1/n=$graphname as graphtitle
graphname = s_name graphname = s_name
@ -104,7 +123,7 @@ function /s ad_display_histogram(image)
string dfname = ReplaceString("root:", GetDataFolder(1, imagedf), "") string dfname = ReplaceString("root:", GetDataFolder(1, imagedf), "")
string graphtitle = dfname + " Histogram" string graphtitle = dfname + " Histogram"
string /g hist_graphname = CleanupName("hist_" + dfname, 0) string /g hist_graphname = graphname_from_dfref(imagedf, "hist_")
svar graphname = hist_graphname svar graphname = hist_graphname
display /k=1/n=$graphname as graphtitle display /k=1/n=$graphname as graphtitle
graphname = s_name graphname = s_name
@ -171,16 +190,16 @@ function /s ad_display_profiles(image, [filter])
duplicate /o image, $viewname /wave=view duplicate /o image, $viewname /wave=view
make /n=(3,3)/o xprofiles // NX x 3 wave with 3 one-dimensional profiles along Y dimension make /n=(3,3)/o xprofiles // NX x 3 wave with 3 one-dimensional profiles along Y dimension
make /n=(3,3)/o yprofiles // NY x 3 wave with 3 one-dimensional profiles along X dimension make /n=(3,3)/o yprofiles // NY x 3 wave with 3 one-dimensional profiles along X dimension
make /n=(1)/o hist // histogram
string /g view_filter string /g view_filter
string /g view_filter_options string /g view_filter_options
view_filter = filter view_filter = filter
view_filter_options = "" view_filter_options = ""
variable /g view_filter_smoothing_x = 1 variable /g view_filter_smoothing_x = 1
variable /g view_filter_smoothing_y = 1 variable /g view_filter_smoothing_y = 1
string dfname = GetDataFolder(0, imagedf) variable /g view_cursor_mode = 0
string graphtitle = dfname + ":" + NameOfWave(image) + " Profiles" string dfname = ReplaceString("root:", GetDataFolder(1, imagedf), "")
string /g prof_graphname = CleanupName("prof_" + dfname, 0) string graphtitle = dfname + NameOfWave(image) + " Profiles"
string /g prof_graphname = graphname_from_dfref(imagedf, "prof_")
svar graphname = prof_graphname svar graphname = prof_graphname
variable /g graph_avg // average value in ROI (ROI is defined by the crosshairs A and B) variable /g graph_avg // average value in ROI (ROI is defined by the crosshairs A and B)
variable /g graph_min // minimum value in ROI variable /g graph_min // minimum value in ROI
@ -193,16 +212,13 @@ function /s ad_display_profiles(image, [filter])
graphname = s_name graphname = s_name
AppendToGraph /w=$graphname /L=xprofiles xprofiles[*][0],xprofiles[*][1],xprofiles[*][2] AppendToGraph /w=$graphname /L=xprofiles xprofiles[*][0],xprofiles[*][1],xprofiles[*][2]
AppendToGraph /w=$graphname /VERT/B=yprofiles yprofiles[*][0],yprofiles[*][1],yprofiles[*][2] AppendToGraph /w=$graphname /VERT/B=yprofiles yprofiles[*][0],yprofiles[*][1],yprofiles[*][2]
AppendToGraph /w=$graphname /R=hist/B=yprofiles hist
AppendImage /w=$graphname view AppendImage /w=$graphname view
string imgname = StringFromList(0, ImageNameList(graphname, ";")) string imgname = StringFromList(0, ImageNameList(graphname, ";"))
ModifyImage /w=$graphname $imgname ctab= {*,*,BlueGreenOrange,0} ModifyImage /w=$graphname $imgname ctab= {*,*,BlueGreenOrange,0}
ModifyGraph /w=$graphname rgb(xprofiles)=(39168,0,0),rgb(yprofiles)=(39168,0,0) ModifyGraph /w=$graphname rgb(xprofiles)=(39168,0,0),rgb(yprofiles)=(39168,0,0)
ModifyGraph /w=$graphname rgb(xprofiles#1)=(0,26112,0),rgb(yprofiles#1)=(0,26112,0) ModifyGraph /w=$graphname rgb(xprofiles#1)=(0,26112,0),rgb(yprofiles#1)=(0,26112,0)
ModifyGraph /w=$graphname rgb(xprofiles#2)=(0,9472,39168),rgb(yprofiles#2)=(0,9472,39168) ModifyGraph /w=$graphname rgb(xprofiles#2)=(0,9472,39168),rgb(yprofiles#2)=(0,9472,39168)
ModifyGraph /w=$graphname rgb(hist)=(43520,43520,43520) ModifyGraph /w=$graphname mirror(xprofiles)=2,mirror(bottom)=3,mirror(yprofiles)=2,mirror(left)=3
ModifyGraph /w=$graphname mode(hist)=5,hbFill(hist)=2
ModifyGraph /w=$graphname mirror(xprofiles)=0,mirror(bottom)=3,mirror(yprofiles)=3,mirror(left)=3
ModifyGraph /w=$graphname nticks=3 ModifyGraph /w=$graphname nticks=3
ModifyGraph /w=$graphname minor=1 ModifyGraph /w=$graphname minor=1
ModifyGraph /w=$graphname axThick=0.5 ModifyGraph /w=$graphname axThick=0.5
@ -210,21 +226,33 @@ function /s ad_display_profiles(image, [filter])
ModifyGraph /w=$graphname btLen=4 ModifyGraph /w=$graphname btLen=4
ModifyGraph /w=$graphname freePos(xprofiles)=0 ModifyGraph /w=$graphname freePos(xprofiles)=0
ModifyGraph /w=$graphname freePos(yprofiles)=0 ModifyGraph /w=$graphname freePos(yprofiles)=0
ModifyGraph /w=$graphname freePos(hist)=0
ModifyGraph /w=$graphname axisEnab(xprofiles)={0.64,1} ModifyGraph /w=$graphname axisEnab(xprofiles)={0.64,1}
ModifyGraph /w=$graphname axisEnab(hist)={0.64,1}
ModifyGraph /w=$graphname axisEnab(bottom)={0,0.6} ModifyGraph /w=$graphname axisEnab(bottom)={0,0.6}
ModifyGraph /w=$graphname axisEnab(yprofiles)={0.64,1} ModifyGraph /w=$graphname axisEnab(yprofiles)={0.64,1}
ModifyGraph /w=$graphname axisEnab(left)={0,0.6} ModifyGraph /w=$graphname axisEnab(left)={0,0.6}
ModifyGraph /w=$graphname zero(left)=8 ModifyGraph /w=$graphname zero(left)=8
ModifyGraph /w=$graphname margin(left)=40,margin(bottom)=30,margin(top)=20,margin(right)=40 ModifyGraph /w=$graphname margin(left)=40,margin(bottom)=30,margin(top)=20,margin(right)=40
ModifyGraph /w=$graphname gfSize=10 ModifyGraph /w=$graphname gfSize=10
Label /w=$graphname xprofiles "value (\\U)"
Label /w=$graphname bottom "X (\\U)" // axis labels
Label /w=$graphname yprofiles "value (\\U)" string labels = note(image)
Label /w=$graphname left "Y (\\U)" string lab
Label /w=$graphname hist "\\Epixels" lab = StringByKey("AxisLabelX", labels, "=", "\r")
SetAxis /w=$graphname /A /E=1 hist if (!strlen(lab))
lab = "X"
endif
Label /w=$graphname bottom lab + " (\\U)"
lab = StringByKey("AxisLabelY", labels, "=", "\r")
if (!strlen(lab))
lab = "Y"
endif
Label /w=$graphname left lab + " (\\U)"
lab = StringByKey("AxisLabelD", labels, "=", "\r")
if (!strlen(lab))
lab = "value"
endif
Label /w=$graphname xprofiles lab + " (\\U)"
Label /w=$graphname yprofiles lab + " (\\U)"
// legend // legend
if (show_legend) if (show_legend)
@ -233,13 +261,18 @@ function /s ad_display_profiles(image, [filter])
AppendText /w=$graphname "\\s(xprofiles#2)\tROI average" AppendText /w=$graphname "\\s(xprofiles#2)\tROI average"
AppendText /w=$graphname "min\t\\{" + s_viewdf + "graph_min}" AppendText /w=$graphname "min\t\\{" + s_viewdf + "graph_min}"
AppendText /w=$graphname "max\t\\{" + s_viewdf + "graph_max}" AppendText /w=$graphname "max\t\\{" + s_viewdf + "graph_max}"
AppendText /w=$graphname "avg\t\\{" + s_viewdf + "graph_avg}"
AppendText /w=$graphname "sum\t\\{" + s_viewdf + "graph_sum}" AppendText /w=$graphname "sum\t\\{" + s_viewdf + "graph_sum}"
AppendText /w=$graphname "avg\t\\{" + s_viewdf + "graph_avg}"
AppendText /w=$graphname "sdev\t\\{" + s_viewdf + "graph_sdev}" AppendText /w=$graphname "sdev\t\\{" + s_viewdf + "graph_sdev}"
else else
TextBox /w=$graphname /C/N=text_sum/F=0/B=1/X=1.00/Y=1.00 "sum \\{" + s_viewdf + "graph_sum}" TextBox /w=$graphname /C/N=text0 /F=0 /B=1 /X=1.00 /Y=1.00
TextBox /w=$graphname /C/N=text_avg/F=0/B=1/X=1.00/Y=6.00 "avg \\{" + s_viewdf + "graph_avg}" lab = StringByKey("Dataset", labels, "=", "\r")
TextBox /w=$graphname /C/N=text_sdev/F=0/B=1/X=1.00/Y=11.00 "sdev \\{" + s_viewdf + "graph_sdev}" if (strlen(lab))
AppendText /w=$graphname lab
endif
AppendText /w=$graphname "sum\t\\{" + s_viewdf + "graph_sum}"
AppendText /w=$graphname "avg\t\\{" + s_viewdf + "graph_avg}"
AppendText /w=$graphname "sdev\t\\{" + s_viewdf + "graph_sdev}"
endif endif
// interactive elements // interactive elements
@ -316,15 +349,88 @@ function ad_update_profiles(image)
return 0 return 0
end 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. /// 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]) 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. wave image
string cursorname // name of the cursor. must be "A" or "B". string cursorname
variable xa, ya // position to move the cursor to. variable xa, ya
// the position is coerced to the image scale. +/-inf is allowed. variable pscale
variable pscale // scaling of the position argument
// 0 (default) = wave scaling
// 1 = point scaling
if (ParamIsDefault(pscale)) if (ParamIsDefault(pscale))
pscale = 0 pscale = 0
@ -991,7 +1097,7 @@ function /s ad_display_brick(data)
setdatafolder viewdf setdatafolder viewdf
string dfname = ReplaceString("root:", s_datadf, "") string dfname = ReplaceString("root:", s_datadf, "")
string graphtitle = dfname + " Gizmo" string graphtitle = dfname + " Gizmo"
string /g gizmo_graphname = CleanupName("giz_" + dfname, 0) string /g gizmo_graphname = graphname_from_dfref(datadf, "giz_")
svar graphname = gizmo_graphname svar graphname = gizmo_graphname
if ((strlen(graphname) > 0) && (wintype(graphname) == 13)) if ((strlen(graphname) > 0) && (wintype(graphname) == 13))
@ -1115,13 +1221,32 @@ function ad_brick_slicer(data)
variable /g x_autoinc = 0 variable /g x_autoinc = 0
variable /g y_autoinc = 0 variable /g y_autoinc = 0
variable /g z_autoinc = 0 variable /g z_autoinc = 0
// axis labels
string labels = note(data)
string xlabel = StringByKey("AxisLabelX", labels, "=", "\r")
if (!strlen(xlabel))
xlabel = "X"
endif
string ylabel = StringByKey("AxisLabelY", labels, "=", "\r")
if (!strlen(ylabel))
ylabel = "Y"
endif
string zlabel = StringByKey("AxisLabelZ", labels, "=", "\r")
if (!strlen(zlabel))
zlabel = "Z"
endif
string dlabel = StringByKey("Dataset", labels, "=", "\r")
if (!strlen(dlabel))
dlabel = NameOfWave(data)
endif
// this section copied from slicer panel // this section copied from slicer panel
NewPanel /k=1 /W=(500,600,890,940) /N=SlicerPanel as "Brick Slicer" NewPanel /k=1 /W=(500,600,890,940) /N=SlicerPanel as "Brick Slicer"
string /g slicer_panelname = S_name string /g slicer_panelname = S_name
string panel = s_name string panel = s_name
GroupBox g_xslice win=$panel,pos={8,8},size={376,96},title="X Slice" GroupBox g_xslice win=$panel,pos={8,8},size={376,96},title=xlabel
Slider sl_xslice_position win=$panel,pos={16,32},size={240,56},proc=PearlAreaDisplay#slp_slice_position Slider sl_xslice_position win=$panel,pos={16,32},size={240,56},proc=PearlAreaDisplay#slp_slice_position
Slider sl_xslice_position win=$panel,limits={0,100,1},variable=x_slice_pos,vert= 0 Slider sl_xslice_position win=$panel,limits={0,100,1},variable=x_slice_pos,vert= 0
SetVariable sv_xslice_position win=$panel,pos={20,80},size={92,16},proc=PearlAreaDisplay#svp_slice_position,title="X" SetVariable sv_xslice_position win=$panel,pos={20,80},size={92,16},proc=PearlAreaDisplay#svp_slice_position,title="X"
@ -1141,7 +1266,7 @@ function ad_brick_slicer(data)
Button b_xslice_stop win=$panel,pos={336,48},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W616" Button b_xslice_stop win=$panel,pos={336,48},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W616"
Button b_xslice_stop win=$panel,help={"stop animation"} Button b_xslice_stop win=$panel,help={"stop animation"}
GroupBox g_yslice win=$panel,pos={8,108},size={376,96},title="Y Slice" GroupBox g_yslice win=$panel,pos={8,108},size={376,96},title=ylabel
Slider sl_yslice_position win=$panel,pos={16,132},size={240,56},proc=PearlAreaDisplay#slp_slice_position Slider sl_yslice_position win=$panel,pos={16,132},size={240,56},proc=PearlAreaDisplay#slp_slice_position
Slider sl_yslice_position win=$panel,limits={0,100,1},variable=y_slice_pos,vert= 0 Slider sl_yslice_position win=$panel,limits={0,100,1},variable=y_slice_pos,vert= 0
SetVariable sv_yslice_position win=$panel,pos={20,180},size={92,16},proc=PearlAreaDisplay#svp_slice_position,title="Y" SetVariable sv_yslice_position win=$panel,pos={20,180},size={92,16},proc=PearlAreaDisplay#svp_slice_position,title="Y"
@ -1161,7 +1286,7 @@ function ad_brick_slicer(data)
Button b_yslice_stop win=$panel,pos={336,148},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W616" Button b_yslice_stop win=$panel,pos={336,148},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W616"
Button b_yslice_stop win=$panel,help={"stop animation"} Button b_yslice_stop win=$panel,help={"stop animation"}
GroupBox g_zslice win=$panel,pos={8,208},size={376,96},title="Z Slice" GroupBox g_zslice win=$panel,pos={8,208},size={376,96},title=zlabel
Slider sl_zslice_position win=$panel,pos={16,232},size={240,56},proc=PearlAreaDisplay#slp_slice_position Slider sl_zslice_position win=$panel,pos={16,232},size={240,56},proc=PearlAreaDisplay#slp_slice_position
Slider sl_zslice_position win=$panel,limits={0,100,1},variable=z_slice_pos,vert= 0 Slider sl_zslice_position win=$panel,limits={0,100,1},variable=z_slice_pos,vert= 0
SetVariable sv_zslice_position win=$panel,pos={20,280},size={92,16},proc=PearlAreaDisplay#svp_slice_position,title="Z" SetVariable sv_zslice_position win=$panel,pos={20,280},size={92,16},proc=PearlAreaDisplay#svp_slice_position,title="Z"
@ -1181,7 +1306,7 @@ function ad_brick_slicer(data)
Button b_zslice_stop win=$panel,pos={336,248},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W616" Button b_zslice_stop win=$panel,pos={336,248},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W616"
Button b_zslice_stop win=$panel,help={"stop animation"} Button b_zslice_stop win=$panel,help={"stop animation"}
TitleBox t_slicerpath win=$panel,pos={8,316},size={128,20},disable=2,title=GetDataFolder(1,viewdf) TitleBox t_slicerpath win=$panel,pos={8,316},size={128,20},disable=2,title=dlabel
//SetVariable setvar0 win=$panel,pos={240,316},size={120,16},title="slab thickness" //SetVariable setvar0 win=$panel,pos={240,316},size={120,16},title="slab thickness"
//SetVariable setvar0 win=$panel,limits={1,inf,1},value=slab_thickness //SetVariable setvar0 win=$panel,limits={1,inf,1},value=slab_thickness

View File

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

View File

@ -613,3 +613,36 @@ threadsafe function calc_y_profile_mins(image)
yminlocs[ix] = v_minloc yminlocs[ix] = v_minloc
endfor endfor
end end
/// collect profiles from a multi-scan.
///
/// @warning experimental: name and interface of this function may change.
///
function ad_collect_multiscan_y(dataset, positions, destwave, [noavg])
wave dataset
wave positions
wave destwave
variable noavg
variable tol = (wavemax(positions) - wavemin(positions)) / numpnts(positions) / 100
duplicate /free positions, positions_sorted
sort positions_sorted, positions_sorted
duplicate /free positions_sorted, positions_diff
differentiate /p /meth=2 positions_sorted /d=positions_diff
positions_diff[0] = 1
extract /free positions_sorted, positions_unique, positions_diff > tol
variable n_unique = numpnts(positions_unique)
redimension /n=(dimsize(dataset, 0), n_unique) destwave
variable i
variable nx, ny
for (i = 0; i < n_unique; i += 1)
extract /free dataset, data_extract, abs(positions[q] - positions_unique[i]) < tol
nx = dimsize(dataset, 0)
ny = dimsize(data_extract, 0) / nx
redimension /n=(nx, ny) data_extract
wave profile = ad_profile_x(data_extract, -inf, inf, "", noavg=noavg)
destwave[][i] = profile[p]
endfor
end

View File

@ -1,11 +1,14 @@
#pragma rtGlobals=3 // Use modern global access method and strict wave access. #pragma rtGlobals=3 // Use modern global access method and strict wave access.
#pragma IgorVersion = 6.1 #pragma IgorVersion = 6.1
#pragma ModuleName = PearlDataExplorer #pragma ModuleName = PearlDataExplorer
#pragma version = 1.43 #pragma version = 1.50
#include "pearl-area-import" #include "pearl-area-import"
#include "pearl-area-profiles" #include "pearl-area-profiles"
#include "pearl-area-display" #include "pearl-area-display"
#include "pearl-pshell-import" #include "pearl-pshell-import"
#if exists("MFR_OpenResultFile")
#include "pearl-matrix-import"
#endif
// copyright (c) 2013-16 Paul Scherrer Institut // copyright (c) 2013-16 Paul Scherrer Institut
// //
@ -20,7 +23,10 @@
/// ///
/// ///
/// preview and import panel for PEARL data: /// 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 /// @namespace PearlDataExplorer
/// @brief preview and import panel for PEARL data /// @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_adh5 = "*.h5"
static strconstant ks_filematch_pshell = "psh*.h5" static strconstant ks_filematch_pshell = "psh*.h5"
static strconstant ks_filematch_itx = "*.itx" static strconstant ks_filematch_itx = "*.itx"
static strconstant ks_filematch_mtrx = "*_mtrx"
function pearl_data_explorer() function pearl_data_explorer()
init_package() init_package()
@ -140,31 +147,64 @@ static function load_prefs()
return result return result
end 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() static function update_filelist()
dfref saveDF = GetDataFolderDFR() dfref saveDF = GetDataFolderDFR()
string hdf_files, itx_files, all_files string all_files
wave /t wtFiles = $(package_path + "wtFiles") wave /t wtFiles = $(package_path + "wtFiles")
wave wSelectedFiles = $(package_path + "wSelectedFiles") wave wSelectedFiles = $(package_path + "wSelectedFiles")
variable nn variable nn
PathInfo pearl_explorer_filepath PathInfo pearl_explorer_filepath
if (v_flag == 1) if (v_flag == 1)
hdf_files = IndexedFile(pearl_explorer_filepath, -1, ".h5") all_files = IndexedFile(pearl_explorer_filepath, -1, "????")
itx_files = IndexedFile(pearl_explorer_filepath, -1, ".itx")
all_files = hdf_files + itx_files
all_files = SortList(hdf_files + itx_files, ";", 4)
nn = ItemsInList(all_files) nn = ItemsInList(all_files)
else else
all_files = "" all_files = ""
nn = 0 nn = 0
endif endif
redimension /n=(nn) wtFiles, wSelectedFiles make /n=(nn) /t /free wtAllFiles
if (nn > 0) wtAllFiles = StringFromList(p, all_files)
wtFiles = StringFromList(p, all_files) Extract /o /t wtAllFiles, wtFiles, pearl_file_type(wtAllFiles[p])
wSelectedFiles = 0 Sort /A /R wtFiles, wtFiles
endif
redimension /n=(numpnts(wtFiles)) wSelectedFiles
wSelectedFiles = 0
setdatafolder saveDF setdatafolder saveDF
end end
@ -216,14 +256,24 @@ static function preview_file(filename)
string filename string filename
dfref saveDF = GetDataFolderDFR() dfref saveDF = GetDataFolderDFR()
if (StringMatch(filename, ks_filematch_pshell)) variable ft = pearl_file_type(filename)
wave /z image = preview_pshell_file(filename) switch(ft)
elseif (StringMatch(filename, ks_filematch_adh5)) case 1:
wave /z image = preview_hdf_file(filename) wave /z image = preview_pshell_file(filename)
elseif (StringMatch(filename, ks_filematch_itx)) break
wave /z image = preview_itx_file(filename) case 2:
endif wave /z image = preview_hdf_file(filename)
break
case 3:
wave /z image = preview_itx_file(filename)
break
case 4:
wave /z image = preview_mtrx_file(filename)
break
default:
wave /z image = $""
endswitch
if (WaveExists(image)) if (WaveExists(image))
string graphname = show_preview_graph(image) string graphname = show_preview_graph(image)
@ -240,9 +290,10 @@ static function preview_file(filename)
endif endif
setdatafolder saveDF setdatafolder saveDF
return 0
end 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 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. /// 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 return preview_image
end 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) static function extract_preview_image(data, preview)
// extracts a preview image from a wave of arbitrary dimension // extracts a preview image from a wave of arbitrary dimension
wave data wave data
@ -759,18 +867,21 @@ static function /s show_preview_graph(data, [xdata])
svar s_profiles_graph svar s_profiles_graph
svar s_preview_file svar s_preview_file
svar s_preview_source svar s_preview_source
svar s_preview_trace_graph
if ((strlen(s_profiles_graph) > 0) && (WinType(s_profiles_graph) == 1))
KillWindow $s_profiles_graph
endif
if ((strlen(s_preview_trace_graph) > 0) && (WinType(s_preview_trace_graph) == 1))
KillWindow $s_preview_trace_graph
endif
string graphname string graphname
if (wavedims(data) == 2) if (wavedims(data) == 2)
if ((strlen(s_profiles_graph) > 0) && (WinType(s_profiles_graph) == 1)) s_profiles_graph = ad_display_profiles(data)
ad_update_profiles(data) ModifyGraph /w=$s_profiles_graph /z wbRGB=(48640,56832,60160)
else
s_profiles_graph = ad_display_profiles(data)
ModifyGraph /w=$s_profiles_graph /z wbRGB=(48640,56832,60160)
endif
graphname = s_profiles_graph graphname = s_profiles_graph
elseif (wavedims(data) == 1) elseif (wavedims(data) == 1)
svar s_preview_trace_graph
duplicate /o data, preview_trace duplicate /o data, preview_trace
if (!ParamIsDefault(xdata)) if (!ParamIsDefault(xdata))
duplicate /o xdata, preview_trace_x duplicate /o xdata, preview_trace_x
@ -779,20 +890,8 @@ static function /s show_preview_graph(data, [xdata])
preview_trace_x = x preview_trace_x = x
setscale d 0, 0, WaveUnits(data, 0), preview_trace_x setscale d 0, 0, WaveUnits(data, 0), preview_trace_x
endif endif
if ((strlen(s_preview_trace_graph) == 0) || (WinType(s_preview_trace_graph) != 1)) s_preview_trace_graph = display_preview_trace(preview_trace_x, preview_trace)
display /n=pearl_explorer_1d /k=1 preview_trace vs preview_trace_x as "Preview" ModifyGraph /w=$s_preview_trace_graph wbRGB=(48640,56832,60160)
s_preview_trace_graph = s_name
ModifyGraph /w=$s_preview_trace_graph wbRGB=(48640,56832,60160)
ModifyGraph /w=$s_preview_trace_graph rgb[0]=(0,0,0)
ModifyGraph /w=$s_preview_trace_graph grid=2
ModifyGraph /w=$s_preview_trace_graph mirror=1
ModifyGraph /w=$s_preview_trace_graph minor=1
ModifyGraph /w=$s_preview_trace_graph axThick=0.5
ModifyGraph /w=$s_preview_trace_graph gridRGB=(52224,52224,52224)
ModifyGraph /w=$s_preview_trace_graph gridHair=0
ModifyGraph /w=$s_preview_trace_graph tick=0
ModifyGraph /w=$s_preview_trace_graph btLen=4
endif
graphname = s_preview_trace_graph graphname = s_preview_trace_graph
else else
return "" return ""
@ -808,6 +907,39 @@ static function /s show_preview_graph(data, [xdata])
return graphname return graphname
end end
static function /s display_preview_trace(xtrace, ytrace)
wave xtrace
wave ytrace
display /n=pearl_explorer_1d /k=1 ytrace vs xtrace as "Preview"
string graphname = s_name
ModifyGraph /w=$graphname rgb[0]=(0,0,0)
ModifyGraph /w=$graphname grid=2
ModifyGraph /w=$graphname mirror=1
ModifyGraph /w=$graphname minor=1
ModifyGraph /w=$graphname axThick=0.5
ModifyGraph /w=$graphname gridRGB=(52224,52224,52224)
ModifyGraph /w=$graphname gridHair=0
ModifyGraph /w=$graphname tick=0
ModifyGraph /w=$graphname btLen=4
// axis labels
string labels = note(ytrace)
string lab
lab = StringByKey("AxisLabelX", labels, "=", "\r")
if (!strlen(lab))
lab = "X"
endif
Label /w=$graphname bottom lab + " (\\U)"
lab = StringByKey("AxisLabelD", labels, "=", "\r")
if (!strlen(lab))
lab = "value"
endif
Label /w=$graphname left lab + " (\\U)"
return s_name
end
static function load_selected_files([options]) static function load_selected_files([options])
string options string options
@ -838,22 +970,32 @@ static function load_file(filename, [options])
dfref saveDF = GetDataFolderDFR() dfref saveDF = GetDataFolderDFR()
if (StringMatch(filename, ks_filematch_pshell)) variable ft = pearl_file_type(filename)
if (ParamIsDefault(options)) switch(ft)
load_pshell_file(filename) case 1:
else if (ParamIsDefault(options))
load_pshell_file(filename, options=options) load_pshell_file(filename)
endif else
elseif (StringMatch(filename, ks_filematch_adh5)) load_pshell_file(filename, options=options)
if (ParamIsDefault(options)) endif
load_hdf_file(filename) break
else case 2:
load_hdf_file(filename, options=options) if (ParamIsDefault(options))
endif load_hdf_file(filename)
elseif (StringMatch(filename, ks_filematch_itx)) else
load_itx_file(filename) load_hdf_file(filename, options=options)
endif endif
break
case 3:
load_itx_file(filename)
break
case 4:
load_mtrx_file(filename)
break
default:
break
endswitch
setdatafolder saveDF setdatafolder saveDF
end end
@ -948,6 +1090,7 @@ static function /df load_pshell_file(filename, [options])
string reduction_params = pref_params string reduction_params = pref_params
if (prompt_func_params(reduction_func, reduction_params) == 0) if (prompt_func_params(reduction_func, reduction_params) == 0)
pref_params = reduction_params pref_params = reduction_params
print reduction_func, reduction_params
psh5_load_reduced(nickname, "pearl_explorer_filepath", filename, $reduction_func, reduction_params) psh5_load_reduced(nickname, "pearl_explorer_filepath", filename, $reduction_func, reduction_params)
svar s_filepath svar s_filepath
loaded_filename = s_filepath loaded_filename = s_filepath
@ -999,6 +1142,7 @@ static function /df load_hdf_file(filename, [options])
string reduction_params = pref_params string reduction_params = pref_params
if (prompt_func_params(reduction_func, reduction_params) == 0) if (prompt_func_params(reduction_func, reduction_params) == 0)
pref_params = reduction_params pref_params = reduction_params
print reduction_func, reduction_params
loaded_filename = adh5_load_reduced(nickname, "pearl_explorer_filepath", filename, $reduction_func, reduction_params) loaded_filename = adh5_load_reduced(nickname, "pearl_explorer_filepath", filename, $reduction_func, reduction_params)
endif endif
break break
@ -1056,6 +1200,32 @@ static function /df load_itx_file(filename, [options])
return actDF return actDF
end 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]) function /s itx_suggest_foldername(filename, [ignoredate,sourcename,unique])
// suggests the name of a data folder based on a file name // suggests the name of a data folder based on a file name
// if the file name follows the naming convention source-date-index.extension, // if the file name follows the naming convention source-date-index.extension,
@ -1426,6 +1596,9 @@ static function bp_dataset_folder(ba) : ButtonControl
string cmd string cmd
sprintf cmd, "setdatafolder root:%s", PossiblyQuoteName(dataset) sprintf cmd, "setdatafolder root:%s", PossiblyQuoteName(dataset)
execute /q /z cmd execute /q /z cmd
cmd = "setdatafolder :scan1"
execute /q /z cmd
sprintf cmd, "setdatafolder %s", GetDataFolder(1)
print cmd print cmd
endif endif
break break

View File

@ -1,5 +1,5 @@
#pragma rtGlobals=3 // Use modern global access method and strict wave access. #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 IgorVersion = 6.2
#pragma ModuleName = PearlElog #pragma ModuleName = PearlElog
@ -16,13 +16,38 @@
/// @ingroup ArpesPackage /// @ingroup ArpesPackage
/// ///
/// ///
/// the functions in this module support the following work flows: /// the functions in this module support the following ELOG features:
/// 1. send a preview of a selected measurement to ELOG. /// - submit new entries and replies to existing entries.
/// 2. send any Igor graph to ELOG. (CLI and GUI) /// - text field, list box, and check box attributes.
/// 3. direct access to all ELOG parameters. (CLI only) /// - 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.
/// ///
/// the configuration of the ELOG server and logbooks (except user name and password) /// usage:
/// as well as the most recently used attributes are persisted in the preference file. /// 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 /// elog command line
///@verbatim ///@verbatim
@ -43,12 +68,6 @@
/// -m <textfile>] | <text> /// -m <textfile>] | <text>
///@endverbatim ///@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 /// @author matthias muntwiler, matthias.muntwiler@psi.ch
/// ///
@ -82,7 +101,7 @@ function pearl_elog(logbook)
load_prefs() load_prefs()
string templates = list_logbooks(templates=1) string templates = list_logbooks(templates=1)
if (ItemsInList(templates) < 1) if (ItemsInList(templates) < 1)
init_pearl_templates() elog_init_pearl_templates()
endif endif
endif endif
@ -95,7 +114,11 @@ function pearl_elog(logbook)
if (strlen(WinList(win_name, ";", "")) > 0) if (strlen(WinList(win_name, ";", "")) > 0)
DoWindow /F $win_name DoWindow /F $win_name
else else
PearlElogPanel(logbook) win_name = PearlElogPanel(logbook)
STRUCT WMWinHookStruct s
s.eventCode = 0
s.winName = win_name
elog_panel_hook(s)
endif endif
endif endif
end end
@ -104,6 +127,7 @@ end
static function IgorBeforeNewHook(igorApplicationNameStr) static function IgorBeforeNewHook(igorApplicationNameStr)
string igorApplicationNameStr string igorApplicationNameStr
save_prefs() save_prefs()
cleanup_temp_files()
return 0 return 0
end end
@ -111,6 +135,7 @@ end
static function IgorQuitHook(igorApplicationNameStr) static function IgorQuitHook(igorApplicationNameStr)
string igorApplicationNameStr string igorApplicationNameStr
save_prefs() save_prefs()
cleanup_temp_files()
return 0 return 0
end end
@ -234,7 +259,7 @@ end
/// ///
/// @remark this function is specific to the setup at PEARL. /// @remark this function is specific to the setup at PEARL.
/// ///
static function init_pearl_templates() function elog_init_pearl_templates()
dfref savedf = getdatafolderdfr() dfref savedf = getdatafolderdfr()
dfref df_root = get_elog_df("", kdfRoot) dfref df_root = get_elog_df("", kdfRoot)
@ -247,10 +272,10 @@ static function init_pearl_templates()
// attributes (persistent) // attributes (persistent)
// available attributes // 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 // controls corresponding to attributes
// prefix determines the control type: sv_ = setvariable (string), pm_ = popup menu, cb = check box // 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 // attributes with fixed options, value item declares the options string
string /g options = "source=sources;task=tasks;technique=techniques" string /g options = "source=sources;task=tasks;technique=techniques"
// attributes which must be defined // attributes which must be defined
@ -258,8 +283,8 @@ static function init_pearl_templates()
// option lists // 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 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 tasks = "Measurement;Optimization;Analysis;Sample Preparation;Sample Storage;Comment;Development;Maintenance;Test;Other"
string /g techniques = "XPS;UPS;XPD;XAS;XMCD;PhD;ARUPS;LEED;AES;STM;STS;QMS;MBE;Test;Other" string /g techniques = "XPS;UPS;XPD;XAS;XMCD;PhD;ARUPS;STM;STS;LEED;AES;QMS;MBE;Sputter/Anneal;Test;Other"
// Calculations template // Calculations template
setdatafolder df_templates setdatafolder df_templates
@ -267,18 +292,38 @@ static function init_pearl_templates()
// attributes (persistent) // attributes (persistent)
// available attributes // 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 // controls corresponding to attributes
// prefix determines the control type: sv_ = setvariable (string), pm_ = popup menu, cb = check box // 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 // attributes with fixed options, value item declares the options string
string /g options = "program=programs;machine=machines" string /g options = "program=programs;machine=machines"
// attributes which must be defined // attributes which must be defined
string /g required_attributes = "author;project;sample" string /g required_attributes = "author;project;sample"
// option lists // option lists
string /g programs = "DMSUP;EDAC;MSC;MUFPOT;SSC" string /g programs = "PMSCO;EDAC;MSC;SSC;MUFPOT;DMSUP;Other"
string /g machines = "llcx;Merlin;PC" 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 setdatafolder savedf
return 0 return 0
@ -303,6 +348,11 @@ static function init_volatile_vars()
variable nlb = ItemsInList(logbooks) variable nlb = ItemsInList(logbooks)
variable ilb 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) for (ilb = 0; ilb < nlb; ilb += 1)
logbook = StringFromList(ilb, logbooks) logbook = StringFromList(ilb, logbooks)
@ -322,6 +372,13 @@ static function init_volatile_vars()
if (exists("msg_id") != 2) if (exists("msg_id") != 2)
variable /g msg_id = 0 variable /g msg_id = 0
endif 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 endfor
SetDataFolder savedf SetDataFolder savedf
@ -347,6 +404,9 @@ end
/// create a new empty logbook or duplicate from a template. /// create a new empty logbook or duplicate from a template.
/// ///
/// @param name name of the new logbook. /// @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. /// @param template name of the template.
/// if empty string, a new empty logbook is created. /// 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_root = get_elog_df("", kdfVolatile)
dfref df_volatile_parent = df_volatile_root:logbooks 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) if (strlen(template) > 0)
dfref df_template = get_elog_df(template, kdfTemplates) 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 DuplicateDataFolder df_template, df_persistent_parent:$name
else else
NewDataFolder /o/s df_persistent_parent:$name NewDataFolder /o/s df_persistent_parent:$name
@ -695,7 +766,6 @@ function elog_create_entry(logbook, attributes, message, [encoding, graphs, repl
endif endif
result = -4 result = -4
endif endif
cleanup_temp_files()
else else
if (loglevel >= 2) if (loglevel >= 2)
print "ELOG: failed to create temporary message file." print "ELOG: failed to create temporary message file."
@ -759,7 +829,6 @@ function elog_add_attachment(logbook, id, graphs)
endif endif
result = -4 // error: elog returned error result = -4 // error: elog returned error
endif endif
cleanup_temp_files()
endif endif
setdatafolder savedf setdatafolder savedf
@ -817,6 +886,39 @@ static function /s prepare_command_line(logbook)
return cmd return cmd
end 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 /// prepare screenshots of graph windows for attachments
/// ///
/// prepares the attachment files from Igor graph windows /// prepares the attachment files from Igor graph windows
@ -875,13 +977,18 @@ static function /s create_graph_file(graphname, fileindex)
string graphname string graphname
variable fileindex 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 path = SpecialDirPath("Temporary", 0, 1, 0)
string ts = get_timestamp("_") string ts = get_timestamp("_")
variable len = strlen(path) variable len = strlen(path)
if (numtype(len) == 0) if (numtype(len) == 0)
path += "elog_" + ts + "_" + num2str(fileindex) + ".png" path += "elog_" + ts + "_" + num2str(fileindex) + ".png"
SavePICT /B=72 /E=-5 /M /O /W=(0,0,8,6) /WIN=$graphname /Z as path 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 = "" path = ""
endif endif
else else
@ -921,12 +1028,30 @@ static function /s get_log_path()
return path return path
end end
static function /s cleanup_temp_files() /// delete temporary files created by the ELOG module.
string path = SpecialDirPath("Temporary", 0, 1, 0) ///
string cmd /// this deletes all temporary graph files that are referenced by the volatile temp_graph_files list.
sprintf cmd, "del \"%s\elog*.*\"", path /// temp_graph_files is a semicolon-delimited string.
//ExecuteScriptText cmd /// items are added by create_graph_file().
return path ///
/// 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 end
static strconstant elog_success_msg = "Message successfully transmitted" static strconstant elog_success_msg = "Message successfully transmitted"
@ -1048,14 +1173,17 @@ function /s PearlElogPanel(logbook)
string win_name = logbook + "ElogPanel" string win_name = logbook + "ElogPanel"
string win_title = "ELOG " + logbook 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 win_name = s_name
ModifyPanel /w=$win_name cbRGB=(52224,52224,65280) ModifyPanel /w=$win_name cbRGB=(52224,52224,65280)
svar /sdfr=df_persistent attributes svar /sdfr=df_persistent attributes
svar /sdfr=df_persistent controls svar /sdfr=df_persistent controls
svar /sdfr=df_persistent options 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 iattr
variable nattr = ItemsInList(attributes, ";") variable nattr = ItemsInList(attributes, ";")
string s_attr string s_attr
@ -1066,35 +1194,28 @@ function /s PearlElogPanel(logbook)
string options_path string options_path
string variable_path string variable_path
variable ypos = 2 variable ypos = 2
variable height = 0
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
for (iattr = 0; iattr < nattr; iattr += 1) for (iattr = 0; iattr < nattr; iattr += 1)
s_attr = StringFromList(iattr, attributes, ";") s_attr = StringFromList(iattr, attributes, ";")
s_control = StringFromList(iattr, controls, ";") s_control = StringFromList(iattr, controls, ";")
strswitch(s_control[0,1]) strswitch(s_control[0,1])
case "sv": 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, title=s_attr, value= _STR:""
SetVariable $s_control, win=$win_name, userdata(attribute)=s_attr SetVariable $s_control, win=$win_name, userdata(attribute)=s_attr
ypos += 18 ypos += 18
break break
case "pm": case "pm":
options_path = persistent_path + StringByKey(s_attr, options, "=", ";") 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, title=s_attr
PopupMenu $s_control, win=$win_name, mode=1, popvalue="Test", value= #options_path PopupMenu $s_control, win=$win_name, mode=1, popvalue="Test", value= #options_path
PopupMenu $s_control, win=$win_name, userdata(attribute)=s_attr PopupMenu $s_control, win=$win_name, userdata(attribute)=s_attr
ypos += 23 ypos += 23
break break
case "cb": 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, title=s_attr, value= 1
CheckBox $s_control, win=$win_name, userdata(attribute)=s_attr CheckBox $s_control, win=$win_name, userdata(attribute)=s_attr
ypos += 17 ypos += 17
@ -1102,48 +1223,81 @@ function /s PearlElogPanel(logbook)
endswitch endswitch
endfor endfor
PopupMenu pm_attach,win=$win_name, pos={0,ypos},size={260,21},bodyWidth=200,title="Attachment" TitleBox t_attach, win=$win_name, pos={308,5}, size={70,14}, title="Attachments", frame=0
PopupMenu pm_attach,win=$win_name, mode=1,popvalue="(none)",value=PearlElog#pm_list_attach_items() height = ypos - 21 - 4
PopupMenu pm_attach,win=$win_name, help={"Choose any visible Igor graph for attachment."} ListBox lb_attach, win=$win_name, pos={308,21}, size={264,height}
Button b_select_attach_top,win=$win_name, pos={264,ypos},size={60,20},proc=PearlElog#bp_select_attach_top,title="Top Graph" ListBox lb_attach, win=$win_name, listWave=attach_list
Button b_select_attach_top,win=$win_name, help={"Select top graph window."} ListBox lb_attach, win=$win_name, mode=1, selWave=attach_sel, selRow=-1
Button b_select_attach_top,win=$win_name, fcolor=(56576,60928,47872) 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 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, help={"Submit form data to ELOG (new entry)."}
Button b_submit,win=$win_name, fcolor=(56576,60928,47872) Button b_submit,win=$win_name, fcolor=(56576,60928,47872)
Button b_clear,win=$win_name, pos={120,ypos},size={46,20},proc=PearlElog#bp_clear,title="Clear"
Button b_clear,win=$win_name, pos={110,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, help={"Clear the form fields"}
Button b_clear,win=$win_name, fcolor=(56576,60928,47872) Button b_clear,win=$win_name, fcolor=(56576,60928,47872)
ypos += 272-246 ypos += 272-246
variable_path = volatile_path + "msg_id" 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, title="ID",value=$variable_path
SetVariable sv_id,win=$win_name, help={"ID of last submitted message, or message to attach or reply to."} 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 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, 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_attach,win=$win_name, fcolor=(56576,60928,47872)
Button b_reply,win=$win_name, pos={220,ypos},size={48,20},proc=PearlElog#bp_submit,title="Reply"
Button b_reply,win=$win_name, pos={210,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, 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) Button b_reply,win=$win_name, fcolor=(56576,60928,47872)
Button b_login,win=$win_name, pos={550,ypos},size={46,20},proc=PearlElog#bp_login,title="Login"
ypos += 184-270 Button b_login,win=$win_name, help={"Enter user name and password."}
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, 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, hook(elogPanelHook)=PearlElog#elog_panel_hook
SetWindow $win_name, userdata(logbook)=logbook 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=# 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, 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 RenameWindow #,Message
string nb_name = win_name + "#Message"
SetActiveSubwindow ## SetActiveSubwindow ##
// restore recently used attributes and message // restore recently used attributes and message
@ -1155,6 +1309,7 @@ function /s PearlElogPanel(logbook)
if (svar_exists(recent_message) && (strlen(recent_message) > 0)) if (svar_exists(recent_message) && (strlen(recent_message) > 0))
set_panel_message(win_name, recent_message) set_panel_message(win_name, recent_message)
endif endif
Notebook $nb_name selection={startOfFile,startOfFile}, findText={"",1}
setdatafolder savedf setdatafolder savedf
return win_name return win_name
@ -1166,49 +1321,153 @@ static function elog_panel_hook(s)
Variable hookResult = 0 Variable hookResult = 0
switch(s.eventCode) 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 case 6: // resize
// move bottom-aligned controls when the window is resized // move bottom-aligned controls when the window is resized
variable b_top = s.winRect.bottom + 4 variable b_top = s.winRect.bottom + 4
Button b_submit,pos={60,b_top} Button b_submit,pos={70,b_top}
Button b_clear,pos={110,b_top} Button b_clear,pos={120,b_top}
TitleBox t_host, pos={170,b_top+4}
b_top += 24 b_top += 24
Button b_attach,pos={160,b_top} Button b_attach,pos={170,b_top}
Button b_reply,pos={210,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 b_top += 2
SetVariable sv_id,pos={46,b_top} SetVariable sv_id,pos={51,b_top}
break break
endswitch endswitch
return hookResult // 0 if nothing done, else 1 return hookResult // 0 if nothing done, else 1
end end
/// get a list of graph windows for a popup menu. static constant kAttachColSel = 0
static function /s pm_list_attach_items() 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") string names = WinList("*", ";", "WIN:1;VISIBLE:1")
names = SortList(names, ";", 16) names = SortList(names, ";", 16)
// get corresponding graph titles // remove closed graphs
variable nnames = ItemsInList(names, ";") variable i
variable iname variable k
string name variable n = DimSize(attach_list, 0)
string item string s
string items = "" for (i = n-1; i >= 0; i -= 1)
s = attach_list[i][kAttachColName]
// format each entry like "name: title" if (WhichListItem(s, names) < 0)
for (iname = 0; iname < nnames; iname += 1) DeletePoints /M=0 i, 1, attach_list, attach_sel
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)
endif endif
endfor endfor
items = AddListItem("(none)", items, ";") // add new graphs
return items 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 end
/// button procedure for the Submit and Reply buttons /// button procedure for the Submit and Reply buttons
@ -1259,7 +1518,7 @@ static function bp_submit(ba) : ButtonControl
end end
/// select top graph window for attachment /// select top graph window for attachment
static function bp_select_attach_top(ba) : ButtonControl static function bp_attach_top(ba) : ButtonControl
STRUCT WMButtonAction &ba STRUCT WMButtonAction &ba
switch( ba.eventCode ) switch( ba.eventCode )
@ -1274,6 +1533,28 @@ static function bp_select_attach_top(ba) : ButtonControl
return 0 return 0
end 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 static function bp_attach(ba) : ButtonControl
STRUCT WMButtonAction &ba STRUCT WMButtonAction &ba
@ -1307,6 +1588,34 @@ static function bp_attach(ba) : ButtonControl
return 0 return 0
end 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 static function bp_clear(ba) : ButtonControl
STRUCT WMButtonAction &ba STRUCT WMButtonAction &ba
@ -1522,15 +1831,14 @@ end
/// get the names of the graphs selected for attachment /// get the names of the graphs selected for attachment
/// ///
/// @param windowname panel window name
/// @returns a semicolon-separated list, /// @returns a semicolon-separated list,
/// or the empty string if the selection is not valid. /// 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) static function /s get_panel_graphs(windowname)
string windowname // panel window name string windowname // panel window name
dfref savedf = getdatafolderdfr()
if (strlen(windowname) == 0) if (strlen(windowname) == 0)
windowname = get_default_panel_name() windowname = get_default_panel_name()
endif endif
@ -1538,24 +1846,38 @@ static function /s get_panel_graphs(windowname)
return "" return ""
endif endif
ControlInfo /W=$windowname pm_attach string logbook = GetUserData(windowname, "", "logbook")
dfref df_volatile = get_elog_df(logbook, kdfVolatile)
// menu item has the form: "title (name)" wave /t /sdfr=df_volatile attach_list
string graphname = ReplaceString(")", StringFromList(ItemsInList(s_value, "(") - 1, s_value, "("), "") wave /sdfr=df_volatile attach_sel
string graphs = "" string graphs = ""
string windows = WinList(graphname, ";", "WIN:1") string windows = ""
if (ItemsInList(windows) == 1) string graphname
graphs = graphname
else variable n = DimSize(attach_sel, 0)
graphs = "" variable i
endif 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 = AddListItem(graphname, graphs, ";", inf)
endif
endif
endfor
return graphs return graphs
end 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) static function /s set_panel_graphs(windowname, graphs)
string windowname // panel window name. looks for default panel if empty. string windowname
string graphs // name of graph window to select for attachment. string graphs
if (strlen(windowname) == 0) if (strlen(windowname) == 0)
windowname = get_default_panel_name() windowname = get_default_panel_name()
@ -1564,23 +1886,21 @@ static function /s set_panel_graphs(windowname, graphs)
return "" return ""
endif endif
// the panel supports only one graph string logbook = GetUserData(windowname, "", "logbook")
string graph = StringFromList(0, graphs, ";") update_attach_items(logbook)
dfref df_volatile = get_elog_df(logbook, kdfVolatile)
string items = pm_list_attach_items() wave /t /sdfr=df_volatile attach_list
string item wave /sdfr=df_volatile attach_sel
string itemname
variable nitems = ItemsInList(items, ";") variable n = DimSize(attach_sel, 0)
variable iitem variable i
for (iitem = 0; iitem < nitems; iitem += 1) string graphname
item = StringFromList(iitem, items, ";") for (i = 0; i < n; i += 1)
itemname = ReplaceString(")", StringFromList(ItemsInList(item, "(") - 1, item, "("), "") graphname = attach_list[i][kAttachColName]
if (cmpstr(graph, itemname) == 0) if (WhichListItem(graphname, graphs)>= 0)
iitem += 1 attach_sel[i][kAttachColSel] = 48
PopupMenu pm_attach mode=iitem, win=$windowname else
break attach_sel[i][kAttachColSel] = 32
endif endif
endfor endfor
return graph
end end

View File

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