Changeset 68425bf in sasmodels


Ignore:
Timestamp:
Oct 15, 2016 10:33:26 PM (8 years ago)
Author:
Paul Kienzle <pkienzle@…>
Branches:
master, core_shell_microgels, costrafo411, magnetic_model, ticket-1257-vesicle-product, ticket_1156, ticket_1265_superball, ticket_822_more_unit_tests
Children:
4f79d94
Parents:
e30d645
Message:

elliptical_cylinder: use ORIENT macros and simplify code

Location:
sasmodels
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • sasmodels/conversion_table.py

    r14838a3 r68425bf  
    257257        "EllipticalCylinderModel", 
    258258        { 
     259            "axis_ratio": "r_ratio", 
     260            "radius_minor": "r_minor", 
     261            "sld": "sldCyl", 
     262            "sld_solvent": "sldSolv", 
     263            "theta": "cyl_theta", 
    259264            "phi": "cyl_phi", 
    260265            "psi": "cyl_psi", 
    261             "theta": "cyl_theta", 
    262             "sld": "sldCyl", 
    263             "axis_ratio": "r_ratio", 
    264             "sld_solvent": "sldSolv" 
    265266        } 
    266267    ], 
  • sasmodels/models/elliptical_cylinder.c

    ra807206 r68425bf  
    66 
    77 
    8 double _elliptical_cylinder_kernel(double q, double radius_minor, double r_ratio, double theta); 
    98 
    10 double _elliptical_cylinder_kernel(double q, double radius_minor, double r_ratio, double theta) 
     9static double 
     10_kernel(double q, double radius_minor, double r_ratio, double theta) 
    1111{ 
    1212    // This is the function LAMBDA1^2 in Feigin's notation 
     
    3030} 
    3131 
    32 double Iq(double q, double radius_minor, double r_ratio, double length, 
    33           double sld, double solvent_sld) { 
     32double 
     33Iq(double q, double radius_minor, double r_ratio, double length, 
     34   double sld, double solvent_sld) 
     35{ 
     36    // orientational average limits 
     37    const double va = 0.0; 
     38    const double vb = 1.0; 
     39    // inner integral limits 
     40    const double vaj=0.0; 
     41    const double vbj=M_PI; 
    3442 
    35     const int nordi=76; //order of integration 
    36     const int nordj=20; 
    37     double va,vb;       //upper and lower integration limits 
    38     double summ,zi,yyy,answer;         //running tally of integration 
    39     double summj,vaj,vbj,zij,arg,si;            //for the inner integration 
    40  
    41     // orientational average limits 
    42     va = 0.0; 
    43     vb = 1.0; 
    44     // inner integral limits 
    45     vaj=0.0; 
    46     vbj=M_PI; 
     43    const double radius_major = r_ratio * radius_minor; 
     44    const double rA = 0.5*(square(radius_major) + square(radius_minor)); 
     45    const double rB = 0.5*(square(radius_major) - square(radius_minor)); 
    4746 
    4847    //initialize integral 
    49     summ = 0.0; 
    50  
    51     const double delrho = sld - solvent_sld; 
    52  
    53     for(int i=0;i<nordi;i++) { 
     48    double outer_sum = 0.0; 
     49    for(int i=0;i<76;i++) { 
    5450        //setup inner integral over the ellipsoidal cross-section 
    55         summj=0; 
    56         zi = ( Gauss76Z[i]*(vb-va) + va + vb )/2.0;     //the "x" dummy 
    57         arg = radius_minor*sqrt(1.0-zi*zi); 
    58         for(int j=0;j<nordj;j++) { 
     51        const double cos_val = ( Gauss76Z[i]*(vb-va) + va + vb )/2.0; 
     52        const double sin_val = sqrt(1.0 - cos_val*cos_val); 
     53        //const double arg = radius_minor*sin_val; 
     54        double inner_sum=0; 
     55        for(int j=0;j<20;j++) { 
    5956            //20 gauss points for the inner integral 
    60             zij = ( Gauss20Z[j]*(vbj-vaj) + vaj + vbj )/2.0;        //the "y" dummy 
    61             yyy = Gauss20Wt[j] * _elliptical_cylinder_kernel(q, arg, r_ratio, zij); 
    62             summj += yyy; 
     57            const double theta = ( Gauss20Z[j]*(vbj-vaj) + vaj + vbj )/2.0; 
     58            const double r = sin_val*sqrt(rA - rB*cos(theta)); 
     59            const double be = sas_J1c(q*r); 
     60            inner_sum += Gauss20Wt[j] * be * be; 
    6361        } 
    6462        //now calculate the value of the inner integral 
    65         answer = (vbj-vaj)/2.0*summj; 
     63        inner_sum *= 0.5*(vbj-vaj); 
    6664 
    6765        //now calculate outer integral 
    68         arg = q*length*zi/2.0; 
    69         si = square(sinc(arg)); 
    70         yyy = Gauss76Wt[i] * answer * si; 
    71         summ += yyy; 
     66        const double si = sinc(q*0.5*length*cos_val); 
     67        outer_sum += Gauss76Wt[i] * inner_sum * si * si; 
    7268    } 
     69    outer_sum *= 0.5*(vb-va); 
    7370 
    7471    //divide integral by Pi 
    75     answer = (vb-va)/2.0*summ/M_PI; 
    76     // Multiply by contrast^2 
    77     answer *= delrho*delrho; 
     72    const double form = outer_sum/M_PI; 
    7873 
     74    // scale by contrast and volume, and convert to to 1/cm units 
    7975    const double vol = form_volume(radius_minor, r_ratio, length); 
    80     return answer*vol*vol*1.0e-4; 
     76    const double delrho = sld - solvent_sld; 
     77    return 1.0e-4*square(delrho*vol)*form; 
    8178} 
    8279 
    8380 
    84 double Iqxy(double qx, double qy, double radius_minor, double r_ratio, double length, 
    85             double sld, double solvent_sld, double theta, double phi, double psi) { 
    86     const double _theta = theta * M_PI / 180.0; 
    87     const double _phi = phi * M_PI / 180.0; 
    88     const double _psi = psi * M_PI / 180.0; 
    89     const double q = sqrt(qx*qx+qy*qy); 
    90     const double q_x = qx/q; 
    91     const double q_y = qy/q; 
     81double 
     82Iqxy(double qx, double qy, 
     83     double radius_minor, double r_ratio, double length, 
     84     double sld, double solvent_sld, 
     85     double theta, double phi, double psi) 
     86{ 
     87    double q, cos_val, cos_mu, cos_nu; 
     88    ORIENT_ASYMMETRIC(qx, qy, theta, phi, psi, q, cos_val, cos_mu, cos_nu); 
    9289 
    93     //Cylinder orientation 
    94     double cyl_x = cos(_theta) * cos(_phi); 
    95     double cyl_y = sin(_theta); 
    96  
    97     //cyl_z = -cos(_theta) * sin(_phi); 
    98  
    99     // q vector 
    100     //q_z = 0; 
    101  
    102     // Note: cos(alpha) = 0 and 1 will get an 
    103     // undefined value from CylKernel 
    104     //alpha = acos( cos_val ); 
    105  
    106     //ellipse orientation: 
    107     // the elliptical corss section was transformed and projected 
    108     // into the detector plane already through sin(alpha)and furthermore psi remains as same 
    109     // on the detector plane. 
    110     // So, all we need is to calculate the angle (nu) of the minor axis of the ellipse wrt 
    111     // the wave vector q. 
    112  
    113     //x- y- component on the detector plane. 
    114     const double ella_x =  -cos(_phi)*sin(_psi) * sin(_theta)+sin(_phi)*cos(_psi); 
    115     const double ella_y =  sin(_psi)*cos(_theta); 
    116     const double ellb_x =  -sin(_theta)*cos(_psi)*cos(_phi)-sin(_psi)*sin(_phi); 
    117     const double ellb_y =  cos(_theta)*cos(_psi); 
    118  
    119     // Compute the angle btw vector q and the 
    120     // axis of the cylinder 
    121     double cos_val = cyl_x*q_x + cyl_y*q_y;// + cyl_z*q_z; 
    122  
    123     // calculate the axis of the ellipse wrt q-coord. 
    124     double cos_nu = ella_x*q_x + ella_y*q_y; 
    125     double cos_mu = ellb_x*q_x + ellb_y*q_y; 
    126  
    127     // The following test should always pass 
    128     if (fabs(cos_val)>1.0) { 
    129       //printf("cyl_ana_2D: Unexpected error: cos(alpha)>1\n"); 
    130       cos_val = 1.0; 
    131     } 
    132     if (fabs(cos_nu)>1.0) { 
    133       //printf("cyl_ana_2D: Unexpected error: cos(nu)>1\n"); 
    134       cos_nu = 1.0; 
    135     } 
    136     if (fabs(cos_mu)>1.0) { 
    137       //printf("cyl_ana_2D: Unexpected error: cos(nu)>1\n"); 
    138       cos_mu = 1.0; 
    139     } 
    140  
    141     const double r_major = r_ratio * radius_minor; 
    142     const double qr = q*sqrt( r_major*r_major*cos_nu*cos_nu + radius_minor*radius_minor*cos_mu*cos_mu ); 
    143     const double qL = q*length*cos_val/2.0; 
    144  
    145     double Be; 
    146     if (qr==0){ 
    147       Be = 0.5; 
    148     }else{ 
    149       //Be = NR_BessJ1(qr)/qr; 
    150       Be = 0.5*sas_J1c(qr); 
    151     } 
    152  
    153     double Si; 
    154     if (qL==0){ 
    155       Si = 1.0; 
    156     }else{ 
    157       Si = sin(qL)/qL; 
    158     } 
    159  
    160     const double k = 2.0 * Be * Si; 
     90    // Compute:  r = sqrt((radius_major*cos_nu)^2 + (radius_minor*cos_mu)^2) 
     91    // Given:    radius_major = r_ratio * radius_minor 
     92    const double r = radius_minor*sqrt(square(r_ratio*cos_nu) + cos_mu*cos_mu); 
     93    const double be = sas_J1c(q*r); 
     94    const double si = sinc(q*0.5*length*cos_val); 
     95    const double Aq = be * si; 
     96    const double delrho = sld - solvent_sld; 
    16197    const double vol = form_volume(radius_minor, r_ratio, length); 
    162     return (sld - solvent_sld) * (sld - solvent_sld) * k * k *vol*vol*1.0e-4; 
     98    return 1.0e-4 * square(delrho * vol * Aq); 
    16399} 
Note: See TracChangeset for help on using the changeset viewer.