PEARL Procedures  rev-distro-3.0.0-0-gfa24916-dirty
Igor procedures for the analysis of PEARL data
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 
28 function 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
97 end
98 
99 function 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
115 end
116 
117 function 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
172 end
173 
174 function 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
214 end
215 
216 //------------------------------------------------------------------------------
217 threadsafe 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])
239 end
240 
241 //------------------------------------------------------------------------------
242 threadsafe 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 )
257 end
258 
260 static constant mcp_radius_pix = 555
262 static constant mcp_radius_mm = 20
264 static constant hemi_radius_mm = 200
266 static constant mcp_radius_epass = 0.04
267 
268 threadsafe 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 
275  variable rpix = mcp_radius_pix * hemi_radius_mm / mcp_radius_mm
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
283 end
284 
285 function 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
299 end
300 
FermiFuncLinDOS2D_corr
threadsafe variable FermiFuncLinDOS2D_corr(variable w, threadsafe x, wave y)
Definition: fermi-edge-analysis.ipf:217
integrate_curved_edge
variable integrate_curved_edge(wave data, wave data_sig)
Definition: fermi-edge-analysis.ipf:117
hemi_radius_mm
static const variable hemi_radius_mm
physical size (radius) of the hemisphere in mm
Definition: fermi-edge-analysis.ipf:264
ad_profile_x
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.
Definition: pearl-area-profiles.ipf:481
slit_correction
variable slit_correction(wave data, wave data_out, variable epass)
Definition: fermi-edge-analysis.ipf:174
ad_profile_y
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.
Definition: pearl-area-profiles.ipf:543
mcp_radius_mm
static const variable mcp_radius_mm
physical size (radius) of the MCP in mm
Definition: fermi-edge-analysis.ipf:262
show_shift
variable show_shift(wave data)
Definition: fermi-edge-analysis.ipf:285
analyse_curved_edge
variable analyse_curved_edge(wave data)
Definition: fermi-edge-analysis.ipf:28
slit_shift
threadsafe variable slit_shift(variable ypix, variable epass)
Definition: fermi-edge-analysis.ipf:268
record_results
variable record_results(variable index)
Definition: fermi-edge-analysis.ipf:99
mcp_radius_pix
static const variable mcp_radius_pix
MCP radius seen by the camera in pixels.
Definition: fermi-edge-analysis.ipf:260
mcp_radius_epass
static const variable mcp_radius_epass
energy range imaged on MCP relative to the pass energy
Definition: fermi-edge-analysis.ipf:266