new user distribution of PEARL procedures

This commit is contained in:
2016-02-10 16:00:34 +01:00
commit 1e9fbf0beb
37 changed files with 18585 additions and 0 deletions

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
*~
~*
*.bak
*.ipfT*
doc/html/*
doc/latex/*

2381
doc/Doxyfile Normal file

File diff suppressed because it is too large Load Diff

194
doc/DoxygenLayout.xml Normal file
View File

@ -0,0 +1,194 @@
<doxygenlayout version="1.0">
<!-- Generated by doxygen 1.8.9.1 -->
<!-- Navigation index tabs for HTML output -->
<navindex>
<tab type="mainpage" visible="yes" title=""/>
<tab type="pages" visible="yes" title="" intro=""/>
<tab type="modules" visible="yes" title="Packages" intro="Packages are collections of procedure files to be loaded together. PEARL defines the following packages:"/>
<tab type="namespaces" visible="yes" title="">
<tab type="namespacelist" visible="yes" title="" intro=""/>
<tab type="namespacemembers" visible="yes" title="" intro=""/>
</tab>
<tab type="classes" visible="no" title="">
<tab type="classlist" visible="yes" title="" intro=""/>
<tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/>
<tab type="hierarchy" visible="yes" title="" intro=""/>
<tab type="classmembers" visible="yes" title="" intro=""/>
</tab>
<tab type="files" visible="yes" title="">
<tab type="filelist" visible="yes" title="" intro=""/>
<tab type="globals" visible="yes" title="" intro=""/>
</tab>
<tab type="examples" visible="yes" title="" intro=""/>
</navindex>
<!-- Layout definition for a class page -->
<class>
<briefdescription visible="yes"/>
<includes visible="$SHOW_INCLUDE_FILES"/>
<inheritancegraph visible="$CLASS_GRAPH"/>
<collaborationgraph visible="$COLLABORATION_GRAPH"/>
<memberdecl>
<nestedclasses visible="yes" title=""/>
<publictypes title=""/>
<services title=""/>
<interfaces title=""/>
<publicslots title=""/>
<signals title=""/>
<publicmethods title=""/>
<publicstaticmethods title=""/>
<publicattributes title=""/>
<publicstaticattributes title=""/>
<protectedtypes title=""/>
<protectedslots title=""/>
<protectedmethods title=""/>
<protectedstaticmethods title=""/>
<protectedattributes title=""/>
<protectedstaticattributes title=""/>
<packagetypes title=""/>
<packagemethods title=""/>
<packagestaticmethods title=""/>
<packageattributes title=""/>
<packagestaticattributes title=""/>
<properties title=""/>
<events title=""/>
<privatetypes title=""/>
<privateslots title=""/>
<privatemethods title=""/>
<privatestaticmethods title=""/>
<privateattributes title=""/>
<privatestaticattributes title=""/>
<friends title=""/>
<related title="" subtitle=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<inlineclasses title=""/>
<typedefs title=""/>
<enums title=""/>
<services title=""/>
<interfaces title=""/>
<constructors title=""/>
<functions title=""/>
<related title=""/>
<variables title=""/>
<properties title=""/>
<events title=""/>
</memberdef>
<allmemberslink visible="yes"/>
<usedfiles visible="$SHOW_USED_FILES"/>
<authorsection visible="yes"/>
</class>
<!-- Layout definition for a namespace page -->
<namespace>
<briefdescription visible="yes"/>
<memberdecl>
<nestednamespaces visible="yes" title=""/>
<constantgroups visible="yes" title=""/>
<classes visible="yes" title=""/>
<typedefs title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<inlineclasses title=""/>
<typedefs title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
</memberdef>
<authorsection visible="yes"/>
</namespace>
<!-- Layout definition for a file page -->
<file>
<briefdescription visible="yes"/>
<includes visible="$SHOW_INCLUDE_FILES"/>
<includegraph visible="$INCLUDE_GRAPH"/>
<includedbygraph visible="$INCLUDED_BY_GRAPH"/>
<sourcelink visible="yes"/>
<memberdecl>
<classes visible="yes" title=""/>
<namespaces visible="yes" title=""/>
<constantgroups visible="yes" title=""/>
<defines title=""/>
<typedefs title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<inlineclasses title=""/>
<defines title=""/>
<typedefs title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
</memberdef>
<authorsection/>
</file>
<!-- Layout definition for a group page -->
<group>
<briefdescription visible="yes"/>
<groupgraph visible="$GROUP_GRAPHS"/>
<memberdecl>
<nestedgroups visible="yes" title=""/>
<dirs visible="yes" title=""/>
<files visible="yes" title=""/>
<namespaces visible="yes" title=""/>
<classes visible="yes" title=""/>
<defines title=""/>
<typedefs title=""/>
<enums title=""/>
<enumvalues title=""/>
<functions title=""/>
<variables title=""/>
<signals title=""/>
<publicslots title=""/>
<protectedslots title=""/>
<privateslots title=""/>
<events title=""/>
<properties title=""/>
<friends title=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<pagedocs/>
<inlineclasses title=""/>
<defines title=""/>
<typedefs title=""/>
<enums title=""/>
<enumvalues title=""/>
<functions title=""/>
<variables title=""/>
<signals title=""/>
<publicslots title=""/>
<protectedslots title=""/>
<privateslots title=""/>
<events title=""/>
<properties title=""/>
<friends title=""/>
</memberdef>
<authorsection visible="yes"/>
</group>
<!-- Layout definition for a directory page -->
<directory>
<briefdescription visible="yes"/>
<directorygraph visible="yes"/>
<memberdecl>
<dirs visible="yes"/>
<files visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
</directory>
</doxygenlayout>

242
doc/doxygen-filter-ipf.awk Normal file
View File

@ -0,0 +1,242 @@
# Proof of concept implementation for using doxygen to document Igor Pro procedures
# This awk script serves as input filter for Igor procedures and produces a C-ish version of the declarations
# Tested with Igor Pro 6.34A and doxygen 1.8.7
#
# Thomas Braun: 9/2014
# Version: 0.23
# Supported Features:
# -Functions
# -Macros
# -File constants
# -Menu items are currently ignored
# TODO
# - don't delete the function/macro subType
BEGIN{
# allows to bail out for code found outside of functions/macros
DO_WARN=0
IGNORECASE=1
output=""
warning=""
menuEndCount=0
}
# Remove whitespace at beginning and end of string
# Return the whitespace in front of the string in the
# global variable frontSpace to be able
# to reconstruct the indentation
function trim(str)
{
if(match(str, /^[[:space:]]+/))
{
frontSpace = substr(str, 1, RLENGTH)
str = substr(str, RLENGTH + 1)
}
else
frontSpace = ""
gsub(/[[:space:]]+$/,"",str)
return str
}
# Split an already trimmed line into words
# Returns the number of words
function splitIntoWords(str, a, numEntries)
{
return split(str,a,/[[:space:],&*]+/)
}
# Split params into words and prefix each with "__Param__$i"
# where $i is increased for every parameter
# Returns the concatenation of all prefixed parameters
function handleParameter(params, a, i, iOpt, str, entry)
{
numParams = splitIntoWords(params, a)
str=""
entry=""
iOpt=numParams
for(i=1; i <= numParams; i++)
{
# convert igor optional parameters to something doxygen understands
# igor dictates that the optional arguments are the last arguments,
# meaning no normal argument can follow the optional arguments
if(gsub(/[\[\]]/,"",a[i]) || i > iOpt)
{
iOpt = i
entry = a[i] " = defaultValue"
}
else
entry = a[i]
str = str "__Param__" i " " entry
if(i < numParams)
str = str ", "
}
return str
}
{
# split current line into code and comment
if(match($0,/\/\/.*/))
{
code=substr($0,0,RSTART-1)
comment=substr($0,RSTART,RLENGTH)
}
else
{
code=$0
comment=""
}
# remove whitespace from front and back
code=trim(code)
# begin of macro definition
if(!insideFunction && !insideMacro && ( match(code,/^Window/)|| match(code,/^Proc/) || match(code,/^Macro/) ) )
{
insideMacro=1
gsub(/^Window/,"void",code)
gsub(/^Macro/,"void",code)
gsub(/^Proc/,"void",code)
# add opening bracket, this also throws away any function subType
gsub(/\).*/,"){",code)
}
# end of macro definition
else if(!insideFunction && insideMacro && ( match(code,/^EndMacro$/) || match(code,/^End$/) ) )
{
insideMacro=0
code = "}"
}
# begin of function declaration
else if(!insideFunction && ( match(code,/[[:space:]]function[\/[[:space:]]/) || match(code,/^function[\/[[:space:]]/) ) )
{
insideFunction=1
# remove whitespace between function and return type flag
gsub(/function[[:space:]]*\//,"function/",code)
# different return types
gsub(/function /,"variable ",code)
gsub(/function\/df/,"dfr",code)
gsub(/function\/wave/,"wave",code)
gsub(/function\/c/,"complex",code)
gsub(/function\/s/,"string",code)
gsub(/function\/t/,"string",code) # deprecated definition of string return type
gsub(/function\/d/,"variable",code)
# add opening bracket, this also throws away any function subType
gsub(/\).*/,"){",code)
# do we have function parameters
if(match(code,/\(.*[a-z]+.*\)/))
{
paramStr = substr(code,RSTART+1,RLENGTH-2)
paramStrWithTypes = handleParameter(paramStr, params)
paramsToHandle = numParams
# print "paramStr __ " paramStr
# print "paramStrWithTypes __ " paramStrWithTypes
# print "paramsToHandle __ " paramsToHandle
code = substr(code,0,RSTART) "" paramStrWithTypes "" substr(code,RSTART+RLENGTH-1)
}
}
else if(insideFunction && paramsToHandle > 0)
{
numEntries = splitIntoWords(code,entries)
# printf("Found %d words in line \"%s\"\n",numEntries,code)
for(i=2; i <= numEntries; i++)
for(j=1; j <= numParams; j++)
{
variableName = entries[i]
if( entries[i] == params[j] )
{
paramsToHandle--
# now replace __Param__$i with the real parameter type
if(entries[1] == "struct")
paramType = entries[2]
else
paramType = tolower(entries[1])
# add asterisk for call-by-reference parameters
if(match(code,/\&/))
paramType = paramType "*"
output = gensub("__Param__" j " ",paramType " ","g",output)
# printf("Found parameter type %s at index %d\n",paramType,j)
}
}
}
# end of function declaration
else if(insideFunction && match(code,/^end$/))
{
insideFunction=0
code = "}"
}
# structure declaration
if(!insideFunction && !insideMacro && ( match(code,/[[:space:]]structure[[:space:]]/) || match(code,/^structure[[:space:]]/) ) )
{
insideStructure=1
gsub(/structure/,"struct",code)
code = code "{"
}
if(insideStructure && match(code,/EndStructure/))
{
insideStructure=0
code = "}"
}
# menu definition
# submenues can be nested in menus. Therefore we have to keep track
# of the number of expected "End" keywords
if(!insideFunction && !insideMacro && ( match(code,/\yMenu\y/) || match(code,/\ySubMenu\y/) ))
{
menuEndCount++
insideMenu=1
}
if(insideMenu && match(code,/\yEnd[[:space:]]*/))
{
menuEndCount--
if(menuEndCount == 0)
{
insideMenu=0
code = ""
}
}
# global constants
gsub(/\ystrconstant\y/,"const string",code)
gsub(/\yconstant\y/,"const variable",code)
# prevent that doxygen sees elseif as a function call
gsub(/\yelseif\y/,"else if",code)
# code outside of function/macro definitions is "translated" into statements
if(!insideFunction && !insideMacro && !insideMenu && code != "" && substr(code,0,1) != "#")
{
if(code != "}" && !insideStructure && DO_WARN)
warning = warning "\n" "warning " NR ": outside code \"" code "\""
code = code ";"
}
if(!insideMenu)
{
output = output frontSpace code comment
}
output = output "\n"
}
END{
print output
if(DO_WARN)
print warning
}

27
doc/makefile Normal file
View File

@ -0,0 +1,27 @@
SHELL=/bin/sh
# makefile for PEARL procedures documentation
#
.SUFFIXES:
.SUFFIXES: .c .cpp .cxx .exe .f .h .i .o .py .pyf .so .html
.PHONY: all docs clean
DOX=doxygen
DOXOPTS=
LATEX_DIR=latex
all: docs
docs: doxygen pdf
doxygen:
$(DOX) $(DOXOPTS) Doxyfile
pdf: doxygen
-$(MAKE) -C $(LATEX_DIR)
clean:
-rm latex/*
-rm html/*

17
doc/readme.txt Normal file
View File

@ -0,0 +1,17 @@
this folder and subfolders contain the documentation of the PEARL procedures in HTML and PDF format.
the documentation is currently migrated to the doxygen format.
descriptions may be incomplete until the migration is finished.
to compile the documentation the following pieces of software are required:
doxygen:
http://www.doxygen.org/
gawk:
http://gnuwin32.sourceforge.net/packages/gawk.htm (windows)
doxygen-filter-ipf.awk:
http://www.igorexchange.com/project/doxIPFFilter
please see the original web sites for terms of use.

202
pearl/LICENSE.txt Normal file
View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

6
pearl/NOTICE.txt Normal file
View File

@ -0,0 +1,6 @@
PEARL Igor Procedures
Copyright 2009-2014 Paul Scherrer Institut
This product includes software developed at the
Paul Scherrer Institut, Villigen, Switzerland (http://www.psi.ch/).

View File

@ -0,0 +1,320 @@
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
#include "pearl-area-profiles"
// $Id$
/// @file
/// @brief tools for analysing the Fermi edge measured by the Scienta EW4000 analyser.
/// @ingroup ArpesPackage
///
/// proposed procedure
///
/// * angular normalization
/// * fit curved fermi function
/// * calculate corrected energy coordinates and map to single independent variable
/// * fit normal fermi function
///
/// @author matthias muntwiler, matthias.muntwiler@psi.ch
/// @author thomas dienel
///
/// @copyright 2013-15 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
function analyse_curved_edge(data)
wave data // 2D counts data, x-scale = kinetic energy, y-scale = analyser angle
variable guess_EF // initial guess of the Fermi level
dfref savedf = GetDataFolderDFR()
dfref datadf = GetWavesDataFolderDFR(data)
setdatafolder datadf
make /n=5 /d /o w_coef_int
make /n=7 /d /o w_coef_curved
// 1) integrate data
wave xint = ad_profile_x(data, -inf, inf, "", noavg=1)
duplicate /free xint, xint_sig
xint_sig = sqrt(xint * 4) / 4
variable xmin = wavemin(xint)
variable xmax = wavemax(xint)
variable xmean = mean(xint)
// 2) fit integrated data for reference
w_coef_int[0] = xmin
w_coef_int[1] = 0
w_coef_int[2] = xmax - xmin
w_coef_int[3] = dimoffset(xint, 0) + dimdelta(xint, 0) * dimsize(xint, 0) / 2
w_coef_int[4] = 100
FuncFit /NTHR=0 FermiFuncLinDOS w_coef_int xint /D /I=1 /W=xint_sig
wave w_sigma
duplicate /o w_sigma, w_sigma_int
// 3) normalize data
wave yavg = ad_profile_y(data, -inf, inf, "")
variable ymean = mean(yavg)
duplicate /o data, data_norm, data_sig
data_sig = sqrt(data * 4) / 4
data_norm = data_norm * ymean / yavg[q]
data_sig = data_sig * ymean / yavg[q]
// 4) fit normalized data
wave xavg = ad_profile_x(data, -inf, inf, "")
xmin = wavemin(xavg)
xmax = wavemax(xavg)
xmean = mean(xavg)
w_coef_curved[0] = {0, 0, 1, 95.5, 100, 0, -0.0001}
w_coef_curved[0] = xmin
w_coef_curved[2] = xmax - xmin
w_coef_curved[3] = w_coef_int[3]
w_coef_curved[4] = w_coef_int[4]
//variable box = min(11, numpnts(xavg) / 5)
//FindLevel /B=(box) /EDGE=2 /Q xavg, (xmin + xmax) / 2
//if (v_flag == 0)
// w_coef_curved[3] = v_levelx
//else
// w_coef_curved[3] = dimoffset(data, 0) + dimdelta(data, 0) * dimsize(data, 0) / 2
//endif
duplicate /o data_norm, fit_data_norm
FuncFitMD /X=1 /NTHR=0 FermiFuncLinDOS_2Dcorr w_coef_curved data_norm /D=fit_data_norm /I=1 /W=data_sig
wave w_sigma
duplicate /o w_sigma, w_sigma_curved
display /k=1; appendimage data_norm
ModifyImage data_norm ctab= {xmin,xmax,Grays,0}
AppendMatrixContour fit_data_norm
setdatafolder savedf
return 0
end
function record_results(index)
variable index
dfref savedf = GetDataFolderDFR()
wave /sdfr=root: Tint, Tint_sig, Tcurv, Tcurv_sig, EFcurv, EFcurv_sig
wave w_coef_int, w_coef_curved
wave w_sigma_int, w_sigma_curved
Tint[index] = w_coef_int[4]
Tint_sig[index] = w_sigma_int[4]
Tcurv[index] = w_coef_curved[4]
Tcurv_sig[index] = w_sigma_curved[4]
EFcurv[index] = w_coef_curved[3]
EFcurv_sig[index] = w_sigma_curved[3]
setdatafolder savedf
end
function integrate_curved_edge(data, data_sig)
wave data
wave /z data_sig
//wave coef
string name = nameofwave(data)
duplicate /o data, data_out
redimension /n=(dimsize(data,0)) data_out
data_out = 0
if (waveexists(data_sig))
duplicate /o data_sig, sig_out
redimension /n=(dimsize(data,0)) sig_out
sig_out = 0
endif
wave ywgt = ad_profile_y(data, -inf, inf, "", noavg=1)
ywgt = 1 / ywgt / 4
//ywgt = 1 / 4
variable sum_ywgt = sum(ywgt)
variable nx = dimsize(data, 0)
variable ny = dimsize(data, 1)
variable iy
variable yy
variable dx
variable dy
variable dp
variable dp_min = 0
wave PassEnergy = :attr:PassEnergy
wave NumSlices = :attr:NumSlices
for (iy = 0; iy < ny; iy += 1)
dy = dimoffset(data, 1) + dimdelta(data, 1) * iy
dy = dy / dimdelta(data, 1)
dx = slit_shift(dy * 902 / NumSlices[0], PassEnergy[0])
dp = round(dx / dimdelta(data, 0)) // <= 0
dp_min = min(dp_min, dp)
data_out[] = p+dp >= 0 ? data_out + data[p+dp][iy] * ywgt[iy] : data_out
if (waveexists(data_sig))
sig_out = p+dp >= 0 ? sig_out + data_sig[p+dp][iy] * ywgt[iy] : sig_out
endif
endfor
data_out /= sum_ywgt
data_out[0, -dp_min][] = nan
if (waveexists(sig_out))
sig_out /= sum_ywgt
//sig_out[0, -dp_min] = nan
endif
end
function slit_correction(data, data_out, epass)
wave data // must be image with original dimensions (no cropping!)
wave /z data_out // 2D or 1D wave to receive the result
// X dimension must be identical to the one of data
// if 2D, Y dimension must be either identical to the one of data
// if 1D, the result will be the sum of the corrected slices
variable epass // pass energy
if (!WaveExists(data_out))
string name = nameofwave(data) + "_corr"
duplicate /o data, $name
wave data_out = $name
//redimension /n=(dimsize(data,0)) data_out
endif
data_out = 0
variable nx = dimsize(data, 0)
variable ny = dimsize(data, 1)
variable iy
variable yy
variable dx
variable dy
variable dp
variable dp_min = 0
for (iy = 0; iy < ny; iy += 1)
dy = dimoffset(data, 1) + dimdelta(data, 1) * iy
dy = dy / dimdelta(data, 1)
dx = slit_shift(dy * 902 / ny, epass)
dp = round(dx / dimdelta(data, 0)) // <= 0
dp_min = min(dp_min, dp)
if (wavedims(data_out) >= 2)
data_out[][iy] = p+dp >= 0 ? data_out + data[p+dp][iy] : data_out
else
data_out = p+dp >= 0 ? data_out + data[p+dp][iy] : data_out
endif
endfor
data_out[0, -dp_min][] = nan
end
//------------------------------------------------------------------------------
threadsafe Function FermiFuncLinDOS2D_corr(w,x,y) : FitFunc
// linear density of states below Fermi level
// 2D data with corrections:
// - straight slit (slit shift)
// - transmission function (polynomial)
//------------------------------------------------------------------------------
Wave w; Variable x; variable y
// w[0] = background far above the fermi level
// w[1] = slope of the linear background
// w[2] = amplitude
// w[3] = fermi level in eV
// w[4] = temperature in K
// w[5] = transmission - linear term
// w[6] = transmission - quadratic term
// w[7] = transmission - cubic term
// w[8] = pass energy (hold this value)
// w[9] = y scale: pixels / unit of y
variable pos = w[3] + slit_shift(y * w[9], w[8])
variable transm = 1 + w[5] * y + w[6] * y^2 + w[7] * y^3
variable fermi = (w[1] * min(x - pos, 0) + w[2]) / ( exp( (x - pos) / (kBoltzmann * w[4]) ) + 1.0 )
return transm * (fermi + w[0])
end
//------------------------------------------------------------------------------
threadsafe Function FermiFuncLinDOS_2Dcorr_old(w,x,y) : FitFunc
// linear density of states below Fermi level
// 2D data with a polynomial shift of the Fermi level in the second dimension
//------------------------------------------------------------------------------
Wave w; Variable x; variable y
// w[0] = background far above the fermi level
// w[1] = slope of the linear background
// w[2] = amplitude
// w[3] = fermi level in eV
// w[4] = temperature in K
// w[5] = shift - linear term
// w[6] = shift - quadratic term
variable pos = w[3] + w[5] * y + w[6] * y^2
return w[0] + (w[1] * min(x - pos, 0) + w[2]) / ( exp( (x - pos) / (kBoltzmann * w[4]) ) + 1.0 )
end
/// MCP radius seen by the camera in pixels
static constant mcp_radius_pix = 555
/// physical size (radius) of the MCP in mm
static constant mcp_radius_mm = 20
/// physical size (radius) of the hemisphere in mm
static constant hemi_radius_mm = 200
/// energy range imaged on MCP relative to the pass energy
static constant mcp_radius_epass = 0.04
threadsafe function slit_shift(ypix, epass)
// calculates the energy shift due to straight slit
// the radius of the curve is 1/2 of the hemisphere radius
variable ypix // vertical (angle/position) pixels distance from center
// = slice coordinate * 902 / number of slices
variable epass // pass energy
variable rpix = mcp_radius_pix * hemi_radius_mm / mcp_radius_mm
//variable rpix = mcp_radius_pix * hemi_radius_mm / 2 / mcp_radius_mm
variable rene = epass * mcp_radius_epass * hemi_radius_mm / 2 / mcp_radius_mm
variable isin = asin(ypix / rpix)
variable dene = rene * (cos(isin) - 1)
return dene
end
function show_shift(data)
wave data
variable epass
variable ny = dimsize(data, 1)
make /o /n=(ny) shift_x
setscale /i x -ny/2, ny/2, "", shift_x
wave PassEnergy = :attr:PassEnergy
wave NumSlices = :attr:NumSlices
shift_x = slit_shift(x * 902 / NumSlices[0], PassEnergy[0])
variable ecenter = dimoffset(data, 0) + dimdelta(data, 0) * dimsize(data, 0) / 2
shift_x += ecenter
end
/// calculate the energy resolution of the analyser
///
/// @param epass pass energy in eV
/// @param slit analyser entrance slit in mm
///
/// @return energy resolution (FWHM)
function analyser_energy_resolution(epass, slit)
variable epass
variable slit
variable respow
if (epass < 4)
respow = 1110
elseif (epass < 8)
respow = 1400
else
respow = 1750
endif
return epass * max(0.2, slit) / 0.2 / respow
end

View File

@ -0,0 +1,80 @@
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
#pragma IgorVersion = 6.1
#pragma ModuleName = PearlAnglescanProcessTest
#pragma version = 1.0
#include "pearl-anglescan-process"
#include "unit-testing"
// test suite for pearl-anglescan-process.ipf
// unit testing framework: http://www.igorexchange.com/project/unitTesting
// run all test cases with RunTest("pearl-anglescan-process.ipf")
// if wave equalities fail, EnableDebugOutput() and read Igor help on equalWaves().
// created: matthias.muntwiler@psi.ch, 2013-11-18
// Copyright (c) 2013 Paul Scherrer Institut
// $Id$
static function test_convert_angles_ttpa()
// function parameters
variable ntests = 3
make /n=(ntests)/d/free i_theta, i_tilt, i_phi
make /n=3/d/free i_ana
make /n=1/d/free o_polar, o_azi
i_theta = {0, 90, 90}
i_tilt = {0, 0, 0}
i_phi = {0, 0, 10}
i_ana = {-30, 0, +30}
make /n=(3,ntests)/d/free e_polar, e_azi
e_polar[][0] = {30, 0, 30}
e_azi[][0] = {-90, 0, 90} // 180, 90, 0
e_polar[][1] = {90, 90, 90}
e_azi[][1] = {-30, 0, +30}
e_polar[][2] = {90, 90, 90}
e_azi[][2] = {-20, 10, +40}
variable phi0 = 0
e_azi += phi0
convert_angles_ttpa2polar(i_theta, i_tilt, i_phi, i_ana, o_polar, o_azi)
CHECK_EQUAL_WAVES(o_polar, e_polar, tol=0.001)
CHECK_EQUAL_WAVES(o_azi, e_azi, tol=0.001)
nvar /z errors = root:packages:unittesting:error_count
if ((nvar_exists(errors)) && (errors > 0))
print o_azi
print e_azi
endif
end
static function test_hist_hemi_aziscan()
CHECK_EMPTY_FOLDER()
make /n=360/d/free value, azi
azi = p
value = 1
variable polar = 45 // dphi = 2
make_hemi_grid(91, "")
wave w_index = index
wave w_nphis = nphis
wave w_dphi = dphi
wave w_values = values
wave w_azim = azim
wave w_polar = polar
duplicate /free w_values, e_values
variable p1 = w_index[44]
variable p2 = w_index[45]
e_values = (p >= p1) && (p < p2) ? 1 : 0
hemi_add_aziscan("", value, polar, azi)
CHECK_EQUAL_WAVES(w_values, e_values, tol=0.001)
end

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1508
pearl/pearl-anneal.ipf Normal file

File diff suppressed because it is too large Load Diff

1668
pearl/pearl-area-display.ipf Normal file

File diff suppressed because it is too large Load Diff

1613
pearl/pearl-area-import.ipf Normal file

File diff suppressed because it is too large Load Diff

368
pearl/pearl-area-live.ipf Normal file
View File

@ -0,0 +1,368 @@
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
#pragma IgorVersion = 6.1
#pragma ModuleName = PearlAreaLive
#pragma version = 1.03
#include "pearl-epics", version >= 1.02
// preview panel for EPICS area detectors
// such as CCD cameras, 2D electron analysers
// the image is read from the NDPluginStdArrays plugin of the area detector
// make sure that plugin is enabled
// created: matthias.muntwiler@psi.ch, 2013-05-29
// $Id$
static strconstant package_name = "pearl_epics"
static strconstant package_path = "root:pearl_epics:"
// semicolon-separated list of persistent variable, string, and wave names
static strconstant prefs_objects = ""
function ad_connect(epicsname, nickname)
// connects to the necessary EPICS channels of the detector
// to disconnect, call epics_disconnect()
// (caution: this will disconnect all EPICS channels of all PEARL EPICS procedures!)
string epicsname // base name of the detector, e.g. X03DA-SCIENTA:
// image1: and cam1: are appended by the function
string nickname // nick name under which this detector is referred to in Igor
// must be a valid data folder name
// the data folder is created under root:pearl_epics
dfref savedf = GetDataFolderDFR()
setdatafolder root:
// data folder for common EPICS metadata
newdatafolder /o/s $package_name
dfref epicsdf = GetDataFolderDFR()
string /g ad_chids
string /g ad_nicknames
// data folder this detector
string foldername = nickname
newdatafolder /s/o $foldername
dfref detectordf = GetDataFolderDFR()
// create variables and waves
make /n=(1)/o arraydata, xscale, yscale
make /n=(1,1)/o image
variable /g ndimensions
variable /g arraysize0, arraysize1
variable /g datatype
variable /g colormode
string /g controls, monitors
string /g xunits, yunits
print "connecting EPICS channels..."
// channel lists
controls = ""
monitors = ""
string imagename = epicsname + "image1:"
string camname = epicsname + "cam1:"
// we will set our own monitor on ArrayData, so add this to the controls list
controls = ReplaceStringByKey("ArrayData", controls, imagename + "ArrayData", "=")
// check whether it has been set already
variable chidArrayData = epics_chid(imagename + "ArrayData")
variable array_connected = chidArrayData > 0
monitors = ReplaceStringByKey("NDimensions", monitors, imagename + "NDimensions_RBV", "=")
monitors = ReplaceStringByKey("ArraySize0", monitors, imagename + "ArraySize0_RBV", "=")
monitors = ReplaceStringByKey("ArraySize1", monitors, imagename + "ArraySize1_RBV", "=")
monitors = ReplaceStringByKey("DataType", monitors, imagename + "DataType_RBV", "=")
monitors = ReplaceStringByKey("ColorMode", monitors, imagename + "ColorMode_RBV", "=")
monitors = ReplaceStringByKey("XScale", monitors, camname + "CHANNEL_SCALE_RBV", "=")
monitors = ReplaceStringByKey("YScale", monitors, camname + "SLICE_SCALE_RBV", "=")
variable nroi = 4
variable iroi
string roikey, roiname
for (iroi = 0; iroi < nroi; iroi += 1)
roikey = "ROI" + num2str(iroi + 1)
roiname = epicsname + "ROI" + num2str(iroi + 1) + ":"
controls = ReplaceStringByKey(roikey + "Enable", controls, roiname + "EnableCallbacks", "=")
controls = ReplaceStringByKey(roikey + "EnableX", controls, roiname + "EnableX", "=")
controls = ReplaceStringByKey(roikey + "MinX", controls, roiname + "MinX", "=")
controls = ReplaceStringByKey(roikey + "SizeX", controls, roiname + "SizeX", "=")
controls = ReplaceStringByKey(roikey + "EnableY", controls, roiname + "EnableY", "=")
controls = ReplaceStringByKey(roikey + "MinY", controls, roiname + "MinY", "=")
controls = ReplaceStringByKey(roikey + "SizeY", controls, roiname + "SizeY", "=")
monitors = ReplaceStringByKey(roikey + "Enable", monitors, roiname + "EnableCallbacks_RBV", "=")
monitors = ReplaceStringByKey(roikey + "EnableX", monitors, roiname + "EnableX_RBV", "=")
monitors = ReplaceStringByKey(roikey + "MinX", monitors, roiname + "MinX_RBV", "=")
monitors = ReplaceStringByKey(roikey + "SizeX", monitors, roiname + "SizeX_RBV", "=")
monitors = ReplaceStringByKey(roikey + "EnableY", monitors, roiname + "EnableY_RBV", "=")
monitors = ReplaceStringByKey(roikey + "MinY", monitors, roiname + "MinY_RBV", "=")
monitors = ReplaceStringByKey(roikey + "SizeY", monitors, roiname + "SizeY_RBV", "=")
endfor
// connect EPICS channels
epics_connect(controls, monitors)
// keep track of detector IDs
ad_nicknames = AddListItem(nickname, ad_nicknames)
variable iad = WhichListItem(nickname, ad_nicknames, ";", 0, 0)
ad_chids = AddListItem(num2istr(epics_chid(imagename + "ArrayData")), ad_chids, ";", iad)
// set callback function
if (!array_connected)
pvMonitor /F=ad_live_callback epics_chid(imagename + "ArrayData")
endif
print "...done"
setdatafolder savedf
end
function ad_live_callback(chan)
variable chan
dfref savedf = GetDataFolderDFR()
setdatafolder $package_path
// find the data folder of the detector
svar ad_chids
svar ad_nicknames
variable iad = WhichListItem(num2istr(chan), ad_chids, ";", 0, 0)
if (iad >= 0)
string nickname = StringFromList(iad, ad_nicknames)
else
return -1
endif
setdatafolder $nickname
// retrieve data
svar controls
svar monitors
variable chidArrayData = epics_chid(StringByKey("ArrayData", controls, "="))
variable chidNDimensions = epics_chid(StringByKey("NDimensions", monitors, "="))
variable chidArraySize0 = epics_chid(StringByKey("ArraySize0", monitors, "="))
variable chidArraySize1 = epics_chid(StringByKey("ArraySize1", monitors, "="))
variable chidDataType = epics_chid(StringByKey("DataType", monitors, "="))
variable chidColorMode = epics_chid(StringByKey("ColorMode", monitors, "="))
variable chidXScale = epics_chid(StringByKey("XScale", monitors, "="))
variable chidYScale = epics_chid(StringByKey("YScale", monitors, "="))
wave arraydata
wave image
nvar ndimensions
nvar arraysize0
nvar arraysize1
nvar datatype
nvar colormode
wave xscale
wave yscale
pvGet chidNDimensions, ndimensions
pvGet chidArraySize0, arraysize0
pvGet chidArraySize1, arraysize1
pvGet chidDataType, datatype
pvGet chidColorMode, colormode
// sanity checks
if (ndimensions != 2)
return -2
endif
if (colormode != 0)
return -3
endif
redimension /n=(arraysize0 * arraysize1) arraydata
redimension /n=(arraysize0, arraysize1) image
redimension /n=(arraysize0) xscale
redimension /n=(arraysize1) yscale
switch(datatype)
case 0: // int8
redimension /b arraydata, image
break
case 1: // uint8
redimension /b/u arraydata, image
break
case 2: // int16
redimension /w arraydata, image
break
case 3: // uint16
redimension /w/u arraydata, image
break
case 4: // int32
redimension /i arraydata, image
break
case 5: // uint32
redimension /i/u arraydata, image
break
case 6: // float32
redimension /s arraydata, image
break
case 7: // float64
redimension /d arraydata, image
break
endswitch
pvGetWave chidArrayData, arraydata
pvGetWave chidXScale, xscale
pvGetWave chidYScale, yscale
image = arraydata[p + q * arraysize0]
setscale /i x xscale[0], xscale[numpnts(xscale)-1], image
setscale /i y yscale[0], yscale[numpnts(yscale)-1], image
ad_update_profiles(image)
// update ROI rectangles
svar /z graphname = :view_image:prof_graphname
if (svar_exists(graphname))
variable nroi = 4
variable iroi
for (iroi = 0; iroi < nroi; iroi += 1)
ad_update_ROI(graphname, iroi)
endfor
endif
setdatafolder savedf
return 0
end
static function ad_update_ROI(graphname, iroi)
string graphname
variable iroi
string roikey
variable enable
svar monitors
wave xscale
wave yscale
variable enableX = 0
variable minX = 0
variable sizeX = numpnts(xscale)
variable enableY = 0
variable minY = 0
variable sizeY = numpnts(yscale)
roikey = "ROI" + num2str(iroi + 1)
enable = epics_get_num(StringByKey(roikey + "Enable", monitors, "="))
if (enable)
enableX = epics_get_num(StringByKey(roikey + "EnableX", monitors, "="))
if (enableX)
minX = epics_get_num(StringByKey(roikey + "MinX", monitors, "="))
sizeX = epics_get_num(StringByKey(roikey + "SizeX", monitors, "="))
endif
enableY = epics_get_num(StringByKey(roikey + "EnableY", monitors, "="))
if (enableY)
minY = epics_get_num(StringByKey(roikey + "MinY", monitors, "="))
sizeY = epics_get_num(StringByKey(roikey + "SizeY", monitors, "="))
endif
variable x1 = xscale[minX]
variable x2 = xscale[minX + sizeX - 1]
variable y1 = yscale[minY]
variable y2 = yscale[minY + sizeY - 1]
endif
ad_update_ROI_rect(graphname, iroi, x1, y1, x2, y2, enable)
end
static function ad_update_ROI_rect(graphname, iroi, x1, y1, x2, y2, enable)
string graphname
variable iroi // 0...3
variable x1,y1,x2,y2
variable enable // enable = 1; disable = 0
string roiname = "roi" + num2str(iroi + 1)
variable color = 65536 * (1 - iroi/8) - 1
if (enable)
DrawAction /w=$graphname getgroup=$roiname, delete, begininsert
SetDrawEnv /w=$graphname gstart,gname=$roiname
SetDrawEnv /w=$graphname xcoord= bottom,ycoord= left
SetDrawEnv /w=$graphname linefgc= (65535,color,color)
SetDrawEnv /w=$graphname fillpat= 0
SetDrawEnv /w=$graphname linethick= 0.50
DrawRect /w=$graphname x1,y1,x2,y2
SetDrawEnv /w=$graphname gstop
DrawAction /w=$graphname endinsert
else
DrawAction /w=$graphname getgroup=$roiname, delete
endif
end
function ad_set_ROI(nickname, iroi, p1, q1, p2, q2, enable)
// set a ROI rectangle to the given coordinates
string nickname
variable iroi // 0...3
variable p1,q1,p2,q2 // rectangular coordinates of the new ROI (point scaling)
variable enable // enable = 1; disable = 0
string roiname = "roi" + num2str(iroi + 1)
string roikey
dfref savedf = GetDataFolderDFR()
setdatafolder $package_path
setdatafolder $nickname
svar controls
wave xscale
wave yscale
variable minX = min(p1, p2)
variable sizeX = max(p1, p2) - min(p1, p2) + 1
variable enableX = sizeX > 0
variable minY = min(q1, q2)
variable sizeY = max(q1, q2) - min(q1, q2) + 1
variable enableY = sizeY > 0
roikey = "ROI" + num2str(iroi + 1)
epics_set_num(StringByKey(roikey + "Enable", controls, "="), enable)
if (enable)
epics_set_num(StringByKey(roikey + "EnableX", controls, "="), enableX)
if (enableX)
epics_set_num(StringByKey(roikey + "MinX", controls, "="), minX)
epics_set_num(StringByKey(roikey + "SizeX", controls, "="), sizeX)
endif
epics_set_num(StringByKey(roikey + "EnableY", controls, "="), enableY)
if (enableY)
epics_set_num(StringByKey(roikey + "MinY", controls, "="), minY)
epics_set_num(StringByKey(roikey + "SizeY", controls, "="), sizeY)
endif
endif
svar graphname = :view_image:prof_graphname
ad_update_ROI(graphname, iroi)
setdatafolder savedf
end
function add_roi_controls()
PopupMenu pm_set_roi mode=0,value="ROI 1;ROI 2;ROI 3;ROI 4",title="Set ROI"
PopupMenu pm_set_roi pos={400,0},bodyWidth=60,proc=PearlAreaLive#pmp_set_roi
PopupMenu pm_set_roi help={"Set a detector ROI to the current cursor selection"}
end
static function pmp_set_roi(pa) : PopupMenuControl
STRUCT WMPopupAction &pa
switch( pa.eventCode )
case 2: // mouse up
variable popNum = pa.popNum
string imgname = StringFromList(0, ImageNameList(pa.win, ";"))
wave /z image = ImageNameToWaveRef(pa.win, imgname)
if (waveexists(image))
wave /z source = PearlAreaDisplay#get_source_image(image)
if (waveexists(source))
dfref sourcedf = GetWavesDataFolderDFR(source)
string nickname = GetDataFolder(0, sourcedf)
ad_set_ROI(nickname, popNum - 1, pcsr(A, pa.win), qcsr(A, pa.win), pcsr(B, pa.win), qcsr(B, pa.win), 1)
endif
endif
break
case -1: // control being killed
break
endswitch
return 0
End

View File

@ -0,0 +1,454 @@
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
#pragma IgorVersion = 6.1
#pragma ModuleName = PearlAreaProfilesTest
#pragma version = 1.02
#include "pearl-area-profiles"
#include "unit-testing"
/// @file
/// @brief test suite for pearl-area-profiles.ipf
///
/// unit testing framework: http://www.igorexchange.com/project/unitTesting.
/// run all test cases with <code>RunTest("pearl-area-profiles-test.ipf")</code>.
/// if wave equalities fail, EnableDebugOutput() and read Igor help on equalWaves().
///
/// @author matthias muntwiler, matthias.muntwiler@psi.ch
///
/// @copyright 2013-15 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 PearlAreaProfilesTest
/// @brief profile extraction for multi-dimensional datasets acquired from area detectors.
///
/// PearlAreaProfilesTest is declared in @ref pearl-area-profiles-test.ipf.
///
/// test the ad_profile_x() function
static function test_ad_profile_x_w()
make /n=(11,21) /d /free source
setscale /p x 10, 1, "X", source
setscale /p y 100, 100, "Y", source
setscale d 0, 0, "D", source
source = x + y
make /n=11 /d /free expected
setscale /p x 10, 1, "X", expected
setscale d 0, 0, "D", expected
expected = 30 + 3 * p + 500 + 600 + 700
make /n=1 /d /free result1, result0
variable p1, p2
p1 = 4
p2 = 6
ad_profile_x_w(source, p1, p2, result1, noavg=1)
CHECK_EQUAL_WAVES(result1, expected, tol=1e-6)
expected /= 3
ad_profile_x_w(source, p1, p2, result0, noavg=0)
CHECK_EQUAL_WAVES(result0, expected, tol=1e-6)
end
/// test the ad_profile_y() function
static function test_ad_profile_y_w()
make /n=(11,21) /d /free source
setscale /p x 10, 1, "X", source
setscale /p y 100, 100, "Y", source
setscale d 0, 0, "D", source
source = x + y
make /n=21 /d /free expected
setscale /p x 100, 100, "Y", expected
setscale d 0, 0, "D", expected
expected = 3 * x + 14 + 15 + 16
make /n=1 /d /free result1, result0
variable p1, p2
p1 = 4
p2 = 6
ad_profile_y_w(source, p1, p2, result1, noavg=1)
CHECK_EQUAL_WAVES(result1, expected)
expected /= 3
ad_profile_y_w(source, p1, p2, result0, noavg=0)
CHECK_EQUAL_WAVES(result0, expected)
end
/// test the ad_extract_slab_x() function
static function test_ad_extract_slab_x()
variable nx = 11
variable ny = 16
variable nz = 21
make /n=(nx,ny,nz) /d /free source
setscale /i x -1, 1, "X", source
setscale /i y -2, 2, "Y", source
setscale /i z -3, 3, "Z", source
setscale d 0, 0, "D", source
source = x + y + z
source[4][][] = 1
source[5][][] = 1
make /n=(ny,nz) /d /free expected
setscale /i x -2, 2, "Y", expected
setscale /i y -3, 3, "Z", expected
setscale d 0, 0, "D", expected
expected = 2
variable p1, p2
p1 = 4
p2 = 5
wave result = ad_extract_slab_x(source, p1, p2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
expected = 1
wave result = ad_extract_slab_x(source, p1, p2, "", noavg=0)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
p1 = -inf
p2 = 5
source = y + z
expected = (x + y) * 6
wave result = ad_extract_slab_x(source, p1, p2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
p1 = 4
p2 = +inf
expected = (x + y) * (nx - 4)
wave result = ad_extract_slab_x(source, p1, p2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
end
/// test the ad_extract_slab_y() function
static function test_ad_extract_slab_y()
variable nx = 11
variable ny = 16
variable nz = 21
make /n=(nx,ny,nz) /d /free source
setscale /i x -1, 1, "X", source
setscale /i y -2, 2, "Y", source
setscale /i z -3, 3, "Z", source
setscale d 0, 0, "D", source
source = x + y + z
source[][4][] = 1
source[][5][] = 1
make /n=(nx,nz) /d /free expected
setscale /i x -1, 1, "X", expected
setscale /i y -3, 3, "Z", expected
setscale d 0, 0, "D", expected
expected = 2
variable p1, p2
p1 = 4
p2 = 5
wave result = ad_extract_slab_y(source, p1, p2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
expected = 1
wave result = ad_extract_slab_y(source, p1, p2, "", noavg=0)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
p1 = -inf
p2 = 5
source = x + z
expected = (x + y) * 6
wave result = ad_extract_slab_y(source, p1, p2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
p1 = 4
p2 = +inf
expected = (x + y) * (ny - 4)
wave result = ad_extract_slab_y(source, p1, p2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
end
/// test the ad_extract_slab_z() function
static function test_ad_extract_slab_z()
variable nx = 11
variable ny = 16
variable nz = 21
make /n=(nx,ny,nz) /d /free source
setscale /i x -1, 1, "X", source
setscale /i y -2, 2, "Y", source
setscale /i z -3, 3, "Z", source
setscale d 0, 0, "D", source
source = x + y + z
source[][][4] = 1
source[][][5] = 1
make /n=(nx,ny) /d /free expected
setscale /i x -1, 1, "X", expected
setscale /i y -2, 2, "Y", expected
setscale d 0, 0, "D", expected
expected = 2
variable p1, p2
p1 = 4
p2 = 5
wave result = ad_extract_slab_z(source, p1, p2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
expected = 1
wave result = ad_extract_slab_z(source, p1, p2, "", noavg=0)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
p1 = -inf
p2 = 5
source = x + y
expected = (x + y) * 6
wave result = ad_extract_slab_z(source, p1, p2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
p1 = 4
p2 = +inf
expected = (x + y) * (nz - 4)
wave result = ad_extract_slab_z(source, p1, p2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
end
/// test the ad_extract_slab() function
static function test_ad_extract_slab()
variable nx = 11
variable ny = 16
variable nz = 21
make /n=(nx,ny,nz) /d /free source
setscale /i x -1, 1, "X", source
setscale /i y -2, 2, "Y", source
setscale /i z -3, 3, "Z", source
setscale d 0, 0, "D", source
source = x + y + z
variable x1, x2
variable y1, y2
variable z1, z2
make /n=(ny,nz) /d /free expected
setscale /i x -2, 2, "Y", expected
setscale /i y -3, 3, "Z", expected
setscale d 0, 0, "D", expected
x1 = 0
x2 = 0
y1 = nan
y2 = nan
z1 = nan
z2 = nan
expected = source[(nx-1)/2][p][q]
wave result = ad_extract_slab(source, x1, x2, y1, y2, z1, z2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
x1 = -inf
x2 = inf
expected = (x + y) * nx
wave result = ad_extract_slab(source, x1, x2, y1, y2, z1, z2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
make /n=(nx,nz) /d /free expected
setscale /i x -1, 1, "X", expected
setscale /i y -3, 3, "Z", expected
setscale d 0, 0, "D", expected
x1 = nan
x2 = nan
y1 = 0
y2 = 0
z1 = nan
z2 = nan
expected = source[p][(ny-1)/2][q]
wave result = ad_extract_slab(source, x1, x2, y1, y2, z1, z2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
y1 = -inf
y2 = +inf
expected = (x + y) * ny
wave result = ad_extract_slab(source, x1, x2, y1, y2, z1, z2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
make /n=(nx,ny) /d /free expected
setscale /i x -1, 1, "X", expected
setscale /i y -2, 2, "Y", expected
setscale d 0, 0, "D", expected
x1 = nan
x2 = nan
y1 = nan
y2 = nan
z1 = 0
z2 = 0
expected = source[p][q][(nz-1)/2]
wave result = ad_extract_slab(source, x1, x2, y1, y2, z1, z2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
z1 = -inf
z2 = inf
expected = (x + y) * nz
wave result = ad_extract_slab(source, x1, x2, y1, y2, z1, z2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
end
/// test the ad_extract_rod_x() function
static function test_ad_extract_rod_x()
variable nx = 11
variable ny = 16
variable nz = 21
make /n=(nx,ny,nz) /d /free source
setscale /i x -1, 1, "X", source
setscale /i y -2, 2, "Y", source
setscale /i z -3, 3, "Z", source
setscale d 0, 0, "D", source
source = x + y + z
source[][4][4] = 1
source[][4][5] = 1
source[][5][4] = 1
source[][5][5] = 1
make /n=(nx) /d /free expected
setscale /i x -1, 1, "X", expected
setscale d 0, 0, "D", expected
expected = 4
variable q1, q2
variable r1, r2
q1 = 4
q2 = 5
r1 = 4
r2 = 5
wave result = ad_extract_rod_x(source, q1, q2, r1, r2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
expected = 1
wave result = ad_extract_rod_x(source, q1, q2, r1, r2, "", noavg=0)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
end
/// test the ad_extract_rod() function, X coordinate
static function test_ad_extract_rod__x()
variable nx = 11
variable ny = 16
variable nz = 21
make /n=(nx,ny,nz) /d /free source
setscale /i x -1, 1, "X", source
setscale /i y -2, 2, "Y", source
setscale /i z -3, 3, "Z", source
setscale d 0, 0, "D", source
source = x + y + z
variable x1, x2
variable y1, y2
variable z1, z2
make /n=(nx) /d /free expected
setscale /i x -1, 1, "X", expected
setscale d 0, 0, "D", expected
x1 = nan
x2 = nan
y1 = 0
y2 = 0
z1 = 0
z2 = 0
expected = source[p][(ny-1)/2][(nz-1)/2]
wave result = ad_extract_rod(source, x1, x2, y1, y2, z1, z2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
y1 = -inf
y2 = +inf
z1 = -inf
z2 = +inf
expected = x * ny * nz
wave result = ad_extract_rod(source, x1, x2, y1, y2, z1, z2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
end
/// test the ad_extract_rod() function, Y coordinate
static function test_ad_extract_rod__y()
variable nx = 11
variable ny = 16
variable nz = 21
make /n=(nx,ny,nz) /d /free source
setscale /i x -1, 1, "X", source
setscale /i y -2, 2, "Y", source
setscale /i z -3, 3, "Z", source
setscale d 0, 0, "D", source
source = x + y + z
variable x1, x2
variable y1, y2
variable z1, z2
make /n=(ny) /d /free expected
setscale /i x -2, 2, "Y", expected
setscale d 0, 0, "D", expected
x1 = 0
x2 = 0
y1 = nan
y2 = nan
z1 = 0
z2 = 0
expected = source[(nx-1)/2][p][(nz-1)/2]
wave result = ad_extract_rod(source, x1, x2, y1, y2, z1, z2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
x1 = -inf
x2 = +inf
z1 = -inf
z2 = +inf
expected = x * nx * nz
wave result = ad_extract_rod(source, x1, x2, y1, y2, z1, z2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
end
/// test the ad_extract_rod() function, Z coordinate
static function test_ad_extract_rod__z()
variable nx = 11
variable ny = 16
variable nz = 21
make /n=(nx,ny,nz) /d /free source
setscale /i x -1, 1, "X", source
setscale /i y -2, 2, "Y", source
setscale /i z -3, 3, "Z", source
setscale d 0, 0, "D", source
source = x + y + z
variable x1, x2
variable y1, y2
variable z1, z2
make /n=(nz) /d /free expected
setscale /i x -3, 3, "Z", expected
setscale d 0, 0, "D", expected
x1 = 0
x2 = 0
y1 = 0
y2 = 0
z1 = nan
z2 = nan
expected = source[(nx-1)/2][(ny-1)/2][p]
wave result = ad_extract_rod(source, x1, x2, y1, y2, z1, z2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
x1 = -inf
x2 = +inf
y1 = -inf
y2 = +inf
expected = x * nx * ny
wave result = ad_extract_rod(source, x1, x2, y1, y2, z1, z2, "", noavg=1)
CHECK_EQUAL_WAVES(result, expected, tol=0.001)
end

View File

@ -0,0 +1,615 @@
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
#pragma IgorVersion = 6.1
#pragma ModuleName = PearlAreaProfiles
#pragma version = 1.05
/// @file
/// @brief profile extraction for multi-dimensional datasets acquired from area detectors.
/// @ingroup ArpesPackage
///
///
///
/// @author matthias muntwiler, matthias.muntwiler@psi.ch
///
/// @copyright 2013-15 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 PearlAreaProfiles
/// @brief profile extraction for multi-dimensional datasets acquired from area detectors.
///
/// PearlAnglescanTracker is declared in @ref pearl-area-profiles.ipf.
///
/// 1D cut through 3D dataset, integrate in normal dimensions
///
/// @param dataset
/// @param x1, x2, y1, y2, z1, z2
/// coordinates of integration region
/// by default, the coordinates use wave scaling
/// coordinates of rod dimensions (to be preserved) must be nan
/// coordinate pairs don't have to be ordered, i.e. both x1 <= x2 and x1 >= x2 are allowed.
/// @param destname
/// name of destination wave. to be created in current data folder.
/// if empty, the function returns a free wave
/// @param noavg
/// non-zero = calculate the sum, default = 0
/// as of version 1.05, this option should rather be called "calc_sum" or similar.
/// it is noavg for compatibility with older code.
/// @param sdev
/// non-zero = calculate the standard deviation, default = 0
/// by default, the function calculates the average of the integration region
/// set either the noavg or sdev option to select the sum or the standard deviation, respectively.
/// if both options are set, noavg (sum) takes precedence.
/// @param pscale
/// scaling of the slab coordinates x1, x2, ..., z2:
/// zero or default = wave scaling, non-zero = point scaling
///
/// @remark
/// * version 1.02: the specification of the destination coordinates has changed
/// * version 1.04: the function returns an empty wave reference if an error occurred
///
threadsafe function /wave ad_extract_rod(dataset, x1, x2, y1, y2, z1, z2, destname, [noavg, sdev, pscale])
wave dataset
variable x1, x2, y1, y2, z1, z2
string destname
variable noavg
variable sdev
variable pscale
if (wavedims(dataset) != 3)
return $""
endif
if (ParamIsDefault(noavg))
noavg = 0
endif
if (ParamIsDefault(sdev))
sdev = 0
endif
if (ParamIsDefault(pscale))
pscale = 0
endif
variable p1, p2, q1, q2, r1, r2
if (pscale)
p1 = x1
p2 = x2
q1 = y1
q2 = y2
r1 = z1
r2 = z2
else
p1 = round((x1 - DimOffset(dataset, 0)) / DimDelta(dataset, 0))
p2 = round((x2 - DimOffset(dataset, 0)) / DimDelta(dataset, 0))
q1 = round((y1 - DimOffset(dataset, 1)) / DimDelta(dataset, 1))
q2 = round((y2 - DimOffset(dataset, 1)) / DimDelta(dataset, 1))
r1 = round((z1 - DimOffset(dataset, 2)) / DimDelta(dataset, 2))
r2 = round((z2 - DimOffset(dataset, 2)) / DimDelta(dataset, 2))
endif
if ((numtype(p1) == 2) || (numtype(p2) == 2))
return ad_extract_rod_x(dataset, min(q1, q2), max(q1, q2), min(r1, r2), max(r1, r2), destname, noavg=noavg, sdev=sdev)
elseif ((numtype(q1) == 2) || (numtype(q2) == 2))
return ad_extract_rod_y(dataset, min(p1, p2), max(p1, p2), min(r1, r2), max(r1, r2), destname, noavg=noavg, sdev=sdev)
elseif ((numtype(r1) == 2) || (numtype(r2) == 2))
return ad_extract_rod_z(dataset, min(p1, p2), max(p1, p2), min(q1, q2), max(q1, q2), destname, noavg=noavg, sdev=sdev)
else
return $""
endif
end
/// 1D cut through 3D dataset along X dimension.
///
/// see ad_extract_rod() for descriptions of common parameters.
threadsafe function /wave ad_extract_rod_x(dataset, q1, q2, r1, r2, destname, [noavg, sdev])
wave dataset
variable q1, q2, r1, r2
// -inf < q1 < q2 < +inf, -inf < r1 < r2 < +inf
string destname
variable noavg
variable sdev
if (ParamIsDefault(noavg))
noavg = 0
endif
if (ParamIsDefault(sdev))
sdev = 0
endif
variable avg = !noavg && !sdev
q1 = max(q1, 0)
q2 = min(q2, dimsize(dataset, 1) - 1)
r1 = max(r1, 0)
r2 = min(r2, dimsize(dataset, 2) - 1)
if (strlen(destname) > 0)
duplicate /r=[][q1,q1][r1,r1]/o dataset, $destname
wave w_dest = $destname
else
duplicate /r=[][q1,q1][r1,r1] /free dataset, w_dest
endif
redimension /n=(dimsize(w_dest, 0)) w_dest
setscale /p x dimoffset(dataset, 0), dimdelta(dataset, 0), waveunits(dataset, 0), w_dest
w_dest = 0
variable qq, rr
variable nn = 0
for (qq = q1; qq <= q2; qq += 1)
for (rr = r1; rr <= r2; rr += 1)
w_dest += dataset[p][qq][rr]
nn += 1
endfor
endfor
if (sdev)
duplicate /free w_dest, w_squares
w_squares = 0
for (qq = q1; qq <= q2; qq += 1)
for (rr = r1; rr <= r2; rr += 1)
w_squares += dataset[p][qq][rr]^2
endfor
endfor
endif
if (avg)
w_dest /= nn
elseif (sdev)
w_dest = sqrt( (w_squares - w_dest^2 / nn) / (nn - 1) )
endif
return w_dest
end
/// 1D cut through 3D dataset along Y dimension.
///
/// see ad_extract_rod() for descriptions of common parameters.
threadsafe function /wave ad_extract_rod_y(dataset, p1, p2, r1, r2, destname, [noavg, sdev])
wave dataset
variable p1, p2, r1, r2
// 0 <= p1 < p2 < dimsize(0), 0 <= r1 < r2 < dimsize(2)
string destname
variable noavg
variable sdev
if (ParamIsDefault(noavg))
noavg = 0
endif
if (ParamIsDefault(sdev))
sdev = 0
endif
variable avg = !noavg && !sdev
p1 = max(p1, 0)
p2 = min(p2, dimsize(dataset, 0) - 1)
r1 = max(r1, 0)
r2 = min(r2, dimsize(dataset, 2) - 1)
if (strlen(destname) > 0)
duplicate /r=[p1,p1][][r1,r1]/o dataset, $destname
wave w_dest = $destname
else
duplicate /r=[p1,p1][][r1,r1] /free dataset, w_dest
endif
redimension /n=(dimsize(w_dest, 1)) w_dest
setscale /p x dimoffset(dataset, 1), dimdelta(dataset, 1), waveunits(dataset, 1), w_dest
w_dest = 0
variable pp, rr
variable nn = 0
for (pp = p1; pp <= p2; pp += 1)
for (rr = r1; rr <= r2; rr += 1)
w_dest += dataset[pp][p][rr]
nn += 1
endfor
endfor
if (sdev)
duplicate /free w_dest, w_squares
w_squares = 0
for (pp = p1; pp <= p2; pp += 1)
for (rr = r1; rr <= r2; rr += 1)
w_squares += dataset[pp][p][rr]^2
nn += 1
endfor
endfor
endif
if (avg)
w_dest /= nn
elseif (sdev)
w_dest = sqrt( (w_squares - w_dest^2 / nn) / (nn - 1) )
endif
return w_dest
end
/// 1D cut through 3D dataset along Z dimension.
///
/// see ad_extract_rod() for descriptions of common parameters.
threadsafe function /wave ad_extract_rod_z(dataset, p1, p2, q1, q2, destname, [noavg, sdev])
wave dataset
variable p1, p2, q1, q2
// 0 <= p1 < p2 < dimsize(0), 0 <= q1 < q2 < dimsize(1)
string destname
variable noavg
variable sdev
if (ParamIsDefault(noavg))
noavg = 0
endif
if (ParamIsDefault(sdev))
sdev = 0
endif
variable avg = !noavg && !sdev
p1 = max(p1, 0)
p2 = min(p2, dimsize(dataset, 0) - 1)
q1 = max(q1, 0)
q2 = min(q2, dimsize(dataset, 1) - 1)
if (strlen(destname) > 0)
duplicate /r=[p1,p1][q1,q1][]/o dataset, $destname
wave w_dest = $destname
else
duplicate /r=[p1,p1][q1,q1][] /free dataset, w_dest
endif
redimension /n=(dimsize(w_dest, 2)) w_dest
setscale /p x dimoffset(dataset, 2), dimdelta(dataset, 2), waveunits(dataset, 2), w_dest
w_dest = 0
variable pp, qq
variable nn = 0
for (pp = p1; pp <= p2; pp += 1)
for (qq = q1; qq <= q2; qq += 1)
w_dest += dataset[pp][qq][p]
nn += 1
endfor
endfor
if (sdev)
duplicate /free w_dest, w_squares
w_squares = 0
for (pp = p1; pp <= p2; pp += 1)
for (qq = q1; qq <= q2; qq += 1)
w_squares += dataset[pp][qq][p]^2
nn += 1
endfor
endfor
endif
if (avg)
w_dest /= nn
elseif (sdev)
w_dest = sqrt( (w_squares - w_dest^2 / nn) / (nn - 1) )
endif
return w_dest
end
/// 2D cut through 3D dataset, integrate in normal dimension
///
/// @param dataset
/// @param x1, x2, y1, y2, z1, z2
/// coordinates of integration region.
/// by default, the coordinates use wave scaling.
/// coordinates of slab dimensions (to be preserved) must be nan.
/// coordinate pairs don't have to be ordered, i.e. both x1 <= x2 and x1 >= x2 are allowed.
/// coordinates can be out of range (-inf and +inf allowed) to select the whole range.
/// @param destname
/// name of destination wave. to be created in current data folder.
/// if empty, the function returns a free wave.
/// @param noavg
/// zero or default = average, non-zero = sum.
/// @param pscale
/// scaling of the slab coordinates x1, x2, ..., z2:
/// zero or default = wave scaling, non-zero = point scaling.
///
/// @remark
/// * version 1.02: the specification of the destination coordinates has changed
/// * version 1.04: the function returns an empty wave reference if an error occurred
///
threadsafe function /wave ad_extract_slab(dataset, x1, x2, y1, y2, z1, z2, destname, [noavg, pscale])
wave dataset
variable x1, x2, y1, y2, z1, z2
string destname
variable noavg
variable pscale
if (wavedims(dataset) != 3)
return $""
endif
if (ParamIsDefault(noavg))
noavg = 0
endif
if (ParamIsDefault(pscale))
pscale = 0
endif
variable p1, p2, q1, q2, r1, r2
if (pscale)
p1 = x1
p2 = x2
q1 = y1
q2 = y2
r1 = z1
r2 = z2
else
p1 = round((x1 - DimOffset(dataset, 0)) / DimDelta(dataset, 0))
p2 = round((x2 - DimOffset(dataset, 0)) / DimDelta(dataset, 0))
q1 = round((y1 - DimOffset(dataset, 1)) / DimDelta(dataset, 1))
q2 = round((y2 - DimOffset(dataset, 1)) / DimDelta(dataset, 1))
r1 = round((z1 - DimOffset(dataset, 2)) / DimDelta(dataset, 2))
r2 = round((z2 - DimOffset(dataset, 2)) / DimDelta(dataset, 2))
endif
if ((numtype(p1) < 2) && (numtype(p2) < 2))
return ad_extract_slab_x(dataset, min(p1, p2), max(p1, p2), destname, noavg=noavg)
elseif ((numtype(q1) < 2) && (numtype(q2) < 2))
return ad_extract_slab_y(dataset, min(q1, q2), max(q1, q2), destname, noavg=noavg)
elseif ((numtype(r1) < 2) && (numtype(r2) < 2))
return ad_extract_slab_z(dataset, min(r1, r2), max(r1, r2), destname, noavg=noavg)
else
return $""
endif
end
threadsafe function /wave ad_extract_slab_x(dataset, p1, p2, destname, [noavg])
wave dataset
variable p1, p2
// x coordinate range (point scaling) to be integrated
// -inf <= p1 < p2 <= +inf
string destname // name of destination wave. to be created in current data folder. overrides existing.
// if empty, the function returns a free wave
variable noavg // zero or default = average, non-zero = sum
if (ParamIsDefault(noavg))
noavg = 0
endif
p1 = max(p1, 0)
p2 = min(p2, dimsize(dataset, 0) - 1)
if (strlen(destname) > 0)
duplicate /r=[p1,p1][][]/o dataset, $destname
wave w_dest = $destname
else
duplicate /r=[p1,p1][][] /free dataset, w_dest
endif
redimension /n=(dimsize(w_dest, 1), dimsize(w_dest, 2)) w_dest
setscale /p x dimoffset(dataset, 1), dimdelta(dataset, 1), waveunits(dataset, 1), w_dest
setscale /p y dimoffset(dataset, 2), dimdelta(dataset, 2), waveunits(dataset, 2), w_dest
w_dest = 0
variable pp
variable nn = 0
for (pp = p1; pp <= p2; pp += 1)
w_dest += dataset[pp][p][q]
nn += 1
endfor
if (noavg == 0)
w_dest /= nn
endif
return w_dest
end
threadsafe function /wave ad_extract_slab_y(dataset, q1, q2, destname, [noavg])
wave dataset
variable q1, q2
// y coordinate range (point scaling) to be integrated
// -inf <= q1 < q2 <= +inf
string destname // name of destination wave. to be created in current data folder. overrides existing.
// if empty, the function returns a free wave
variable noavg // zero or default = average, non-zero = sum
if (ParamIsDefault(noavg))
noavg = 0
endif
q1 = max(q1, 0)
q2 = min(q2, dimsize(dataset, 1) - 1)
if (strlen(destname) > 0)
duplicate /r=[][q1,q1][]/o dataset, $destname
wave w_dest = $destname
else
duplicate /r=[][q1,q1][] /free dataset, w_dest
endif
redimension /n=(dimsize(w_dest, 0), dimsize(w_dest, 2)) w_dest
setscale /p x dimoffset(dataset, 0), dimdelta(dataset, 0), waveunits(dataset, 0), w_dest
setscale /p y dimoffset(dataset, 2), dimdelta(dataset, 2), waveunits(dataset, 2), w_dest
w_dest = 0
variable qq
variable nn = 0
for (qq = q1; qq <= q2; qq += 1)
w_dest += dataset[p][qq][q]
nn += 1
endfor
if (noavg == 0)
w_dest /= nn
endif
return w_dest
end
threadsafe function /wave ad_extract_slab_z(dataset, r1, r2, destname, [noavg])
wave dataset
variable r1, r2
// z coordinate range (point scaling) to be integrated
// -inf <= r1 < r2 <= +inf
string destname // name of destination wave. to be created in current data folder. overrides existing.
// if empty, the function returns a free wave
variable noavg // zero or default = average, non-zero = sum
if (ParamIsDefault(noavg))
noavg = 0
endif
r1 = max(r1, 0)
r2 = min(r2, dimsize(dataset, 2) - 1)
if (strlen(destname) > 0)
duplicate /r=[][][r1,r1]/o dataset, $destname
wave w_dest = $destname
else
duplicate /r=[][][r1,r1] /free dataset, w_dest
endif
redimension /n=(dimsize(w_dest, 0), dimsize(w_dest, 1)) w_dest
setscale /p x dimoffset(dataset, 0), dimdelta(dataset, 0), waveunits(dataset, 0), w_dest
setscale /p y dimoffset(dataset, 1), dimdelta(dataset, 1), waveunits(dataset, 1), w_dest
w_dest = 0
variable rr
variable nn = 0
for (rr = r1; rr <= r2; rr += 1)
w_dest += dataset[p][q][rr]
nn += 1
endfor
if (noavg == 0)
w_dest /= nn
endif
return w_dest
end
/// 1D cut through 2D dataset along X dimension, new destination wave.
///
threadsafe function /wave ad_profile_x(dataset, q1, q2, destname, [noavg])
wave dataset
variable q1, q2 // -inf <= q1 < q2 <= +inf
// deprecated: q2 = -1 stands for dimsize(0) - 1
string destname // name of destination wave. to be created in current data folder. overrides existing.
// if empty, the function returns a free wave
variable noavg // zero or default = average, non-zero = sum
if (ParamIsDefault(noavg))
noavg = 0
endif
if (strlen(destname) > 0)
duplicate /r=[0,0][] /o dataset, $destname
wave w_dest = $destname
else
duplicate /r=[0,0][] /free dataset, w_dest
endif
return ad_profile_x_w(dataset, q1, q2, w_dest, noavg=noavg)
end
/// 1D cut through 2D dataset along X dimension, existing destination wave.
///
threadsafe function /wave ad_profile_x_w(dataset, q1, q2, destwave, [noavg])
wave dataset
variable q1, q2 // -inf <= q1 < q2 <= +inf
// deprecated: q2 = -1 stands for dimsize(0) - 1
wave destwave // existing destination wave
variable noavg // zero or default = average, non-zero = sum
if (ParamIsDefault(noavg))
noavg = 0
endif
redimension /n=(dimsize(dataset, 0)) destwave
setscale /p x dimoffset(dataset, 0), dimdelta(dataset, 0), waveunits(dataset, 0), destwave
setscale d 0, 0, waveunits(dataset, -1), destwave
q1 = max(q1, 0)
if (q2 < 0)
q2 = inf
endif
q2 = min(q2, dimsize(dataset, 1) - 1)
destwave = 0
variable qq
variable nn = 0
for (qq = q1; qq <= q2; qq += 1)
destwave += dataset[p][qq]
nn += 1
endfor
if (noavg == 0)
destwave /= nn
endif
return destwave
end
/// 1D cut through 2D dataset along Y dimension, new destination wave.
///
threadsafe function /wave ad_profile_y(dataset, p1, p2, destname, [noavg])
wave dataset
variable p1, p2 // -inf <= p1 < p2 < inf
// deprecated: p2 = -1 stands for dimsize(0) - 1
string destname // name of destination wave. to be created in current data folder. overrides existing.
// if empty, the function returns a free wave
variable noavg // zero or default = average, non-zero = sum
if (ParamIsDefault(noavg))
noavg = 0
endif
if (strlen(destname) > 0)
duplicate /r=[][0,0] /o dataset, $destname
wave w_dest = $destname
else
duplicate /r=[][0,0] /free dataset, w_dest
endif
MatrixTranspose w_dest
return ad_profile_y_w(dataset, p1, p2, w_dest, noavg=noavg)
end
/// 1D cut through 2D dataset along X dimension, existing destination wave.
///
threadsafe function /wave ad_profile_y_w(dataset, p1, p2, destwave, [noavg])
wave dataset
variable p1, p2 // -inf <= p1 < p2 < inf
// deprecated: p2 = -1 stands for dimsize(0) - 1
wave destwave // existing destination wave
variable noavg // zero or default = average, non-zero = sum
if (ParamIsDefault(noavg))
noavg = 0
endif
redimension /n=(dimsize(dataset, 1)) destwave
setscale /p x dimoffset(dataset, 1), dimdelta(dataset, 1), waveunits(dataset, 1), destwave
setscale d 0, 0, waveunits(dataset, -1), destwave
p1 = max(p1, 0)
if (p2 < 0)
p2 = inf
endif
p2 = min(p2, dimsize(dataset, 0) - 1)
destwave = 0
variable pp
variable nn = 0
for (pp = p1; pp <= p2; pp += 1)
destwave += dataset[pp][p]
nn += 1
endfor
if (noavg == 0)
destwave /= nn
endif
return destwave
end
threadsafe function calc_y_profile_mins(image)
// experimental
wave image
wave yminlocs = ad_profile_x(image, 0, 0, "ymins", noavg=1)
variable nx = dimsize(image, 0)
variable ix
for (ix = 0; ix < nx; ix += 1)
wave profile = ad_profile_y(image, ix, ix, "", noavg=1)
wavestats /q/m=1 profile
yminlocs[ix] = v_minloc
endfor
end

152
pearl/pearl-arpes-scans.ipf Normal file
View File

@ -0,0 +1,152 @@
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
#pragma IgorVersion = 6.1
#pragma ModuleName = PearlArpesScans
#pragma version = 1.01
#include "mm-physconst"
#include "pearl-optics-theory"
#include "pearl-epics", version >= 1.01
// EPICS scans of Scienta
// matthias muntwiler, 2013-03-15
// $Id: pearl-optics-scans.ipf 129 2013-06-26 15:53:13Z muntwiler_m $
static strconstant basename = "X03DA-SCIENTA:"
static strconstant camname = "cam1:"
static strconstant hdfname = "HDF1:"
static strconstant imgname = "image1:"
static strconstant statsname = "Stats1:"
function scienta_connect()
dfref savedf = GetDataFolderDFR()
print "connecting EPICS channels..."
// channel lists
string controls = ""
controls += basename + camname + "PASS_ENERGY;"
controls += basename + camname + "LOW_ENERGY;"
controls += basename + camname + "CENTRE_ENERGY;"
controls += basename + camname + "HIGH_ENERGY;"
controls += basename + camname + "LENS_MODE;"
controls += basename + camname + "ACQ_MODE;"
controls += basename + camname + "ENERGY_MODE;"
controls += basename + camname + "DETECTOR_MODE;"
controls += basename + camname + "ELEMENT_SET;"
controls += basename + camname + "STEP_SIZE;"
controls += basename + camname + "SLICES;"
controls += basename + camname + "NumExposures;"
controls += basename + camname + "FRAMES;"
controls += basename + camname + "STEP_TIME;"
string monitors = ""
monitors += basename + camname + "PASS_ENERGY_RBV;"
monitors += basename + camname + "LOW_ENERGY_RBV;"
monitors += basename + camname + "CENTRE_ENERGY_RBV;"
monitors += basename + camname + "HIGH_ENERGY_RBV;"
monitors += basename + camname + "ENERGY_WIDTH_RBV;"
monitors += basename + camname + "LENS_MODE_RBV;"
monitors += basename + camname + "ACQ_MODE_RBV;"
monitors += basename + camname + "ENERGY_MODE_RBV;"
monitors += basename + camname + "DETECTOR_MODE_RBV;"
monitors += basename + camname + "ELEMENT_SET_RBV;"
monitors += basename + camname + "STEP_SIZE_RBV;"
monitors += basename + camname + "SLICES_RBV;"
monitors += basename + camname + "NumExposures_RBV;"
monitors += basename + camname + "CURRENT_CHANNEL_RBV;"
monitors += basename + camname + "TOTAL_POINTS_RBV;"
monitors += basename + camname + "PROGRESS_RBV;"
//monitors += basename + camname + "INT_SPECTRUM;"
monitors += basename + camname + "BinX_RBV;"
monitors += basename + camname + "BinY_RBV;"
monitors += basename + camname + "MinX_RBV;"
monitors += basename + camname + "MinY_RBV;"
monitors += basename + camname + "SizeX_RBV;"
monitors += basename + camname + "SizeY_RBV;"
monitors += basename + camname + "ReverseX_RBV;"
monitors += basename + camname + "ReverseY_RBV;"
// variable name list corresponding to channel lists
string variables = ""
variables = AddListItem("ArrayData", variables, ";", ItemsInList(variables))
// connect EPICS channels
epics_connect(controls, monitors)
print "...done"
setdatafolder savedf
end
function pearl_set_attr_ch(attr_wave_name, attr_channel_name)
string attr_wave_name
string attr_channel_name
variable result
variable chid
pvOpen chid, attr_channel_name
switch(wavetype($attr_wave_name, 1))
case 1: // numeric
wave w_attr = $attr_wave_name
pvPutNumber /Q chid, w_attr[0]
result = 0
break
case 2: // text
wave /t wt_attr = $attr_wave_name
pvPutString /Q chid, wt_attr[0]
result = 0
break
default: // error
result = -1
endswitch
pvClose chid
return result
end
function pearl_set_sscan(scan_rec_num)
variable scan_rec_num
string chan_base = "X03DA-PC:scan" + num2str(scan_rec_num) + ":"
string wave_base = "Scan" + num2str(scan_rec_num)
variable nfields
variable ifield
string wave_name
string chan_name
wave /z w_active = $(wave_base + "Active")
if (WaveExists(w_active))
if (w_active[0] != 0)
nfields = 4
for (ifield = 1; ifield <= nfields; ifield += 1)
sscanf wave_name, "%sPositioner%u", ifield
sscanf chan_name, "%sP%uPV", chan_base, ifield
pearl_set_attr_ch(wave_name, chan_name)
sscanf wave_name, "%sReadback%u", ifield
sscanf chan_name, "%sR%uPV", chan_base, ifield
pearl_set_attr_ch(wave_name, chan_name)
sscanf wave_name, "%sTrigger%u", ifield
sscanf chan_name, "%sT%uPV", chan_base, ifield
pearl_set_attr_ch(wave_name, chan_name)
endfor
nfields = 20
for (ifield = 1; ifield <= nfields; ifield += 1)
sscanf wave_name, "%sDetector%u", ifield
sscanf chan_name, "%sD%uPV", chan_base, ifield
pearl_set_attr_ch(wave_name, chan_name)
endfor
endif
endif
end
function pearl_repeat_scan()
// set up a scan according to the attributes of the given dataset
dfref savedf = GetDataFolderDFR()
setdatafolder :attr
setdatafolder savedf
end

90
pearl/pearl-arpes.ipf Normal file
View File

@ -0,0 +1,90 @@
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
#pragma IgorVersion = 6.1
#pragma ModuleName = PearlArpes
#pragma version = 1.04
#include "pearl-area-display" // 2D and 3D data visualization
#include "pearl-area-profiles" // data processing for multi-dimensional datasets
#include "pearl-area-import" // import data files generated by area detector software
#include "pearl-data-explorer" // preview and import panel for PEARL data
#include "pearl-anglescan-process"
#include "pearl-anglescan-tracker" // live preview of hemispherical angle scan
#include "pearl-scienta-preprocess" // pre-processing functions for Scienta detector images
#include "pearl-elog"
#if exists("pvOpen")
#include "pearl-area-live" // live view of area detector
#include "pearl-epics" // EPICS access under Igor
#include "pearl-arpes-scans" // run ARPES scans under Igor
#endif
// $Id$
//
// author: matthias.muntwiler@psi.ch
// Copyright (c) 2012-15 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 acquisition and analysis package for ARPES at PEARL.
///
/// this procedure defines the PEARL ARPES package
/// the main purpose of this file is to load the necessary dependent procedures
/// (see the include statements at the top)
///
/// @pre
/// * HDF5 XOP must be loaded.
/// * on-line data acquisition functionality requires the EPICS XOP to be loaded
///
/// @author matthias muntwiler, matthias.muntwiler@psi.ch
///
/// @copyright 2012-15 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 PearlArpes
/// @brief data acquisition and analysis package for ARPES at PEARL.
///
/// PearlArpes is declared in @ref pearl-arpes.ipf.
///
/// @defgroup ArpesPackage ARPES package
/// @brief data acquisition and analysis package for ARPES at PEARL.
///
/// The purpose of a package is to load a bunch of dependent procedure files.
/// The ARPES package loads the following files
/// which are helpful when working with ARPES data
/// (any data from the Scienta analyser, that is) from PEARL.
///
/// * pearl-area-import.ipf
/// * pearl-area-display.ipf
/// * pearl-area-profiles.ipf
/// * pearl-data-explorer.ipf
/// * pearl-scienta-preprocess.ipf
/// * pearl-anglescan-process.ipf
/// * pearl-anglescan-tracker.ipf
/// * pearl-elog.ipf
///
/// Most of these files require the HDF5.XOP.
/// The following files are loaded if the EPICS.XOP is present:
///
/// * pearl-area-live.ipf
/// * pearl-epics.ipf
/// * pearl-arpes-scans.ipf
///
/// initializes package data once when the procedure is first loaded
static function AfterCompiledHook()
dfref savefolder = GetDataFolderDFR()
return 0
end
function UnloadPearlArpesPackage()
execute /p/q/z "DELETEINCLUDE \"pearl-arpes\""
execute /p/q/z "COMPILEPROCEDURES "
end

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,28 @@
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
function export_otf()
// export OTF folders to text files
string objname
variable index= 0
setdatafolder root:
dfref parentfolder = getdatafolderdfr()
string filename
do
objname = GetindexedObjNameDFR(parentfolder, 4, index)
if (strlen(objname) > 0)
if (cmpstr(StringFromList(0, objname, "_"), "otf") == 0)
setdatafolder parentfolder
setdatafolder $objname
wave ringcurrent,photonenergy,current_ch1,current_ch2
filename = objname + ".txt"
Save/G/M="\r\n"/W/P=pearl_explorer_filepath photonenergy,current_ch1,current_ch2,ringcurrent as filename
endif
index += 1
else
break
endif
while(1)
end

1261
pearl/pearl-elog.ipf Normal file

File diff suppressed because it is too large Load Diff

715
pearl/pearl-fitfuncs.ipf Normal file
View File

@ -0,0 +1,715 @@
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
#pragma IgorVersion = 6.2
#pragma ModuleName = PearlFitFuncs
#pragma version = 1.01
// various fit functions for photoelectron spectroscopy
// $Id$
// author: matthias.muntwiler@psi.ch
// Copyright (c) 2013-14 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
//------------------------------------------------------------------------------
// Doniach-Sunjic fit functions
//------------------------------------------------------------------------------
threadsafe function DoniachSunjic(x, amp, pos, sing, fwhm)
// Doniach-Sunjic line shape
// [S. Doniach, M. Sunjic, J. Phys. C 3 (1970) 285]
variable x // independent variable
variable amp // amplitude
variable pos // position
variable sing // singularity index (0 <= sing < 1)
variable fwhm // width
variable nom, denom
nom = cos(pi * sing / 2 + (1 - sing) * atan((x - pos) / fwhm * 2))
denom = ((x - pos)^2 + fwhm^2 / 4)^((1 - sing) / 2)
return amp * nom / denom * fwhm / 2
end
threadsafe function ds1_bg(w, x): FitFunc
// Doniach-Sunjic fit function
// 0 <= sing < 1
wave w // coefficients - see below
variable x // independent variable
//CurveFitDialog/ These comments were created by the Curve Fitting dialog. Altering them will
//CurveFitDialog/ make the function less convenient to work with in the Curve Fitting dialog.
//CurveFitDialog/ Equation:
//CurveFitDialog/ f(x) = DoniachSunjic(x, amp, pos, sing, fwhm) + bg
//CurveFitDialog/ End of Equation
//CurveFitDialog/ Independent Variables 1
//CurveFitDialog/ x
//CurveFitDialog/ Coefficients 5
//CurveFitDialog/ w[0] = bg
//CurveFitDialog/ w[1] = amp
//CurveFitDialog/ w[2] = pos
//CurveFitDialog/ w[3] = sing
//CurveFitDialog/ w[4] = FWHM
return DoniachSunjic(x, w[1], w[2], w[3], w[4]) + w[0]
end
threadsafe function ds2_bg(w,x) : FitFunc
Wave w
Variable x
//CurveFitDialog/ These comments were created by the Curve Fitting dialog. Altering them will
//CurveFitDialog/ make the function less convenient to work with in the Curve Fitting dialog.
//CurveFitDialog/ Equation:
//CurveFitDialog/ f(x) = w_0+( w_1*cos(pi*w_3/2+(1-w_3)*atan((x-w_2)/w_4)))/(((x-w_2)^2+w_4^2)^((1-w_3)/2)) +(w_5*cos(pi*w_7/2+(1-w_7)*atan((x-(w_6))/w_8)))/(((x-w_6)^2+w_8^2)^((1-w_7)/2))
//CurveFitDialog/ End of Equation
//CurveFitDialog/ Independent Variables 1
//CurveFitDialog/ x
//CurveFitDialog/ Coefficients 9
//CurveFitDialog/ w[0] = bg
//CurveFitDialog/ w[1] = amp1
//CurveFitDialog/ w[2] = pos1
//CurveFitDialog/ w[3] = sing1
//CurveFitDialog/ w[4] = wid1
//CurveFitDialog/ w[5] = amp2
//CurveFitDialog/ w[6] = pos2
//CurveFitDialog/ w[7] = sing2
//CurveFitDialog/ w[8] = wid2
variable ds1 = DoniachSunjic(x, w[1], w[2], w[3], w[4])
variable ds2 = DoniachSunjic(x, w[5], w[6], w[7], w[8])
return w[0] + ds1 + ds2
End
Function ds4_bg(w,x) : FitFunc
Wave w
Variable x
//CurveFitDialog/ These comments were created by the Curve Fitting dialog. Altering them will
//CurveFitDialog/ make the function less convenient to work with in the Curve Fitting dialog.
//CurveFitDialog/ Equation:
//CurveFitDialog/ f(x) = w_0+( w_1*cos(pi*w_3/2+(1-w_3)*atan((x-w_2)/w_4)))/(((x-w_2)^2+w_4^2)^((1-w_3)/2)) +(w_5*cos(pi*w_7/2+(1-w_7)*atan((x-(w_6))/w_8)))/(((x-w_6)^2+w_8^2)^((1-w_7)/2)) +( w_9*cos(pi*w_11/2+(1-w_11)*atan((x-w_10)/w_12)))/(((x-w_10)^2+w_12^2)^((1-w_11)/2)) +( w_13*cos(pi*w_15/2+(1-w_15)*atan((x-w_14)/w_16)))/(((x-w_14)^2+w_16^2)^((1-w_15)/2))
//CurveFitDialog/ End of Equation
//CurveFitDialog/ Independent Variables 1
//CurveFitDialog/ x
//CurveFitDialog/ Coefficients 17
//CurveFitDialog/ w[0] = w_0
//CurveFitDialog/ w[1] = w_11
//CurveFitDialog/ w[2] = w_12
//CurveFitDialog/ w[3] = w_13
//CurveFitDialog/ w[4] = w_14
//CurveFitDialog/ w[5] = w_21
//CurveFitDialog/ w[6] = w_22
//CurveFitDialog/ w[7] = w_23
//CurveFitDialog/ w[8] = w_24
//CurveFitDialog/ w[9] = w_31
//CurveFitDialog/ w[10] = w_32
//CurveFitDialog/ w[11] = w_33
//CurveFitDialog/ w[12] = w_34
//CurveFitDialog/ w[13] = w_41
//CurveFitDialog/ w[14] = w_42
//CurveFitDialog/ w[15] = w_43
//CurveFitDialog/ w[16] = w_44
Variable ds1, ds2, ds3, ds4
ds1=( w[1]*cos(pi*w[3]/2+(1-w[3])*atan((x-w[2])/w[4])))/(((x-w[2])^2+w[4]^2)^((1-w[3])/2))
ds2=( w[5]*cos(pi*w[7]/2+(1-w[7])*atan((x-w[6])/w[8])))/(((x-w[6])^2+w[8]^2)^((1-w[7])/2))
ds3=( w[9]*cos(pi*w[11]/2+(1-w[11])*atan((x-w[10])/w[12])))/(((x-w[10])^2+w[12]^2)^((1-w[11])/2))
ds4=( w[13]*cos(pi*w[15]/2+(1-w[15])*atan((x-w[14])/w[16])))/(((x-w[14])^2+w[16]^2)^((1-w[15])/2))
return w[0]+ds1+ds2+ds3+ds4
End
Function ds6_bg(w,x) : FitFunc
Wave w
Variable x
//CurveFitDialog/ These comments were created by the Curve Fitting dialog. Altering them will
//CurveFitDialog/ make the function less convenient to work with in the Curve Fitting dialog.
//CurveFitDialog/ Equation:
//CurveFitDialog/
//CurveFitDialog/ Variable g, ds1, ds2, ds3, ds4, ds5, ds6
//CurveFitDialog/ ds1=( w_11*cos(pi*w_13/2+(1-w_13)*atan((x-w_12)/w_14)))/(((x-w_12)^2+w_14^2)^((1-w_13)/2))
//CurveFitDialog/ ds2=( w_21*cos(pi*w_23/2+(1-w_23)*atan((x-w_22)/w_24)))/(((x-w_22)^2+w_24^2)^((1-w_23)/2))
//CurveFitDialog/ ds3=( w_31*cos(pi*w_33/2+(1-w_33)*atan((x-w_32)/w_34)))/(((x-w_32)^2+w_34^2)^((1-w_33)/2))
//CurveFitDialog/ ds4=( w_41*cos(pi*w_43/2+(1-w_43)*atan((x-w_42)/w_44)))/(((x-w_42)^2+w_44^2)^((1-w_43)/2))
//CurveFitDialog/ ds5=( w_51*cos(pi*w_53/2+(1-w_53)*atan((x-w_52)/w_54)))/(((x-w_52)^2+w_54^2)^((1-w_53)/2))
//CurveFitDialog/ ds6=( w_61*cos(pi*w_63/2+(1-w_63)*atan((x-w_62)/w_64)))/(((x-w_62)^2+w_64^2)^((1-w_63)/2))
//CurveFitDialog/
//CurveFitDialog/ f(x) =w_0+ds1+ds2+ds3+ds4+ds5+ds6
//CurveFitDialog/
//CurveFitDialog/ End of Equation
//CurveFitDialog/ Independent Variables 1
//CurveFitDialog/ x
//CurveFitDialog/ Coefficients 25
//CurveFitDialog/ w[0] = w_0
//CurveFitDialog/ w[1] = w_11
//CurveFitDialog/ w[2] = w_12
//CurveFitDialog/ w[3] = w_13
//CurveFitDialog/ w[4] = w_14
//CurveFitDialog/ w[5] = w_21
//CurveFitDialog/ w[6] = w_22
//CurveFitDialog/ w[7] = w_23
//CurveFitDialog/ w[8] = w_24
//CurveFitDialog/ w[9] = w_31
//CurveFitDialog/ w[10] = w_32
//CurveFitDialog/ w[11] = w_33
//CurveFitDialog/ w[12] = w_34
//CurveFitDialog/ w[13] = w_41
//CurveFitDialog/ w[14] = w_42
//CurveFitDialog/ w[15] = w_43
//CurveFitDialog/ w[16] = w_44
//CurveFitDialog/ w[17] = w_51
//CurveFitDialog/ w[18] = w_52
//CurveFitDialog/ w[19] = w_53
//CurveFitDialog/ w[20] = w_54
//CurveFitDialog/ w[21] = w_61
//CurveFitDialog/ w[22] = w_62
//CurveFitDialog/ w[23] = w_63
//CurveFitDialog/ w[24] = w_64
Variable ds1, ds2, ds3, ds4, ds5, ds6
ds1=( w[1]*cos(pi*w[3]/2+(1-w[3])*atan((x-w[2])/w[4])))/(((x-w[2])^2+w[4]^2)^((1-w[3])/2))
ds2=( w[5]*cos(pi*w[7]/2+(1-w[7])*atan((x-w[6])/w[8])))/(((x-w[6])^2+w[8]^2)^((1-w[7])/2))
ds3=( w[9]*cos(pi*w[11]/2+(1-w[11])*atan((x-w[10])/w[12])))/(((x-w[10])^2+w[12]^2)^((1-w[11])/2))
ds4=( w[13]*cos(pi*w[15]/2+(1-w[15])*atan((x-w[14])/w[16])))/(((x-w[14])^2+w[16]^2)^((1-w[15])/2))
ds5=( w[17]*cos(pi*w[19]/2+(1-w[19])*atan((x-w[18])/w[20])))/(((x-w[18])^2+w[20]^2)^((1-w[19])/2))
ds6=( w[21]*cos(pi*w[23]/2+(1-w[23])*atan((x-w[22])/w[24])))/(((x-w[22])^2+w[24]^2)^((1-w[23])/2))
return w[0]+ds1+ds2+ds3+ds4+ds5+ds6
End
structure DoniachSunjicStruct
// data structure for DoniachSunjicBroadS structural function fit
// waves populated by the FuncFit operation
wave pw
wave yw
wave xw
// convolution parameters to be set upon creation of the structure
variable precision
variable oversampling
// auxiliary fields used internally by DoniachSunjicBroadS
// do not touch these
wave xdw
wave model
wave broadening
wave convolution
EndStructure
//------------------------------------------------------------------------------
threadsafe function DoniachSunjicBroadS(s) : FitFunc
//------------------------------------------------------------------------------
// Two-peak (bulk + surface) Doniach-Sunjic line shape with Gaussian broadening (convolution).
// Hold parameter 5 at 0 to fit just one peak.
// Structural fit function for efficient fitting in procedures.
// Calculating the convolution requires auxiliary waves and additional, non-fitting parameters.
// To eliminate the time-consuming overhead of creating and killing the auxiliary waves,
// these waves are held in the fitting structure.
// Caution: The function on its own is thread-safe.
// However, since FuncFit uses the same structure in all threads, the fitting cannot run in parallel.
// Set /NTHR=1.
// See also Fit_DoniachSunjicBroad (example), DoniachSunjicBroad (conventional fit function)
Struct DoniachSunjicStruct &s
// pw[0] = bulk amplitude
// pw[1] = bulk position
// pw[2] = Lorentzian FWHM
// pw[3] = Donjach-Sunjic singularity index (0..1)
// pw[4] = surface shift
// pw[5] = surface/bulk ratio
// pw[6] = Gaussian FWHM
// pw[7] = constant background
// pw[8] = linear background
wave xw = s.xw
wave yw = s.yw
wave pw = s.pw
variable precision = s.precision
variable oversampling = s.oversampling
if (WaveExists(s.xdw))
wave xdw = s.xdw
wave model = s.model
wave broadening = s.broadening
wave convolution = s.convolution
else
make /n=0 /free xdw, model, broadening, convolution
redimension /d xdw, model, broadening, convolution
wave fs.xdw = xdw
wave fs.model = model
wave fs.broadening = broadening
wave fs.convolution = convolution
endif
// calculate wave spacing based on minimum spacing of desired x points
differentiate /p xw /d=xdw
xdw = abs(xdw)
variable xd = wavemin(xdw) / oversampling
// calculate broadening wave size based on width and precision variable
variable x0b = pw[6] * precision
variable nb = 2 * floor(x0b / xd) + 1
// calculate model size based on desired range for yw
variable x0m = max(abs(wavemax(xw) - pw[1]), abs(wavemin(xw) - pw[1])) + x0b
variable nm = 2 * floor(x0m / xd) + 1
nb = min(nb, nm * 10) // limit wave size to avoid runtime errors for unphysically large parameter
// create and calculate initial waves, normalize exponential
redimension /n=(nb) broadening
redimension /n=(nm) model
setscale/i x -x0b, x0b, "", broadening
setscale/i x -x0m, x0m, "", model
broadening = exp( - (x / pw[6])^2 * 4 * ln(2))
variable nrm = area(broadening)
broadening /= nrm
model = DoniachSunjic(x, 1, 0, pw[3], pw[2]) // bulk
model += DoniachSunjic(x, pw[5], pw[4], pw[3], pw[2]) // surface
// calculate the convolution
Convolve /a broadening, model
variable scale = pw[0] / wavemax(model)
model *= scale
// prepare output
nm = numpnts(model)
x0m = xd * (nm - 1) / 2
setscale/i x -x0m, x0m, "", model
yw = model(xw[p] - pw[1]) + pw[7] + pw[8] * xw[p]
yw = numtype(yw) ? 0 : yw
end
//------------------------------------------------------------------------------
function DoniachSunjicBroad(pw, yw, xw) : FitFunc
//------------------------------------------------------------------------------
// Two-peak (bulk + surface) Doniach-Sunjic line shape with Gaussian broadening (convolution).
// Hold parameter 5 at 0 to fit just one peak.
// Conventional fit function for use with the curve-fitting dialog.
// Compared to DoniachSunjicBroadS this function incurs extra overhead
// because auxiliary waves are created and killed between function calls.
// See also DoniachSunjicBroadS (optimized structural fit function)
Wave pw
Wave yw
Wave xw
// pw[0] = bulk amplitude
// pw[1] = bulk position
// pw[2] = Lorentzian FWHM
// pw[3] = Donjach-Sunjic singularity index (0..1)
// pw[4] = surface shift
// pw[5] = surface/bulk ratio
// pw[6] = Gaussian FWHM
// pw[7] = constant background
// pw[8] = linear background
// set up data structure
struct DoniachSunjicStruct fs
fs.precision = 5
fs.oversampling = 4
wave fs.pw = pw
wave fs.xw = xw
wave fs.yw = yw
// create temporary calculation waves in a global folder
dfref df = root:packages:pearl_fitfuncs:doniach_sunjic
if (DataFolderRefStatus(df) == 0)
newdatafolder root:packages:pearl_fitfuncs:doniach_sunjic
dfref df = root:packages:pearl_fitfuncs:doniach_sunjic
endif
wave /z /sdfr=df fs.xdw = xdw
wave /z /sdfr=df fs.model = model
wave /z /sdfr=df fs.broadening = broadening
wave /z /sdfr=df fs.convolution = convolution
if (WaveExists(fs.xdw) == 0)
dfref savedf = GetDataFolderDFR()
setdatafolder df
make /n=0 /d xdw, model, broadening, convolution
wave fs.xdw = xdw
wave fs.model = model
wave fs.broadening = broadening
wave fs.convolution = convolution
setdatafolder savedf
endif
// calculate
DoniachSunjicBroadS(fs)
yw = fs.yw
end
//------------------------------------------------------------------------------
function Calc_DoniachSunjicBroad(pw, yw)
//------------------------------------------------------------------------------
// Calculate the DoniachSunjicBroadS line shape
Wave pw // coefficient wave
Wave yw // output wave, correct x-scaling required on input
struct DoniachSunjicStruct fs
fs.precision = 5
fs.oversampling = 4
duplicate /free pw, fs.pw
duplicate /free yw, fs.xw
fs.xw = x
duplicate /free yw, fs.yw
DoniachSunjicBroadS(fs)
yw = fs.yw
end
//------------------------------------------------------------------------------
Function Fit_DoniachSunjicBroad(pw, yw, xw, ww)
//------------------------------------------------------------------------------
// Fit the DoniachSunjicBroadS line shape.
// The function applies constraints which assume that the energy scale is in eV.
// Returns chi^2.
wave pw // coefficient wave- pre-load it with initial guess
wave yw
wave /z xw
wave /z ww // weights (standard deviation)
struct DoniachSunjicStruct fs
fs.precision = 5
fs.oversampling = 4
duplicate /free pw, fs.pw
if (WaveExists(xw))
duplicate /free xw, fs.xw
else
duplicate /free yw, fs.xw
fs.xw = x
endif
duplicate /free yw, fs.yw
variable v_chisq = nan
variable V_FitMaxIters = 100
make /n=1 /t /free constraints = {"K0 >= 0", "K2 > 0", "K2 < 10", "K3 >= 0", "K3 < 1", "K4 >= -10", "K4 <= 10", "K5 >= 0", "K5 <= 1", "K6 >= 0", "K6 < 10"}
// note: only single thread allowed
FuncFit /NTHR=1 DoniachSunjicBroadS, pw, yw /X=xw /D /STRC=fs /C=constraints /NWOK /I=1 /W=ww
return v_chisq
End
//------------------------------------------------------------------------------
// peak-specific fit functions
//------------------------------------------------------------------------------
function Au4f(w, x): fitfunc
// fit function for a nitrogen 1s-pi* absorption spectrum
// modelled as multiple Voigt shapes on a constant background
// similar to the Igor VoigtFit function
// but with a constant gaussian width (instrumental broadening) for all peaks
// gaussian and lorentzian widths are specified as FWHM
wave w // parameters
// w[0] constant background
// w[1] linear background
// w[2] global gaussian FWHM
// w[3 + 0 + (n-1) * 3] peak n area
// w[3 + 1 + (n-1) * 3] peak n position
// w[3 + 2 + (n-1) * 3] peak n lorentzian FWHM
// length of wave defines number of peaks
// for compatibility with older code the linear background term can be omitted.
// if the number of parameters divides by 3, the linear background term is added,
// otherwise only the constant background.
variable x
variable np = 15
variable ip, ip0
variable bg = w[0]
variable v = bg
if (mod(np, 3) == 0)
v += w[1] * x
ip0 = 3
else
ip0 = 2
endif
variable vc1, vc2, vc3, vc4
vc2 = 2 * sqrt(ln(2)) / w[ip0-1]
for (ip = ip0; ip < np; ip += 3)
vc1 = w[ip] / sqrt(pi) * vc2
vc3 = w[ip+1]
vc4 = vc2 * w[ip+2] / 2
v += vc1 * Voigt(vc2 * (x - vc3), vc4)
endfor
return v
end
function Au4f_2p2(w, x): fitfunc
// Au 4f 5/2 and 7/2 2-component Voigt fit with a common gaussian width
// gaussian and lorentzian widths are specified as FWHM
wave w // parameters
// w[0] constant background
// w[1] linear background
// w[2] global gaussian FWHM
// w[3] 5/2 bulk area
// w[4] 5/2 bulk position
// w[5] 5/2 lorentzian FWHM
// w[6] 7/2 bulk area
// w[7] 7/2 bulk position
// w[8] 7/2 lorentzian FWHM
// w[9] surface/bulk area ratio
// w[10] surface core level shift
variable x
variable bg = w[0] + w[1] * x
variable v = bg
variable vc1 // amplitude
variable vc2 // width
variable vc3 // position
variable vc4 // shape
vc2 = 2 * sqrt(ln(2)) / w[2]
// 5/2 bulk
vc1 = w[3] / sqrt(pi) * vc2
vc3 = w[4]
vc4 = vc2 * w[5] / 2
v += vc1 * Voigt(vc2 * (x - vc3), vc4)
// 5/2 surface
vc1 = w[3] / sqrt(pi) * vc2 * w[9]
vc3 = w[4] + w[10]
vc4 = vc2 * w[5] / 2
v += vc1 * Voigt(vc2 * (x - vc3), vc4)
// 7/2 bulk
vc1 = w[6] / sqrt(pi) * vc2
vc3 = w[7]
vc4 = vc2 * w[8] / 2
v += vc1 * Voigt(vc2 * (x - vc3), vc4)
// 7/2 surface
vc1 = w[6] / sqrt(pi) * vc2 * w[9]
vc3 = w[7] + w[10]
vc4 = vc2 * w[8] / 2
v += vc1 * Voigt(vc2 * (x - vc3), vc4)
return v
end
function ShowComponents_Au4f_2p2(coef_wave, fit_wave)
wave coef_wave
wave fit_wave
duplicate /free coef_wave, coef1, coef2
coef1[9] = 0
coef2[3] *= coef_wave[9]
coef2[4] += coef_wave[10]
coef2[6] *= coef_wave[9]
coef2[7] += coef_wave[10]
coef2[9] = 0
string s_fit_wave = NameOfWave(fit_wave)
string s_fit_p1 = s_fit_wave + "_p1"
string s_fit_p2 = s_fit_wave + "_p2"
duplicate /o fit_wave, $(s_fit_p1) /wave=fit_p1
duplicate /o fit_wave, $(s_fit_p2) /wave=fit_p2
fit_p1 = Au4f_2p2(coef1, x)
fit_p2 = Au4f_2p2(coef2, x)
string traces = TraceNameList("", ";", 1)
if ((WhichListItem(s_fit_wave, traces, ";") >= 0) && (WhichListItem(s_fit_p1, traces, ";") < 0))
appendtograph fit_p1, fit_p2
ModifyGraph lstyle($s_fit_p1)=2
ModifyGraph lstyle($s_fit_p2)=2
ModifyGraph rgb($s_fit_p1)=(0,0,65280)
ModifyGraph rgb($s_fit_p2)=(0,0,65280)
endif
end
function Au4f_2p3(w, x): fitfunc
// Au 4f 5/2 and 7/2 3-component Voigt fit with a common gaussian width
// gaussian and lorentzian widths are specified as FWHM
wave w // parameters
// w[0] constant background
// w[1] linear background
// w[2] global gaussian FWHM
// w[3] 5/2 bulk area
// w[4] 5/2 bulk position
// w[5] 5/2 lorentzian FWHM
// w[6] 7/2 bulk area
// w[7] 7/2 bulk position
// w[8] 7/2 lorentzian FWHM
// w[9] surface/bulk area ratio
// w[10] surface core level shift
// w[11] 2nd layer/bulk area ratio
// w[12] 2nd layer core level shift
variable x
variable bg = w[0] + w[1] * x
variable v = bg
variable vc1 // amplitude
variable vc2 // width
variable vc3 // position
variable vc4 // shape
vc2 = 2 * sqrt(ln(2)) / w[2]
// 5/2 bulk
vc1 = w[3] / sqrt(pi) * vc2
vc3 = w[4]
vc4 = vc2 * w[5] / 2
v += vc1 * Voigt(vc2 * (x - vc3), vc4)
// 5/2 surface
vc1 = w[3] / sqrt(pi) * vc2 * w[9]
vc3 = w[4] + w[10]
vc4 = vc2 * w[5] / 2
v += vc1 * Voigt(vc2 * (x - vc3), vc4)
// 5/2 2nd layer
vc1 = w[3] / sqrt(pi) * vc2 * w[11]
vc3 = w[4] + w[12]
vc4 = vc2 * w[5] / 2
v += vc1 * Voigt(vc2 * (x - vc3), vc4)
// 7/2 bulk
vc1 = w[6] / sqrt(pi) * vc2
vc3 = w[7]
vc4 = vc2 * w[8] / 2
v += vc1 * Voigt(vc2 * (x - vc3), vc4)
// 7/2 surface
vc1 = w[6] / sqrt(pi) * vc2 * w[9]
vc3 = w[7] + w[10]
vc4 = vc2 * w[8] / 2
v += vc1 * Voigt(vc2 * (x - vc3), vc4)
// 7/2 2nd layer
vc1 = w[6] / sqrt(pi) * vc2 * w[11]
vc3 = w[7] + w[12]
vc4 = vc2 * w[8] / 2
v += vc1 * Voigt(vc2 * (x - vc3), vc4)
return v
end
function ShowComponents_Au4f_2p3(coef_wave, fit_wave)
wave coef_wave
wave fit_wave
duplicate /free coef_wave, coef1, coef2, coef3
coef1[9] = 0
coef1[11] = 0
coef2[3] *= coef_wave[9]
coef2[4] += coef_wave[10]
coef2[6] *= coef_wave[9]
coef2[7] += coef_wave[10]
coef2[9] = 0
coef2[11] = 0
coef3[3] *= coef_wave[11]
coef3[4] += coef_wave[12]
coef3[6] *= coef_wave[11]
coef3[7] += coef_wave[12]
coef3[9] = 0
coef3[11] = 0
string s_fit_wave = NameOfWave(fit_wave)
string s_fit_p1 = s_fit_wave + "_p1"
string s_fit_p2 = s_fit_wave + "_p2"
string s_fit_p3 = s_fit_wave + "_p3"
duplicate /o fit_wave, $(s_fit_p1) /wave=fit_p1
duplicate /o fit_wave, $(s_fit_p2) /wave=fit_p2
duplicate /o fit_wave, $(s_fit_p3) /wave=fit_p3
fit_p1 = Au4f_2p2(coef1, x)
fit_p2 = Au4f_2p2(coef2, x)
fit_p3 = Au4f_2p2(coef3, x)
string traces = TraceNameList("", ";", 1)
if ((WhichListItem(s_fit_wave, traces, ";") >= 0) && (WhichListItem(s_fit_p1, traces, ";") < 0))
appendtograph fit_p1, fit_p2, fit_p3
ModifyGraph lstyle($s_fit_p1)=2
ModifyGraph lstyle($s_fit_p2)=2
ModifyGraph lstyle($s_fit_p3)=2
ModifyGraph rgb($s_fit_p1)=(0,0,65280)
ModifyGraph rgb($s_fit_p2)=(0,0,65280)
ModifyGraph rgb($s_fit_p3)=(0,0,65280)
endif
end
/// convolution of Fermi-Dirac distribution and a Gaussian.
///
/// @arg pw[0] = constant background
/// @arg pw[1] = linear background
/// @arg pw[2] = amplitude
/// @arg pw[3] = Fermi level in eV
/// @arg pw[4] = temperature in K
/// @arg pw[5] = gaussian width = FWHM / 1.66511
///
function FermiGaussConv(pw, yw, xw) : FitFunc
WAVE pw, yw, xw
// half width of temporary gaussian wave is pw[5] multiplied by this factor (may be fractional)
variable precision_g = 5
variable oversampling = 4
// calculate wave spacing based on minimum spacing of desired x points
duplicate /free xw, xdw
differentiate /p xw /d=xdw
xdw = abs(xdw)
variable xd = wavemin(xdw) / oversampling
// calculate gausswave size based on pw[5] and precision variable
variable x0g = pw[5] * precision_g
variable ng = 2 * floor(x0g / xd) + 1
// calculate fermiwave size based on desired range for yw
variable emax = wavemax(xw)
variable emin = wavemin(xw)
variable x0f = max(abs(emax - pw[3]), abs(emin - pw[3])) + x0g
variable ne = 2 * floor(x0f / xd) + 1
// create and calculate initial waves, normalize exponential
make /d /n=(ng) /free gausswave
make /d /n=(ne) /free fermiwave
setscale/i x -x0g, x0g, "", gausswave
setscale/i x -x0f, x0f, "", fermiwave
gausswave = exp( - (x / pw[5] )^2 )
fermiwave = 1 / (exp( x / (kBoltzmann * pw[4])) + 1.0 )
// calculate the convolution
duplicate /free fermiwave, resultwave
Convolve /a gausswave, resultwave
variable rmax = wavemax(resultwave)
resultwave /= rmax
// prepare output
ng = numpnts(resultwave)
x0g = xd * (ng - 1) / 2
setscale/i x -x0g, x0g, "", resultwave
yw = pw[2] * resultwave(xw[p] - pw[3]) + pw[0] + pw[1] * xw[p]
end

52
pearl/pearl-gui-tools.ipf Normal file
View File

@ -0,0 +1,52 @@
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
#pragma IgorVersion = 6.1
#pragma ModuleName = PearlGuiTools
#pragma version = 1.01
// Miscellaneous GUI tools
// * progress bar
// created: matthias.muntwiler@psi.ch, 2013-11-14
// Copyright (c) 2013 Paul Scherrer Institut
// $Id$
// 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
function display_progress_panel(title, message, progress_max)
string title
string message
variable progress_max
NewPanel /K=1 /N=ProgressPanel /W=(200,200,402,260) as title
TitleBox t_message,pos={2,2},size={189,13},title=message
TitleBox t_message,frame=0
ValDisplay vd_progress,pos={2,20},size={198,13}
ValDisplay vd_progress,limits={0,progress_max,0},barmisc={0,0},mode= 3,value= _NUM:0
Button b_abort,pos={74,38},size={50,20},title="Abort"
DoUpdate /W=ProgressPanel /E=1
end
function update_progress_panel(progress, [message, progress_max])
// returns true if the user clicked the Abort button
variable progress
string message
variable progress_max
if (!ParamIsDefault(message))
TitleBox t_message,title=message,win=ProgressPanel
endif
if (ParamIsDefault(progress_max))
ValDisplay vd_progress,value=_NUM:progress,win=ProgressPanel
else
ValDisplay vd_progress,limits={0,progress_max,0},value=_NUM:progress,win=ProgressPanel
endif
DoUpdate /W=ProgressPanel
return (v_flag == 2)
end
function kill_progress_panel()
KillWindow ProgressPanel
end

194
pearl/pearl-menu.ipf Normal file
View File

@ -0,0 +1,194 @@
#pragma rtGlobals=1 // Use modern global access method.
#pragma ModuleName = PearlMenu
#pragma version = 1.01
// main menu for PEARL data acquisition and analysis packages
// $Id$
// author: matthias.muntwiler@psi.ch
// Copyright (c) 2013-14 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
menu "PEARL"
submenu "Data Files"
PearlMenuEnableFunc("pearl_data_explorer") + "Data Explorer", /Q, pearl_data_explorer()
help = {"Data explorer panel with file import and preview", "Requires ARPES package and HDF5 XOP"}
PearlMenuEnableFunc("ad_load_dialog") + "AD HDF5", /Q, ad_load_dialog("")
help = {"Import area detector HDF5 data file", "Requires ARPES package and HDF5 XOP"}
end
submenu "On-the-Fly Data"
PearlMenuEnableFunc("otf_rename_folders") + "Shorten OTF Folder Names", /Q, otf_rename_folders("010")
help = {"Renames otf_xxxxxx_yyyyyy_zzzz data folders to otf_yyyyyy (removing date and suffix)", "Requires Optics package"}
PearlMenuEnableFunc("otf_gather_batch") + "Gather OTF Batch", /Q, otf_gather_batch("current_ch1", "photonenergy", "otf_batch")
help = {"Copies data from all otf_* folders into otf_batch folder", "Requires Optics package"}
PearlMenuEnableFunc("PearlOpticsPreviewPanel") + "OTF Preview", /Q, PearlOpticsPreviewPanel()
help = {"Opens a preview panel for OTF data in otf_* folders", "Requires Optics package"}
end
submenu "Scienta Analyser"
PearlMenuEnableFunc("ad_display_profiles") + "Scienta Live View", /Q, PearlLiveDisplay("X03DA-SCIENTA:", "EA", "(65280,54528,48896)")
help = {"Display preview panel with latest image from Scienta", "Requires ARPES package and EPICS XOP"}
PearlMenuEnableFunc("ast_setup") + "Angle Scan Tracker", /Q, PearlAnglescanTracker("X03DA-SCIENTA:", "(65280,54528,48896)")
help = {"Preview of acquired angle scan data and current detection angles.", "Requires ARPES package and EPICS XOP"}
end
submenu "Cameras"
PearlMenuEnableFunc("ad_display_profiles") + "Exit Slit Live View", /Q, PearlLiveDisplay("X03DA-OP-PS1:", "OP", "(65280,54528,48896)")
help = {"Display preview panel with latest image from Scienta", "Requires ARPES package and EPICS XOP"}
PearlMenuEnableFunc("ad_display_profiles") + "Manipulator Live View", /Q, PearlLiveDisplay("X03DA-ES-PS1:", "ES", "(65280,54528,48896)")
help = {"Display live panel of the exit slit camera", "Requires ARPES package and EPICS XOP"}
end
submenu "Display"
PearlMenuEnableFunc("ad_display_profiles") + "2D Profiles", /Q, Display2dProfiles()
help = {"Profiles display of 2D data", "Requires ARPES package"}
PearlMenuEnableFunc("ad_display_brick") + "3D Slicer", /Q, Display3dSlicer()
help = {"Slice and profiles display of 3D data", "Requires ARPES package"}
PearlMenuEnableFunc("ad_display_brick") + "3D Gizmo", /Q, DisplayGizmoSlicer()
help = {"Gizmo display of 3D data", "Requires ARPES package"}
end
submenu "Services"
PearlMenuEnableFunc("pearl_elog") + "ELOG Experiments", /Q, pearl_elog("Experiments")
help = {"Create entries in ELOG experiments logbook"}
PearlMenuEnableFunc("pearl_elog") + "ELOG Calculations", /Q, pearl_elog("Calculations")
help = {"Create entries in ELOG calculations logbook"}
end
submenu "Sample Preparation"
PearlMenuEnableFunc("ann_ramp_start") + "Annealing Ramp", /Q, panel_ramp_gen()
help = {"Sample annealing ramp generator"}
end
submenu "Packages"
"Load ARPES Package", /Q, LoadPearlArpes()
help = {"Data processing and analysis for ARPES experiments"}
"Load Preparation Package", /Q, LoadPearlPreparation()
help = {"Process control for sample preparation"}
"Load Optics Package", /Q, LoadPearlOptics()
help = {"Data processing and analysis for beamline commissioning"}
end
end
function /s PearlMenuEnableFunc(funcname)
// checks whether a function name exists
// and conditionally returns a prefix which disables the menu item
// if the function does not exist
string funcname
if (exists(funcname) >= 3)
return ""
else
return "("
endif
end
function LoadPearlOptics()
execute /p/q/z "INSERTINCLUDE \"pearl-optics\""
execute /p/q/z "COMPILEPROCEDURES "
execute /p/q/z "PearlOpticsPanel#po_InitPanel()"
execute /p/q/z "BuildMenu \"PEARL\""
end
function LoadPearlArpes()
execute /p/q/z "INSERTINCLUDE \"pearl-arpes\""
execute /p/q/z "COMPILEPROCEDURES "
execute /p/q/z "BuildMenu \"PEARL\""
end
function LoadPearlPreparation()
execute /p/q/z "INSERTINCLUDE \"pearl-preparation\""
execute /p/q/z "COMPILEPROCEDURES "
execute /p/q/z "BuildMenu \"PEARL\""
end
function Display2dProfiles()
dfref dfBefore = GetDataFolderDFR()
Execute /q/z "CreateBrowser prompt=\"Select 2D wave\", showWaves=1, showVars=0, showStrs=0"
dfref dfAfter = GetDataFolderDFR()
SetDataFolder dfBefore
SVAR list = S_BrowserList
NVAR flag = V_Flag
if ((flag != 0) && (ItemsInList(list) >= 1))
string brickname = StringFromList(0, list)
string cmd
sprintf cmd, "ad_display_profiles(%s)", brickname
execute /q/z cmd
endif
end
function Display3dSlicer()
dfref dfBefore = GetDataFolderDFR()
Execute /q/z "CreateBrowser prompt=\"Select 3D wave\", showWaves=1, showVars=0, showStrs=0"
dfref dfAfter = GetDataFolderDFR()
SetDataFolder dfBefore
SVAR list = S_BrowserList
NVAR flag = V_Flag
if ((flag != 0) && (ItemsInList(list) >= 1))
string brickname = StringFromList(0, list)
string cmd
sprintf cmd, "ad_display_slice(%s)", brickname
execute /q/z cmd
sprintf cmd, "ad_brick_slicer(%s)", brickname
execute /q/z cmd
endif
end
function DisplayGizmoSlicer()
dfref dfBefore = GetDataFolderDFR()
Execute /q/z "CreateBrowser prompt=\"Select 3D wave\", showWaves=1, showVars=0, showStrs=0"
dfref dfAfter = GetDataFolderDFR()
SetDataFolder dfBefore
SVAR list = S_BrowserList
NVAR flag = V_Flag
if ((flag != 0) && (ItemsInList(list) >= 1))
string brickname = StringFromList(0, list)
string cmd
sprintf cmd, "ad_display_brick(%s)", brickname
execute /q/z cmd
sprintf cmd, "ad_brick_slicer(%s)", brickname
execute /q/z cmd
endif
end
function PearlLiveDisplay(epicsname, nickname, wbRGB)
string epicsname // base name of the detector, e.g. X03DA-SCIENTA:
// image1: and cam1: are appended by the function
// see ad_connect
string nickname // nick name under which this detector is referred to in Igor
// must be a valid data folder name
// see ad_connect
string wbRGB // window background color, e.g. "(32768,49152,55296)"
string cmd
sprintf cmd, "ad_connect(\"%s\", \"%s\")", epicsname, nickname
execute /q/z cmd
sprintf cmd, "ad_display_profiles(root:pearl_epics:%s:image)", nickname
execute /q/z cmd
sprintf cmd, "ModifyGraph wbRGB=%s", wbRGB
execute /q/z cmd
sprintf cmd, "add_roi_controls()"
execute /q/z cmd
end
function PearlAnglescanTracker(epicsname, wbRGB)
string epicsname // base name of the detector, e.g. X03DA-SCIENTA:
// image1: and cam1: are appended by the function
// see ast_setup
string wbRGB // window background color, e.g. "(32768,49152,55296)"
string cmd
sprintf cmd, "ast_setup()"
execute /q/z cmd
sprintf cmd, "ModifyGraph wbRGB=%s", wbRGB
execute /q/z cmd
end

314
pearl/pearl-otf-import.ipf Normal file
View File

@ -0,0 +1,314 @@
#pragma rtGlobals=1 // Use modern global access method.
#pragma IgorVersion = 6.1
#pragma ModuleName = PearlOtfImport
#pragma version = 1.01
// procedures for importing on-the-fly (OTF) scans
// OTF scans are saved as ITX files
// matthias muntwiler, 2013-02-22
// $Id$
// introduction
// the latest version of the PEARL OTF server saves data in igor text (ITX)
// the files contain code which saves all data from one file into one data folder with a unique name
// multiple files can be selected in the explorer and loaded by a double click
// description
// OTF data folder names have the format otf_date_time_suffix, where only suffix is user-defined
// thus, raw data folder names are unique
// data folder names can be converted to a shorter format
// an OTF data folder contains a wave for each measured quantity (detector)
// and the IN, ID, IV, and IU waves for additional beamline parameters
// detector waves must have a wave note containing the following key=value pairs:
// PV=name of EPICS process variable
// PhysicalType=physical type of the quantity in the same way as used by pearl-optics-import
// Axis1=wave name of principal X axis
// convergence
// while the file formats may be different, data files generated by the OTF and EPICS scan tools
// shall ultimately produce the same data structures in an Igor experiment
function otf_load_itx_all(pathname)
// loads all OTF files from a given path
// this function is for older files (before 2013-03-01) which do not specify a destination data folder
// newer files can be loaded by double click from the explorer
// without the danger of overwriting data from other files
string pathname
string filename
if (strlen(pathname) <= 0)
newpath /o/q otf_load_itx
pathname = "otf_load_itx"
endif
string filelist = IndexedFile($pathname, -1, ".itx")
filelist = ListMatch(filelist, "otf*.itx", ";")
variable nfile = ItemsInList(filelist, ";")
variable ifile
for (ifile = 0; ifile < nfile; ifile += 1)
filename = StringFromList(ifile, filelist, ";")
otf_load_itx(pathname, filename)
endfor
end
function otf_load_itx_match(pathname, matchstr)
// loads all OTF files from a given path whose names match a given string
// this function is for older files (before 2013-03-01) which do not specify a destination data folder
// newer files can be loaded by double click from the explorer
// without the danger of overwriting data from other files
string pathname
string matchstr
string filename
if (strlen(pathname) <= 0)
newpath /o/q otf_load_itx
pathname = "otf_load_itx"
endif
string filelist = IndexedFile($pathname, -1, ".itx")
filelist = ListMatch(filelist, matchstr, ";")
variable nfile = ItemsInList(filelist, ";")
variable ifile
for (ifile = 0; ifile < nfile; ifile += 1)
filename = StringFromList(ifile, filelist, ";")
otf_load_itx(pathname, filename)
endfor
end
function otf_load_itx(pathname, filename)
// loads a specific OTF file
// this function is for older files (before 2013-03-01) which do not specify a destination data folder
// newer files can be loaded by double click from the explorer
// without the danger of overwriting data from other files
string pathname
string filename
dfref savedf = GetDataFolderDFR()
setdatafolder root:
newdatafolder /s/o otf_load_itx_temp
if (strlen(pathname) > 0)
LoadWave /O/P=$pathname/Q/T filename
else
LoadWave /O/Q/T filename
endif
if (v_flag)
string foldername
foldername = ParseFilePath(3, s_filename, "/", 0, 0)
foldername = foldername[0,16]
foldername = CleanupName(foldername, 0)
//foldername = UniqueName(foldername, 11, 0)
renamedatafolder root:otf_load_itx_temp, $foldername
printf "loaded otf data from file %s into folder %s\r", s_filename, foldername
endif
setdatafolder savedf
end
function otf_gather_iterator(df, sdata)
// data folder iterator used by otf_gather_batch
dfref df
string &sdata // key=value list of parameters
// xwavematch
// ywavematch
// destfolder
string src_name
string dst_name
string src_folder
string dst_folder
string df_id
string prefix, sdate, stime
setdatafolder df
src_folder = GetDataFolder(0, df)
sscanf src_folder, "%[^_]_%[0-9]_%[0-9]", prefix, sdate, stime
df_id = ""
if (strlen(sdate) > 0)
df_id += "_" + sdate
endif
if (strlen(stime) > 0)
df_id += "_" + stime
endif
dst_folder = StringByKey("destfolder", sdata)
src_name = StringByKey("xwavematch", sdata)
src_name = WaveList(src_name, "", "")
if (ItemsInList(src_name) >= 1)
src_name = StringFromList(0, src_name)
dst_name = dst_folder + src_name + df_id
//print src_name, dst_name
duplicate $src_name, $dst_name
endif
src_name = StringByKey("ywavematch", sdata)
src_name = WaveList(src_name, "", "")
if (ItemsInList(src_name) >= 1)
src_name = StringFromList(0, src_name)
dst_name = dst_folder + src_name + df_id
//print src_name, dst_name
duplicate $src_name, $dst_name
endif
end
function otf_gather_batch(ywavematch, xwavematch, destfolder)
// gathers (copies) OTF datasets in one data folder
// can be used for example for the Igor batch curve fitting tool
string ywavematch // match string identifies the y wave to be copied
string xwavematch // match string identifies the x wave to be copied
string destfolder // name of the destination data folder. folder does not have to exist.
return gather_batch("otf*", ywavematch, xwavematch, destfolder)
end
function gather_batch(foldermatch, ywavematch, xwavematch, destfolder)
// gathers (copies) OTF datasets in one data folder
// can be used for example for the Igor batch curve fitting tool
string foldermatch // match string to select data folders, e.g. "otf*"
string ywavematch // match string identifies the y wave to be copied
string xwavematch // match string identifies the x wave to be copied
string destfolder // name of the destination data folder. folder does not have to exist.
dfref savedf = GetDataFolderDFR()
newdatafolder /o/s $destfolder
destfolder = GetDataFolder(1)
string iteratordata = ""
iteratordata = ReplaceStringByKey("xwavematch", iteratordata, xwavematch)
iteratordata = ReplaceStringByKey("ywavematch", iteratordata, ywavematch)
iteratordata = ReplaceStringByKey("destfolder", iteratordata, destfolder)
setdatafolder savedf
iteratordata = IterateDataFolders(foldermatch, otf_gather_iterator, iteratordata)
setdatafolder savedf
end
function otf_rename_folders_iterator(df, sdata)
// data folder iterator used by otf_rename_folders
dfref df
string &sdata // key=value list of parameters
string pattern = StringByKey("pattern", sdata)
variable unique_index = NumberByKey("unique_index", sdata)
string new_suffix = StringByKey("new_suffix", sdata)
string src_folder
string dst_folder
string sprefix, sdate, stime, ssuffix
setdatafolder df
src_folder = GetDataFolder(0, df)
sprefix = "otf"
sscanf src_folder, "otf_%[0-9]_%[0-9]%s", sdate, stime, ssuffix
// return early if folder name does not match the expected pattern
if ((strlen(sdate) == 0) || (strlen(stime) == 0))
return 1
endif
dst_folder = sprefix
if (cmpstr(pattern[0], "0") != 0)
dst_folder += "_" + sdate
endif
if (cmpstr(pattern[1], "0") != 0)
dst_folder += "_" + stime
endif
if (cmpstr(pattern[2], "0") != 0)
if (strlen(new_suffix) > 0)
ssuffix = "_" + new_suffix
endif
dst_folder += ssuffix
endif
if ((unique_index > 0) || (CheckName(dst_folder, 11) != 0))
dst_folder = UniqueName(dst_folder + "_", 11, unique_index)
endif
setdatafolder ::
print src_folder + " -> " + dst_folder
RenameDataFolder $src_folder, $dst_folder
return 0
end
function otf_rename_folders(pattern, [unique_index, new_suffix, match_str])
// renames OTF data folders by omitting parts of the file name
string pattern // string of zeros and ones indicates which name parts to keep
// pos 1: date
// pos 2: time
// pos 3: custom suffix
variable unique_index // if you remove date and time,
// this start index will be used to make names unique
// if non-zero, new names will be forced to include a unique index
// if zero (default), new names will get a unique index only in case of a conflict
// optional, defaults to 0
string new_suffix
// replace old suffix by this one
// if empty (default), the old suffix will be kept
// optional, defaults to empty string
string match_str // match folder name to rename
// optional, defaults to "otf*" (matches all OTF folders)
dfref savedf = GetDataFolderDFR()
if (ParamIsDefault(unique_index))
unique_index = 0
endif
if (ParamIsDefault(new_suffix))
new_suffix = ""
endif
if (ParamIsDefault(match_str))
match_str = "otf*"
endif
string iteratordata = ""
iteratordata = ReplaceStringByKey("pattern", iteratordata, pattern)
iteratordata = ReplaceNumberByKey("unique_index", iteratordata, unique_index)
iteratordata = ReplaceStringByKey("new_suffix", iteratordata, new_suffix)
iteratordata = IterateDataFolders(match_str, otf_rename_folders_iterator, iteratordata)
setdatafolder savedf
end
function otf_interp(e1, e2, npts, smo)
variable e1
variable e2
variable npts
variable smo
wave ch1 = current_ch1
wave ch2 = current_ch2
wave pe = photonenergy
wave cff
wave rc = ringcurrent
duplicate /o ch1, current_ch1_int
wave ch1i = current_ch1_int
duplicate /o ch2, current_ch2_int
wave ch2i = current_ch2_int
duplicate /o pe, photonenergy_int
wave pei = photonenergy_int
duplicate /o cff, cff_int
wave cffi = cff_int
duplicate /o rc, ringcurrent_int
wave rci = ringcurrent_int
redimension /n=(npts) ch1i, ch2i, pei, cffi, rci
setscale /i x e1, e2, "eV", ch1i, ch2i, pei, cffi, rci
otf_smo_int(ch1, ch1i, pe, smo)
otf_smo_int(ch2, ch2i, pe, smo)
otf_smo_int(pe, pei, pe, smo)
otf_smo_int(cff, cffi, pe, smo)
otf_smo_int(rc, rci, pe, smo)
end
function otf_smo_int(win, wout, wpe, smo)
wave win
wave wout
wave wpe
variable smo
//duplicate /o win, wtmp
duplicate /free win, wtmp
smooth /b /e=3 smo, wtmp
wout = interp(x, wpe, wtmp)
end

View File

@ -0,0 +1,85 @@
#pragma rtGlobals=3
#pragma version = 1.1
#pragma IgorVersion = 6.1
#pragma ModuleName = PearlPolarCoordinates
// author: matthias.muntwiler@psi.ch
// Copyright (c) 2011-13 Paul Scherrer Institut
// $Id$
function cart2polar(xx, yy, zz, radius, theta, phi)
// converts a 3-vector from Cartesian to polar coordinates
variable xx, yy, zz
variable &radius, &theta, &phi // angles in degrees
radius = sqrt(xx^2 + yy^2 + zz^2)
if (radius > 0)
theta = acos(zz / radius) * 180 / pi
else
theta = 0
endif
if (xx > 0)
phi = atan(yy / xx) * 180 / pi
elseif (xx < 0)
phi = atan(yy / xx) * 180 / pi + 180
else
if (yy > 0)
phi = 90
else
phi = 270
endif
endif
end
function cart2polar_wave(in, out)
// converts a wave of 3-vectors from Cartesian to polar coordinates
wave in // wave with dimensions (3, N), N >= 1, (x, y, z)
wave out // wave same dimensions as in, (radius, theta, phi)
// angles in degrees
out[0][] = sqrt(in[0][q]^2 + in[1][q]^2 + in[2][q]^2)
out[1][] = acos(in[2][q] / out[0][q]) * 180 / pi
out[2][] = atan(in[1][q] / in[0][q]) * 180 / pi + 180 * (in[0][q] < 0)
out[2][] = numtype(out[2][q]) == 0 ? out[2][q] : 90 + 180 * (in[1][q] < 0)
end
function polar2cart(radius, theta, phi, xx, yy, zz)
// converts a 3-vector from Cartesian to polar coordinates
variable radius, theta, phi // angles in degrees
variable &xx, &yy, &zz
xx = radius * sin(theta * pi / 180) * cos(phi * pi / 180)
yy = radius * sin(theta * pi / 180) * sin(phi * pi / 180)
zz = radius * cos(theta * pi / 180)
end
function polar2cart_wave(in, out)
// converts a wave of 3-vectors from polar to Cartesian coordinates
wave in // wave with dimensions (3, N), N >= 1, (radius, theta, phi)
// angles in degrees
wave out // wave same dimensions as in, (x, y, z)
out[0][] = in[0][q] * sin(in[1][q] * pi / 180) * cos(in[2][q] * pi / 180)
out[1][] = in[0][q] * sin(in[1][q] * pi / 180) * sin(in[2][q] * pi / 180)
out[2][] = in[0][q] * cos(in[1][q] * pi / 180)
end
function polar_distance(polar1, azim1, polar2, azim2)
// returns the angle between two spherical coordinates
variable polar1, azim1
// angles in degrees
variable polar2, azim2
// angles in degrees
variable xx1, yy1, zz1
variable xx2, yy2, zz2
polar2cart(1, polar1, azim1, xx1, yy1, zz1)
polar2cart(1, polar2, azim2, xx2, yy2, zz2)
variable vv
vv = (xx1 * xx2 + yy1 * yy2 + zz1 * zz2) / sqrt(xx1^2 + yy1^2 + zz1^2) / sqrt(xx2^2 + yy2^2 + zz2^2)
return acos(vv) * 180 / pi
end

View File

@ -0,0 +1,73 @@
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
#pragma IgorVersion = 6.1
#pragma ModuleName = PearlPreparation
#pragma version = 1.04
#include "pearl-area-display" // 2D and 3D data visualization
#include "pearl-area-profiles" // data processing for multi-dimensional datasets
#include "pearl-elog"
#if exists("pvOpen")
#include "pearl-epics" // EPICS access under Igor
#include "pearl-anneal" // automated sample annealing
#endif
// author: matthias.muntwiler@psi.ch
// Copyright (c) 2015 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 PEARL sample preparation package
///
/// this procedure defines the PEARL sample preparation package
/// the main purpose of this file is to load the necessary dependent procedures
/// (see the include statements at the top)
///
/// @pre
/// * on-line process control functionality requires the EPICS XOP to be loaded
///
/// @author matthias muntwiler, matthias.muntwiler@psi.ch
///
/// @copyright 2015 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 PearlPreparation
/// @brief PEARL sample preparation package
///
/// PearlPreparation is declared in @ref pearl-preparation.ipf.
///
/// @defgroup PreparationPackage Sample preparation package
/// @brief PEARL sample preparation package
///
/// The purpose of a package is to load a bunch of dependent procedure files.
/// The sample preparation package loads the following files.
///
/// * pearl-area-import.ipf
/// * pearl-area-display.ipf
/// * pearl-area-profiles.ipf
/// * pearl-elog.ipf
/// * pearl-anneal.ipf
///
/// The following files are loaded if the EPICS.XOP is present:
///
/// * pearl-epics.ipf
///
/// initializes package data once when the procedure is first loaded
static function AfterCompiledHook()
dfref savefolder = GetDataFolderDFR()
return 0
end
function UnloadPearlPreparationPackage()
execute /p/q/z "DELETEINCLUDE \"pearl-preparation\""
execute /p/q/z "COMPILEPROCEDURES "
end

View File

@ -0,0 +1,705 @@
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
#pragma IgorVersion = 6.1
#pragma ModuleName = PearlScientaPreprocess
#pragma version = 1.02
// $Id$
// author: matthias.muntwiler@psi.ch
// Copyright (c) 2013-14 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 preprocessing functions for Scienta detector images.
/// @ingroup ArpesPackage
///
/// this procedure contains functions for data reduction
/// and instrument-specific normalization.
///
/// @author matthias muntwiler, matthias.muntwiler@psi.ch
///
/// @copyright 2013-15 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 PearlScientaPreprocess
/// @brief preprocessing functions for Scienta detector images.
///
/// PearlScientaPreprocess is declared in @ref pearl-scienta-preprocess.ipf.
function prompt_int_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 "int_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
function /s capture_int_linbg_cursors()
// this function is for testing only, until we implement a proper interface
string param = csr_int_linbg_reduction("")
svar /z global_params = root:packages:pearl_explorer:s_reduction_params
if (svar_exists(global_params))
global_params = param
endif
return param
end
function /s csr_int_linbg_reduction(win)
// PRELIMINARY - function arguments may change
// sets reduction parameters from cursors in a graph.
// an even number of cursors (2 or more) must be set on the image.
// cursor names and order do not matter,
// except that the alphabetically first cursor which is attached to an image selects the image.
// the cursors mark the following positions, from innermost to outermost pair:
// 1) low and high limits of peak region.
// 2) peak-side boundary of lower and upper background region.
// 3) lower and upper cropping region.
string win
// read all cursor positions
variable ic
string sc
variable nc = 10
make /n=(nc) /free positions
variable np = 0
wave /z image = $""
string imagename = ""
string tracename = ""
string info
for (ic = 0; ic < nc; ic += 1)
sc = num2char(char2num("A") + ic)
wave /z wc = CsrWaveRef($sc, win)
info = CsrInfo($sc, win)
tracename = StringByKey("TNAME", info, ":", ";")
if (waveexists(wc) && (wavedims(wc) == 2))
if (!waveexists(image))
wave image = wc
imagename = tracename
endif
if (cmpstr(tracename, imagename) == 0)
positions[np] = pcsr($sc, win)
np += 1
endif
endif
endfor
np = floor(np / 2) * 2 // ignore odd cursor
redimension /n=(np) positions
sort positions, positions
// shift upper positions by one so that the rightmost pixel becomes 1.0
positions = p >= np / 2 ? positions + 1 : positions
positions = positions / dimsize(image, 0)
// map innermost cursor pair to peak center and size
variable ip2 = np / 2
variable ip1 = ip2 - 1
variable Cpos = (positions[ip1] + positions[ip2]) / 2
variable Csize = positions[ip2] - positions[ip1]
if (ip1 >= 0)
Cpos = (positions[ip1] + positions[ip2]) / 2
Csize = positions[ip2] - positions[ip1]
else
// default: a small region in the center
Cpos = 0.5
Csize = 0.2
endif
// background region
ip1 -= 1
ip2 += 1
variable Lsize
variable Hsize
if (ip1 >= 0)
Lsize = positions[ip1]
Hsize = 1 - positions[ip2]
else
// default: everything outside the peak region
Lsize = Cpos - Csize / 2
Hsize = 1 - (Cpos + Csize / 2)
endif
// crop region
ip1 -= 1
ip2 += 1
variable Lcrop
variable Hcrop
if (ip1 >= 0)
Lcrop = positions[ip1]
Hcrop = 1 - positions[ip2]
else
// default: dead corners of the EW4000 at PEARL
Lcrop = 0.11
Hcrop = 0.11
endif
Lsize = max(Lsize - Lcrop, 0)
Hsize = max(Hsize - Hcrop, 0)
string param = ""
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, "=", ";")
return param
end
function test_int_linbg(image)
// useful for testing or manual processing
// since the int_linbg_reduction function cannot be called from the command line directly.
wave image
string param = ""
prompt_int_linbg_reduction(param)
string data1_name = "test_data1"
string data2_name = "test_data2"
duplicate /o image, $data1_name, $data2_name
wave w_data1 = $data1_name
wave w_data2 = $data2_name
int_linbg_reduction(image, w_data1, w_data2, param)
end
threadsafe function int_linbg_reduction(source, dest1, dest2, param)
// data reduction function for adh5_load_reduced_detector
// calculates the average pixel value of each angular slice
// in one center and two background intervals.
// a background value is calculated at the center position
// by linear interpolation from the two background values.
// returns the center minus linear background in dest1.
// returns the Poisson one-sigma error in dest2.
wave source // source wave
// Scienta detector image, energy axis along X, angle axis along Y
wave dest1, dest2 // destination waves
// 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.
string &param // parameters in a key1=value1;key2=value2;... list
// all region parameters are relative to the image size (0...1)
// Lcrop = size of the lower cropping region
// Hcrop = size of the upper cropping region
// Lsize = size of the lower background integration region
// Hsize = size of the upper background integration region
// Cpos = center position of the of the peak integration region
// 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
variable nx = dimsize(source, 0)
variable ny = dimsize(source, 1)
// read parameters
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, "=", ";")
// validate parameters
// background parameters are optional, center parameter is required.
if (numtype(lcrop) != 0)
lcrop = 0
endif
if (numtype(lsize) != 0)
lsize = 0
endif
if (numtype(hcrop) != 0)
hcrop = 0
endif
if (numtype(hsize) != 0)
hsize = 0
endif
if (numtype(Cpos) != 0)
return 1 // Cpos parameter missing
endif
if (numtype(Csize) != 0)
return 2 // Csize parameter missing
endif
variable lpos = lcrop + lsize / 2
variable hpos = 1 - (hcrop + hsize / 2)
variable p0
variable p1
adh5_setup_profile(source, dest1, 1)
adh5_setup_profile(source, dest2, 1)
duplicate /free dest1, lbg, hbg
if (lsize > 0)
p0 = round(lcrop * nx)
p1 = round((lcrop + lsize) * nx)
ad_profile_y_w(source, p0, p1, lbg)
else
lbg = 0
endif
if (hsize > 0)
p0 = round((1 - hcrop - hsize) * nx)
p1 = round((1 - hcrop) * nx)
ad_profile_y_w(source, p0, p1, hbg)
else
hbg = 0
endif
if (csize > 0)
p0 = round((cpos - csize/2) * nx)
p1 = round((cpos + csize/2) * nx)
ad_profile_y_w(source, p0, p1, dest1)
else
dest1 = 0
endif
variable scale = (cpos - lpos) / (hpos - lpos)
dest2 = dest1
dest1 -= scale * (hbg - lbg) + lbg
dest2 = sqrt(dest2 + scale^2 * (hbg + lbg))
return 0 // return zero if successful, non-zero if an error occurs
end
function test_shockley_anglefit(image, branch)
// apply the Shockley_anglefit function to a single image
// useful for testing or manual processing
// since the Shockley_anglefit function cannot be called from the command line directly.
wave image
variable branch // +1 or -1
string param = ""
param = ReplaceStringByKey("branch", param, num2str(branch), "=", ";")
string s_branch
if (branch >= 0)
s_branch = "p"
else
s_branch = "n"
endif
string pkpos_name = "saf_pkpos_" + s_branch
string pkwid_name = "saf_pkwid_" + s_branch
duplicate /o image, $pkpos_name, $pkwid_name
wave w_pkpos = $pkpos_name
wave w_pkwid = $pkwid_name
shockley_anglefit(image, w_pkpos, w_pkwid, param)
end
function prompt_Shockley_anglefit(param)
string &param
variable branch = NumberByKey("branch", param, "=", ";")
prompt branch, "Branch (-1 or +1)"
doprompt "Shockley_anglefit_reduction Parameters", branch
if (v_flag == 0)
param = ReplaceNumberByKey("branch", param, branch, "=", ";")
endif
return v_flag
end
threadsafe function Shockley_anglefit(source, dest1, dest2, param)
// data reduction function for adh5_load_reduced_detector
// specialized for analysing the Cu(111) Shockley surface state
// do curve fitting of one branch of the surface state
// the result is peak position versus energy
// TODO: this function contains hard-coded parameters. please generalize as necessary.
wave source // source wave
// Scienta detector image, energy axis along X, angle axis along Y
// the apex of the surface state must be at angle 0
wave dest1, dest2 // destination waves
// dest1: peak position
// dest2: peak width (sigma)
string &param // parameters in a key1=value1;key2=value2;... list
// branch=-1 or +1: select negative (positive) angles for the fit interval, respectively
variable nx = dimsize(source, 0)
variable ny = dimsize(source, 1)
// read parameters
variable branch = NumberByKey("branch", param, "=", ";")
// validate parameters
if (numtype(branch) != 0)
branch = +1
endif
// prepare output
adh5_setup_profile(source, dest1, 0)
adh5_setup_profile(source, dest2, 0)
dest1 = nan
dest2 = nan
// select angle range
// hard-coded for a particular measurement series
variable y0
variable y1
if (branch < 0)
y0 = -5
y1 = 0
else
y0 = 0
y1 = 5
endif
// select energy range
// start at the point of highest intensity and go up 0.45 eV
variable p0
variable p1
variable q0
variable q1
duplicate /free dest1, center
q0 = round((y0 - dimoffset(source, 1)) / dimdelta(source, 1))
q1 = round((y1 - dimoffset(source, 1)) / dimdelta(source, 1))
ad_profile_x_w(source, q0, q1, center)
wavestats /q/m=1 center
p0 = round((v_maxloc - dimoffset(source, 0)) / dimdelta(source, 0))
p1 = round((v_maxloc + 0.4 - dimoffset(source, 0)) / dimdelta(source, 0))
// prepare intermediate data buffer
make /n=(ny)/d/free profile
setscale /p x dimoffset(source,1), dimdelta(source,1), waveunits(source,1), profile
variable pp
for (pp = p0; pp <= p1; pp += 1)
profile = source[pp][p]
curvefit /Q /NTHR=1 /W=2 gauss profile(y0,y1)
wave w_coef
dest1[pp] = w_coef[2]
dest2[pp] = w_coef[3]
endfor
return 0 // return zero if successful, non-zero if an error occurs
end
function prompt_int_quadbg_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 "int_quadbg_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
function test_int_quadbg(image)
// useful for testing or manual processing
// since the int_quadbg_reduction function cannot be called from the command line directly.
wave image
string param = ""
prompt_int_quadbg_reduction(param)
string data1_name = "test_data1"
string data2_name = "test_data2"
duplicate /o image, $data1_name, $data2_name
wave w_data1 = $data1_name
wave w_data2 = $data2_name
int_quadbg_reduction(image, w_data1, w_data2, param)
end
threadsafe function int_quadbg_reduction(source, dest1, dest2, param)
// data reduction function for adh5_load_reduced_detector
// integrates peak area minus a quadratic backgrouind
wave source // source wave
// Scienta detector image, energy axis along X, angle axis along Y
wave dest1, dest2 // destination waves
string &param // parameters in a key1=value1;key2=value2;... list
// all region parameters are relative to the image size (0...1)
// Lcrop = size of the lower cropping region
// Hcrop = size of the upper cropping region
// Lsize = size of the lower background integration region
// Hsize = size of the upper background integration region
// Cpos = center position of the of the peak integration region
// 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
variable nx = dimsize(source, 0)
variable ny = dimsize(source, 1)
// read parameters
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, "=", ";")
// validate parameters
// background parameters are optional, center parameter is required.
if (numtype(lcrop) != 0)
lcrop = 0
endif
if (numtype(lsize) != 0)
lsize = 0
endif
if (numtype(hcrop) != 0)
hcrop = 0
endif
if (numtype(hsize) != 0)
hsize = 0
endif
if (numtype(Cpos) != 0)
return 1 // Cpos parameter missing
endif
if (numtype(Csize) != 0)
return 2 // Csize parameter missing
endif
// crop boundaries
variable pcl = round(lcrop * nx)
variable pch = round((1 - hcrop) * nx)
// fit boundaries
variable pfl = round((lcrop + lsize) * nx)
variable pfh = round((1 - hcrop - hsize) * nx)
// integration boundaries
variable pil = round((cpos - csize/2) * nx)
variable pih = round((cpos + csize/2) * nx)
adh5_setup_profile(source, dest1, 0)
adh5_setup_profile(source, dest2, 0)
// prepare intermediate data buffer
make /n=(nx) /d /free profile, mask, fit
setscale /p x dimoffset(source,0), dimdelta(source,0), waveunits(source,0), profile, mask, fit
mask = ((p >= pcl) && (p < pfl)) || ((p >= pfh) && (p < pch))
variable qq
variable sp, sf
variable xil = x2pnt(profile, pil)
variable xih = x2pnt(profile, pih)
make /n=3 /free /d w_coef
for (qq = 0; qq < ny; qq += 1)
profile = source[p][qq]
curvefit /Q /NTHR=1 /W=2 poly 3, kwCWave=w_coef, profile /M=mask
fit = poly(w_coef, x)
sp = sum(profile, xil, xih)
sf = sum(fit, xil, xih)
dest1[qq] = sp - sf
dest2[qq] = sqrt(sp)
endfor
return 0 // return zero if successful, non-zero if an error occurs
end
function scienta_norm(w, x): fitfunc
wave w
variable x
return w[0] * (x^2 - w[1]^2)
end
function /wave fit_scienta_ang_transm(data, params)
wave data // measured angular distribution (1D)
wave /z params
if (!waveexists(params))
make /n=12 /o params
endif
redimension /n=12/d params
variable h = wavemax(data) - wavemin(data)
params[0] = h / 2
params[1] = 0
params[2] = 7
params[3] = h / 4
params[4] = -23
params[5] = 4
params[6] = h / 4
params[7] = +23
params[8] = 4
params[9] = h / 2
params[10] = 0
params[11] = -0.001
FuncFit /NTHR=0 /q scienta_ang_transm params data
return params
end
threadsafe function scienta_ang_transm(w, x): fitfunc
// parameterized angular transmission function of the analyser
wave w // coefficients
// w[0] = amplitude gauss 1
// w[1] = position gauss 1
// w[2] = width gauss 1
// w[3] = amplitude gauss 2
// w[4] = position gauss 2
// w[5] = width gauss 2
// w[6] = amplitude gauss 3
// w[7] = position gauss 3
// w[8] = width gauss 3
// w[9] = constant background
// w[10] = linear background
// w[11] = quadratic background
variable x
make /free /n=4 /d w_int
w_int[0] = 0
w_int[1,] = w[p - 1]
variable pk1 = gauss1d(w_int, x)
w_int[1,] = w[p + 2]
variable pk2 = gauss1d(w_int, x)
w_int[1,] = w[p + 5]
variable pk3 = gauss1d(w_int, x)
w_int[0,2] = w[9 + p]
w_int[3] = 0
variable bg = poly(w_int, x)
return bg + pk1 + pk2 + pk3
end
function /wave fit_scienta_poly_bg(data, params, bgterms)
wave data // measured distribution (2D)
wave /z params // wave, will be redimensioned for the correct size
variable bgterms // number of terms in the polynomial background: 2, 3, or 4
if (!waveexists(params))
make /n=15 /o params
endif
redimension /n=15 /d params
variable wmax = wavemax(data)
variable wmin = wavemin(data)
params[0] = 0
params[1] = 7
params[2] = 1 / 2
params[3] = -23
params[4] = 4
params[5] = 1 / 2
params[6] = +23
params[7] = 4
params[8] = 1
params[9] = 0
params[10] = -0.001
params[11] = wmin
params[12] = (wmax - wmin) / dimdelta(data,1) / dimsize(data,1)
params[13] = 0
params[14] = 0
string h = "0000000000000"
if (bgterms < 3)
h = h + "1"
else
h = h + "0"
endif
if (bgterms < 4)
h = h + "1"
else
h = h + "0"
endif
FuncFitMD /NTHR=1 /q /h=h scienta_poly_bg params data
return params
end
function scienta_poly_bg(w, e, a): fitfunc
// polynomial background with
// parameterized angular transmission function of the analyser
wave w // coefficients
// angular transmission, varies with a
// amplitude of gauss 1 = 1 constant
// other peak amplitudes and linear terms are relative to gauss 1
// w[0] = position gauss 1
// w[1] = width gauss 1
// w[2] = amplitude gauss 2, relative to gauss 1
// w[3] = position gauss 2
// w[4] = width gauss 2
// w[5] = amplitude gauss 3, relative to gauss 1
// w[6] = position gauss 3
// w[7] = width gauss 3
// w[8] = constant term
// w[9] = linear term
// w[10] = quadratic term
// spectral background, varies with e
// w[11] = constant term
// w[12] = linear term
// w[13] = quadratic term
// w[14] = cubic term
variable a // detection angle
variable e // electron energy
make /free /n=4 /d w_int
variable p0 = 0
w_int[0] = 0
w_int[1] = 1
w_int[2,] = w[p0 + p - 2]
variable pk1 = gauss1d(w_int, a)
p0 += 2
w_int[1,] = w[p0 + p - 1]
variable pk2 = gauss1d(w_int, a)
p0 += 3
w_int[1,] = w[p0 + p - 1]
variable pk3 = gauss1d(w_int, a)
p0 += 3
w_int[0,2] = w[p0 + p]
w_int[3] = 0
variable base = poly(w_int, a)
p0 += 3
w_int[0,3] = w[p0 + p]
variable bg = poly(w_int, e)
return bg * (base + pk1 + pk2 + pk3)
end

135
pearl/pearl-tools.ipf Normal file
View File

@ -0,0 +1,135 @@
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
#pragma version = 1.00
#pragma IgorVersion = 6.2
#pragma ModuleName = PearlTools
#include "pearl-gui-tools"
// general programming tools for Igor
// $Id$
// author: matthias.muntwiler@psi.ch
// Copyright (c) 2009-14 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
function DefaultWaveIterator(w, sdata)
// function prototype for IterateWaves
wave w // wave which the iterator is supposed to work on
string &sdata // string with additional data, shared between calls
// this is a pass-by-reference argument,
// the function may modify the string
end
function AppendToGraphIterator(w, sdata)
// append iterated waves to the current graph
wave w // wave to be displayed
string &sdata // not used
appendtograph w
end
function SumWavesIterator(w, sdata)
// sum waves into one result wave
wave w // wave which the iterator is supposed to work on
string &sdata // name of the result wave, can include absolute path
// the wave must exist and compatible with the summands
// the caller is responsible for initialization of the wave
wave result = $sdata
result += w
end
function/s IterateWaves(matchStr, iterator, sdata)
// iterate over all waves matching a specified pattern (see built-in WaveList function),
// passing each wave to a user-defined iterator function
string matchStr // matchStr as for WaveList
funcref DefaultWaveIterator iterator // iterator function
// use the DefaultWaveIterator function as a template
string sdata // data string passed to iterator function
// the iterator may modify the string
// the function returns the string at the end
string wlist = WaveList(matchStr, ";", "")
variable n = ItemsInList(wlist, ";")
variable i
for (i = 0; i < n; i += 1)
wave w = $(StringFromList(i, wlist, ";"))
iterator(w, sdata)
endfor
return sdata
end
function DefaultFolderIterator(df, sdata)
// function prototype for IterateWaves
dfref df // data folder reference which the iterator is supposed to work on
string &sdata // string with additional data, shared between calls
// this is a pass-by-reference argument,
// the function may modify the string
// switch to requested data folder
setdatafolder df
// for testing
print getdatafolder(1)
// no need to switch back to original folder
end
function/s IterateDataFolders(matchStr, iterator, sdata, [progress_title])
// iterate over all data folders matching a specified pattern in the current data folder,
// passing each folder to a user-defined iterator function
string matchStr // matchStr as for the built-in stringmatch function
funcref DefaultFolderIterator iterator // iterator function
// use the DefaultFolderIterator function as a template
string sdata // data string passed to iterator function
// the iterator may modify the string
// the function returns the string at the end
string progress_title // title of the progress window (optional)
// if not specified or empty, the progress window will not be shown.
// if the progress window is show, the user can abort the iteration.
// the function result does not indicate whether the iteration was completed or aborted.
// the iterator and caller must take care of leaving the data in a consistent state.
if (ParamIsDefault(progress_title))
progress_title = ""
endif
variable show_progress = strlen(progress_title) > 0
dfref origdf = GetDataFolderDFR()
dfref curdf
variable index = 0
variable abort_req = 0
string objName
variable ndf = CountObjectsDFR(origdf, 4)
if (show_progress)
display_progress_panel(progress_title, "", ndf)
endif
do
objName = GetIndexedObjNameDFR(origdf, 4, index)
if (strlen(objName) == 0)
break
endif
if (stringmatch(objname, matchstr))
if (show_progress)
abort_req = update_progress_panel(index, message=objName)
if (abort_req)
break
endif
endif
setdatafolder origdf
curdf = $(":" + objname)
iterator(curdf, sdata)
endif
index += 1
while(1)
if (show_progress)
kill_progress_panel()
endif
setdatafolder origdf
return sdata
end

View File

@ -0,0 +1,135 @@
#pragma rtGlobals=3
#pragma version = 2.0
#pragma IgorVersion = 6.1
#pragma ModuleName = PearlVectorOperations
// author: matthias.muntwiler@psi.ch
// Copyright (c) 2011-13 Paul Scherrer Institut
// $Id$
function rotate2d_x(xx, yy, angle)
// rotates a 2D cartesian vector and returns its x component
variable xx, yy
variable angle // rotation angle in degrees
return xx * cos(angle * pi / 180) - yy * sin(angle * pi / 180)
end
function rotate2d_y(xx, yy, angle)
// rotates a 2D cartesian vector and returns its y component
variable xx, yy
variable angle // rotation angle in degrees
return xx * sin(angle * pi / 180) + yy * cos(angle * pi / 180)
end
function /wave create_rotation_matrix_free()
// creates a matrix which represents a 3-vector rotation
// the matrix is initialized as identity
make /n=(3,3)/free matrix
matrix = p == q // identity
return matrix
end
function /wave set_rotation_x(matrix, angle)
// calculates a matrix representing a 3-vector rotation around the x axis
wave matrix // rotation matrix
variable angle // rotation angle in degrees
variable si = sin(angle * pi / 180)
variable co = cos(angle * pi / 180)
matrix[1][1] = co
matrix[2][2] = co
matrix[2][1] = si
matrix[1][2] = -si
return matrix
end
function /wave set_rotation_y(matrix, angle)
// calculates a matrix representing a 3-vector rotation around the y axis
wave matrix // rotation matrix
variable angle // rotation angle in degrees
variable si = sin(angle * pi / 180)
variable co = cos(angle * pi / 180)
matrix[0][0] = co
matrix[2][2] = co
matrix[0][2] = si
matrix[2][0] = -si
return matrix
end
function /wave set_rotation_z(matrix, angle)
// calculates a matrix representing a 3-vector rotation around the z axis
wave matrix // rotation matrix
variable angle // rotation angle in degrees
variable si = sin(angle * pi / 180)
variable co = cos(angle * pi / 180)
matrix[0][0] = co
matrix[1][1] = co
matrix[1][0] = si
matrix[0][1] = -si
return matrix
end
function rotate_x_wave(inout, angle)
// rotates a wave of 3-vectors about the x axis
wave inout // wave with dimensions (3, N), N >= 1, (x, y, z)
// result will be in same wave
variable angle // rotation angle in degrees
wave m_rotation_x = create_rotation_matrix_free()
make /n=3/d/free w_temp_rotate_x
variable ivec, nvec
nvec = max(DimSize(inout, 1), 1)
for (ivec = 0; ivec < nvec; ivec += 1)
set_rotation_x(m_rotation_x, angle)
w_temp_rotate_x = inout[p][ivec]
matrixop /free w_temp_rotate_x_result = m_rotation_x x w_temp_rotate_x
inout[][ivec] = w_temp_rotate_x_result[p]
endfor
end
function rotate_y_wave(inout, angle)
// rotates a wave of 3-vectors about the y axis
wave inout // wave with dimensions (3, N), N >= 1, (x, y, z)
// result will be in same wave
variable angle // rotation angle in degrees
wave m_rotation_y = create_rotation_matrix_free()
make /n=3/d/free w_temp_rotate_y
variable ivec, nvec
nvec = max(DimSize(inout, 1), 1)
for (ivec = 0; ivec < nvec; ivec += 1)
set_rotation_y(m_rotation_y, angle)
w_temp_rotate_y = inout[p][ivec]
matrixop /free w_temp_rotate_y_result = m_rotation_y x w_temp_rotate_y
inout[][ivec] = w_temp_rotate_y_result[p]
endfor
end
function rotate_z_wave(inout, angle)
// rotates a wave of 3-vectors about the z axis
wave inout // wave with dimensions (3, N), N >= 1, (x, y, z)
// result will be in same wave
variable angle // rotation angle in degrees
wave m_rotation_z = create_rotation_matrix_free()
make /n=3/d/free w_temp_rotate_z
variable ivec, nvec
nvec = max(DimSize(inout, 1), 1)
for (ivec = 0; ivec < nvec; ivec += 1)
set_rotation_z(m_rotation_z, angle)
w_temp_rotate_z = inout[p][ivec]
matrixop /free w_temp_rotate_z_result = m_rotation_z x w_temp_rotate_z
inout[][ivec] = w_temp_rotate_z_result[p]
endfor
end

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,2 @@
default configuration and preferences for pearl procedures.
copy the contents of this folder to "c:\users\{your_username}\AppData\Roaming\WaveMetrics\Igor Pro 6\Packages\".

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB