1 | |
---|
2 | from sans.models.BaseComponent import BaseComponent |
---|
3 | import math |
---|
4 | |
---|
5 | class Smear: |
---|
6 | |
---|
7 | def __init__(self, model, param, sigma): |
---|
8 | """ |
---|
9 | @param model: model to smear |
---|
10 | @param param: parameter to smear |
---|
11 | @param sigma: std deviations for parameter |
---|
12 | """ |
---|
13 | |
---|
14 | |
---|
15 | ## Model to smear |
---|
16 | self.model = model |
---|
17 | ## Standard deviation of the smearing |
---|
18 | self.sigmas = sigma |
---|
19 | ## Parameter to smear |
---|
20 | self.params = param |
---|
21 | ## Nominal value of the smeared parameter |
---|
22 | self.centers = [] |
---|
23 | ## Error on last evaluation |
---|
24 | self.error = 0.0 |
---|
25 | ## Error flag |
---|
26 | self.doErrors = False |
---|
27 | for par in self.params: |
---|
28 | self.centers.append(self.model.getParam(par)) |
---|
29 | |
---|
30 | def smearParam(self, id, x): |
---|
31 | """ |
---|
32 | @param x: input value |
---|
33 | """ |
---|
34 | # from random import random |
---|
35 | # If we exhausted the parameter array, simply evaluate |
---|
36 | # the model |
---|
37 | if id < len(self.params): |
---|
38 | #print "smearing", self.params[id] |
---|
39 | |
---|
40 | # Average over Gaussian distribution (2 sigmas) |
---|
41 | value_sum = 0.0 |
---|
42 | gauss_sum = 0.0 |
---|
43 | |
---|
44 | min_value = self.centers[id] - 2*self.sigmas[id] |
---|
45 | max_value = self.centers[id] + 2*self.sigmas[id] |
---|
46 | n_pts = 25 |
---|
47 | step = (max_value - min_value)/(n_pts-1) |
---|
48 | #print min_value, max_value, step, max_value-min_value |
---|
49 | if step == 0.0: |
---|
50 | return self.smearParam(id+1,x) |
---|
51 | |
---|
52 | # Gaussian function used to weigh points |
---|
53 | gaussian = Gaussian() |
---|
54 | gaussian.setParam('sigma', self.sigmas[id]) |
---|
55 | gaussian.setParam('mean', self.centers[id]) |
---|
56 | |
---|
57 | # Compute average |
---|
58 | prev_value = None |
---|
59 | error_sys = 0.0 |
---|
60 | for i in range(n_pts): |
---|
61 | # Set the parameter value |
---|
62 | value = min_value + i*step |
---|
63 | # value = random()*4.0*self.sigmas[id] + min_value |
---|
64 | # print value |
---|
65 | self.model.setParam(self.params[id], value) |
---|
66 | gauss_value = gaussian.run(value) |
---|
67 | #gauss_value = 1.0 |
---|
68 | #if id==0: print value, gauss_value |
---|
69 | func_value, error_1 = self.smearParam(id+1, x) |
---|
70 | if self.doErrors: |
---|
71 | if not prev_value == None: |
---|
72 | error_sys += (func_value-prev_value)*(func_value-prev_value)/4.0 |
---|
73 | prev_value = func_value |
---|
74 | |
---|
75 | value_sum += gauss_value * func_value |
---|
76 | gauss_sum += gauss_value |
---|
77 | |
---|
78 | #print "Error", math.sqrt(error) |
---|
79 | return value_sum/gauss_sum, math.sqrt(error_sys) |
---|
80 | |
---|
81 | else: |
---|
82 | return self.model.run(x), 0.0 |
---|
83 | |
---|
84 | def run(self, x): |
---|
85 | """ |
---|
86 | @param x: input |
---|
87 | """ |
---|
88 | |
---|
89 | # Go through the list of parameters |
---|
90 | n_par = len(self.params) |
---|
91 | |
---|
92 | # Check array lengths |
---|
93 | if not len(self.centers) == n_par or\ |
---|
94 | not len(self.sigmas) == n_par: |
---|
95 | raise ValueError, "Incompatible array lengths" |
---|
96 | |
---|
97 | # Smear first parameters |
---|
98 | if n_par > 0: |
---|
99 | value, error = self.smearParam(0, x) |
---|
100 | self.error = error |
---|
101 | |
---|
102 | # Put back original values |
---|
103 | for i in range(len(self.centers)): |
---|
104 | self.model.setParam(self.params[i], self.centers[i]) |
---|
105 | |
---|
106 | |
---|
107 | return value |
---|
108 | |
---|
109 | class Gaussian(BaseComponent): |
---|
110 | """ Gaussian function """ |
---|
111 | |
---|
112 | def __init__(self): |
---|
113 | """ Initialization """ |
---|
114 | BaseComponent.__init__(self) |
---|
115 | |
---|
116 | ## Name of the model |
---|
117 | self.name = "Gaussian" |
---|
118 | ## Scale factor |
---|
119 | self.params['scale'] = 1.0 |
---|
120 | ## Mean value |
---|
121 | self.params['mean'] = 0.0 |
---|
122 | ## Standard deviation |
---|
123 | self.params['sigma'] = 1.0 |
---|
124 | ## Internal log |
---|
125 | self.log = {} |
---|
126 | return |
---|
127 | |
---|
128 | def run(self, x=0): |
---|
129 | """ Evaluate the function |
---|
130 | @param x: input q or [q,phi] |
---|
131 | @return: scattering function |
---|
132 | """ |
---|
133 | if(type(x)==type([])): |
---|
134 | # vector input |
---|
135 | if(len(x)==2): |
---|
136 | return self.analytical_2D(x) |
---|
137 | else: |
---|
138 | raise ValueError, "Gaussian takes a scalar or a 2D point" |
---|
139 | else: |
---|
140 | return self.analytical_1D(x) |
---|
141 | |
---|
142 | def analytical_2D(self, x): |
---|
143 | """ Evaluate 2D model |
---|
144 | @param x: input [q,phi] |
---|
145 | @return: scattering function |
---|
146 | """ |
---|
147 | |
---|
148 | # 2D sphere is the same as 1D sphere |
---|
149 | return self.analytical_1D(x[0]) |
---|
150 | |
---|
151 | def analytical_1D(self, x): |
---|
152 | """ Evaluate 1D model |
---|
153 | @param x: input q |
---|
154 | @return: scattering function |
---|
155 | """ |
---|
156 | vary = x-self.params['mean'] |
---|
157 | expo_value = -vary*vary/(2*self.params['sigma']*self.params['sigma']) |
---|
158 | value = self.params['scale'] * math.exp(expo_value) |
---|
159 | |
---|
160 | return value |
---|