new features: data reduction, angle scan panel
- new data reduction interface for more efficient multi-peak fitting. the new interface breaks compatibility with pre-2.0 data reduction functions. user-defined functions must be adapted to the new interface. - new angle scan processing panel for interactive data analysis.
This commit is contained in:
@ -1,11 +1,10 @@
|
||||
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
|
||||
#pragma IgorVersion = 6.2
|
||||
#pragma ModuleName = PearlAreaImport
|
||||
#pragma version = 1.06
|
||||
#include <HDF5 Browser>
|
||||
#include "pearl-gui-tools"
|
||||
|
||||
// copyright (c) 2013-16 Paul Scherrer Institut
|
||||
// copyright (c) 2013-18 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.
|
||||
@ -23,6 +22,14 @@
|
||||
/// as of Igor 6.3, Igor can open datasets of up to rank 4.
|
||||
/// i.e. the extra dimension Y of the file plugin cannot be used.
|
||||
/// the extra dimensions N and X are supported.
|
||||
///
|
||||
/// @author matthias muntwiler, matthias.muntwiler@psi.ch
|
||||
///
|
||||
/// @copyright 2013-18 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 PearlAreaImport
|
||||
/// @brief HDF5 file import from EPICS area detectors
|
||||
@ -1031,7 +1038,7 @@ end
|
||||
/// it may thus include functions which are not suitable as reduction functions.
|
||||
///
|
||||
function /s adh5_list_reduction_funcs()
|
||||
string all_funcs = FunctionList("*", ";", "KIND:6,NPARAMS:4,VALTYPE:1")
|
||||
string all_funcs = FunctionList("*", ";", "KIND:6,NPARAMS:2,VALTYPE:8")
|
||||
string result = ""
|
||||
|
||||
variable ii
|
||||
@ -1045,16 +1052,14 @@ function /s adh5_list_reduction_funcs()
|
||||
for (ii = 0; ii < nn; ii += 1)
|
||||
funcname = StringFromList(ii, all_funcs, ";")
|
||||
info = FunctionInfo(funcname)
|
||||
accept = (NumberByKey("RETURNTYPE", info, ":", ";") == 0x0004)
|
||||
accept = (NumberByKey("RETURNTYPE", info, ":", ";") == 0x4000)
|
||||
accept = accept && (cmpstr(StringByKey("THREADSAFE", info, ":", ";"), "yes") == 0)
|
||||
accept = accept && (NumberByKey("N_PARAMS", info, ":", ";") == 4)
|
||||
accept = accept && (NumberByKey("N_PARAMS", info, ":", ";") == 2)
|
||||
accept = accept && (NumberByKey("N_OPT_PARAMS", info, ":", ";") == 0)
|
||||
if (accept)
|
||||
// 3 numeric waves and one pass-by-reference string
|
||||
// one numeric wave and one pass-by-reference string
|
||||
accept = accept && (NumberByKey("PARAM_0_TYPE", info, ":", ";") == 0x4002)
|
||||
accept = accept && (NumberByKey("PARAM_1_TYPE", info, ":", ";") == 0x4002)
|
||||
accept = accept && (NumberByKey("PARAM_2_TYPE", info, ":", ";") == 0x4002)
|
||||
accept = accept && (NumberByKey("PARAM_3_TYPE", info, ":", ";") == 0x3000)
|
||||
accept = accept && (NumberByKey("PARAM_1_TYPE", info, ":", ";") == 0x3000)
|
||||
endif
|
||||
if (accept)
|
||||
result = AddListItem(funcname, result, ";")
|
||||
@ -1067,9 +1072,18 @@ end
|
||||
|
||||
/// function prototype for adh5_load_reduced_detector
|
||||
///
|
||||
/// derived functions reduce a two-dimensional dataset to a one-dimensional dataset,
|
||||
/// e.g. by ROI-integration, curve fitting, etc.
|
||||
// the resulting wave must have the same size as either dimension of the source image.
|
||||
/// this is a prototype of custom functions that convert (reduce) a two-dimensional detector image
|
||||
/// into one or more one-dimensional waves.
|
||||
/// data processing can be tuned with a set of parameters.
|
||||
///
|
||||
/// reduction functions have a fixed signature (function arguments) so that the file import functions
|
||||
/// can call them efficiently on a series of detector images.
|
||||
/// pearl procedures comes with a number of pre-defined reduction functions
|
||||
/// but you may as well implement your own functions.
|
||||
/// if you write your own function, you must use the same declaration and arguments
|
||||
/// as this function except for the function name.
|
||||
/// you can do many things in a reduction function,
|
||||
/// e.g. integration over a region of interest, curve fitting, etc.
|
||||
///
|
||||
/// each destination wave is a one-dimensional intensity distribution.
|
||||
/// the function must redimension each of these waves to one of the image dimensions
|
||||
@ -1077,32 +1091,38 @@ end
|
||||
/// this function will also copy the scale information and dimension labels,
|
||||
/// which is important for the proper scaling of the result.
|
||||
///
|
||||
/// the meaning of the data in dest1 and dest2 is up to the particular function,
|
||||
/// the meaning of the data in the result waves 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 source source wave
|
||||
/// two-dimensional intensity distribution (image)
|
||||
/// @param dest1, dest2 destination waves
|
||||
/// @param param string with optional parameters, shared between calls.
|
||||
/// @param source source wave.
|
||||
/// two-dimensional intensity distribution (image).
|
||||
/// the scales are carried over to the result waves.
|
||||
///
|
||||
/// @param param string with optional parameters, shared between calls.
|
||||
/// this is a pass-by-reference argument,
|
||||
/// the function may modify the string
|
||||
/// the function may modify the string.
|
||||
///
|
||||
/// @return zero if successful, non-zero if an error occurs.
|
||||
/// @return a free wave containing references of the result waves.
|
||||
/// the result waves should as well be free waves.
|
||||
/// if an error occurred, the reference wave is empty.
|
||||
///
|
||||
threadsafe function adh5_default_reduction(source, dest1, dest2, param)
|
||||
threadsafe function /wave adh5_default_reduction(source, param)
|
||||
wave source
|
||||
wave dest1, dest2
|
||||
string ¶m
|
||||
|
||||
// demo code
|
||||
// integrate along the dimensions
|
||||
// integrate along the dimensions
|
||||
make /n=0 /free dest1, dest2
|
||||
adh5_setup_profile(source, dest1, 0)
|
||||
ad_profile_x_w(source, 0, -1, dest1)
|
||||
adh5_setup_profile(source, dest2, 1)
|
||||
ad_profile_y_w(source, 0, -1, dest2)
|
||||
|
||||
return 0
|
||||
make /n=2 /free /wave results
|
||||
results[0] = dest1
|
||||
results[1] = dest2
|
||||
return results
|
||||
end
|
||||
|
||||
/// set up a one-dimensional wave for a line profile based on a 2D original wave.
|
||||
@ -1123,20 +1143,66 @@ end
|
||||
|
||||
/// wrapper function for testing reduction functions from the command line.
|
||||
///
|
||||
/// Igor does not allow global variables as pass-by-reference parameter for reduction_param.
|
||||
/// reduction functions cannot be used on the command line because they require
|
||||
/// a pass-by-reference argument and return free waves.
|
||||
/// this function expects the reduction parameters in a normal string
|
||||
/// and copies the results into the current data folder.
|
||||
/// the prefix of the result names can be specified.
|
||||
///
|
||||
function /s adh5_test_reduction_func(source, dest1, dest2, reduction_func, reduction_param)
|
||||
/// @param source source wave.
|
||||
/// two-dimensional intensity distribution (image).
|
||||
/// the scales are carried over to the result waves.
|
||||
///
|
||||
/// @param reduction_func name of the reduction function to apply to the source data.
|
||||
///
|
||||
/// @param reduction_param string with reduction parameters as required by the specific reduction function.
|
||||
///
|
||||
/// @param result_prefix name prefix of result waves.
|
||||
/// a numeric index is appended to distinguish the results.
|
||||
/// the index starts at 1. existing waves are overwritten.
|
||||
///
|
||||
/// @return a copy of the reduction_param string, possibly modified by the reduction function.
|
||||
///
|
||||
function /s adh5_test_reduction_func(source, reduction_func, reduction_param, result_prefix)
|
||||
wave source
|
||||
wave dest1
|
||||
wave dest2
|
||||
funcref adh5_default_reduction reduction_func
|
||||
string reduction_param
|
||||
string result_prefix
|
||||
|
||||
reduction_func(source, dest1, dest2, reduction_param)
|
||||
wave /wave results = reduction_func(source, reduction_param)
|
||||
adh5_get_result_waves(results, result_prefix, 1)
|
||||
|
||||
return reduction_param
|
||||
end
|
||||
|
||||
/// copy waves from wave reference wave into current data folder
|
||||
///
|
||||
/// this function copies waves that are referenced in a wave reference wave into the current data folder.
|
||||
/// the destination waves get new names consisting of a prefix and a numeric index.
|
||||
/// the index is the array index of the wave in results plus a chosen offset.
|
||||
///
|
||||
/// @param results a wave reference wave pointing to result waves from data reduction.
|
||||
/// the waves can be free or regular waves.
|
||||
/// results can be a free or regular wave.
|
||||
///
|
||||
/// @param result_prefix name prefix of the copied waves.
|
||||
///
|
||||
/// @param start_index start index (offset) of the copied waves.
|
||||
///
|
||||
threadsafe function adh5_get_result_waves(results, result_prefix, start_index)
|
||||
wave /wave results
|
||||
string result_prefix
|
||||
variable start_index
|
||||
|
||||
variable nw = numpnts(results)
|
||||
variable iw
|
||||
string sw
|
||||
for (iw = 0; iw < nw; iw += 1)
|
||||
sw = result_prefix + num2str(iw + start_index)
|
||||
duplicate /o results[iw], $sw
|
||||
endfor
|
||||
end
|
||||
|
||||
/// load a reduced detector dataset from the open HDF5 file.
|
||||
///
|
||||
/// the function loads the dataset image by image using the hyperslab option
|
||||
@ -1266,6 +1332,10 @@ function adh5_load_reduced_detector(fileID, detectorpath, reduction_func, reduct
|
||||
|
||||
variable iz, it
|
||||
string dfname
|
||||
variable iw, nw
|
||||
string sw
|
||||
make /n=0 /free /wave result_waves
|
||||
|
||||
izt = 0
|
||||
for (iz = 0; iz < nz; iz += 1)
|
||||
for (it = 0; it < nt; it += 1)
|
||||
@ -1287,11 +1357,11 @@ function adh5_load_reduced_detector(fileID, detectorpath, reduction_func, reduct
|
||||
ThreadGroupPutDF threadGroupID, :
|
||||
else
|
||||
processing_folders[izt] = GetDataFolderDFR()
|
||||
make /n=1/d profile1, profile2
|
||||
wave slabdata
|
||||
variable /g func_result
|
||||
func_result = reduce_slab_image(slabdata, image, profile1, profile2, reduction_func, func_param)
|
||||
WaveClear slabdata, image, profile1, profile2
|
||||
wave /wave reduced_waves = reduce_slab_image(slabdata, image, reduction_func, func_param)
|
||||
variable /g func_result = numpnts(reduced_waves)
|
||||
adh5_get_result_waves(reduced_waves, "redw_", 0)
|
||||
WaveClear slabdata, image, reduced_waves
|
||||
setdatafolder ::
|
||||
endif
|
||||
|
||||
@ -1343,26 +1413,32 @@ function adh5_load_reduced_detector(fileID, detectorpath, reduction_func, reduct
|
||||
nvar rr = dfr:r_index
|
||||
nvar ss = dfr:s_index
|
||||
nvar func_result = dfr:func_result
|
||||
wave profile1 = dfr:profile1
|
||||
wave profile2 = dfr:profile2
|
||||
|
||||
if (func_result == 0)
|
||||
if (izt == 0)
|
||||
make /n=(dimsize(profile1, 0), nz, nt)/d/o data1
|
||||
make /n=(dimsize(profile2, 0), nz, nt)/d/o data2
|
||||
setdimlabel 0, -1, $getdimlabel(profile1, 0, -1), data1
|
||||
setdimlabel 0, -1, $getdimlabel(profile2, 0, -1), data2
|
||||
setscale /p x dimoffset(profile1, 0), dimdelta(profile1, 0), waveunits(profile1, 0), data1
|
||||
setscale /p x dimoffset(profile2, 0), dimdelta(profile2, 0), waveunits(profile2, 0), data2
|
||||
setscale d 0, 0, waveunits(profile1, -1), data1
|
||||
setscale d 0, 0, waveunits(profile2, -1), data2
|
||||
endif
|
||||
data1[][rr][ss] = profile1[p]
|
||||
data2[][rr][ss] = profile2[p]
|
||||
else
|
||||
if (func_result < 1)
|
||||
result = -3 // dimension reduction error
|
||||
break
|
||||
endif
|
||||
|
||||
if (numpnts(result_waves) == 0)
|
||||
redimension /n=(func_result) result_waves
|
||||
for (iw = 0; iw < func_result; iw += 1)
|
||||
sw = "redw_" + num2str(iw)
|
||||
wave profile = dfr:$sw
|
||||
sw = "ReducedData" + num2str(iw+1)
|
||||
make /n=(dimsize(profile, 0), nz, nt) /d /o $sw
|
||||
wave data = $sw
|
||||
setdimlabel 0, -1, $getdimlabel(profile, 0, -1), data
|
||||
setscale /p x dimoffset(profile, 0), dimdelta(profile, 0), waveunits(profile, 0), data
|
||||
setscale d 0, 0, waveunits(profile, -1), data
|
||||
result_waves[iw] = data
|
||||
endfor
|
||||
endif
|
||||
for (iw = 0; iw < func_result; iw += 1)
|
||||
sw = "redw_" + num2str(iw)
|
||||
wave profile = dfr:$sw
|
||||
wave data = result_waves[iw]
|
||||
data[][rr][ss] = profile[p]
|
||||
endfor
|
||||
endfor
|
||||
|
||||
if (nthreads > 0)
|
||||
@ -1377,20 +1453,19 @@ function adh5_load_reduced_detector(fileID, detectorpath, reduction_func, reduct
|
||||
endif
|
||||
|
||||
if (result == 0)
|
||||
if (nz == 1)
|
||||
redimension /n=(dimsize(data1,0)) data1
|
||||
redimension /n=(dimsize(data2,0)) data2
|
||||
elseif (nt == 1)
|
||||
redimension /n=(dimsize(data1,0),nz) data1
|
||||
redimension /n=(dimsize(data2,0),nz) data2
|
||||
setdimlabel 1, -1, AD_DimN, data1
|
||||
setdimlabel 1, -1, AD_DimN, data2
|
||||
else
|
||||
setdimlabel 1, -1, AD_DimN, data1
|
||||
setdimlabel 1, -1, AD_DimN, data2
|
||||
setdimlabel 2, -1, AD_DimX, data1
|
||||
setdimlabel 2, -1, AD_DimX, data2
|
||||
endif
|
||||
nw = numpnts(result_waves)
|
||||
for (iw = 0; iw < nw; iw += 1)
|
||||
wave data = result_waves[iw]
|
||||
if (nz == 1)
|
||||
redimension /n=(dimsize(data, 0)) data
|
||||
elseif (nt == 1)
|
||||
redimension /n=(dimsize(data, 0),nz) data
|
||||
setdimlabel 1, -1, AD_DimN, data
|
||||
else
|
||||
setdimlabel 1, -1, AD_DimN, data
|
||||
setdimlabel 2, -1, AD_DimX, data
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
if (progress)
|
||||
kill_progress_panel()
|
||||
@ -1426,14 +1501,14 @@ threadsafe static function reduce_slab_worker(reduction_func)
|
||||
|
||||
// do the work
|
||||
newdatafolder /s outDF
|
||||
make /n=1/d profile1, profile2
|
||||
variable /g r_index = rr
|
||||
variable /g s_index = ss
|
||||
variable /g func_result
|
||||
func_result = reduce_slab_image(slabdata, image, profile1, profile2, reduction_func, func_param)
|
||||
wave /wave reduced_waves = reduce_slab_image(slabdata, image, reduction_func, func_param)
|
||||
variable /g func_result = numpnts(reduced_waves)
|
||||
|
||||
// send output to queue and clean up
|
||||
WaveClear slabdata, image, profile1, profile2
|
||||
adh5_get_result_waves(reduced_waves, "redw_", 0)
|
||||
WaveClear slabdata, image, reduced_waves
|
||||
ThreadGroupPutDF 0, :
|
||||
KillDataFolder dfr
|
||||
while (1)
|
||||
@ -1441,11 +1516,9 @@ threadsafe static function reduce_slab_worker(reduction_func)
|
||||
return 0
|
||||
end
|
||||
|
||||
threadsafe static function reduce_slab_image(slabdata, image, profile1, profile2, reduction_func, reduction_param)
|
||||
threadsafe static function /wave reduce_slab_image(slabdata, image, reduction_func, reduction_param)
|
||||
wave slabdata
|
||||
wave image
|
||||
wave profile1
|
||||
wave profile2
|
||||
funcref adh5_default_reduction reduction_func
|
||||
string reduction_param
|
||||
|
||||
@ -1461,7 +1534,7 @@ threadsafe static function reduce_slab_image(slabdata, image, profile1, profile2
|
||||
break
|
||||
endswitch
|
||||
|
||||
return reduction_func(image, profile1, profile2, reduction_param)
|
||||
return reduction_func(image, reduction_param)
|
||||
end
|
||||
|
||||
/// load an NDAttributes group from an open HDF5 file into the current data folder.
|
||||
@ -1667,12 +1740,12 @@ function adh5_scale_scienta(data)
|
||||
case 1: // Angular45
|
||||
ALow = -45/2
|
||||
AHigh = +45/2
|
||||
AUnit = "°"
|
||||
AUnit = "<EFBFBD>"
|
||||
break
|
||||
case 2: // Angular60
|
||||
ALow = -60/2
|
||||
AHigh = +60/2
|
||||
AUnit = "°"
|
||||
AUnit = "<EFBFBD>"
|
||||
break
|
||||
endswitch
|
||||
endif
|
||||
|
Reference in New Issue
Block a user