source: sasview/sansmodels/src/sans/models/c_models/cylinder.cpp @ fca6936

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since fca6936 was fca6936, checked in by Mathieu Doucet <doucetm@…>, 16 years ago

First cut at better polydisp and averaging implementation for sans models.

  • Property mode set to 100644
File size: 6.3 KB
Line 
1/**
2        This software was developed by the University of Tennessee as part of the
3        Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
4        project funded by the US National Science Foundation.
5
6        If you use DANSE applications to do scientific research that leads to
7        publication, we ask that you acknowledge the use of the software with the
8        following sentence:
9
10        "This work benefited from DANSE software developed under NSF award DMR-0520547."
11
12        copyright 2008, University of Tennessee
13 */
14
15/**
16 * Scattering model classes
17 * The classes use the IGOR library found in
18 *   sansmodels/src/libigor
19 *
20 *      TODO: refactor so that we pull in the old sansmodels.c_extensions
21 */
22
23#include <math.h>
24#include "models.hh"
25#include "parameters.hh"
26#include <stdio.h>
27using namespace std;
28
29extern "C" {
30        #include "libCylinder.h"
31        #include "cylinder.h"
32}
33
34Cylinder :: Cylinder() {
35        scale      = Parameter(1.0);
36        radius     = Parameter(20.0, true);
37        radius.set_min(0.0);
38        length     = Parameter(400.0, true);
39        length.set_min(0.0);
40        contrast   = Parameter(3.e-6);
41        background = Parameter(0.0);
42        cyl_theta  = Parameter(0.0, true);
43        cyl_phi    = Parameter(0.0, true);
44}
45
46/**
47 * Function to evaluate 1D scattering function
48 * The NIST IGOR library is used for the actual calculation.
49 * @param q: q-value
50 * @return: function value
51 */
52double Cylinder :: operator()(double q) {
53        double dp[5];
54
55        // Fill parameter array for IGOR library
56        // Add the background after averaging
57        dp[0] = scale();
58        dp[1] = radius();
59        dp[2] = length();
60        dp[3] = contrast();
61        dp[4] = 0.0;
62
63        // Get the dispersion points for the radius
64        vector<WeightPoint> weights_rad;
65        radius.get_weights(weights_rad);
66
67        // Get the dispersion points for the length
68        vector<WeightPoint> weights_len;
69        length.get_weights(weights_len);
70
71        // Perform the computation, with all weight points
72        double sum = 0.0;
73        double norm = 0.0;
74
75        // Loop over radius weight points
76        for(int i=0; i<weights_rad.size(); i++) {
77                dp[1] = weights_rad[i].value;
78
79                // Loop over length weight points
80                for(int j=0; j<weights_len.size(); j++) {
81                        dp[2] = weights_len[j].value;
82
83                        sum += weights_rad[i].weight
84                                * weights_len[j].weight * CylinderForm(dp, q);
85                        norm += weights_rad[i].weight
86                                * weights_len[j].weight;
87                }
88        }
89        return sum/norm + background();
90}
91
92/**
93 * Function to evaluate 2D scattering function
94 * @param q_x: value of Q along x
95 * @param q_y: value of Q along y
96 * @return: function value
97 */
98double Cylinder :: operator()(double qx, double qy) {
99        CylinderParameters dp;
100        // Fill parameter array
101        dp.scale      = scale();
102        dp.radius     = radius();
103        dp.length     = length();
104        dp.contrast   = contrast();
105        dp.background = 0.0;
106        dp.cyl_theta  = cyl_theta();
107        dp.cyl_phi    = cyl_phi();
108
109        // Get the dispersion points for the radius
110        vector<WeightPoint> weights_rad;
111        radius.get_weights(weights_rad);
112
113        // Get the dispersion points for the length
114        vector<WeightPoint> weights_len;
115        length.get_weights(weights_len);
116
117        // Get angular averaging for theta
118        vector<WeightPoint> weights_theta;
119        cyl_theta.get_weights(weights_theta);
120
121        // Get angular averaging for phi
122        vector<WeightPoint> weights_phi;
123        cyl_phi.get_weights(weights_phi);
124
125        // Perform the computation, with all weight points
126        double sum = 0.0;
127        double norm = 0.0;
128
129        // Loop over radius weight points
130        for(int i=0; i<weights_rad.size(); i++) {
131                dp.radius = weights_rad[i].value;
132
133
134                // Loop over length weight points
135                for(int j=0; j<weights_len.size(); j++) {
136                        dp.length = weights_len[j].value;
137
138                        // Average over theta distribution
139                        for(int k=0; k<weights_theta.size(); k++) {
140                                dp.cyl_theta = weights_theta[k].value;
141
142                                // Average over phi distribution
143                                for(int l=0; l<weights_phi.size(); l++) {
144                                        dp.cyl_phi = weights_phi[l].value;
145
146                                        double _ptvalue = weights_rad[i].weight
147                                                * weights_len[j].weight
148                                                * weights_theta[k].weight
149                                                * weights_phi[l].weight
150                                                * cylinder_analytical_2DXY(&dp, qx, qy);
151                                        if (weights_theta.size()>1) {
152                                                _ptvalue *= sin(weights_theta[k].value);
153                                        }
154                                        sum += _ptvalue;
155
156                                        norm += weights_rad[i].weight
157                                                * weights_len[j].weight
158                                                * weights_theta[k].weight
159                                                * weights_phi[l].weight;
160
161                                }
162                        }
163                }
164        }
165        // Averaging in theta needs an extra normalization
166        // factor to account for the sin(theta) term in the
167        // integration (see documentation).
168        if (weights_theta.size()>1) norm = norm / asin(1.0);
169        return sum/norm + background();
170}
171
172/**
173 * Function to evaluate 2D scattering function
174 * @param pars: parameters of the cylinder
175 * @param q: q-value
176 * @param phi: angle phi
177 * @return: function value
178 */
179double Cylinder :: evaluate_rphi(double q, double phi) {
180        double qx = q*cos(phi);
181        double qy = q*sin(phi);
182        return (*this).operator()(qx, qy);
183}
184
185// Testing code
186int main(void)
187{
188        Cylinder c = Cylinder();
189
190        printf("Length = %g\n", c.length());
191        printf("I(Q=%g) = %g\n", 0.001, c(0.001));
192        c.radius.dispersion = new GaussianDispersion();
193        c.radius.dispersion->npts = 100;
194        c.radius.dispersion->width = 5;
195
196        //c.length.dispersion = GaussianDispersion();
197        //c.length.dispersion.npts = 20;
198        //c.length.dispersion.width = 65;
199
200        printf("I(Q=%g) = %g\n", 0.001, c(0.001));
201        c.scale = 10.0;
202        printf("I(Q=%g) = %g\n", 0.001, c(0.001));
203        printf("I(Qx=%g, Qy=%g) = %g\n", 0.001, 0.001, c(0.001, 0.001));
204        printf("I(Q=%g,  Phi=%g) = %g\n", 0.00447, .7854, c.evaluate_rphi(sqrt(0.00002), .7854));
205
206        // Average over phi at theta=90 deg
207        c.cyl_theta = 1.57;
208        double values_th[100];
209        double values[100];
210        double weights[100];
211        double pi = acos(-1.0);
212        printf("pi=%g\n", pi);
213        for(int i=0; i<100; i++){
214                values[i] = (float)i*2.0*pi/99.0;
215                values_th[i] = (float)i*pi/99.0;
216                weights[i] = 1.0;
217        }
218        //c.radius.dispersion->width = 0;
219        c.cyl_phi.dispersion = new ArrayDispersion();
220        c.cyl_theta.dispersion = new ArrayDispersion();
221        (*c.cyl_phi.dispersion).set_weights(100, values, weights);
222        (*c.cyl_theta.dispersion).set_weights(100, values_th, weights);
223
224        double i_avg = c(0.01, 0.01);
225        double i_1d = c(sqrt(0.0002));
226
227        printf("\nI(Qx=%g, Qy=%g) = %g\n", 0.01, 0.01, i_avg);
228        printf("I(Q=%g)         = %g\n", sqrt(0.0002), i_1d);
229        printf("ratio %g %g\n", i_avg/i_1d, i_1d/i_avg);
230
231
232        return 0;
233}
Note: See TracBrowser for help on using the repository browser.