/** This software was developed by the University of Tennessee as part of the Distributed Data Analysis of Neutron Scattering Experiments (DANSE) project funded by the US National Science Foundation. If you use DANSE applications to do scientific research that leads to publication, we ask that you acknowledge the use of the software with the following sentence: "This work benefited from DANSE software developed under NSF award DMR-0520547." copyright 2008, University of Tennessee */ /** * Scattering model classes * The classes use the IGOR library found in * sansmodels/src/libigor * */ #include #include "parameters.hh" #include #include using namespace std; #include "onion.h" // Convenience parameter structure typedef struct { int n_shells; double scale; double rad_core0; double sld_core0; double sld_solv; double background; double sld_out_shell1; double sld_out_shell2; double sld_out_shell3; double sld_out_shell4; double sld_out_shell5; double sld_out_shell6; double sld_out_shell7; double sld_out_shell8; double sld_out_shell9; double sld_out_shell10; double sld_in_shell1; double sld_in_shell2; double sld_in_shell3; double sld_in_shell4; double sld_in_shell5; double sld_in_shell6; double sld_in_shell7; double sld_in_shell8; double sld_in_shell9; double sld_in_shell10; double A_shell1; double A_shell2; double A_shell3; double A_shell4; double A_shell5; double A_shell6; double A_shell7; double A_shell8; double A_shell9; double A_shell10; double thick_shell1; double thick_shell2; double thick_shell3; double thick_shell4; double thick_shell5; double thick_shell6; double thick_shell7; double thick_shell8; double thick_shell9; double thick_shell10; int func_shell1; int func_shell2; int func_shell3; int func_shell4; int func_shell5; int func_shell6; int func_shell7; int func_shell8; int func_shell9; int func_shell10; } OnionParameters; // some details can be found in sld_cal.c static double so_kernel(double dp[], double q) { int n = dp[0]; double scale = dp[1]; double rad_core0 = dp[2]; double sld_core0 = dp[3]; double sld_solv = dp[4]; double background = dp[5]; int i,j; double bes,fun,alpha,f,vol,vol_pre,vol_sub,qr,r,contr,f2; double sign; double pi; double r0 = 0.0; double *sld_out; double *slope; double *sld_in; double *thick; double *A; int *fun_type; sld_out = (double*)malloc((n+2)*sizeof(double)); slope = (double*)malloc((n+2)*sizeof(double)); sld_in = (double*)malloc((n+2)*sizeof(double)); thick = (double*)malloc((n+2)*sizeof(double)); A = (double*)malloc((n+2)*sizeof(double)); fun_type = (int*)malloc((n+2)*sizeof(int)); for (i =1; i<=n; i++){ sld_out[i] = dp[i+5]; sld_in[i] = dp[i+15]; A[i] = dp[i+25]; thick[i] = dp[i+35]; fun_type[i] = dp[i+45]; } sld_out[0] = sld_core0; sld_out[n+1] = sld_solv; sld_in[0] = sld_core0; sld_in[n+1] = sld_solv; thick[0] = rad_core0; thick[n+1] = 1e+10; A[0] = 0.0; A[n+1] = 0.0; fun_type[0] = 0; fun_type[n+1] = 0; pi = 4.0*atan(1.0); f = 0.0; r = 0.0; vol = 0.0; vol_pre = 0.0; vol_sub = 0.0; for (i =0; i<= n+1; i++){ if (thick[i] == 0.0){ continue; } if (fun_type[i]== 0 ){ slope[i] = 0.0; A[i] = 0.0; } vol_pre = vol; switch(fun_type[i]){ case 2 : r0 = r; if (A[i] == 0.0){ slope[i] = 0.0; } else{ slope[i] = (sld_out[i]-sld_in[i])/(exp(A[i])-1.0); } for (j=0; j<2; j++){ if ( i == 0 && j == 0){ continue; } if (i == n+1 && j == 1){ continue; } if ( j == 1){ sign = 1.0; r += thick[i]; } else{ sign = -1.0; } qr = q * r; alpha = A[i] * r/thick[i]; fun = 0.0; if(qr == 0.0){ fun = sign * 1.0; bes = sign * 1.0; } else{ if (fabs(A[i]) > 0.0 ){ fun = 3.0 * ((alpha*alpha - qr * qr) * sin(qr) - 2.0 * alpha * qr * cos(qr))/ ((alpha * alpha + qr * qr) * (alpha * alpha + qr * qr) * qr); fun = fun - 3.0 * (alpha * sin(qr) - qr * cos(qr)) / ((alpha * alpha + qr * qr) * qr); fun = - sign *fun; bes = sign * 3.0 * (sin(qr) - qr * cos(qr)) / (qr * qr * qr); } else { fun = sign * 3.0 * (sin(qr) - qr * cos(qr)) / (qr * qr * qr); bes = sign * 3.0 * (sin(qr) - qr * cos(qr)) / (qr * qr * qr); } } contr = slope[i]*exp(A[i]*(r-r0)/thick[i]); vol = 4.0 * pi / 3.0 * r * r * r; //if (j == 1 && fabs(sld_in[i]-sld_solv) < 1e-04*fabs(sld_solv) && A[i]==0.0){ // vol_sub += (vol_pre - vol); //} f += vol * (contr * (fun) + (sld_in[i]-slope[i]) * bes); } break; default : if (fun_type[i]==0){ slope[i] = 0.0; } else{ slope[i]= (sld_out[i] -sld_in[i])/thick[i]; } contr = sld_in[i]-slope[i]*r; for (j=0; j<2; j++){ if ( i == 0 && j == 0){ continue; } if (i == n+1 && j == 1){ continue; } if ( j == 1){ sign = 1.0; r += thick[i]; } else{ sign = -1.0; } qr = q * r; fun = 0.0; if(qr == 0.0){ bes = sign * 1.0; } else{ bes = sign * 3.0 * (sin(qr) - qr * cos(qr)) / (qr * qr * qr); if (fabs(slope[i]) > 0.0 ){ fun = sign * 3.0 * r * (2.0*qr*sin(qr)-((qr*qr)-2.0)*cos(qr))/(qr * qr * qr * qr); } } vol = 4.0 * pi / 3.0 * r * r * r; //if (j == 1 && fabs(sld_in[i]-sld_solv) < 1e-04*fabs(sld_solv) && fun_type[i]==0){ // vol_sub += (vol_pre - vol); //} f += vol * (bes * contr + fun * slope[i]); } break; } } //vol += vol_sub; f2 = f * f / vol * 1.0e8; f2 *= scale; f2 += background; free(sld_out); free(slope); free(sld_in); free(thick); free(A); free(fun_type); return (f2); } OnionModel :: OnionModel() { n_shells = Parameter(1.0); scale = Parameter(1.0); rad_core0 = Parameter(200.0); rad_core0.set_min(0.0); sld_core0 = Parameter(1e-06); sld_solv = Parameter(6.4e-06); background = Parameter(0.0); sld_out_shell1 = Parameter(1.0e-06); sld_out_shell2 = Parameter(1.0e-06); sld_out_shell3 = Parameter(1.0e-06); sld_out_shell4 = Parameter(1.0e-06); sld_out_shell5 = Parameter(1.0e-06); sld_out_shell6 = Parameter(1.0e-06); sld_out_shell7 = Parameter(1.0e-06); sld_out_shell8 = Parameter(1.0e-06); sld_out_shell9 = Parameter(1.0e-06); sld_out_shell10 = Parameter(1.0e-06); sld_in_shell1 = Parameter(2.3e-06); sld_in_shell2 = Parameter(2.6e-06); sld_in_shell3 = Parameter(2.9e-06); sld_in_shell4 = Parameter(3.2e-06); sld_in_shell5 = Parameter(3.5e-06); sld_in_shell6 = Parameter(3.8e-06); sld_in_shell7 = Parameter(4.1e-06); sld_in_shell8 = Parameter(4.4e-06); sld_in_shell9 = Parameter(4.7e-06); sld_in_shell10 = Parameter(5.0e-06); A_shell1 = Parameter(1.0); A_shell2 = Parameter(1.0); A_shell3 = Parameter(1.0); A_shell4 = Parameter(1.0); A_shell5 = Parameter(1.0); A_shell6 = Parameter(1.0); A_shell7 = Parameter(1.0); A_shell8 = Parameter(1.0); A_shell9 = Parameter(1.0); A_shell10 = Parameter(1.0); thick_shell1 = Parameter(50.0); thick_shell1.set_min(0.0); thick_shell2 = Parameter(50.0); thick_shell2.set_min(0.0); thick_shell3 = Parameter(50.0); thick_shell3.set_min(0.0); thick_shell4 = Parameter(50.0); thick_shell4.set_min(0.0); thick_shell5 = Parameter(50.0); thick_shell5.set_min(0.0); thick_shell6 = Parameter(50.0); thick_shell6.set_min(0.0); thick_shell7 = Parameter(50.0); thick_shell7.set_min(0.0); thick_shell8 = Parameter(50.0); thick_shell8.set_min(0.0); thick_shell9 = Parameter(50.0); thick_shell9.set_min(0.0); thick_shell10 = Parameter(50.0); thick_shell10.set_min(0.0); func_shell1 = Parameter(2); func_shell2 = Parameter(2); func_shell3 = Parameter(2); func_shell4 = Parameter(2); func_shell5 = Parameter(2); func_shell6 = Parameter(2); func_shell7 = Parameter(2); func_shell8 = Parameter(2); func_shell9 = Parameter(2); func_shell10 = Parameter(2); } /** * Function to evaluate 1D scattering function * The NIST IGOR library is used for the actual calculation. * @param q: q-value * @return: function value */ double OnionModel :: operator()(double q) { double dp[56]; // Fill parameter array for IGOR library // Add the background after averaging dp[0] = n_shells(); dp[1] = scale(); dp[2] = rad_core0(); dp[3] = sld_core0(); dp[4] = sld_solv(); dp[5] = 0.0; dp[6] = sld_out_shell1(); dp[7] = sld_out_shell2(); dp[8] = sld_out_shell3(); dp[9] = sld_out_shell4(); dp[10] = sld_out_shell5(); dp[11] = sld_out_shell6(); dp[12] = sld_out_shell7(); dp[13] = sld_out_shell8(); dp[14] = sld_out_shell9(); dp[15] = sld_out_shell10(); dp[16] = sld_in_shell1(); dp[17] = sld_in_shell2(); dp[18] = sld_in_shell3(); dp[19] = sld_in_shell4(); dp[20] = sld_in_shell5(); dp[21] = sld_in_shell6(); dp[22] = sld_in_shell7(); dp[23] = sld_in_shell8(); dp[24] = sld_in_shell9(); dp[25] = sld_in_shell10(); dp[26] = A_shell1(); dp[27] = A_shell2(); dp[28] = A_shell3(); dp[29] = A_shell4(); dp[30] = A_shell5(); dp[31] = A_shell6(); dp[32] = A_shell7(); dp[33] = A_shell8(); dp[34] = A_shell9(); dp[35] = A_shell10(); dp[36] = thick_shell1(); dp[37] = thick_shell2(); dp[38] = thick_shell3(); dp[39] = thick_shell4(); dp[40] = thick_shell5(); dp[41] = thick_shell6(); dp[42] = thick_shell7(); dp[43] = thick_shell8(); dp[44] = thick_shell9(); dp[45] = thick_shell10(); dp[46] = func_shell1(); dp[47] = func_shell2(); dp[48] = func_shell3(); dp[49] = func_shell4(); dp[50] = func_shell5(); dp[51] = func_shell6(); dp[52] = func_shell7(); dp[53] = func_shell8(); dp[54] = func_shell9(); dp[55] = func_shell10(); // Get the dispersion points for the radius vector weights_rad; rad_core0.get_weights(weights_rad); // Get the dispersion points for the thick 1 vector weights_s1; thick_shell1.get_weights(weights_s1); // Get the dispersion points for the thick 2 vector weights_s2; thick_shell2.get_weights(weights_s2); // Get the dispersion points for the thick 3 vector weights_s3; thick_shell3.get_weights(weights_s3); // Get the dispersion points for the thick 4 vector weights_s4; thick_shell4.get_weights(weights_s4); // Get the dispersion points for the thick 5 vector weights_s5; thick_shell5.get_weights(weights_s5); // Get the dispersion points for the thick 6 vector weights_s6; thick_shell6.get_weights(weights_s6); // Get the dispersion points for the thick 7 vector weights_s7; thick_shell7.get_weights(weights_s7); // Get the dispersion points for the thick 8 vector weights_s8; thick_shell8.get_weights(weights_s8); // Get the dispersion points for the thick 9 vector weights_s9; thick_shell9.get_weights(weights_s9); // Get the dispersion points for the thick 10 vector weights_s10; thick_shell10.get_weights(weights_s10); // Perform the computation, with all weight points double sum = 0.0; double norm = 0.0; double vol = 0.0; // Loop over radius weight points for(size_t i=0; i weights_rad; rad_core0.get_weights(weights_rad); // Get the dispersion points for the thick 1 vector weights_s1; thick_shell1.get_weights(weights_s1); // Get the dispersion points for the thick 2 vector weights_s2; thick_shell2.get_weights(weights_s2); // Get the dispersion points for the thick 3 vector weights_s3; thick_shell3.get_weights(weights_s3); // Get the dispersion points for the thick 4 vector weights_s4; thick_shell4.get_weights(weights_s4); // Get the dispersion points for the thick 5 vector weights_s5; thick_shell5.get_weights(weights_s5); // Get the dispersion points for the thick 6 vector weights_s6; thick_shell6.get_weights(weights_s6); // Get the dispersion points for the thick 7 vector weights_s7; thick_shell7.get_weights(weights_s7); // Get the dispersion points for the thick 8 vector weights_s8; thick_shell8.get_weights(weights_s8); // Get the dispersion points for the thick 9 vector weights_s9; thick_shell9.get_weights(weights_s9); // Get the dispersion points for the thick 10 vector weights_s10; thick_shell10.get_weights(weights_s10); // Loop over radius weight points for(size_t i=0; i