Changeset 0ba3b08 in sasview for sansmodels/src/c_models/fcc.cpp
- Timestamp:
- Jan 5, 2012 12:16:29 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:
- 011e0e4
- Parents:
- bbbed8c
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
sansmodels/src/c_models/fcc.cpp
r67424cd r0ba3b08 21 21 22 22 #include <math.h> 23 #include "models.hh"24 23 #include "parameters.hh" 25 24 #include <stdio.h> 26 25 using namespace std; 26 #include "fcc.h" 27 27 28 28 extern "C" { 29 #include "libSphere.h" 30 #include "fcc.h" 29 #include "libSphere.h" 30 } 31 32 // Convenience parameter structure 33 typedef struct { 34 double scale; 35 double dnn; 36 double d_factor; 37 double radius; 38 double sldSph; 39 double sldSolv; 40 double background; 41 double theta; 42 double phi; 43 double psi; 44 } FCParameters; 45 46 /** 47 * Function to evaluate 2D scattering function 48 * @param pars: parameters of the FCCCrystalModel 49 * @param q: q-value 50 * @param q_x: q_x / q 51 * @param q_y: q_y / q 52 * @return: function value 53 */ 54 static double fc_analytical_2D_scaled(FCParameters *pars, double q, double q_x, double q_y) { 55 double b3_x, b3_y, b3_z, b1_x, b1_y; 56 double q_z; 57 double alpha, cos_val_b3, cos_val_b2, cos_val_b1; 58 double a1_dot_q, a2_dot_q,a3_dot_q; 59 double answer; 60 double Pi = 4.0*atan(1.0); 61 double aa, Da, qDa_2, latticeScale, Zq, Fkq, Fkq_2; 62 63 double dp[5]; 64 //convert angle degree to radian 65 double theta = pars->theta * Pi/180.0; 66 double phi = pars->phi * Pi/180.0; 67 double psi = pars->psi * Pi/180.0; 68 dp[0] = 1.0; 69 dp[1] = pars->radius; 70 dp[2] = pars->sldSph; 71 dp[3] = pars->sldSolv; 72 dp[4] = 0.0; 73 74 aa = pars->dnn; 75 Da = pars->d_factor*aa; 76 qDa_2 = pow(q*Da,2.0); 77 //contrast = pars->sldSph - pars->sldSolv; 78 79 latticeScale = 4.0*(4.0/3.0)*Pi*(dp[1]*dp[1]*dp[1])/pow(aa*sqrt(2.0),3.0); 80 // q vector 81 q_z = 0.0; // for SANS; assuming qz is negligible 82 /// Angles here are respect to detector coordinate 83 /// instead of against q coordinate in PRB 36(46), 3(6), 1754(3854) 84 // b3 axis orientation 85 b3_x = sin(theta) * cos(phi);//negative sign here??? 86 b3_y = sin(theta) * sin(phi); 87 b3_z = cos(theta); 88 cos_val_b3 = b3_x*q_x + b3_y*q_y + b3_z*q_z; 89 alpha = acos(cos_val_b3); 90 // b1 axis orientation 91 b1_x = sin(psi); 92 b1_y = cos(psi); 93 cos_val_b1 = (b1_x*q_x + b1_y*q_y); 94 // b2 axis orientation 95 cos_val_b2 = sin(acos(cos_val_b1)); 96 // alpha correction 97 cos_val_b2 *= sin(alpha); 98 cos_val_b1 *= sin(alpha); 99 100 // Compute the angle btw vector q and the a3 axis 101 a3_dot_q = 0.5*aa*q*(cos_val_b2+cos_val_b1); 102 103 // a1 axis 104 a1_dot_q = 0.5*aa*q*(cos_val_b2+cos_val_b3); 105 106 // a2 axis 107 a2_dot_q = 0.5*aa*q*(cos_val_b3+cos_val_b1); 108 109 // The following test should always pass 110 if (fabs(cos_val_b3)>1.0) { 111 printf("fcc_ana_2D: Unexpected error: cos(alpha)>1\n"); 112 return 0; 113 } 114 // Get Fkq and Fkq_2 115 Fkq = exp(-0.5*pow(Da/aa,2.0)*(a1_dot_q*a1_dot_q+a2_dot_q*a2_dot_q+a3_dot_q*a3_dot_q)); 116 Fkq_2 = Fkq*Fkq; 117 // Call Zq=Z1*Z2*Z3 118 Zq = (1.0-Fkq_2)/(1.0-2.0*Fkq*cos(a1_dot_q)+Fkq_2); 119 Zq = Zq * (1.0-Fkq_2)/(1.0-2.0*Fkq*cos(a2_dot_q)+Fkq_2); 120 Zq = Zq * (1.0-Fkq_2)/(1.0-2.0*Fkq*cos(a3_dot_q)+Fkq_2); 121 122 // Use SphereForm directly from libigor 123 answer = SphereForm(dp,q)*Zq; 124 125 //consider scales 126 answer *= latticeScale * pars->scale; 127 128 // This FIXES a singualrity the kernel in libigor. 129 if ( answer == INFINITY || answer == NAN){ 130 answer = 0.0; 131 } 132 133 // add background 134 answer += pars->background; 135 136 return answer; 137 } 138 139 /** 140 * Function to evaluate 2D scattering function 141 * @param pars: parameters of the FCC_ParaCrystal 142 * @param q: q-value 143 * @return: function value 144 */ 145 static double fc_analytical_2DXY(FCParameters *pars, double qx, double qy){ 146 double q; 147 q = sqrt(qx*qx+qy*qy); 148 return fc_analytical_2D_scaled(pars, q, qx/q, qy/q); 31 149 } 32 150 33 151 FCCrystalModel :: FCCrystalModel() { 34 35 36 37 38 39 40 41 42 43 44 152 scale = Parameter(1.0); 153 dnn = Parameter(220.0); 154 d_factor = Parameter(0.06); 155 radius = Parameter(40.0, true); 156 radius.set_min(0.0); 157 sldSph = Parameter(3.0e-6); 158 sldSolv = Parameter(6.3e-6); 159 background = Parameter(0.0); 160 theta = Parameter(0.0, true); 161 phi = Parameter(0.0, true); 162 psi = Parameter(0.0, true); 45 163 } 46 164 … … 52 170 */ 53 171 double FCCrystalModel :: operator()(double q) { 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 172 double dp[7]; 173 174 // Fill parameter array for IGOR library 175 // Add the background after averaging 176 dp[0] = scale(); 177 dp[1] = dnn(); 178 dp[2] = d_factor(); 179 dp[3] = radius(); 180 dp[4] = sldSph(); 181 dp[5] = sldSolv(); 182 dp[6] = 0.0; 183 184 // Get the dispersion points for the radius 185 vector<WeightPoint> weights_rad; 186 radius.get_weights(weights_rad); 187 188 // Perform the computation, with all weight points 189 double sum = 0.0; 190 double norm = 0.0; 191 double vol = 0.0; 192 double result; 193 194 // Loop over radius weight points 195 for(size_t i=0; i<weights_rad.size(); i++) { 196 dp[3] = weights_rad[i].value; 197 198 //Un-normalize SphereForm by volume 199 result = FCC_ParaCrystal(dp, q) * pow(weights_rad[i].value,3); 200 // This FIXES a singualrity the kernel in libigor. 201 if ( result == INFINITY || result == NAN){ 202 result = 0.0; 203 } 204 sum += weights_rad[i].weight 205 * result; 206 //Find average volume 207 vol += weights_rad[i].weight 208 * pow(weights_rad[i].value,3); 209 210 norm += weights_rad[i].weight; 211 } 212 213 if (vol != 0.0 && norm != 0.0) { 214 //Re-normalize by avg volume 215 sum = sum/(vol/norm);} 216 return sum/norm + background(); 99 217 } 100 218 … … 106 224 */ 107 225 double FCCrystalModel :: operator()(double qx, double qy) { 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 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 226 FCParameters dp; 227 dp.scale = scale(); 228 dp.dnn = dnn(); 229 dp.d_factor = d_factor(); 230 dp.radius = radius(); 231 dp.sldSph = sldSph(); 232 dp.sldSolv = sldSolv(); 233 dp.background = 0.0; 234 dp.theta = theta(); 235 dp.phi = phi(); 236 dp.psi = psi(); 237 238 // Get the dispersion points for the radius 239 vector<WeightPoint> weights_rad; 240 radius.get_weights(weights_rad); 241 242 // Get angular averaging for theta 243 vector<WeightPoint> weights_theta; 244 theta.get_weights(weights_theta); 245 246 // Get angular averaging for phi 247 vector<WeightPoint> weights_phi; 248 phi.get_weights(weights_phi); 249 250 // Get angular averaging for psi 251 vector<WeightPoint> weights_psi; 252 psi.get_weights(weights_psi); 253 254 // Perform the computation, with all weight points 255 double sum = 0.0; 256 double norm = 0.0; 257 double norm_vol = 0.0; 258 double vol = 0.0; 259 double pi = 4.0*atan(1.0); 260 // Loop over radius weight points 261 for(size_t i=0; i<weights_rad.size(); i++) { 262 dp.radius = weights_rad[i].value; 263 // Average over theta distribution 264 for(size_t j=0; j< weights_theta.size(); j++) { 265 dp.theta = weights_theta[j].value; 266 // Average over phi distribution 267 for(size_t k=0; k< weights_phi.size(); k++) { 268 dp.phi = weights_phi[k].value; 269 // Average over phi distribution 270 for(size_t l=0; l< weights_psi.size(); l++) { 271 dp.psi = weights_psi[l].value; 272 //Un-normalize SphereForm by volume 273 double _ptvalue = weights_rad[i].weight 274 * weights_theta[j].weight 275 * weights_phi[k].weight 276 * weights_psi[l].weight 277 * fc_analytical_2DXY(&dp, qx, qy); 278 //* pow(weights_rad[i].value,3.0); 279 // Consider when there is infinte or nan. 280 if ( _ptvalue == INFINITY || _ptvalue == NAN){ 281 _ptvalue = 0.0; 282 } 283 if (weights_theta.size()>1) { 284 _ptvalue *= fabs(sin(weights_theta[j].value*pi/180.0)); 285 } 286 sum += _ptvalue; 287 // This model dose not need the volume of spheres correction!!! 288 norm += weights_rad[i].weight 289 * weights_theta[j].weight 290 * weights_phi[k].weight 291 * weights_psi[l].weight; 292 } 293 } 294 } 295 } 296 // Averaging in theta needs an extra normalization 297 // factor to account for the sin(theta) term in the 298 // integration (see documentation). 299 if (weights_theta.size()>1) norm = norm / asin(1.0); 300 301 if (vol != 0.0 && norm_vol != 0.0) { 302 //Re-normalize by avg volume 303 sum = sum/(vol/norm_vol);} 304 305 return sum/norm + background(); 188 306 } 189 307 … … 196 314 */ 197 315 double FCCrystalModel :: evaluate_rphi(double q, double phi) { 198 316 return (*this).operator()(q); 199 317 } 200 318 … … 204 322 */ 205 323 double FCCrystalModel :: calculate_ER() { 206 207 208 } 324 //NOT implemented yet!!! 325 return 0.0; 326 }
Note: See TracChangeset
for help on using the changeset viewer.