code changes for release 2.2.0
This commit is contained in:
@ -1,12 +1,13 @@
|
||||
#pragma TextEncoding = "UTF-8"
|
||||
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
|
||||
#pragma version = 1.8
|
||||
#pragma version = 1.9
|
||||
#pragma IgorVersion = 6.2
|
||||
#pragma ModuleName = PearlAnglescanProcess
|
||||
#include "pearl-vector-operations"
|
||||
#include "pearl-polar-coordinates"
|
||||
#include <New Polar Graphs>
|
||||
|
||||
// copyright (c) 2013-17 Paul Scherrer Institut
|
||||
// copyright (c) 2013-21 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.
|
||||
@ -64,7 +65,7 @@
|
||||
///
|
||||
/// @author matthias muntwiler, matthias.muntwiler@psi.ch
|
||||
///
|
||||
/// @copyright 2013-17 Paul Scherrer Institut @n
|
||||
/// @copyright 2013-21 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
|
||||
@ -80,6 +81,70 @@
|
||||
/// PearlAnglescanProcess is declared in @ref pearl-anglescan-process.ipf.
|
||||
|
||||
|
||||
/// append an angle scan strip to another one
|
||||
///
|
||||
/// concatenate two angle scan strips including matching attribute waves
|
||||
/// and replace the first strip with the resulting waves.
|
||||
/// this is useful if a scan was interrupted and continues in a second data file.
|
||||
///
|
||||
/// all accompanying 1D waves which have a matching length and exist in both source and destination folders
|
||||
/// are concatenated and stored in the destination.
|
||||
/// 'accompanying waves' are those in the same folder as the 2D strip wave and those in the :attr sub-folder.
|
||||
///
|
||||
/// @attention this function modifies all matching waves in the data and attr folders of strip1!
|
||||
/// consider a backup before calling the function, or work on a copy of the original data
|
||||
/// (cf. Igor's DuplicateDataFolder operation)!
|
||||
///
|
||||
/// @param[in,out] strip1 2D data, X-axis = analyser angle, Y-axis = arbitrary manipulator scan.
|
||||
/// this is the first source wave and destination wave.
|
||||
///
|
||||
/// @param[in] strip2 2D data, X-axis = analyser angle, Y-axis = arbitrary manipulator scan.
|
||||
/// this is the second source wave.
|
||||
///
|
||||
/// @return (string) semicolon-separated list of modified wave names (without folder path).
|
||||
///
|
||||
function /s strip_append(strip1, strip2)
|
||||
wave strip1
|
||||
wave strip2
|
||||
|
||||
dfref df1 = GetWavesDataFolderDFR(strip1)
|
||||
dfref df2 = GetWavesDataFolderDFR(strip2)
|
||||
variable ny1 = dimsize(strip1, 1)
|
||||
variable ny2 = dimsize(strip2, 1)
|
||||
|
||||
concatenate /np=1 {strip2}, strip1
|
||||
string modified = AddListItem(NameOfWave(strip1), "")
|
||||
|
||||
variable idf = 0
|
||||
do
|
||||
variable iw = 0
|
||||
do
|
||||
wave /z w1 = WaveRefIndexedDFR(df1, iw)
|
||||
if (!WaveExists(w1))
|
||||
break
|
||||
endif
|
||||
|
||||
wave /z w2 = df2:$(NameOfWave(w1))
|
||||
if (WaveExists(w1) && WaveExists(w2))
|
||||
if ((DimSize(w1, 0) == ny1) && (DimSize(w1, 1) == 0) && (DimSize(w2, 0) == ny2) && (DimSize(w2, 1) == 0))
|
||||
concatenate /np=0 {w2}, w1
|
||||
modified = AddListItem(NameOfWave(w1), modified, "", Inf)
|
||||
endif
|
||||
endif
|
||||
iw += 1
|
||||
while(1)
|
||||
|
||||
df1 = df1:attr
|
||||
df2 = df2:attr
|
||||
if ((DataFolderRefStatus(df1) != 1) || (DataFolderRefStatus(df2) != 1))
|
||||
break
|
||||
endif
|
||||
idf += 1
|
||||
while(idf < 2)
|
||||
|
||||
return modified
|
||||
end
|
||||
|
||||
/// 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.
|
||||
@ -299,7 +364,9 @@ function normalize_strip_phi(strip, theta, phi, [theta_offset, theta_range, chec
|
||||
endif
|
||||
|
||||
// average over analyser angles
|
||||
wave dist = ad_profile_y(strip, -inf, inf, "")
|
||||
duplicate /free strip, strip_copy
|
||||
MatrixFilter NanZapMedian strip_copy
|
||||
wave dist = ad_profile_y(strip_copy, -inf, inf, "")
|
||||
|
||||
// smooth distribution function
|
||||
duplicate /free dist, dist_smoo
|
||||
@ -385,7 +452,9 @@ function normalize_strip_theta(strip, theta, [theta_offset, smooth_method, smoot
|
||||
endif
|
||||
|
||||
// average over analyser angles
|
||||
wave dist = ad_profile_y(strip, -inf, inf, "")
|
||||
duplicate /free strip, strip_copy
|
||||
MatrixFilter NanZapMedian strip_copy
|
||||
wave dist = ad_profile_y(strip_copy, -inf, inf, "")
|
||||
|
||||
// smooth distribution function
|
||||
duplicate /free dist, dist_smoo
|
||||
@ -484,7 +553,9 @@ function normalize_strip_thetaphi(strip, theta, phi, [theta_offset, smooth_metho
|
||||
endif
|
||||
|
||||
// average over analyser angles
|
||||
wave dist = ad_profile_y(strip, -inf, inf, "")
|
||||
duplicate /free strip, strip_copy
|
||||
MatrixFilter NanZapMedian strip_copy
|
||||
wave dist = ad_profile_y(strip_copy, -inf, inf, "")
|
||||
|
||||
// smooth distribution function
|
||||
duplicate /free dist, dist_smoo
|
||||
@ -542,7 +613,9 @@ function normalize_strip_theta_scans(strip, theta, [theta_offset, smooth_method,
|
||||
endif
|
||||
|
||||
// average over analyser angles
|
||||
wave dist = ad_profile_y(strip, -inf, inf, "")
|
||||
duplicate /free strip, strip_copy
|
||||
MatrixFilter NanZapMedian strip_copy
|
||||
wave dist = ad_profile_y(strip_copy, -inf, inf, "")
|
||||
|
||||
// smooth distribution function
|
||||
duplicate /free dist, dist_smoo
|
||||
@ -635,6 +708,7 @@ function normalize_strip_2d(strip, theta, [theta_offset, smooth_method, smooth_f
|
||||
variable ny = dimsize(strip, 1)
|
||||
|
||||
duplicate /free strip, dist, alpha_int, theta_int
|
||||
MatrixFilter NanZapMedian dist
|
||||
theta_int = theta[q] - theta_offset
|
||||
alpha_int = dimoffset(strip, 0) + p * dimdelta(strip, 0)
|
||||
redimension /n=(nx * ny) dist, alpha_int, theta_int
|
||||
@ -1955,7 +2029,7 @@ static function /s display_polar_graph(graphname, [angle_offset, do_ticks])
|
||||
WMPolarGraphSetVar(graphname, "doAngleTickLabelSubRange", 1)
|
||||
WMPolarGraphSetVar(graphname, "angleTickLabelRangeStart", 0)
|
||||
WMPolarGraphSetVar(graphname, "angleTickLabelRangeExtent", 90)
|
||||
WMPolarGraphSetStr(graphname, "angleTickLabelNotation", "%g<EFBFBD>")
|
||||
WMPolarGraphSetStr(graphname, "angleTickLabelNotation", "%g°")
|
||||
|
||||
WMPolarGraphSetVar(graphname, "doPolarGrids", 0)
|
||||
WMPolarGraphSetVar(graphname, "doRadiusTickLabels", 0)
|
||||
@ -2083,9 +2157,9 @@ static function /s draw_hemi_axes(graphname, [do_grids])
|
||||
SetDrawEnv /W=$graphname textxjust= 1,textyjust= 2
|
||||
SetDrawEnv /W=$graphname save
|
||||
radi = calc_graph_radius(30, projection=projection)
|
||||
DrawText /W=$graphname radi, -0.1, "30<EFBFBD>"
|
||||
DrawText /W=$graphname radi, -0.1, "30°"
|
||||
radi = calc_graph_radius(60, projection=projection)
|
||||
DrawText /W=$graphname radi, -0.1, "60<EFBFBD>"
|
||||
DrawText /W=$graphname radi, -0.1, "60°"
|
||||
endif
|
||||
|
||||
setdatafolder savedf
|
||||
@ -2205,7 +2279,7 @@ function /s display_scanlines(nickname, alpha_lo, alpha_hi, m_theta, m_tilt, m_p
|
||||
make /n=1 /d /free d_polar, d_azi
|
||||
variable n_alpha = round(alpha_hi - alpha_lo) + 1
|
||||
make /n=(n_alpha) /d /free analyser
|
||||
setscale /i x alpha_lo, alpha_hi, "<EFBFBD>", analyser
|
||||
setscale /i x alpha_lo, alpha_hi, "°", analyser
|
||||
analyser = x
|
||||
|
||||
convert_angles_ttpa2polar(m_theta, loc_m_tilt, m_phi, analyser, d_polar, d_azi)
|
||||
@ -2526,50 +2600,78 @@ function set_polar_graph_cursor(nickname, cursorname, polar_angle, azim_angle, [
|
||||
endif
|
||||
end
|
||||
|
||||
/// add an arbitrary angle scan to a hemispherical scan grid.
|
||||
|
||||
/// add arbitrary angle scan data to a hemispherical scan grid.
|
||||
///
|
||||
/// the hemi grid must have been created in the current data folder by the make_hemi_grid function.
|
||||
/// the function determines the bin size at the given polar angle,
|
||||
/// and adds all data points which fall into a bin.
|
||||
/// a point which lies exactly on the upper boundary falls into the next bin.
|
||||
/// this function does not clear previous values before adding new data.
|
||||
/// the function fills the input data into bins defined by the hemi scan grid.
|
||||
/// it sums up the values and weights of the data points which fall into each bin,
|
||||
/// and adds the results to the totals and weights waves of the existing hemi grid.
|
||||
/// finally, it updates the values wave (values divided by weights).
|
||||
///
|
||||
/// the hemi grid must have been created in the current data folder by the make_hemi_grid() function.
|
||||
/// the function does not clear previous values before adding new data.
|
||||
/// values are added to the _tot wave, weights to the _wt wave.
|
||||
/// the intensity (_i) wave is calculated as _tot / _wt.
|
||||
/// the intensity (_i/values) wave is calculated as _tot divided by _wt.
|
||||
///
|
||||
/// @param nickname name prefix of holo waves.
|
||||
/// empty if waves are in current data folder.
|
||||
/// @param values counts/intensity values at the positions given in the polara nd azi waves.
|
||||
/// one- or two-dimensional.
|
||||
/// NaN values are ignored.
|
||||
/// @param polar polar angles (in degrees) of each data point.
|
||||
/// allowed range 0 <= theta <= 90.
|
||||
/// no specific ordering required.
|
||||
/// @param azi azimuthal angles (in degrees) of each data point.
|
||||
/// allowed range -360 <= phi < +360.
|
||||
/// no specific order required.
|
||||
/// @param weights weight or accumulation time of each point of values.
|
||||
/// weights must be positive. values with weight 0 are ignored.
|
||||
/// defaults to 1 if not specified.
|
||||
///
|
||||
/// the values, weights, polar and azi waves must have the same dimensions (one- or two-dimensional).
|
||||
/// no specific order is required, the function sorts (copies of) the arrays internally.
|
||||
///
|
||||
/// the actual binning is delegated to the thread-safe add_anglescan_worker() function
|
||||
/// under Igor's automatic multi-threading facility.
|
||||
///
|
||||
function hemi_add_anglescan(nickname, values, polar, azi, [weights])
|
||||
string nickname // name prefix of holo waves.
|
||||
// may be empty.
|
||||
wave values // intensity values
|
||||
// the wave can be one- or two-dimensional.
|
||||
// no specific order required, the function sorts the arrays internally
|
||||
wave polar // polar coordinates. allowed range 0 <= theta <= 90
|
||||
// dimensions corresponding to value.
|
||||
wave azi // azimuthal coordinates. allowed range -360 <= phi < +360
|
||||
// dimensions corresponding to value.
|
||||
wave weights // total accumulation time of each point of values. default = 1
|
||||
string nickname
|
||||
wave values
|
||||
wave polar
|
||||
wave azi
|
||||
wave weights
|
||||
|
||||
dfref savedf = GetDataFolderDFR()
|
||||
|
||||
if (ParamIsDefault(weights))
|
||||
duplicate /free values, weights
|
||||
weights = 1
|
||||
endif
|
||||
|
||||
// quick check whether hemi grid is existing
|
||||
|
||||
string s_prefix = ""
|
||||
string s_int = "values"
|
||||
dfref df = find_hemi_data(nickname, s_prefix, s_int)
|
||||
|
||||
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"
|
||||
|
||||
wave /sdfr=df /z w_values = $s_int
|
||||
wave /sdfr=df /z w_azim = $s_azim
|
||||
wave /sdfr=df /z w_polar = $s_polar
|
||||
wave /sdfr=df /z w_theta = $s_theta
|
||||
if (!waveexists(w_values) || !waveexists(w_azim) || !waveexists(w_polar))
|
||||
abort "Missing hemispherical scan grid. Please call make_hemi_grid() first."
|
||||
endif
|
||||
string s_dphi = s_prefix + "dphi"
|
||||
string s_nphis = s_prefix + "nphis"
|
||||
|
||||
// make internal copies, one-dimensional, ordered in theta
|
||||
wave /sdfr=df w_polar = $s_polar
|
||||
wave /sdfr=df w_azim = $s_azim
|
||||
wave /sdfr=df w_values = $s_int
|
||||
wave /sdfr=df w_totals = $s_totals
|
||||
wave /sdfr=df w_weights = $s_weights
|
||||
wave /sdfr=df w_index = $s_index
|
||||
wave /sdfr=df w_theta = $s_theta
|
||||
wave /sdfr=df w_dphi = $s_dphi
|
||||
wave /sdfr=df w_nphis = $s_nphis
|
||||
|
||||
// make internal copies of input, one-dimensional, ordered in theta
|
||||
duplicate /free values, values_copy
|
||||
duplicate /free polar, polar_copy
|
||||
duplicate /free azi, azi_copy
|
||||
@ -2577,49 +2679,186 @@ function hemi_add_anglescan(nickname, values, polar, azi, [weights])
|
||||
variable nn = dimsize(values, 0) * max(dimsize(values, 1), 1)
|
||||
redimension /n=(nn) values_copy, polar_copy, azi_copy, weights_copy
|
||||
sort /r polar_copy, polar_copy, azi_copy, values_copy, weights_copy
|
||||
|
||||
make /n=(numpnts(w_theta)) /free /df dfw
|
||||
// for debugging: remove the MultiThread keyword and the ThreadSafe keywords of sub-functions
|
||||
MultiThread dfw = add_anglescan_worker(p, values_copy, weights_copy, polar_copy, azi_copy, w_polar, w_azim, w_theta, w_index, w_dphi, w_nphis)
|
||||
|
||||
variable pp
|
||||
for (pp = 0; pp < numpnts(dfw); pp += 1)
|
||||
dfref tdf= dfw[pp]
|
||||
wave df_totals = tdf:w_totals
|
||||
wave df_weights = tdf:w_weights
|
||||
w_totals += df_totals
|
||||
w_weights += df_weights
|
||||
endfor
|
||||
w_values = w_weights > 0 ? w_totals / w_weights : nan
|
||||
|
||||
variable pol
|
||||
SetDataFolder savedf
|
||||
end
|
||||
|
||||
/// thread worker for hemi_add_anglescan
|
||||
///
|
||||
/// this function extracts one azimuthal scan from the input data and adds it to an existing holo scan.
|
||||
/// it should be considered as a part of hemi_add_anglescan and not used elsewhere,
|
||||
/// as its interface may change in the future.
|
||||
///
|
||||
/// the function takes as input the entire input data, an existing hemi grid and the index of a polar angle to work on.
|
||||
/// the results are a w_totals and w_weights wave that can be added to the hemi scan.
|
||||
/// the two waves are returned in a free data folder referenced by the return value of the function.
|
||||
/// the function does not change global data.
|
||||
///
|
||||
threadsafe static function /df add_anglescan_worker(ith, values, weights, polar, azi, w_polar, w_azim, w_theta, w_index, w_dphi, w_nphis)
|
||||
variable ith // index into w_theta
|
||||
wave values // input data: intensity/counts
|
||||
wave weights // input data: weights/dwell time
|
||||
wave polar // input data: polar angles
|
||||
wave azi // input data: azimuthal angles
|
||||
wave w_polar // hemi grid
|
||||
wave w_azim // hemi grid
|
||||
wave w_theta // hemi grid
|
||||
wave w_index // hemi grid
|
||||
wave w_dphi // hemi grid
|
||||
wave w_nphis // hemi grid
|
||||
|
||||
dfref savedf= GetDataFolderDFR()
|
||||
dfref freedf= NewFreeDataFolder()
|
||||
SetDataFolder freedf
|
||||
make /n=(numpnts(w_polar)) /d w_totals, w_weights
|
||||
|
||||
variable pol = w_theta[ith]
|
||||
variable pol_st = abs(w_theta[1] - w_theta[0])
|
||||
variable pol1, pol2
|
||||
variable pol1 = pol - pol_st / 2
|
||||
variable pol2 = pol + pol_st / 2
|
||||
|
||||
extract /free /indx polar, sel, (pol1 < polar) && (polar <= pol2) && (numtype(values) == 0) && (weights > 0)
|
||||
if (numpnts(sel) > 0)
|
||||
duplicate /free /r=[0, numpnts(sel)-1] azi, azi_slice
|
||||
duplicate /free /r=[0, numpnts(sel)-1] values, values_slice
|
||||
duplicate /free /r=[0, numpnts(sel)-1] weights, weights_slice
|
||||
azi_slice = azi[sel]
|
||||
values_slice = values[sel]
|
||||
weights_slice = weights[sel]
|
||||
add_aziscan_core(values_slice, weights_slice, pol, azi_slice, w_theta, w_azim, w_index, w_dphi, w_totals, w_weights)
|
||||
endif
|
||||
|
||||
SetDataFolder savedf
|
||||
return freedf
|
||||
end
|
||||
|
||||
/// thread worker for hemi_add_anglescan and hemi_add_aziscan
|
||||
///
|
||||
/// this function adds one azimuthal scan to an existing holo scan.
|
||||
/// it should be considered as a part of hemi_add_anglescan and hemi_add_aziscan and not used elsewhere,
|
||||
/// as its interface may change in the future.
|
||||
///
|
||||
/// the function takes as input an azimuthal scan and an existing hemi grid.
|
||||
/// the results are added to w_totals and w_weights waves.
|
||||
///
|
||||
/// @attention the function sorts the input arrays by azimuthal angle!
|
||||
/// these waves must not refer to global objects if multi-threading is used!
|
||||
///
|
||||
threadsafe static function add_aziscan_core(values, weights, polar, azi, w_theta, w_azim, w_index, w_dphi, w_totals, w_weights)
|
||||
wave values // input data: intensity/counts
|
||||
wave weights // input data: weights/dwell time
|
||||
variable polar // input data: polar angle
|
||||
wave azi // input data: angle positions of the azimuthal scan
|
||||
// acceptable range: >= -360 and < +360
|
||||
// no specific order required, the function sorts the array in place (!)
|
||||
wave w_theta // hemi grid
|
||||
wave w_azim // hemi grid
|
||||
wave w_index // hemi grid
|
||||
wave w_dphi // hemi grid
|
||||
wave w_totals // output data: total counts in hemi grid order
|
||||
wave w_weights // output data: total weights in hemi grid order
|
||||
|
||||
duplicate /free azi_copy, azi_slice
|
||||
duplicate /free values_copy, values_slice
|
||||
duplicate /free weights_copy, weights_slice
|
||||
for (pol = 90; pol >= 0; pol -= pol_st)
|
||||
pol1 = pol - pol_st / 2
|
||||
pol2 = pol + pol_st / 2
|
||||
extract /free /indx polar_copy, sel, (pol1 < polar_copy) && (polar_copy <= pol2)
|
||||
if (numpnts(sel) > 0)
|
||||
redimension /n=(numpnts(sel)) azi_slice, values_slice, weights_slice
|
||||
azi_slice = azi_copy[sel]
|
||||
values_slice = values_copy[sel]
|
||||
weights_slice = weights_copy[sel]
|
||||
hemi_add_aziscan(nickname, values_slice, pol, azi_slice, weights=weights_slice)
|
||||
// destination slice coordinates
|
||||
variable ipol = BinarySearch(w_theta, polar)
|
||||
if (ipol < 0)
|
||||
return -1
|
||||
endif
|
||||
|
||||
variable d1, d2
|
||||
if (ipol >= 1)
|
||||
d1 = w_index[ipol - 1]
|
||||
else
|
||||
d1 = 0
|
||||
endif
|
||||
d2 = w_index[ipol] - 1
|
||||
variable nd = d2 - d1 + 1
|
||||
variable dphi = w_dphi[ipol]
|
||||
make /n=(nd+1) /free bin_index
|
||||
setscale /i x w_azim[d1] - dphi/2, w_azim[d2] + dphi/2, "deg", bin_index
|
||||
|
||||
// source slice coordinates
|
||||
// order the slice from -dphi/2 to 360-dphi/2
|
||||
azi = azi < 0 ? azi + 360 : azi
|
||||
azi = azi >= 360 - dphi/2 ? azi - 360 : azi
|
||||
sort azi, values, weights, azi
|
||||
setscale /p x 0, 1, "", values, weights, azi
|
||||
|
||||
bin_index = BinarySearch(azi, x) + 1
|
||||
bin_index = bin_index == -2 ? 0 : bin_index[p]
|
||||
bin_index = bin_index == -1 ? numpnts(azi) : bin_index[p]
|
||||
bin_index[nd] = numpnts(azi)
|
||||
|
||||
// loop over destination
|
||||
variable id
|
||||
variable v1, v2, w1, w2
|
||||
for (id = 0; id < nd; id += 1)
|
||||
if (bin_index[id+1] > bin_index[id])
|
||||
v1 = w_totals[d1 + id]
|
||||
w1 = w_weights[d1 + id]
|
||||
if ((numtype(v1) == 2) || (w1 <= 0))
|
||||
v1 = 0
|
||||
w1 = 0
|
||||
endif
|
||||
v2 = sum(values, bin_index[id], bin_index[id+1] - 1)
|
||||
w2 = sum(weights, bin_index[id], bin_index[id+1] - 1)
|
||||
w_totals[d1 + id] = v1 + v2
|
||||
w_weights[d1 + id] = w1 + w2
|
||||
endif
|
||||
endfor
|
||||
end
|
||||
|
||||
/// add an azimuthal scan to a hemispherical scan grid.
|
||||
/// add azimuthal data to a hemispherical scan grid.
|
||||
///
|
||||
/// the hemi grid must have been created in the current data folder by the make_hemi_grid function.
|
||||
/// the hemi grid must have been created in the current data folder by the make_hemi_grid() function.
|
||||
/// the function determines the bin size at the given polar angle,
|
||||
/// and calculates the mean values of the data points which fall into a bin.
|
||||
/// a point which lies exactly on the upper boundary falls into the next bin.
|
||||
/// sums up the values and weights of the data points which fall into each bin,
|
||||
/// and adds the results to the totals and weights waves of the existing hemi grid.
|
||||
/// finally, it updates the values wave (values divided by weights).
|
||||
///
|
||||
/// @param nickname name prefix of holo waves.
|
||||
/// empty if waves are in current data folder.
|
||||
/// @param values counts/intensity values of the azimuthal scan at the positions given in the azi parameter.
|
||||
/// @param polar polar angle (in degrees) where to add the azi scan.
|
||||
/// @param azi angle positions of the azimuthal scan.
|
||||
/// acceptable range: >= -360 and < +360.
|
||||
/// no specific order required, the function sorts the array internally.
|
||||
/// @param weights weight or accumulation time of each point of values.
|
||||
/// defaults to 1 if not specified.
|
||||
///
|
||||
/// the actual binning is delegated to the thread-safe add_aziscan_core() function shared with hemi_add_anglescan().
|
||||
///
|
||||
function hemi_add_aziscan(nickname, values, polar, azi, [weights])
|
||||
string nickname // name prefix of holo waves.
|
||||
// may be empty.
|
||||
wave values // intensity values of the azimuthal scan at the positions given in the azi parameter
|
||||
variable polar // polar angle where to add the azi scan
|
||||
wave azi // angle positions of the azimuthal scan
|
||||
// acceptable range: >= -360 and < +360
|
||||
// no specific order required, the function sorts the array internally
|
||||
wave weights // total accumulation time of each point of values. default = 1
|
||||
string nickname
|
||||
wave values
|
||||
variable polar
|
||||
wave azi
|
||||
wave weights
|
||||
|
||||
dfref savedf = GetDataFolderDFR()
|
||||
|
||||
duplicate /free values, values_copy
|
||||
duplicate /free azi, azi_copy
|
||||
if (ParamIsDefault(weights))
|
||||
duplicate /free values, weights
|
||||
weights = 1
|
||||
duplicate /free values, weights_copy
|
||||
weights_copy = 1
|
||||
else
|
||||
duplicate /free weights, weights_copy
|
||||
endif
|
||||
|
||||
|
||||
// hemi grid waves
|
||||
string s_prefix = ""
|
||||
string s_int = "values"
|
||||
@ -2644,56 +2883,11 @@ function hemi_add_aziscan(nickname, values, polar, azi, [weights])
|
||||
wave /sdfr=df w_dphi = $s_dphi
|
||||
wave /sdfr=df w_nphis = $s_nphis
|
||||
|
||||
// destination slice coordinates
|
||||
//polar = round(polar)
|
||||
//variable ipol = 90 - polar
|
||||
variable ipol = BinarySearch(w_theta, polar)
|
||||
if (ipol < 0)
|
||||
abort "assertion failed in hemi_add_aziscan(): polar angle not found in grid."
|
||||
endif
|
||||
|
||||
variable d1, d2
|
||||
if (ipol >= 1)
|
||||
d1 = w_index[ipol - 1]
|
||||
else
|
||||
d1 = 0
|
||||
endif
|
||||
d2 = w_index[ipol] - 1
|
||||
variable nd = d2 - d1 + 1
|
||||
variable dphi = w_dphi[ipol]
|
||||
variable az1, az2
|
||||
|
||||
// source slice coordinates
|
||||
// order the slice from -dphi/2 to 360-dphi/2
|
||||
azi = azi < 0 ? azi + 360 : azi
|
||||
azi = azi >= 360 - dphi/2 ? azi - 360 : azi
|
||||
duplicate /free values, sel_values
|
||||
duplicate /free weights, sel_weights
|
||||
|
||||
// loop over destination
|
||||
variable id
|
||||
variable v1, v2, w1, w2
|
||||
for (id = 0; id < nd; id += 1)
|
||||
az1 = (id - 0.5) * dphi
|
||||
az2 = (id + 0.5) * dphi
|
||||
extract /free /indx azi, sel, (az1 <= azi) && (azi < az2)
|
||||
if (numpnts(sel) > 0)
|
||||
redimension /n=(numpnts(sel)) sel_values, sel_weights
|
||||
sel_values = values[sel]
|
||||
sel_weights = weights[sel]
|
||||
v1 = w_totals[d1 + id]
|
||||
w1 = w_weights[d1 + id]
|
||||
if ((numtype(v1) == 2) || (w1 <= 0))
|
||||
v1 = 0
|
||||
w1 = 0
|
||||
endif
|
||||
v2 = sum(sel_values)
|
||||
w2 = sum(sel_weights)
|
||||
w_totals[d1 + id] = v1 + v2
|
||||
w_weights[d1 + id] = w1 + w2
|
||||
endif
|
||||
endfor
|
||||
w_values[d1, d1 + nd - 1] = w_totals[p] / w_weights[p]
|
||||
add_aziscan_core(values_copy, weights_copy, polar, azi_copy, w_theta, w_azim, w_index, w_dphi, w_totals, w_weights)
|
||||
|
||||
w_values = w_weights > 0 ? w_totals / w_weights : nan
|
||||
|
||||
SetDataFolder savedf
|
||||
end
|
||||
|
||||
/// interpolate a hemispherical scan onto a rectangular grid
|
||||
@ -3011,8 +3205,9 @@ function import_tpi_scan(nickname, theta, phi, intensity, [folding, npolar, nogr
|
||||
variable ifold
|
||||
duplicate /free phi, fold_phi
|
||||
for (ifold = 0; ifold < folding; ifold += 1)
|
||||
fold_phi = fold_phi >= 360 ? fold_phi - 360 : fold_phi
|
||||
hemi_add_anglescan(nickname, intensity, theta, fold_phi)
|
||||
fold_phi = fold_phi >= 180 ? fold_phi + 360 / folding - fold_phi : fold_phi + 360 / folding
|
||||
fold_phi += 360 / folding
|
||||
endfor
|
||||
|
||||
if (nograph==0)
|
||||
@ -3199,7 +3394,7 @@ function /wave hemi_azi_cut(nickname, pol)
|
||||
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]], "<EFBFBD>", w_cut
|
||||
setscale /i x w_azim[sel[0]], w_azim[sel[nsel-1]], "°", w_cut
|
||||
setdatafolder savedf
|
||||
return w_cut
|
||||
else
|
||||
@ -3209,23 +3404,37 @@ function /wave hemi_azi_cut(nickname, pol)
|
||||
setdatafolder savedf
|
||||
end
|
||||
|
||||
static function check_contrast(values, pcmin, pcmax, vmin, vmax)
|
||||
static function check_contrast(values, pcmin, pcmax, vmin, vmax, sym)
|
||||
wave values
|
||||
variable pcmin
|
||||
variable pcmax
|
||||
variable &vmin
|
||||
variable &vmax
|
||||
variable sym
|
||||
|
||||
dfref save_df = GetDataFolderDFR()
|
||||
dfref dfr = NewFreeDataFolder()
|
||||
setdatafolder dfr
|
||||
StatsQuantiles /inan /iw /q /z values
|
||||
wave index = w_quantilesindex
|
||||
variable imin = round(numpnts(index) * pcmin / 100)
|
||||
variable imax = round(numpnts(index) * (100 - pcmax) / 100)
|
||||
vmin = values[index[imin]]
|
||||
vmax = values[index[imax]]
|
||||
wave /z index = w_quantilesindex
|
||||
setdatafolder save_df
|
||||
|
||||
if (waveexists(index))
|
||||
variable imin = round(numpnts(index) * pcmin / 100)
|
||||
variable imax = round(numpnts(index) * (100 - pcmax) / 100)
|
||||
vmin = values[index[imin]]
|
||||
vmax = values[index[imax]]
|
||||
if (sym)
|
||||
variable d = vmax - vmin
|
||||
if ((vmax >= d/4) && (-vmin >= d/4))
|
||||
vmax = min(abs(vmin), abs(vmax))
|
||||
vmin = -vmax
|
||||
endif
|
||||
endif
|
||||
else
|
||||
vmin = wavemin(values)
|
||||
vmax = wavemax(values)
|
||||
endif
|
||||
end
|
||||
|
||||
/// set the pseudocolor contrast by percentile.
|
||||
@ -3243,12 +3452,21 @@ end
|
||||
/// @param pcmax percentile above the maximum color (0-100).
|
||||
/// @param graphname name of graph. default: top graph.
|
||||
/// @param colortable name of new colortable. default: keep current table.
|
||||
/// @param reversecolors reverse colors of new colorable.
|
||||
/// takes effect only if colortable argument is defined.
|
||||
/// @arg 0 (default) normal colors,
|
||||
/// @arg 1 reverse color table
|
||||
/// @param symmetric make scale symmetric about zero (for modulation functions, e.g.).
|
||||
/// @arg 0 (default) do not enforce symmetry.
|
||||
/// @arg 1 try symmetric scale if "reasonable".
|
||||
///
|
||||
function set_contrast(pcmin, pcmax, [graphname, colortable])
|
||||
function set_contrast(pcmin, pcmax, [graphname, colortable, reversecolors, symmetric])
|
||||
variable pcmin
|
||||
variable pcmax
|
||||
string graphname
|
||||
string colortable
|
||||
variable reversecolors
|
||||
variable symmetric
|
||||
|
||||
if (ParamIsDefault(graphname))
|
||||
graphname = ""
|
||||
@ -3256,6 +3474,12 @@ function set_contrast(pcmin, pcmax, [graphname, colortable])
|
||||
if (ParamIsDefault(colortable))
|
||||
colortable = ""
|
||||
endif
|
||||
if (ParamIsDefault(reversecolors))
|
||||
reversecolors = 0
|
||||
endif
|
||||
if (ParamIsDefault(symmetric))
|
||||
symmetric = 0
|
||||
endif
|
||||
|
||||
dfref save_df = GetDataFolderDFR()
|
||||
|
||||
@ -3285,9 +3509,12 @@ function set_contrast(pcmin, pcmax, [graphname, colortable])
|
||||
rev = str2num("0" + StringFromList(4, info, ","))
|
||||
if (strlen(colortable) > 0)
|
||||
ctab = colortable
|
||||
rev = reversecolors
|
||||
endif
|
||||
check_contrast(w, pcmin, pcmax, vmin, vmax, symmetric)
|
||||
if (vmax > vmin)
|
||||
ModifyGraph /w=$graphname zColor($objname)={w, vmin, vmax, $ctab, rev}
|
||||
endif
|
||||
check_contrast(w, pcmin, pcmax, vmin, vmax)
|
||||
ModifyGraph /w=$graphname zColor($objname)={w, vmin, vmax, $ctab, rev}
|
||||
endif
|
||||
endif
|
||||
endfor
|
||||
@ -3307,9 +3534,12 @@ function set_contrast(pcmin, pcmax, [graphname, colortable])
|
||||
rev = str2num("0" + StringFromList(3, info, ","))
|
||||
if (strlen(colortable) > 0)
|
||||
ctab = colortable
|
||||
rev = reversecolors
|
||||
endif
|
||||
check_contrast(w, pcmin, pcmax, vmin, vmax, symmetric)
|
||||
if (vmax > vmin)
|
||||
ModifyImage /w=$graphname $objname ctab={vmin, vmax, $ctab, rev}
|
||||
endif
|
||||
check_contrast(w, pcmin, pcmax, vmin, vmax)
|
||||
ModifyImage /w=$graphname $objname ctab={vmin, vmax, $ctab, rev}
|
||||
endif
|
||||
endif
|
||||
endfor
|
||||
|
Reference in New Issue
Block a user