forked from hoogerheide/autonomous
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathssblm.py
More file actions
153 lines (119 loc) · 6.59 KB
/
ssblm.py
File metadata and controls
153 lines (119 loc) · 6.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
## === Import section ===
import sys
# append path to your molgroups, or just link molgroups to your same directory
sys.path.append('')
import numpy as np
from molgroups import PC, ssBLM
import components as cmp
from refl1d.names import load4, Parameter, SLD, Slab, Stack, Experiment, FitProblem
from refl1d.flayer import FunctionalProfile
## === Film structure definition section ===
### Bilayer profile definition function
def bilayer(z, sigma, bulknsld, global_rough, rho_substrate, l_submembrane, l_lipid1, l_lipid2, vf_bilayer):
""" Fairly generic bilayer. This assumes a stack of materials already existing because siox.l is set to zero """
# Set unused parameters
l_siox = 0.0 # could make a parameter in the future
rho_siox = 0.0
# Scale all SLDs from Refl1D units (1e-6 Ang^-2) to molgroups units (Ang^-2)
bulknsld *= 1e-6
rho_substrate *= 1e-6
blm.fnSet(sigma, bulknsld, global_rough, rho_substrate, rho_siox, l_siox, l_submembrane, l_lipid1, l_lipid2, vf_bilayer)
# Calculate scattering properties of volume occupied by bilayer
normarea, area, nsl = blm.fnWriteProfile(z)
# Fill in the remaining volume with buffer of appropriate nSLD
nsld = nsl / (normarea * np.gradient(z)) + (1.0 - area / normarea) * bulknsld
# Return nSLD profile in Refl1D units
return nsld*1e6
### Define bilayer parameters
vf_bilayer = Parameter(name='volume fraction bilayer', value=0.9).range(0.0, 1.0)
l_lipid1 = Parameter(name='inner acyl chain thickness', value=10.0).range(8, 16)
l_lipid2 = Parameter(name='outer acyl chain thickness', value=10.0).range(8, 16)
sigma = Parameter(name='bilayer roughness', value=5).range(2, 9)
global_rough = Parameter(name ='tiox roughness', value=5).range(2, 9)
l_tiox = Parameter(name='total tiox thickness', value=120).range(50, 150)
l_submembrane = Parameter(name='submembrane thickness', value=10).range(0, 50)
### Define bilayer object
DOPC = cmp.Lipid(name='DOPC', headgroup=PC, tails=[cmp.oleoyl, cmp.oleoyl], methyls=cmp.methyl)
blm = ssBLM(lipids=[DOPC], lipid_nf=[1.0])
### Define molgroups space.
dimension=300 # Number of steps
stepsize=0.5 # Length of steps
## === Stack ===
##
## First, we create a 'material' for each bulk layer, which has an real and imaginary
## scattering length density, stored in a Refl1d object called 'SLD'
d2o = SLD(name='d2o', rho=6.3000, irho=0.0000)
h2o = SLD(name='h2o', rho=-0.56, irho=0.0000)
tiox = SLD(name='tiox', rho=2.1630, irho=0.0000)
siox = SLD(name='siox', rho=4.1000, irho=0.0000)
silicon = SLD(name='silicon', rho=2.0690, irho=0.0000)
## Then bulk layers are created, each with its own 'material'. If you want to force
## two layers to always match SLD you can use the same material in multiple layers.
## The roughnesses of each layer are set to zero to begin with:
layer_d2o = Slab(material=d2o, thickness=0.0000, interface=5.0000)
layer_h2o = Slab(material=h2o, thickness=0.0000, interface=5.0000)
layer_tiox = Slab(material=tiox, thickness=l_tiox - (blm.substrate.z + 0.5 * blm.substrate.l), interface=0.0)
layer_siox = Slab(material=siox, thickness=7.5804, interface=10.000)
layer_silicon = Slab(material=silicon, thickness=0.0000, interface=0.0000)
## Use the bilayer definition function to generate the bilayer SLD profile, passing in the relevant parameters.
## Note that substrate and bulk SLDs are linked to their respective materials.
mollayer = FunctionalProfile(dimension*stepsize, 0, profile=bilayer, sigma=sigma,
bulknsld=d2o.rho, global_rough=global_rough, rho_substrate=tiox.rho,
l_submembrane=l_submembrane, l_lipid1=l_lipid1, l_lipid2=l_lipid2,
vf_bilayer=vf_bilayer)
mollayerh = FunctionalProfile(dimension*stepsize, 0, profile=bilayer, sigma=sigma,
bulknsld=h2o.rho, global_rough=global_rough, rho_substrate=tiox.rho,
l_submembrane=l_submembrane, l_lipid1=l_lipid1, l_lipid2=l_lipid2,
vf_bilayer=vf_bilayer)
## Stack the layers into individual samples, using common layer objects for layers that are unchanged between samples
## As a convention, always build the sample from the substrate up. If the neutron beam is incident from the substrate side,
## set back_reflectivity = True in the probe definition later.
sample = layer_silicon | layer_siox | layer_tiox | mollayer | layer_d2o
sampleh = layer_silicon | layer_siox | layer_tiox | mollayerh | layer_h2o
## Set sample parameter ranges and constraints between layer properties
# nSLD parameters
d2o.rho.range(5.3000, 6.5000)
h2o.rho.range(-0.6, 0.6)
tiox.rho.range(1.1630, 3.1630)
siox.rho.range(3.1000, 5.1000)
# layer thickness parameters
layer_tiox.thickness.range(66.379, 266.38)
layer_siox.thickness.range(5, 40)
# layer roughness parameters
###################################################################
## the 'interface' associated with layer0 is the boundary between #
## layer0 and layer1, and similarly for layer(N) and layer(N+1) #
###################################################################
layer_siox.interface.range(2.0000, 9.000)
# Si and SiOx roughnesses are the same
layer_silicon.interface = layer_siox.interface
## === Data files ===
probe = load4('ch061.refl', back_reflectivity=True)
probeh = load4('ch060.refl', back_reflectivity=True)
# Set instrumental (probe) parameters
probe.background.range(-1e-7, 1e-5)
probeh.background.range(-1e-7, 1e-5)
probe.intensity.range(0.9, 1.05)
probeh.intensity = probe.intensity
probe.theta_offset.range(-0.015, 0.005)
probeh.theta_offset = probe.theta_offset
probe.sample_broadening.range(-0.005, 0.02)
probeh.sample_broadening = probe.sample_broadening
# Define critical edge oversampling for samples that require it
probe.critical_edge(substrate=silicon, surface=d2o)
## === Problem definition ===
## a model object consists of a sample and a probe.
## step = True corresponds to a calculation of the reflectivity from an actual profile
## with microslabbed interfaces. When step = False, the Nevot-Croce
## approximation is used to account for roughness. This approximation speeds up
## the calculation tremendously, and is reasonably accuarate as long as the
## roughness is much less than the layer thickness
step = False
model = Experiment(sample=sample, probe=probe, dz=stepsize, step_interfaces = step)
modelh = Experiment(sample=sampleh, probe=probeh, dz=stepsize, step_interfaces = step)
problem = FitProblem([model, modelh])
## === Export objects for post analysis ===
problem.name = "DOPC bilayer on TiOx substrate"
problem.bilayers = [blm]
problem.dimension = dimension
problem.stepsize = stepsize