PEARL Procedures rev-distro-3.1.0-0-gea838b3-dirty
Igor procedures for the analysis of PEARL data
Loading...
Searching...
No Matches
fermi-edge-analysis.ipf
Go to the documentation of this file.
1#pragma TextEncoding = "UTF-8"
2#pragma rtGlobals=3 // Use modern global access method and strict wave access.
3#include "pearl-area-profiles"
4
5// $Id$
6
26
27
28function analyse_curved_edge(data)
29 wave data // 2D counts data, x-scale = kinetic energy, y-scale = analyser angle
30 variable guess_EF // initial guess of the Fermi level
31
32 dfref savedf = GetDataFolderDFR()
33 dfref datadf = GetWavesDataFolderDFR(data)
34 setdatafolder datadf
35
36 make /n=5 /d /o w_coef_int
37 make /n=7 /d /o w_coef_curved
38
39 // 1) integrate data
40 wave xint = ad_profile_x(data, -inf, inf, "", noavg=1)
41 duplicate /free xint, xint_sig
42 xint_sig = sqrt(xint * 4) / 4
43 variable xmin = wavemin(xint)
44 variable xmax = wavemax(xint)
45 variable xmean = mean(xint)
46
47 // 2) fit integrated data for reference
48 w_coef_int[0] = xmin
49 w_coef_int[1] = 0
50 w_coef_int[2] = xmax - xmin
51 w_coef_int[3] = dimoffset(xint, 0) + dimdelta(xint, 0) * dimsize(xint, 0) / 2
52 w_coef_int[4] = 100
53 FuncFit /NTHR=0 FermiFuncLinDOS w_coef_int xint /D /I=1 /W=xint_sig
54 wave w_sigma
55 duplicate /o w_sigma, w_sigma_int
56
57 // 3) normalize data
58 wave yavg = ad_profile_y(data, -inf, inf, "")
59 variable ymean = mean(yavg)
60
61 duplicate /o data, data_norm, data_sig
62 data_sig = sqrt(data * 4) / 4
63 data_norm = data_norm * ymean / yavg[q]
64 data_sig = data_sig * ymean / yavg[q]
65
66 // 4) fit normalized data
67 wave xavg = ad_profile_x(data, -inf, inf, "")
68 xmin = wavemin(xavg)
69 xmax = wavemax(xavg)
70 xmean = mean(xavg)
71
72 w_coef_curved[0] = {0, 0, 1, 95.5, 100, 0, -0.0001}
73 w_coef_curved[0] = xmin
74 w_coef_curved[2] = xmax - xmin
75 w_coef_curved[3] = w_coef_int[3]
76 w_coef_curved[4] = w_coef_int[4]
77
78 //variable box = min(11, numpnts(xavg) / 5)
79 //FindLevel /B=(box) /EDGE=2 /Q xavg, (xmin + xmax) / 2
80 //if (v_flag == 0)
81 // w_coef_curved[3] = v_levelx
82 //else
83 // w_coef_curved[3] = dimoffset(data, 0) + dimdelta(data, 0) * dimsize(data, 0) / 2
84 //endif
85
86 duplicate /o data_norm, fit_data_norm
87 FuncFitMD /X=1 /NTHR=0 FermiFuncLinDOS_2Dcorr w_coef_curved data_norm /D=fit_data_norm /I=1 /W=data_sig
88 wave w_sigma
89 duplicate /o w_sigma, w_sigma_curved
90
91 display /k=1; appendimage data_norm
92 ModifyImage data_norm ctab= {xmin,xmax,Grays,0}
93 AppendMatrixContour fit_data_norm
94
95 setdatafolder savedf
96 return 0
97end
98
99function record_results(index)
100 variable index
101
102 dfref savedf = GetDataFolderDFR()
103 wave /sdfr=root: Tint, Tint_sig, Tcurv, Tcurv_sig, EFcurv, EFcurv_sig
104 wave w_coef_int, w_coef_curved
105 wave w_sigma_int, w_sigma_curved
106
107 Tint[index] = w_coef_int[4]
108 Tint_sig[index] = w_sigma_int[4]
109 Tcurv[index] = w_coef_curved[4]
110 Tcurv_sig[index] = w_sigma_curved[4]
111 EFcurv[index] = w_coef_curved[3]
112 EFcurv_sig[index] = w_sigma_curved[3]
113
114 setdatafolder savedf
115end
116
117function integrate_curved_edge(data, data_sig)
118 wave data
119 wave /z data_sig
120 //wave coef
121
122 string name = nameofwave(data)
123
124 duplicate /o data, data_out
125 redimension /n=(dimsize(data,0)) data_out
126 data_out = 0
127
128 if (waveexists(data_sig))
129 duplicate /o data_sig, sig_out
130 redimension /n=(dimsize(data,0)) sig_out
131 sig_out = 0
132 endif
133
134 wave ywgt = ad_profile_y(data, -inf, inf, "", noavg=1)
135 ywgt = 1 / ywgt / 4
136 //ywgt = 1 / 4
137 variable sum_ywgt = sum(ywgt)
138
139 variable nx = dimsize(data, 0)
140 variable ny = dimsize(data, 1)
141 variable iy
142 variable yy
143 variable dx
144 variable dy
145 variable dp
146 variable dp_min = 0
147
148 wave PassEnergy = :attr:PassEnergy
149 wave NumSlices = :attr:NumSlices
150
151 for (iy = 0; iy < ny; iy += 1)
152 dy = dimoffset(data, 1) + dimdelta(data, 1) * iy
153 dy = dy / dimdelta(data, 1)
154 dx = slit_shift(dy * 902 / NumSlices[0], PassEnergy[0])
155 dp = round(dx / dimdelta(data, 0)) // <= 0
156 dp_min = min(dp_min, dp)
157
158 data_out[] = p+dp >= 0 ? data_out + data[p+dp][iy] * ywgt[iy] : data_out
159
160 if (waveexists(data_sig))
161 sig_out = p+dp >= 0 ? sig_out + data_sig[p+dp][iy] * ywgt[iy] : sig_out
162 endif
163 endfor
164
165 data_out /= sum_ywgt
166 data_out[0, -dp_min][] = nan
167
168 if (waveexists(sig_out))
169 sig_out /= sum_ywgt
170 //sig_out[0, -dp_min] = nan
171 endif
172end
173
174function slit_correction(data, data_out, epass)
175 wave data // must be image with original dimensions (no cropping!)
176 wave /z data_out // 2D or 1D wave to receive the result
177 // X dimension must be identical to the one of data
178 // if 2D, Y dimension must be either identical to the one of data
179 // if 1D, the result will be the sum of the corrected slices
180 variable epass // pass energy
181
182 if (!WaveExists(data_out))
183 string name = nameofwave(data) + "_corr"
184 duplicate /o data, $name
185 wave data_out = $name
186 //redimension /n=(dimsize(data,0)) data_out
187 endif
188 data_out = 0
189
190 variable nx = dimsize(data, 0)
191 variable ny = dimsize(data, 1)
192 variable iy
193 variable yy
194 variable dx
195 variable dy
196 variable dp
197 variable dp_min = 0
198
199 for (iy = 0; iy < ny; iy += 1)
200 dy = dimoffset(data, 1) + dimdelta(data, 1) * iy
201 dy = dy / dimdelta(data, 1)
202 dx = slit_shift(dy * 902 / ny, epass)
203 dp = round(dx / dimdelta(data, 0)) // <= 0
204 dp_min = min(dp_min, dp)
205
206 if (wavedims(data_out) >= 2)
207 data_out[][iy] = p+dp >= 0 ? data_out + data[p+dp][iy] : data_out
208 else
209 data_out = p+dp >= 0 ? data_out + data[p+dp][iy] : data_out
210 endif
211 endfor
212
213 data_out[0, -dp_min][] = nan
214end
215
216//------------------------------------------------------------------------------
217threadsafe Function FermiFuncLinDOS2D_corr(w,x,y) : FitFunc
218// linear density of states below Fermi level
219// 2D data with corrections:
220// - straight slit (slit shift)
221// - transmission function (polynomial)
222//------------------------------------------------------------------------------
223 Wave w; Variable x; variable y
224 // w[0] = background far above the fermi level
225 // w[1] = slope of the linear background
226 // w[2] = amplitude
227 // w[3] = fermi level in eV
228 // w[4] = temperature in K
229 // w[5] = transmission - linear term
230 // w[6] = transmission - quadratic term
231 // w[7] = transmission - cubic term
232 // w[8] = pass energy (hold this value)
233 // w[9] = y scale: pixels / unit of y
234
235 variable pos = w[3] + slit_shift(y * w[9], w[8])
236 variable transm = 1 + w[5] * y + w[6] * y^2 + w[7] * y^3
237 variable fermi = (w[1] * min(x - pos, 0) + w[2]) / ( exp( (x - pos) / (kBoltzmann * w[4]) ) + 1.0 )
238 return transm * (fermi + w[0])
239end
240
241//------------------------------------------------------------------------------
242threadsafe Function FermiFuncLinDOS_2Dcorr_old(w,x,y) : FitFunc
243// linear density of states below Fermi level
244// 2D data with a polynomial shift of the Fermi level in the second dimension
245//------------------------------------------------------------------------------
246 Wave w; Variable x; variable y
247 // w[0] = background far above the fermi level
248 // w[1] = slope of the linear background
249 // w[2] = amplitude
250 // w[3] = fermi level in eV
251 // w[4] = temperature in K
252 // w[5] = shift - linear term
253 // w[6] = shift - quadratic term
254
255 variable pos = w[3] + w[5] * y + w[6] * y^2
256 return w[0] + (w[1] * min(x - pos, 0) + w[2]) / ( exp( (x - pos) / (kBoltzmann * w[4]) ) + 1.0 )
257end
258
260static constant mcp_radius_pix = 555
262static constant mcp_radius_mm = 20
264static constant hemi_radius_mm = 200
266static constant mcp_radius_epass = 0.04
267
268threadsafe function slit_shift(ypix, epass)
269 // calculates the energy shift due to straight slit
270 // the radius of the curve is 1/2 of the hemisphere radius
271 variable ypix // vertical (angle/position) pixels distance from center
272 // = slice coordinate * 902 / number of slices
273 variable epass // pass energy
274
276 //variable rpix = mcp_radius_pix * hemi_radius_mm / 2 / mcp_radius_mm
277 variable rene = epass * mcp_radius_epass * hemi_radius_mm / 2 / mcp_radius_mm
278
279 variable isin = asin(ypix / rpix)
280 variable dene = rene * (cos(isin) - 1)
281
282 return dene
283end
284
285function show_shift(data)
286 wave data
287 variable epass
288
289 variable ny = dimsize(data, 1)
290 make /o /n=(ny) shift_x
291 setscale /i x -ny/2, ny/2, "", shift_x
292 wave PassEnergy = :attr:PassEnergy
293 wave NumSlices = :attr:NumSlices
294
295 shift_x = slit_shift(x * 902 / NumSlices[0], PassEnergy[0])
296
297 variable ecenter = dimoffset(data, 0) + dimdelta(data, 0) * dimsize(data, 0) / 2
298 shift_x += ecenter
299end
300
static const variable mcp_radius_pix
MCP radius seen by the camera in pixels.
static const variable hemi_radius_mm
physical size (radius) of the hemisphere in mm
variable analyse_curved_edge(wave data)
threadsafe variable slit_shift(variable ypix, variable epass)
variable integrate_curved_edge(wave data, wave data_sig)
static const variable mcp_radius_epass
energy range imaged on MCP relative to the pass energy
variable slit_correction(wave data, wave data_out, variable epass)
static const variable mcp_radius_mm
physical size (radius) of the MCP in mm
threadsafe variable FermiFuncLinDOS2D_corr(variable w, threadsafe x, wave y)
variable record_results(variable index)
variable show_shift(wave data)
threadsafe wave ad_profile_x(wave dataset, variable q1, variable q2, string destname, variable noavg=defaultValue)
1D cut through 2D dataset along X dimension, new destination wave.
threadsafe wave ad_profile_y(wave dataset, variable p1, variable p2, string destname, variable noavg=defaultValue)
1D cut through 2D dataset along Y dimension, new destination wave.