Handbook
Handbook
The Manual
c 1997–99 Christian Braun, HMI Berlin
current address: ETH Zürich
Laboratorium für Atmosphärenphysik
(LAPETH)
Hönggerberg HPP
8093 Zürich
Schweiz
e–mail: [email protected]
Contents
1 Introduction 4
2 The Programme 4
2.1 The Graphical User Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
4 Some Internals 16
4.1 The SLD Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
4.2 Hidden Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
4.3 Trouble is... . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
6 Appendix 28
2 The Programme
Parratt32 is a programme to calculate the optical reflectivity of neutrons or x-rays from flat
surfaces. The calculation is based on Parratt’s recursion scheme for stratified media [Parratt54].
Parratt32 is a Microsoft Windows application (either Windows 95, Windows 98 or Windows
NT 4.0 — the i386 edition works fine, other platforms, such as FX32 on DEC Alpha could not
be tested). The 32 bit extensions for 16bit-Windows (versions 3.1x, also known as Win32s)
are not sufficient!
Parratt32’s graphical user interface (GUI for short, or main window) is shown in figure 2.1.
The main elements, depicted by the arrows are described in the next sections.
3 M [g/mol]
neutrons: V [Å ] = 3 −1
· 1024
ρmass [g/cm ] · NA [mol ]
−2 bcoh [fm] −5
ρ[Å ] = 3 · 10
V [Å ]
−2 abs xs[barn] −8
Im(ρ)[Å ] = 3 · 10
1.789[Å] · 2 · V [Å ]
−2 2πδ
x–rays: ρ[Å ] =
1.5412
−2 2πβ
Im(ρ)[Å ] =
1.541 · λ
Note: 1.789 Å (2200m/s) is the wavelength for which the absorption cross section values are
tabulated, and 1.541 Å (Cu–Kα , 8047 eV) is the wavelength for which the δ and β values are
supplied in the table.
Installshield Express Delphi Edition that came with Delphi 3.0 (which was the development tool
for Parratt32) was not working correctly any more with this edition of the BDE. The support
site of ’Installshield.com’ had a little work–around for about two weeks in the late summer of
1998. It didn’t work error free (as you see) but at least is does not prevent the installation
of the software, completely. Then they stopped supporting this version of their software and
removed the patch from their server. In the meanwhile Inprise came out with Delphi 4 which
was bundled with a) the BDE 5.0 and b) a new version of Installshield Express Delphi Edition.
But this also means that people like me, who do not own a Delphi 4 or an InstallShieldExpress
2.03 will never be able to make correctly working sets of installation media.
All this only concerns the installation of Parratt32. Once installed there are no known
problems with BDE 5.0!
5.1.2 Globals
This is the file called globals.pas where all the global constants, types and variables are stored.
It’s not too much I guess...
1 unit Globals;
2 {************************************************************************}
3 { some constants and some types that are used globally }
4 {************************************************************************}
5 interface
6
7 const { some upper array boundaries and misc. constants }
8 maxLayers = 499;
9 maxQValues = 999;
10 map = maxLayers*4+10;
11 { different values for variable ’sampletype’ }
12 simplesample = 1;
13 functionsample = 2;
14 multisample = 3;
15 { different function types }
16 ft_builtin = 0;
17 ft_user = 1;
18 { Window IDs}
19 wnd_Plot = 1;
20 wnd_Model = 2;
21 wnd_Profile = 3;
22 { dataset IDs}
23 ds_data = 0;
24 ds_calc = 1;
25 ds_prof = 0;
26 ds_minus = 2;
27 ds_plus = 3;
28 ds_trans = 4;
29 ds_fitwindow = 9;
30 { Help IDs}
31 hcIndex = 10;
32 hcfrmPlot = 80;
33 hcfrmModel = 40;
34 hcfrmProfile = 70;
35 fittingdialog = 350;
36 settingsdialog = 330;
37 functiondialog = 340;
38 DatabaseEditor = 375;
39
40 RegFilename = ’\SOFTWARE\HMI\Parratt32’;
41
42 type float = double;
43 flarray = array[-5..maxLayers*4+5] of float;
44 Pflarray = ^flarray;
45 flarray1 = array[0..maxQValues] of float;
46 PFlarray1 = ^flarray1;
47 IntegerArrayMFIT = ARRAY [1..map] OF integer;
48 FitParameter = array[1..maxLayers*4+10] of float;
49
50 var a: Pflarray; { layer parameters for fitting }
51 q, refl, errors: Pflarray1; { loaded data }
52 resltn, bg: Pflarray1; { resolution and background }
53 ndata: integer; { number of datapoints in loaded data }
54 nlparms: integer; { number of layer parameters }
55 c_MinZ, c_MaxZ: integer;
56 dataavail, hasbeenfitted, expert,
57 splashing, databaseing: Boolean;
58 sampletype, functiontype: Byte;
59 fitwindow: array[0..1] of float;
60 www_hmi, www_bensc, author_e_mail: String;
61 datafilename, fn_databasename: String;
62
63 implementation
64
65 {************************************************************************}
66
67
68 end.
NB: ρn is complex: ρn = %n + iIm(%n ), where %n and Im(%n ) are the values given in the model
window.
The source is somewhat documented. Only a few remarks: procedures kadd, ksub, kmul, kdiv,
kexp, and ksqrt all work on complex numbers (type kompl) and are defined in cxmath.pas. Since
Pascal knowns no way of passing back user defined types in functions these all had to be made
procedures that pass back the result in the last argument. For this reason there is heavy use of
temporary variables in the code. The bare reflectivity is calculated by cParratt(...), whereas
the plotting routine calls CalcParratt(...), where things like background and resolution are
handled.
1 unit Uparratt;
2 {************************************************************************}
3 { This Unit calculates the reflectivity of a n-layer system at given Qz }
4 { R(Qz) := cParratt(Qz, resolution, nlayers, parameters) }
5 { }
6 { }
7 { input is as follows: }
8 { double Qz: z-component of the scattering vector }
9 { double Resolution: Qz-resolution }
10 { integer nlayers: number of layers (no bulk, no vacuum) }
11 { pointer parameters: points to an array of the following parameters: }
12 { parameters[1] := rho(air) }
13 { [2] := Imrho(air) }
14 { [3] := d(1st layer) }
15 { [4] := rho(1st layer) }
16 { [5] := Imrho(1st layer) }
17 { [6] := sigma(1st layer) }
18 { ... }
19 { [4*nlayer+3] := d(nth layer) }
20 { ... }
21 { [4*nlayer+6] := sigma(nth layer) }
22 { [4*nlayer+7] := rho(bulk) }
23 { [4*nlayer+8] := Imrho(bulk) }
24 { [4*nlayer+9] := sigma(bulk) }
25 { example: }
26 { for a single interface there will be 5 parameters: }
27 { rho(air), Imrho(air), rho(bulk), Imrho(bulk), sigma(bulk) }
28 { }
29 { d is in Angstroms (AA) }
30 { rho is in AA^-2: rho_el * r_0 for x-rays, }
31 { Nb for neutrons }
32 { Imrho is in AA^-2: calculated from beta for xrays, }
33 { calculated from abs. cross section for neutrons }
34 { sigma is in AA }
35 {************************************************************************}
36
37 interface
38
39 uses Globals, cxmath;
40
41 function calcParratt(qz, rsltn, bg: float;
42 nlayers: integer; parameters: Pflarray;
43 UseRsltn, UseBG: Boolean): float;
44
45 implementation
46
47 var rrn: array[0..maxLayers+1] of kompl;
48
49 function cParratt(qz: float; nlayers: integer; parameters: Pflarray): float;
50 var
51 d, rho, imrho, sigma: array[0..maxLayers] of float;
52 rcc, rnn1, arg, temp1, temp2, num, den: kompl;
53 n : integer;
54 e2idk, rme: kompl;
55 kz0: float;
56
57 procedure kzn(kz0: float; ni: integer; var res: kompl);
58 var radix: kompl;
59 begin
60 radix[1] := kz0*kz0-4*pi*rho[ni];
61 radix[2] := 4*pi*imrho[ni]; // changed 08-02-98, cb
62 ksqrt(radix, res);
63 end;
64
65 procedure rn(kz0: float; ni: integer; var res: kompl);
66 var kz_n, kz_np1, rnum, rden, e2kks, rfres, arg1, arg2: kompl;
67 begin
68 kzn(kz0, ni, kz_n);
69 kzn(kz0, ni+1, kz_np1);
70 ksub(kz_n, kz_np1, rnum);
71 kadd(kz_n, kz_np1, rden);
72 kdiv(rnum, rden, rfres);
73 { include roughness according to Nevot & Croce }
74 kmul(kz_n, kz_np1, arg1);
75 rmul(-2*sqr(sigma[ni+1]), arg1, arg2);
76 kexp(arg2, e2kks);
77 kmul(rfres, e2kks, res);
78 end;
79
80 begin
81 { map parameters^[] to d[], rho[], my[], sigma[] }
82 rho[0]:= parameters^[1];
83 imrho[0]:= parameters^[2];
84 { calculate wavevector kz0’: 1. vacuum, air -> Qz/2 }
85 { 2. n0 <> 0 -> sqrt(Qz0^2/4+4*pi*rho0+4*pi*mu0)}
86 temp1[1] := qz*qz/4+4*pi*rho[0];
87 temp1[2] := 4*pi*imrho[0];
88 ksqrt(temp1, temp2);
89 kz0 := kabs(temp2);
90 for n := 1 to nlayers do
91 begin
92 d[n] := abs(parameters^[(n-1)*4+3]); // abs() added 22-01-98
93 rho[n] := parameters^[(n-1)*4+4];
94 imrho[n] := parameters^[(n-1)*4+5];
95 sigma[n] := parameters^[(n-1)*4+6];
96 end;
97 rho[nlayers+1] := parameters^[nlayers*4+3];
98 imrho[nlayers+1] := parameters^[nlayers*4+4];
99 sigma[nlayers+1] := parameters^[nlayers*4+5];
100 { done with remapping }
101 rrn[nlayers+1, 1] := 0;
102 rrn[nlayers+1, 2] := 0;
103 { calculate rrn[nlayers]: bulk interface }
104 rn(kz0, nlayers, rrn[nlayers]);
105 { calculate the rrn[...] for the remaining layers }
106 for n := nlayers-1 downto 0 do
107 begin
108 rn(kz0, n, rnn1); { r_n,n+1 }
109 kzn(kz0, n+1, temp1); { k_z,n+1 }
110 arg[1] := 0;
111 arg[2] := 2*d[n+1];
112 kmul(temp1, arg, temp2); { 2 * i * k_z,n+1 * z_n+1 }
113 kexp(temp2, e2idk);
114 kmul(e2idk, rrn[n+1], rme); { X_n+1 * exp(2 i k_z,n+1 z_n+1) }
115 kadd(rnn1, rme, num); { r_n,n+1 + X_n+1 * exp(---) }
116 kmul(rnn1, rme, den); { r_n,n+1 * X_n+1 * exp(---) }
117 den[1] := den[1] + 1;
118 kdiv(num, den, rrn[n]);
119 end;
120 rcc[1] := rrn[0,1]; rcc[2] := -1*rrn[0,2];
121 kmul(rrn[0], rcc, temp1);
122 cParratt := temp1[1];
123 end;
124
125 function calcParratt(qz, rsltn, bg: float;
126 nlayers: integer; parameters: Pflarray;
127 Usersltn, UseBG: Boolean): float;
128 var refl: float;
129 begin
130 refl := cParratt(qz, nlayers, parameters);
131 if UseRsltn then
132 begin
133 { approximate Gaussian beam profile by 8 pivot points }
134 refl := refl + 0.135*cParratt(qz-rsltn, nlayers, parameters);
135 refl := refl + 0.135*cParratt(qz+rsltn, nlayers, parameters);
136 refl := refl + 0.325*cParratt(qz-rsltn*3/4, nlayers, parameters);
137 refl := refl + 0.325*cParratt(qz+rsltn*3/4, nlayers, parameters);
138 refl := refl + 0.605*cParratt(qz-rsltn/2, nlayers, parameters);
139 refl := refl + 0.605*cParratt(qz+rsltn/2, nlayers, parameters);
140 refl := refl + 0.88*cParratt(qz-rsltn/4, nlayers, parameters);
141 refl := refl + 0.88*cParratt(qz+rsltn/4, nlayers, parameters);
142 refl := refl/4.89;
143 end;
144 if UseBG then refl := refl + bg;
145 calcParratt := refl;
146 end;
147 end.
where Tsubst (Qz ) is the transmission through the substrate, which is calculated by the following
code:
1 function calcTrans(qz: float; nlayers: integer; parameters: Pflarray;
2 wavelength, substratethickness: float): float;
3 var pathlength: float;
4 d, rho, imrho: float;
5 temp1, temp2, temp3: kompl;
6 n: integer;
7 currentk: kompl;
8 begin
9 pathlength := 0;
10 for n := 1 to nlayers do
11 begin
12 d := abs(parameters^[(n-1)*4+3]);
13 rho := parameters^[(n-1)*4+4];
14 imrho := parameters^[(n-1)*4+5];
15 temp1[1] := d*2*pi/wavelength;
16 temp1[2] := 0;
17 temp2[1] := qz*qz/4-4*pi*rho;
18 temp2[2] := 4*pi*imrho;
19 ksqrt(temp2, currentk);
20 kdiv(temp1, currentk, temp3);
21 pathlength := pathlength + temp3[1];
22 end;
23 rho := parameters^[nlayers*4+3];
24 imrho := parameters^[nlayers*4+4];
25 d := substratethickness*1e7; // thickness is in millimeters, we need AA
26 temp1[1] := d*2*pi/wavelength;
27 temp1[2] := 0;
28 temp2[1] := qz*qz/4-4*pi*rho;
29 temp2[2] := 4*pi*imrho;
30 ksqrt(temp2, currentk);
31 kdiv(temp1, currentk, temp3);
32 pathlength := pathlength + temp3[1];
33 if pathlength > 0 then result := exp(-2*wavelength*imrho*pathlength)
34 else result := 0;
35 end;
where N is the overall number of layers, %i is the scattering length density of the ith layer at
position zi and with a gaussian roughness σi . The error function erf(x) is approximated by a
5th order polynomial given by Press et al.[Press88].
1 procedure TfrmProfile.ShowProfile;
2 var i, j, s_index, r_index, d_index,
3 lastlayer, zstart, zend, temp: integer;
4 z, zinc, sum,
5 deltarho, sigma, zi: float;
6
7 function erfcc(x: float): float; { according to ’NumRecip’ }
8 var
9 t,z,ans: extended;
10 begin
11 z := abs(x);
12 t := 1.0/(1.0+0.5*z);
13 try
14 ans := t*exp(-z*z-1.26551223+t*(1.00002368+t*(0.37409196+t*(0.09678418
15 +t*(-0.18628806+t*(0.27886807+t*(-1.13520398+t*(1.48851587
16 +t*(-0.82215223+t*0.17087277)))))))));
17 except
18 ans := 0;
19 end;
20 if x >= 0.0 then erfcc := ans
21 else erfcc := 2.0-ans
22 end;
23
24 begin
25 Screen.Cursor := crHourGlass;
26 GetParameters(0);
27 xyGraph1[ds_prof].Free;
28 xyGraph1.Plotting := False;
29 with xyGraph1[ds_prof] do
30 begin
31 DrawPoints := False;
32 LineColor := clBlack;
33 end;
34 if SettingsDlg.cbUserZ.Checked then
35 with SettingsDlg do
36 begin
37 zstart := edtMinZ.Value;
38 zend := edtMaxZ.Value;
39 if zstart > zend then
40 begin
41 temp := zstart;
42 zstart := zend;
43 zend := temp;
44 end;
45 end
46 else CalcZBounds(zstart, zend);
47 z := zstart;
48 zinc := (zend-zstart)/SettingsDlg.edtNumPointsZ.Value;
49 while z <= zend do
50 begin
51 lastlayer := 0;
52 case sampletype of
53 simplesample:
54 lastlayer := frmModel.edtLayers.Value;
55 functionsample:
56 lastlayer := frmModel.edtLayers.Value+frmModel.edtNumCalcLayers.Value;
57 multisample:
58 lastlayer := frmModel.edtLayers.Value
59 +frmModel.edtRepts.Value*frmModel.edtStackedLayers.Value;
60 end;
61 sum := a^[1];
62 for i:= 1 to lastlayer+1 do
63 begin
64 if i = lastlayer+1 then
65 begin
66 r_index := 4*i-1; { rho_bulk }
67 s_index := r_index+2; { sigma_bulk }
68 if lastlayer = 0
69 then deltarho := a^[r_index] - a^[r_index-2]
70 else deltarho := a^[r_index] - a^[r_index-3];
71 end else
72 begin
73 s_index := 4*i+2;
74 r_index := 4*i;
75 if i = 1
76 then deltarho := a^[r_index]-a^[r_index-3]
77 else deltarho := a^[r_index]-a^[r_index-4];
78 end;
79 zi := 0;
80 j := 1;
81 if i>1 then while j<i do
82 begin
83 d_index := 4*(j-1)+3;
84 zi := zi + a^[d_index];
85 inc(j);
86 end;
87 if a^[s_index] = 0 then sigma := 1e-3
88 else sigma := a^[s_index];
89 sum := sum + deltarho/2*(2-erfcc((z-zi)*sqrt(2)/2/sigma)); // changed on 24-NOV-99
90 end;
91 xyGraph1[ds_prof][z] := sum;
92 Form1.Statusbar1.Panels[0].Text :=
93 Format(’calculating rho(z), z = %f’, [z]);
94 Form1.Statusbar1.Refresh;
95 z := z + zinc;
96 end;
97 Screen.Cursor := crDefault;
98 xyGraph1.Dimensions.YAxisTitleOffset := 20;
99 xyGraph1.Plotting := True;
100 Form1.Statusbar1.Panels[0].Text := ’’;
101 end;
75 fac := fac/2;
76 Application.Processmessages;
77 if ModalResult = mrCancel then stopfitting := True;
78 until ((abs(chidiff)<=edtTolerance.Value) and (iter>2)) or stopfitting;
79 end;
80
81 begin
82 stopfitting := False;
83 converged := False;
84 lblconverged.Visible := False;
85 btnStop.Enabled := True;
86 Screen.Cursor := crHourGlass;
87 { set weighting method }
88 if RBNone.Checked then weightingmethod := 3;
89 if RBStat.Checked then weightingmethod := 2;
90 if RBErrors.Checked then weightingmethod := 1;
91 { get variable parameters from CheckListBox1 }
92 nvarpar := 0;
93 i := 0;
94 while i <= CheckListBox1.Items.Count-1 do
95 begin
96 if CheckListBox1.Checked[i] then
97 begin
98 lista[nvarpar+1] := i+1;
99 inc(nvarpar);
100 end;
101 inc(i);
102 end;
103 { set overall number of layers }
104 nol := frmModel.edtLayers.Value;
105 case sampletype of
106 functionsample: nol := nol + frmModel.edtNumCalcLayers.Value;
107 multisample: nol := nol + frmModel.edtStackedLayers.Value
108 *frmModel.edtRepts.Value;
109 end;
110 { get fitting region }
111 if (fitwindow[0] = -1) and (fitwindow[1]=-1) then
112 begin { no user region specified }
113 fitndataStart := 1;
114 fitndataEnd := ndata;
115 end else
116 begin { user has specified a region }
117 i := 0;
118 repeat
119 inc(i);
120 until (i > ndata) or (q^[i] > fitwindow[0]);
121 fitndataStart := i-1;
122 i := 0;
123 repeat
124 inc(i);
125 until (i > ndata) or (q^[i] > fitwindow[1]);
126 fitndataEnd := i-1;
127 end;
128 { check if user wants to fit or only the chisq }
129 RB := 0;
130 if RBchisq.Checked then RB := 1;
131 if RBfulliter.Checked then RB := 2;
132 case RB of
133 1: lblChisq.Caption := FormatFloat(’0.0000E+00’, CalcChisq(weightingmethod));
134 2: begin
135 { ’make’ all parameters are still unminimized }
136 for i := 1 to nvarpar do listadone[i] := 1;
137 finished := False;
138 lastvarpar := -1;
139 repeat
140 if nvarpar > 1 then
141 repeat
142 j := Trunc(Random*nvarpar)+1;
143 until j <> lastvarpar
144 else j := 1;
145 lastvarpar := j;
146 if listadone[j]=1 then
147 begin
148 chiold := CalcChisq(weightingmethod);
149 Newton(lista[j]);
150 if chisq<chiold then for i:=1 to nvarpar do listadone[i]:=1
151 else listadone[j] := 0;
152 end;
153 lblChisq.Caption := FormatFloat(’0.0000E+00’, chisq);
154 { replot the graph }
155 frmPlot.xyGraph1.Plotting := False;
156 frmPlot.xyGraph1[ds_calc].Free;
157 with frmPlot.xyGraph1[ds_calc] do
158 begin
5.2 Compiling
5.2.1 What you need...
1. The sources. These can be obtained from Christian Braun by e–mail:
[email protected] or ask Roland Steitz ([email protected]) for my whereabouts.
All of them are freeware and can be found on the Delphi Super Page.
References
[Parratt54] L. G. Parratt, Phys. Rev, 95(2), 359-369, 1954
data reflectivity
ASCII files, 6 calculation of, 7, 8, 20
copying, 14 resolution, 11
errors in experimental, 6 angular, 11
experimental, 6
raw, 11 sample
database, 12 free, 10
scattering length, 12 scattering length density
dialogue calculation of, 7, 9, 23
model function, 7 settings
settings, 9 background, 11
database, 12
error function, 23 profile calculation, 10
reflectivity calculation, 9
fitting, 12, 24 resolution, 11
χ2 , 24 transmission calculation, 10
least squares, 24 source code, 4
subset of data, 13 fitting procedure, 24
discard, 13 reflectivity calculation, 20
function SLD profile calculation, 23
built in, 7 transmission calculation, 22
user, 7 status bar, 5
graphical user interface, 4 thickness
of substrate, 10
instrument tool bar, 5
collimation system, 11 transmission
noise, 11 calculation of, 10, 22
velocity selector, 11
user function, 7
layer
multiple, 8 wavelength, 9, 10
number of, 7 distribution, 11
thickness, 10 window
graph
magnetization rescaling, 9
including, 10 main, 4
menu bar, 5 model, 5, 6
model profile, 5, 9
independent layers, 7 reflectivity, 5, 6, 8
multi layer, 8
setting up, 6, 12
simple, 7
with function, 7
noise, 11