Changeset 82c11d3 in sasview for sansmodels/src/c_models/triaxialellipsoid.cpp
- Timestamp:
- Jan 5, 2012 6:24:51 PM (13 years ago)
- Branches:
- master, ESS_GUI, ESS_GUI_Docs, ESS_GUI_batch_fitting, ESS_GUI_bumps_abstraction, ESS_GUI_iss1116, ESS_GUI_iss879, ESS_GUI_iss959, ESS_GUI_opencl, ESS_GUI_ordering, ESS_GUI_sync_sascalc, costrafo411, magnetic_scatt, release-4.1.1, release-4.1.2, release-4.2.2, release_4.0.1, ticket-1009, ticket-1094-headless, ticket-1242-2d-resolution, ticket-1243, ticket-1249, ticket885, unittest-saveload
- Children:
- 20d91bd
- Parents:
- 98fdccd
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
sansmodels/src/c_models/triaxialellipsoid.cpp
r67424cd r82c11d3 18 18 * sansmodels/src/libigor 19 19 * 20 * TODO: refactor so that we pull in the old sansmodels.c_extensions21 20 */ 22 21 23 22 #include <math.h> 24 #include "models.hh"25 23 #include "parameters.hh" 26 24 #include <stdio.h> 25 #include <stdlib.h> 27 26 using namespace std; 27 #include "triaxial_ellipsoid.h" 28 28 29 29 extern "C" { 30 #include "libCylinder.h" 31 #include "libStructureFactor.h" 32 #include "triaxial_ellipsoid.h" 33 } 30 #include "libCylinder.h" 31 #include "libStructureFactor.h" 32 } 33 34 typedef struct { 35 double scale; 36 double semi_axisA; 37 double semi_axisB; 38 double semi_axisC; 39 double sldEll; 40 double sldSolv; 41 double background; 42 double axis_theta; 43 double axis_phi; 44 double axis_psi; 45 46 } TriaxialEllipsoidParameters; 47 48 static double triaxial_ellipsoid_kernel(TriaxialEllipsoidParameters *pars, double q, double alpha, double nu) { 49 double t,a,b,c; 50 double kernel; 51 52 a = pars->semi_axisA ; 53 b = pars->semi_axisB ; 54 c = pars->semi_axisC ; 55 56 t = q * sqrt(a*a*cos(nu)*cos(nu)+b*b*sin(nu)*sin(nu)*sin(alpha)*sin(alpha)+c*c*cos(alpha)*cos(alpha)); 57 if (t==0.0){ 58 kernel = 1.0; 59 }else{ 60 kernel = 3.0*(sin(t)-t*cos(t))/(t*t*t); 61 } 62 return kernel*kernel; 63 } 64 65 66 /** 67 * Function to evaluate 2D scattering function 68 * @param pars: parameters of the triaxial ellipsoid 69 * @param q: q-value 70 * @param q_x: q_x / q 71 * @param q_y: q_y / q 72 * @return: function value 73 */ 74 static double triaxial_ellipsoid_analytical_2D_scaled(TriaxialEllipsoidParameters *pars, double q, double q_x, double q_y) { 75 double cyl_x, cyl_y, cyl_z, ell_x, ell_y; 76 double q_z; 77 double cos_nu,nu; 78 double alpha, vol, cos_val; 79 double answer; 80 double pi = 4.0*atan(1.0); 81 82 //convert angle degree to radian 83 double theta = pars->axis_theta * pi/180.0; 84 double phi = pars->axis_phi * pi/180.0; 85 double psi = pars->axis_psi * pi/180.0; 86 87 // Cylinder orientation 88 cyl_x = sin(theta) * cos(phi); 89 cyl_y = sin(theta) * sin(phi); 90 cyl_z = cos(theta); 91 92 // q vector 93 q_z = 0.0; 94 95 //dx = 1.0; 96 //dy = 1.0; 97 // Compute the angle btw vector q and the 98 // axis of the cylinder 99 cos_val = cyl_x*q_x + cyl_y*q_y + cyl_z*q_z; 100 101 // The following test should always pass 102 if (fabs(cos_val)>1.0) { 103 printf("cyl_ana_2D: Unexpected error: cos(alpha)>1\n"); 104 return 0; 105 } 106 107 // Note: cos(alpha) = 0 and 1 will get an 108 // undefined value from CylKernel 109 alpha = acos( cos_val ); 110 111 //ellipse orientation: 112 // the elliptical corss section was transformed and projected 113 // into the detector plane already through sin(alpha)and furthermore psi remains as same 114 // on the detector plane. 115 // So, all we need is to calculate the angle (nu) of the minor axis of the ellipse wrt 116 // the wave vector q. 117 118 //x- y- component on the detector plane. 119 ell_x = cos(psi); 120 ell_y = sin(psi); 121 122 // calculate the axis of the ellipse wrt q-coord. 123 cos_nu = ell_x*q_x + ell_y*q_y; 124 nu = acos(cos_nu); 125 126 // Call the IGOR library function to get the kernel 127 answer = triaxial_ellipsoid_kernel(pars, q, alpha, nu); 128 129 // Multiply by contrast^2 130 answer *= (pars->sldEll- pars->sldSolv)*(pars->sldEll- pars->sldSolv); 131 132 //normalize by cylinder volume 133 //NOTE that for this (Fournet) definition of the integral, one must MULTIPLY by Vcyl 134 vol = 4.0* pi/3.0 * pars->semi_axisA * pars->semi_axisB * pars->semi_axisC; 135 answer *= vol; 136 //convert to [cm-1] 137 answer *= 1.0e8; 138 //Scale 139 answer *= pars->scale; 140 141 // add in the background 142 answer += pars->background; 143 144 return answer; 145 } 146 147 /** 148 * Function to evaluate 2D scattering function 149 * @param pars: parameters of the triaxial ellipsoid 150 * @param q: q-value 151 * @return: function value 152 */ 153 static double triaxial_ellipsoid_analytical_2DXY(TriaxialEllipsoidParameters *pars, double qx, double qy) { 154 double q; 155 q = sqrt(qx*qx+qy*qy); 156 return triaxial_ellipsoid_analytical_2D_scaled(pars, q, qx/q, qy/q); 157 } 158 159 34 160 35 161 TriaxialEllipsoidModel :: TriaxialEllipsoidModel() { 36 37 38 39 40 41 42 43 44 45 46 47 48 162 scale = Parameter(1.0); 163 semi_axisA = Parameter(35.0, true); 164 semi_axisA.set_min(0.0); 165 semi_axisB = Parameter(100.0, true); 166 semi_axisB.set_min(0.0); 167 semi_axisC = Parameter(400.0, true); 168 semi_axisC.set_min(0.0); 169 sldEll = Parameter(1.0e-6); 170 sldSolv = Parameter(6.3e-6); 171 background = Parameter(0.0); 172 axis_theta = Parameter(57.325, true); 173 axis_phi = Parameter(57.325, true); 174 axis_psi = Parameter(0.0, true); 49 175 } 50 176 … … 56 182 */ 57 183 double TriaxialEllipsoidModel :: operator()(double q) { 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 184 double dp[7]; 185 186 // Fill parameter array for IGOR library 187 // Add the background after averaging 188 dp[0] = scale(); 189 dp[1] = semi_axisA(); 190 dp[2] = semi_axisB(); 191 dp[3] = semi_axisC(); 192 dp[4] = sldEll(); 193 dp[5] = sldSolv(); 194 dp[6] = 0.0; 195 196 // Get the dispersion points for the semi axis A 197 vector<WeightPoint> weights_semi_axisA; 198 semi_axisA.get_weights(weights_semi_axisA); 199 200 // Get the dispersion points for the semi axis B 201 vector<WeightPoint> weights_semi_axisB; 202 semi_axisB.get_weights(weights_semi_axisB); 203 204 // Get the dispersion points for the semi axis C 205 vector<WeightPoint> weights_semi_axisC; 206 semi_axisC.get_weights(weights_semi_axisC); 207 208 // Perform the computation, with all weight points 209 double sum = 0.0; 210 double norm = 0.0; 211 double vol = 0.0; 212 213 // Loop over semi axis A weight points 214 for(int i=0; i< (int)weights_semi_axisA.size(); i++) { 215 dp[1] = weights_semi_axisA[i].value; 216 217 // Loop over semi axis B weight points 218 for(int j=0; j< (int)weights_semi_axisB.size(); j++) { 219 dp[2] = weights_semi_axisB[j].value; 220 221 // Loop over semi axis C weight points 222 for(int k=0; k< (int)weights_semi_axisC.size(); k++) { 223 dp[3] = weights_semi_axisC[k].value; 224 //Un-normalize by volume 225 sum += weights_semi_axisA[i].weight 226 * weights_semi_axisB[j].weight * weights_semi_axisC[k].weight* TriaxialEllipsoid(dp, q) 227 * weights_semi_axisA[i].value*weights_semi_axisB[j].value*weights_semi_axisC[k].value; 228 //Find average volume 229 vol += weights_semi_axisA[i].weight 230 * weights_semi_axisB[j].weight * weights_semi_axisC[k].weight 231 * weights_semi_axisA[i].value*weights_semi_axisB[j].value*weights_semi_axisC[k].value; 232 233 norm += weights_semi_axisA[i].weight 234 * weights_semi_axisB[j].weight * weights_semi_axisC[k].weight; 235 } 236 } 237 } 238 if (vol != 0.0 && norm != 0.0) { 239 //Re-normalize by avg volume 240 sum = sum/(vol/norm);} 241 242 return sum/norm + background(); 117 243 } 118 244 … … 124 250 */ 125 251 double TriaxialEllipsoidModel :: operator()(double qx, double qy) { 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 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 252 TriaxialEllipsoidParameters dp; 253 // Fill parameter array 254 dp.scale = scale(); 255 dp.semi_axisA = semi_axisA(); 256 dp.semi_axisB = semi_axisB(); 257 dp.semi_axisC = semi_axisC(); 258 dp.sldEll = sldEll(); 259 dp.sldSolv = sldSolv(); 260 dp.background = 0.0; 261 dp.axis_theta = axis_theta(); 262 dp.axis_phi = axis_phi(); 263 dp.axis_psi = axis_psi(); 264 265 // Get the dispersion points for the semi_axis A 266 vector<WeightPoint> weights_semi_axisA; 267 semi_axisA.get_weights(weights_semi_axisA); 268 269 // Get the dispersion points for the semi_axis B 270 vector<WeightPoint> weights_semi_axisB; 271 semi_axisB.get_weights(weights_semi_axisB); 272 273 // Get the dispersion points for the semi_axis C 274 vector<WeightPoint> weights_semi_axisC; 275 semi_axisC.get_weights(weights_semi_axisC); 276 277 // Get angular averaging for theta 278 vector<WeightPoint> weights_theta; 279 axis_theta.get_weights(weights_theta); 280 281 // Get angular averaging for phi 282 vector<WeightPoint> weights_phi; 283 axis_phi.get_weights(weights_phi); 284 285 // Get angular averaging for psi 286 vector<WeightPoint> weights_psi; 287 axis_psi.get_weights(weights_psi); 288 289 // Perform the computation, with all weight points 290 double sum = 0.0; 291 double norm = 0.0; 292 double norm_vol = 0.0; 293 double vol = 0.0; 294 double pi = 4.0*atan(1.0); 295 // Loop over semi axis A weight points 296 for(int i=0; i< (int)weights_semi_axisA.size(); i++) { 297 dp.semi_axisA = weights_semi_axisA[i].value; 298 299 // Loop over semi axis B weight points 300 for(int j=0; j< (int)weights_semi_axisB.size(); j++) { 301 dp.semi_axisB = weights_semi_axisB[j].value; 302 303 // Loop over semi axis C weight points 304 for(int k=0; k < (int)weights_semi_axisC.size(); k++) { 305 dp.semi_axisC = weights_semi_axisC[k].value; 306 307 // Average over theta distribution 308 for(int l=0; l< (int)weights_theta.size(); l++) { 309 dp.axis_theta = weights_theta[l].value; 310 311 // Average over phi distribution 312 for(int m=0; m <(int)weights_phi.size(); m++) { 313 dp.axis_phi = weights_phi[m].value; 314 // Average over psi distribution 315 for(int n=0; n <(int)weights_psi.size(); n++) { 316 dp.axis_psi = weights_psi[n].value; 317 //Un-normalize by volume 318 double _ptvalue = weights_semi_axisA[i].weight 319 * weights_semi_axisB[j].weight 320 * weights_semi_axisC[k].weight 321 * weights_theta[l].weight 322 * weights_phi[m].weight 323 * weights_psi[n].weight 324 * triaxial_ellipsoid_analytical_2DXY(&dp, qx, qy) 325 * weights_semi_axisA[i].value*weights_semi_axisB[j].value*weights_semi_axisC[k].value; 326 if (weights_theta.size()>1) { 327 _ptvalue *= fabs(sin(weights_theta[k].value*pi/180.0)); 328 } 329 sum += _ptvalue; 330 //Find average volume 331 vol += weights_semi_axisA[i].weight 332 * weights_semi_axisB[j].weight 333 * weights_semi_axisC[k].weight 334 * weights_semi_axisA[i].value*weights_semi_axisB[j].value*weights_semi_axisC[k].value; 335 //Find norm for volume 336 norm_vol += weights_semi_axisA[i].weight 337 * weights_semi_axisB[j].weight 338 * weights_semi_axisC[k].weight; 339 340 norm += weights_semi_axisA[i].weight 341 * weights_semi_axisB[j].weight 342 * weights_semi_axisC[k].weight 343 * weights_theta[l].weight 344 * weights_phi[m].weight 345 * weights_psi[n].weight; 346 } 347 } 348 349 } 350 } 351 } 352 } 353 // Averaging in theta needs an extra normalization 354 // factor to account for the sin(theta) term in the 355 // integration (see documentation). 356 if (weights_theta.size()>1) norm = norm / asin(1.0); 357 358 if (vol != 0.0 && norm_vol != 0.0) { 359 //Re-normalize by avg volume 360 sum = sum/(vol/norm_vol);} 361 362 return sum/norm + background(); 237 363 } 238 364 … … 245 371 */ 246 372 double TriaxialEllipsoidModel :: evaluate_rphi(double q, double phi) { 247 248 249 373 double qx = q*cos(phi); 374 double qy = q*sin(phi); 375 return (*this).operator()(qx, qy); 250 376 } 251 377 /** … … 254 380 */ 255 381 double TriaxialEllipsoidModel :: calculate_ER() { 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 } 382 TriaxialEllipsoidParameters dp; 383 384 dp.semi_axisA = semi_axisA(); 385 dp.semi_axisB = semi_axisB(); 386 //polar axis C 387 dp.semi_axisC = semi_axisC(); 388 389 double rad_out = 0.0; 390 //Surface average radius at the equat. cross section. 391 double suf_rad = sqrt(dp.semi_axisA * dp.semi_axisB); 392 393 // Perform the computation, with all weight points 394 double sum = 0.0; 395 double norm = 0.0; 396 397 // Get the dispersion points for the semi_axis A 398 vector<WeightPoint> weights_semi_axisA; 399 semi_axisA.get_weights(weights_semi_axisA); 400 401 // Get the dispersion points for the semi_axis B 402 vector<WeightPoint> weights_semi_axisB; 403 semi_axisB.get_weights(weights_semi_axisB); 404 405 // Get the dispersion points for the semi_axis C 406 vector<WeightPoint> weights_semi_axisC; 407 semi_axisC.get_weights(weights_semi_axisC); 408 409 // Loop over semi axis A weight points 410 for(int i=0; i< (int)weights_semi_axisA.size(); i++) { 411 dp.semi_axisA = weights_semi_axisA[i].value; 412 413 // Loop over semi axis B weight points 414 for(int j=0; j< (int)weights_semi_axisB.size(); j++) { 415 dp.semi_axisB = weights_semi_axisB[j].value; 416 417 // Loop over semi axis C weight points 418 for(int k=0; k < (int)weights_semi_axisC.size(); k++) { 419 dp.semi_axisC = weights_semi_axisC[k].value; 420 421 //Calculate surface averaged radius 422 suf_rad = sqrt(dp.semi_axisA * dp.semi_axisB); 423 424 //Sum 425 sum += weights_semi_axisA[i].weight 426 * weights_semi_axisB[j].weight 427 * weights_semi_axisC[k].weight * DiamEllip(dp.semi_axisC, suf_rad)/2.0; 428 //Norm 429 norm += weights_semi_axisA[i].weight* weights_semi_axisB[j].weight 430 * weights_semi_axisC[k].weight; 431 } 432 } 433 } 434 if (norm != 0){ 435 //return the averaged value 436 rad_out = sum/norm;} 437 else{ 438 //return normal value 439 rad_out = DiamEllip(dp.semi_axisC, suf_rad)/2.0;} 440 441 return rad_out; 442 }
Note: See TracChangeset
for help on using the changeset viewer.