Changeset 54bcd4a in sasmodels for sasmodels/models/spherical_sld.c


Ignore:
Timestamp:
Aug 4, 2016 4:48:37 PM (8 years ago)
Author:
Paul Kienzle <pkienzle@…>
Branches:
master, core_shell_microgels, costrafo411, magnetic_model, release_v0.94, release_v0.95, ticket-1257-vesicle-product, ticket_1156, ticket_1265_superball, ticket_822_more_unit_tests
Children:
745b7bb
Parents:
bd49c79
Message:

spherical sld: simplify code so that it works on AMD GPUs

File:
1 edited

Legend:

Unmodified
Added
Removed
  • sasmodels/models/spherical_sld.c

    rdd71228 r54bcd4a  
    11static double form_volume( 
    22    int n_shells, 
    3     double radius_core, 
    4     double thick_inter0, 
    5     double thick_flat[], 
    6     double thick_inter[]) 
     3    double thickness[], 
     4    double interface[]) 
    75{ 
    8     int i; 
    9     double r = radius_core; 
    10     r += thick_inter0; 
    11     for (i=0; i < n_shells; i++) { 
    12         r += thick_inter[i]; 
    13         r += thick_flat[i]; 
     6    double r = 0.0; 
     7    for (int i=0; i < n_shells; i++) { 
     8        r += thickness[i] + interface[i]; 
    149    } 
    1510    return M_4PI_3*cube(r); 
    1611} 
    1712 
     13static double blend(int shape, double nu, double z) 
     14{ 
     15    if (shape==0) { 
     16        const double num = sas_erf(nu * M_SQRT1_2 * (2.0*z - 1.0)); 
     17        const double denom = 2.0 * sas_erf(nu * M_SQRT1_2); 
     18        return num/denom + 0.5; 
     19    } else if (shape==1) { 
     20        return pow(z, nu); 
     21    } else if (shape==2) { 
     22        return 1.0 - pow(1. - z, nu); 
     23    } else if (shape==3) { 
     24        return expm1(-nu*z)/expm1(-nu); 
     25    } else if (shape==4) { 
     26        return expm1(nu*z)/expm1(nu); 
     27    } else { 
     28        return NAN; 
     29    } 
     30} 
    1831 
    19 static double sphere_sld_kernel( 
     32static double f_linear(double q, double r, double contrast, double slope) 
     33{ 
     34    const double qr = q * r; 
     35    const double qrsq = qr * qr; 
     36    const double bes = sph_j1c(qr); 
     37    double sinqr, cosqr; 
     38    SINCOS(qr, sinqr, cosqr); 
     39    const double fun = 3.0*r*(2.0*qr*sinqr - (qrsq-2.0)*cosqr)/(qrsq*qrsq); 
     40    const double vol = M_4PI_3 * cube(r); 
     41    return vol*(bes*contrast + fun*slope); 
     42} 
     43 
     44static double Iq( 
    2045    double q, 
    2146    int n_shells, 
    22     int npts_inter, 
    23     double radius_core, 
    24     double sld_core, 
    2547    double sld_solvent, 
    26     double func_inter_core, 
    27     double thick_inter_core, 
    28     double nu_inter_core, 
    29     double sld_flat[], 
    30     double thick_flat[], 
    31     double func_inter[], 
    32     double thick_inter[], 
    33     double nu_inter[] ) { 
     48    double sld[], 
     49    double thickness[], 
     50    double interface[], 
     51    double shape[], 
     52    double nu[], 
     53    int n_steps) 
     54{ 
     55    // iteration for # of shells + core + solvent 
     56    double f=0.0; 
     57    double r=0.0; 
     58    for (int shell=0; shell<n_shells; shell++){ 
     59        const double sld_l = sld[shell]; 
    3460 
    35     int i,j,k; 
    36     int n_s; 
     61        // uniform shell; r=0 => r^3=0 => f=0, so works for core as well. 
     62        f -= M_4PI_3 * cube(r) * sld_l * sph_j1c(q*r); 
     63        r += thickness[shell]; 
     64        f += M_4PI_3 * cube(r) * sld_l * sph_j1c(q*r); 
    3765 
    38     double sld_i,sld_f,dz,bes,fun,f,vol,qr,r,contr,f2; 
    39     double sign,slope=0.0; 
    40     double pi; 
     66        // iterate over sub_shells in the interface 
     67        const double dr = interface[shell]/n_steps; 
     68        const double delta = (shell==n_shells-1 ? sld_solvent : sld[shell+1]) - sld_l; 
     69        const double nu_shell = fmax(fabs(nu[shell]), 1.e-14); 
     70        const int shape_shell = (int)(shape[shell]); 
    4171 
    42     double total_thick=0.0; 
     72        // if there is no interface the equations don't work 
     73        if (dr == 0.) continue; 
    4374 
    44     //TODO: This part can be further simplified 
    45     int fun_type[12]; 
    46     double sld[12]; 
    47     double thick_internal[12]; 
    48     double thick[12]; 
    49     double fun_coef[12]; 
     75        double sld_in = sld_l; 
     76        for (int step=1; step <= n_steps; step++) { 
     77            // find sld_i at the outer boundary of sub-shell step 
     78            //const double z = (double)step/(double)n_steps; 
     79            const double z = (double)step/(double)n_steps; 
     80            const double fraction = blend(shape_shell, nu_shell, z); 
     81            const double sld_out = fraction*delta + sld_l; 
     82            // calculate slope 
     83            const double slope = (sld_out - sld_in)/dr; 
     84            const double contrast = sld_in - slope*r; 
    5085 
    51     fun_type[0] = func_inter_core; 
    52     fun_coef[0] = fabs(nu_inter_core); 
    53     sld[0] = sld_core; 
    54     thick[0] = radius_core; 
    55     thick_internal[0] = thick_inter_core; 
    56  
    57     for (i =1; i<=n_shells; i++){ 
    58         sld[i] = sld_flat[i-1]; 
    59         thick_internal[i]= thick_inter[i-1]; 
    60         thick[i] = thick_flat[i-1]; 
    61         fun_type[i] = func_inter[i-1]; 
    62         fun_coef[i] = fabs(nu_inter[i-1]); 
    63         total_thick += thick[i]; 
    64         total_thick += thick_internal[i]; //doesn't account for core layer 
    65     } 
    66  
    67     sld[n_shells+1] = sld_solvent; 
    68     thick[n_shells+1] = total_thick/5.0; 
    69     thick_internal[n_shells+1] = 0.0; 
    70     fun_coef[n_shells+1] = 0.0; 
    71     fun_type[n_shells+1] = 0; 
    72  
    73     pi = 4.0*atan(1.0); 
    74     f = 0.0; 
    75     r = 0.0; 
    76     vol = 0.0; 
    77     sld_f = sld_core; 
    78  
    79     dz = 0.0; 
    80     // iteration for # of shells + core + solvent 
    81     for (i=0;i<=n_shells+1; i++){ 
    82         // iteration for flat and interface 
    83         for (j=0;j<2;j++){ 
    84             // iteration for sub_shells in the interface 
    85             // starts from #1 sub-layer 
    86             for (n_s=1;n_s<=npts_inter; n_s++){ 
    87                 // for solvent, it doesn't have an interface 
    88                 if (i==n_shells+1 && j==1) 
    89                     break; 
    90                 // for flat layers 
    91                 if (j==0){ 
    92                     dz = thick[i]; 
    93                     sld_i = sld[i]; 
    94                     slope = 0.0; 
    95                 } 
    96                 // for interfacial sub_shells 
    97                 else{ 
    98                     dz = thick_internal[i]/npts_inter; 
    99                     // find sld_i at the outer boundary of sub-layer #n_s 
    100                     sld_i = intersldfunc(fun_type[i], npts_inter, n_s, 
    101                             fun_coef[i], sld[i], sld[i+1]); 
    102                     // calculate slope 
    103                     slope= (sld_i -sld_f)/dz; 
    104                 } 
    105                 contr = sld_f-slope*r; 
    106                 // iteration for the left and right boundary of the shells 
    107                 for (k=0; k<2; k++){ 
    108                     // At r=0, the contribution to I is zero, so skip it. 
    109                     if ( i == 0 && j == 0 && k == 0){ 
    110                         continue; 
    111                     } 
    112                     // On the top of slovent there is no interface; skip it. 
    113                     if (i == n_shells+1 && k == 1){ 
    114                         continue; 
    115                     } 
    116                     // At the right side (outer) boundary 
    117                     if ( k == 1){ 
    118                         sign = 1.0; 
    119                         r += dz; 
    120                     } 
    121                     // At the left side (inner) boundary 
    122                     else{ 
    123                         sign = -1.0; 
    124                     } 
    125  
    126                     qr = q * r; 
    127                     fun = 0.0; 
    128  
    129                     if(qr == 0.0){ 
    130                         bes = sign * 1.0; 
    131                     } 
    132                     else{ 
    133                         // for flat sub-layer 
    134                         //TODO: Single precision calculation fails here 
    135                         bes = sign *  sph_j1c(qr); 
    136                         if (fabs(slope) > 0.0 ){ 
    137                             const double qrsq = qr*qr; 
    138                             double sinqr, cosqr; 
    139                             SINCOS(qr, sinqr, cosqr); 
    140                             fun = sign * 3.0 * r * 
    141                             (2.0*qr*sinqr - (qrsq-2.0)*cosqr)/(qrsq * qrsq); 
    142                             // In the onion model Jae-He's formula is rederived 
    143                             // and gives following: 
    144                             //fun = 3.0 * sign * r * 
    145                             //(2.0*cosqr + qr*sinqr)/(qrsq*qrsq); 
    146                             //But this seems not to be working in this case... 
    147                         } 
    148                     } 
    149  
    150                     // update total volume 
    151                     vol = M_4PI_3 * cube(r); 
    152                     f += vol * (bes * contr + fun * slope); 
    153                 } 
    154                 sld_f = sld_i; 
    155                 // no sub-layer iteration (n_s loop) for the flat layer 
    156                 if (j==0) 
    157                     break; 
    158             } 
     86            // iteration for the left and right boundary of the shells 
     87            f -= f_linear(q, r, contrast, slope); 
     88            r += dr; 
     89            f += f_linear(q, r, contrast, slope); 
     90            sld_in = sld_out; 
    15991        } 
    16092    } 
     93    // add in solvent effect 
     94    f -= M_4PI_3 * cube(r) * sld_solvent * sph_j1c(q*r); 
    16195 
    162     f2 = f * f * 1.0e-4; 
    163     return (f2); 
     96    const double f2 = f * f * 1.0e-4; 
     97    return f2; 
    16498} 
    16599 
    166  
    167 /** 
    168  * Function to evaluate 1D SphereSLD function 
    169  * @param q: q-value 
    170  * @return: function value 
    171  */ 
    172 static double Iq(double q, 
    173     int n_shells, 
    174     int npts_inter, 
    175     double radius_core, 
    176     double sld_core, 
    177     double sld_solvent, 
    178     double func_inter0, 
    179     double thick_inter0, 
    180     double nu_inter0, 
    181     double sld_flat[], 
    182     double thick_flat[], 
    183     double func_inter[], 
    184     double thick_inter[], 
    185     double nu_inter[] ) { 
    186  
    187     double intensity = sphere_sld_kernel(q, n_shells, npts_inter, radius_core, 
    188                 sld_core, sld_solvent, func_inter0, thick_inter0, nu_inter0, 
    189                 sld_flat, thick_flat, func_inter, thick_inter, nu_inter); 
    190  
    191     return intensity; 
    192 } 
    193  
    194 /** 
    195  * Function to evaluate 2D SphereSLD function 
    196  * @param q_x: value of Q along x 
    197  * @param q_y: value of Q along y 
    198  * @return: function value 
    199  */ 
    200  
    201 /*static double Iqxy(double qx, double qy, 
    202     int n_shells, 
    203     int npts_inter, 
    204     double radius_core 
    205     double sld_core, 
    206     double sld_solvent, 
    207     double sld_flat[], 
    208     double thick_flat[], 
    209     double func_inter[], 
    210     double thick_inter[], 
    211     double nu_inter[], 
    212     ) { 
    213  
    214     double q = sqrt(qx*qx + qy*qy); 
    215     return Iq(q, n_shells, npts_inter, radius_core, sld_core, sld_solvent, 
    216     sld_flat[], thick_flat[], func_inter[], thick_inter[], nu_inter[]) 
    217 }*/ 
    218  
Note: See TracChangeset for help on using the changeset viewer.