1 """
2 Reflectometry layer times.
3
4 A reflectometry layer has a function calc which takes a vector z
5 and a layer thickness d, returning a profile value for each z:
6
7 def calc(self, thickness, z):
8
9 Reflectometry profile interactor.
10 """
11
12 import numpy
13 from bspline import bspline3
14
15
16
18 """ Abstract Layer Class """
19 - def __init__(self,
20 name = "NonType",
21 Val = -10000,
22 span = 1
23 ):
24 self._layerName = name
25 self._val = Val
26 self.span = span
27
28 self.toFloatValue()
29
30
31 self._var = False
32
33
35 try: n = len(self._val)
36 except: n = 1
37 if n==1: self._val = float(self._val)
38 else:
39 for i in xrange(n):
40 self._val[i]=float(self._val[i])
41
42
45
46
49
50
51 - def calc(self, thickness, z):
52 """Compute the values for the profile"""
53 pass
54
55
58
59
60
61
62
64 """
65 Flat section of reflectometry profile
66 """
67 - def __init__(self,
68 name = "Flat",
69 Val = 1.0,
70 span = 1
71 ):
72 """
73 Create a flat layer for a profile. It has a single parameter v
74 indicating the value of the layer.
75
76 The optional span indicates how many model layers are spanned
77 by this portion of the profile.
78 """
79 _Layer.__init__(self, name, Val, span)
80
81
82 - def calc(self, thickness, z):
83 """Compute the values for the profile at depth z (scalar or array)."""
84 return self._val
85
86
88 return "%.6f"%(self._val)
89
90
91
92
93
95 """
96 Sloping section of reflectometry profile
97 """
98 - def __init__(self,
99 name = "Slope",
100 Val = 1.0,
101 span = 1
102 ):
103 """
104 Create a sloping layer for a profile. It has a single tuple v
105 indicating the value at the ends of the layer.
106
107 The optional span indicates how many model layers are spanned
108 by this portion of the profile.
109
110 TODO: line should pick up it's end points from surrounding layers.
111 """
112 _Layer.__init__(self, name, Val, span)
113
114
115 - def calc(self,
116 thickness,
117 z
118 ):
119 """
120 Compute the values for the profile at depth z (scalar or array).
121 """
122 left,right = self._val
123 slope = (right-left)/float(thickness)
124
125 return slope*z + left
126
127
129 return "Slope(%s)" %( self._val )
130
131
132
133
134
136 """
137 Spline section of reflectometry profile
138 """
139 - def __init__(self,
140 name = "spline",
141 Val = 1.0,
142 span = 1,
143 uniform = True
144 ):
145 """
146 Create a spline layer for a profile. It has a single tuple v
147 indicating the control values of the spline.
148 The control points are assumed to be equally spaced.
149
150 The optional span indicates how many model layers are spanned
151 by this portion of the profile.
152
153 TODO: line should pick up it's end points from surrounding layers.
154 TODO: provide methods for adding/deleting points.
155 """
156 if Val == None:
157 raise ValueError, "Must support v value's"
158
159 _Layer.__init__(self, name, Val, span)
160
161 self.control = len( Val )
162
163 if self.control < 3:
164 raise ValueError, "Splines must have at least 3 control points"
165
166 self.control_z = numpy.arange(0.0, self.control)/(self.control-1.0)
167
168
169
170 - def calc(self,
171 thickness,
172 z
173 ):
174 """
175 Compute the values for the profile at depth z (scalar or array).
176 """
177 control_rho = numpy.array(self._val)
178 knots = numpy.concatenate( ( [0.0,0.0], self.control_z, [1.0,1.0] ) )
179
180 knots *= thickness
181
182 if numpy.isscalar(z):
183
184 return bspline3(knots, control_rho, numpy.array([z]))[0]
185 else:
186 return bspline3(knots, control_rho, z)
187
188
190 return "BSpline(%s)" %(self._val)
191
192
193
194
196 """
197 Cosine section of reflectometry profile
198 """
199 - def __init__(self,
200 name = "Cosine",
201 Val = 1.0,
202 span = 1
203 ):
204 """
205 Create a Cosine layer for a profile.
206 It has a single tuple v indicating the 'offset', 'amplitude',
207 'wavelength', and 'phase' of the Cosine.
208
209 The optional span indicates how many model layers are spanned
210 by this portion of the profile.
211 """
212 if Val == None:
213 raise ValueError, "Must support v value's"
214
215 _Layer.__init__(self, name, Val, span)
216
217 self.n = len( Val )
218
219 if self.n < 4:
220 raise ValueError, "Cosine must have at least 4 parameters"
221
222
223 - def calc(self,
224 thickness,
225 z
226 ):
227 """
228 Compute the values for the profile at depth z (scalar or array).
229 """
230 offset,amplitude,wavelength,phase = self._val
231 return offset + \
232 amplitude*numpy.cos( 2.0*numpy.pi*( (z/wavelength) + phase ) )
233
234
236 return "Cosine(%s)" %(self._val)
237
238
239
240
241
243 """
244 PowerLaw section of reflectometry profile
245 """
246 - def __init__(self,
247 name = "Power Law",
248 Val = 1.0,
249 span = 1
250 ):
251 """
252 Create a PowerLaw layer for a profile.
253 It has a single tuple v indicating the 'multiplier', 'lin_coeff',
254 and 'power' of the PowerLaw.
255
256 The optional span indicates how many model layers are spanned
257 by this portion of the profile.
258 """
259 if Val == None:
260 raise ValueError, "Must support v value's"
261
262 _Layer.__init__(self, name, Val, span)
263
264 self.n = len( Val )
265
266 if self.n < 3:
267 raise ValueError, "PowerLaw must have at least 3 parameters"
268
269
270 - def calc(self,
271 thickness,
272 z
273 ):
274 """
275 Compute the values for the profile at depth z (scalar or array).
276 """
277 multiplier,lin_coeff,pownum = self._val
278 return multiplier*numpy.power( 1 + (z*lin_coeff), pownum )
279
281 return "PowerLaw(%s)" %(self._val)
282
283
284
285
286
288 """
289 TetheredPolymer section of reflectometry profile
290 """
291 - def __init__(self,
292 name = "Tethered Polymer",
293 Val = 1.0,
294 span = 1
295 ):
296 """
297 Create a Tethered Polymer layer for a profile.
298 It has a single tuple v indicating the 'Value for polymer',
299 'Value for solvent', 'phi_0', 'Flat fraction', and 'Y'
300 of the Tethered Polymer.
301
302 The optional span indicates how many model layers are spanned
303 by this portion of the profile.
304 """
305 if Val == None:
306 raise ValueError, "Must support v value's"
307
308 _Layer.__init__(self, name, Val, span)
309
310 self.n = len( Val )
311
312 if self.n < 5:
313 raise ValueError, "PowerLaw must have at least 5 parameters"
314
315
316 - def calc(self,
317 thickness,
318 z
319 ):
320 """
321 Compute the values for the profile at depth z (scalar or array).
322 """
323 SLD_polymer, SLD_solvent, L_head, phi0, Y = self._val
324
325 L_tail = thickness - L_head
326 sq_coeffs = (z - L_head) / L_tail
327 sq_coeffs = numpy.clip(sq_coeffs, 0.0, 1.0)
328 power_coeffs = 1.0 - (sq_coeffs ** 2.0)
329 volfrac = phi0 * (power_coeffs ** Y)
330 result = SLD_polymer * volfrac + \
331 SLD_solvent * (1.0-volfrac)
332
333
334
335
336 return result
337
338
340 return "TetheredPolymer(%s)" %(self._val)
341
342
343
344
345
347 """
348 Join the current section of the profile to the previous section
349 """
351 """
352 Create a placeholder which indicates that the previous layer should be
353 extended by the depth of the current layer. The join layer
354 inherently has a span of 0.
355 """
356 if span != 0: raise ValueError("Joined layer span must be zero")
357 self.span = 0
358
359 - def calc(self, thickness, z):
360 """
361 A join layer has no profile and should not be computed.
362 """
363 raise NotImplementedError("Joined layer has no profile")
364
365
366
367
368
370 """
371 Empty layer
372 """
374 """
375 Create a placeholder which indicates that the current layer is empty.
376 This will evaluate as a flat layer of value 0.
377
378 The optional span indicates how many model layers are spanned
379 by this portion of the profile.
380 """
381 self.span = span
382
383 - def calc(self, thickness, z):
384 """
385 Compute the values for the profile at depth z (scalar or array).
386 """
387 return z*0
388
389
390
391
392
393
395 """
396 Construct a layer a simple description. Use 0 for NoLayer,
397 a value for a flat layer, a pair for a sloping layer or a
398 long list for a spline layer.
399 """
400 if isinstance(v, (int,float)):
401
402
403 if v == 10000:
404
405 return NoLayer()
406 else:
407 return FlatLayer( Val = v )
408
409 else:
410 if hasattr(v, 'build' ):
411
412 if len(v.run()[0]) == 2:
413
414 return SlopeLayer( Val = v.run()[0] )
415
416 elif len(v.run()[0]) >= 3 and v.build()[:7]=="BSpline":
417
418 return SplineLayer( Val = v.run()[0] )
419
420 elif len(v.run()[0]) >= 3 and v.build()[:8]=="Tethered":
421
422 return TetheredPolymerLayer( Val = v.run()[0] )
423 else:
424 pass
425
426 else:
427 pass
428