Changeset f12357f in sasmodels


Ignore:
Timestamp:
Feb 3, 2016 6:49:57 AM (9 years ago)
Author:
krzywon
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:
a17fe40
Parents:
8696a87
Message:

Modified the pearl_necklace model for better double precision accuracy
and added unit tests.

Location:
sasmodels/models
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • sasmodels/models/lib/Si.c

    r7d256c8 rf12357f  
    1313 
    1414                // Explicitly writing factorial values triples the speed of the calculation 
    15                 out_cos = 1/x - 2/pow(x,3) + 24/pow(x,5) - 720/pow(x,7) + 40320/pow(x,9); 
    16                 out_sin = 1/x - 6/pow(x,4) + 120/pow(x,6) - 5040/pow(x,8) + 362880/pow(x,10); 
     15                out_cos = 1./x - 2./pow(x,3) + 24./pow(x,5) - 720./pow(x,7); 
     16                out_sin = 1./pow(x,2) - 6./pow(x,4) + 120./pow(x,6) - 5040./pow(x,8); 
    1717 
    1818                out -= cos(x) * out_cos; 
     
    2222 
    2323        // Explicitly writing factorial values triples the speed of the calculation 
    24         out = x - pow(x, 3)/18 + pow(x,5)/600 - pow(x,7)/35280 + pow(x,9)/3265920; 
     24        out = x - pow(x, 3)/18. + pow(x,5)/600. - pow(x,7)/35280. + pow(x,9)/3265920. - pow(x,11)/439084800.; 
    2525 
    26         //printf ("Si=%g %g\n", x, out); 
    2726        return out; 
    2827} 
  • sasmodels/models/pearl_necklace.c

    rcf404cb rf12357f  
    1212        double string_thickness, double number_of_pearls, double sld,  
    1313        double string_sld, double solvent_sld); 
    14          
    15 double ER(double radius, double edge_separation, 
    16         double string_thickness, double number_of_pearls); 
    17 double VR(double radius, double edge_separation, 
    18         double string_thickness, double number_of_pearls); 
    1914 
    2015// From Igor library 
     
    2217        double num_pearls, double sld_pearl, double sld_string, double sld_solv) 
    2318{ 
     19        //relative slds 
    2420        double contrast_pearl = sld_pearl - sld_solv; 
    2521        double contrast_string = sld_string - sld_solv; 
     22         
     23        // number of string segments 
     24        num_pearls = floor(num_pearls + 0.5); //Force integer number of pearls 
     25        double num_strings = num_pearls - 1.0; 
     26         
     27        //Pi 
     28        double pi = 4.0*atan(1.0); 
     29         
     30        // center to center distance between the neighboring pearls 
     31        double A_s = edge_separation + 2.0 * radius; 
     32         
     33        // Repeated Calculations 
     34        double sincasq = sinc(q*A_s); 
     35        double oneminussinc = 1 - sincasq; 
     36        double q_r = q * radius; 
     37        double q_edge = q * edge_separation; 
     38         
     39        // each volume 
     40        double string_vol = edge_separation * pi * thick_string * thick_string / 4.0; 
     41        double pearl_vol = 4.0 / 3.0 * pi * radius * radius * radius; 
    2642 
    2743        //total volume 
    28         double pi = 4.0*atan(1.0); 
    29         double tot_vol = form_volume(radius, edge_separation, thick_string, num_pearls); 
    30         double string_vol = edge_separation * pi * pow((thick_string / 2.0), 2); 
    31         double pearl_vol = 4.0 /3.0 * pi * pow(radius, 3); 
    32         double num_strings = num_pearls - 1; 
    33         //each mass 
     44        double tot_vol; 
     45        //each masses 
    3446        double m_r= contrast_string * string_vol; 
    3547        double m_s= contrast_pearl * pearl_vol; 
    3648        double psi, gamma, beta; 
    3749        //form factors 
    38         double sss; //pearls 
    39         double srr; //strings 
    40         double srs; //cross 
    41         double A_s, srr_1, srr_2, srr_3; 
     50        double sss, srr, srs; //cross 
     51        double srr_1, srr_2, srr_3; 
    4252        double form_factor; 
     53        tot_vol = num_strings * string_vol; 
     54        tot_vol += num_pearls * pearl_vol; 
    4355 
    4456        //sine functions of a pearl 
    45         psi = sin(q*radius); 
    46         psi -= q * radius * cos(q * radius); 
    47         psi /= pow((q * radius), 3); 
     57        psi = sin(q_r); 
     58        psi -= q_r * cos(q_r); 
    4859        psi *= 3.0; 
     60        psi /= q_r * q_r * q_r; 
    4961 
    5062        // Note take only 20 terms in Si series: 10 terms may be enough though. 
    51         gamma = Si(q* edge_separation); 
    52         gamma /= (q* edge_separation); 
    53         beta = Si(q * (edge_separation + radius)); 
    54         beta -= Si(q * radius); 
    55         beta /= (q* edge_separation); 
    56  
    57         // center to center distance between the neighboring pearls 
    58         A_s = edge_separation + 2.0 * radius; 
     63        gamma = Si(q_edge); 
     64        gamma /= (q_edge); 
     65        beta = Si(q * (A_s - radius)); 
     66        beta -= Si(q_r); 
     67        beta /= q_edge; 
    5968 
    6069        // form factor for num_pearls 
    61         sss = 1.0 - pow(sinc(q*A_s), num_pearls ); 
    62         sss /= pow((1.0-sinc(q*A_s)), 2); 
    63         sss *= -sinc(q*A_s); 
    64         sss -= num_pearls/2.0; 
    65         sss += num_pearls/(1.0-sinc(q*A_s)); 
    66         sss *= 2.0 * pow((m_s*psi), 2); 
     70        sss = 1.0 - pow(sincasq, num_pearls); 
     71        sss /= oneminussinc * oneminussinc; 
     72        sss *= -sincasq; 
     73        sss -= num_pearls / 2.0; 
     74        sss += num_pearls / oneminussinc; 
     75        sss *= 2.0 * m_s * psi * m_s * psi; 
    6776 
    6877        // form factor for num_strings (like thin rods) 
    69         srr_1 = -pow(sinc(q*edge_separation/2.0), 2); 
     78        srr_1 = -sinc(q_edge/2.0) * sinc(q_edge/2.0); 
    7079 
    7180        srr_1 += 2.0 * gamma; 
    7281        srr_1 *= num_strings; 
    73         srr_2 = 2.0/(1.0-sinc(q*A_s)); 
    74         srr_2 *= num_strings * pow(beta, 2); 
    75         srr_3 = 1.0 - pow(sinc(q*A_s), num_strings); 
    76         srr_3 /= pow((1.0-sinc(q*A_s)), 2); 
    77         srr_3 *= -2.0 * pow(beta, 2); 
     82        srr_2 = 2.0/oneminussinc; 
     83        srr_2 *= num_strings; 
     84        srr_2 *= beta * beta; 
     85        srr_3 = 1.0 - pow(sincasq, num_strings); 
     86        srr_3 /= oneminussinc * oneminussinc; 
     87        srr_3 *= beta * beta; 
     88        srr_3 *= -2.0; 
    7889 
    7990        // total srr 
    8091        srr = srr_1 + srr_2 + srr_3; 
    81         srr *= pow(m_r, 2); 
     92        srr *= m_r * m_r; 
    8293 
    8394        // form factor for correlations 
    8495        srs = 1.0; 
    85         srs -= pow(sinc(q*A_s), num_strings); 
    86         srs /= pow((1.0-sinc(q*A_s)), 2); 
    87         srs *= -sinc(q*A_s); 
    88         srs += (num_strings/(1.0-sinc(q*A_s))); 
    89         srs *= 4.0 * (m_r * m_s * beta * psi); 
     96        srs -= pow(sincasq, num_strings); 
     97        srs /= oneminussinc * oneminussinc; 
     98        srs *= -sincasq; 
     99        srs += num_strings/oneminussinc; 
     100        srs *= 4.0; 
     101        srs *= (m_r * m_s * beta * psi); 
    90102 
    91103        form_factor = sss + srr + srs; 
     
    103115        double number_of_strings = number_of_pearls - 1.0; 
    104116         
    105         double string_vol = edge_separation * pi * pow((string_thickness / 2.0), 2); 
    106         double pearl_vol = 4.0 /3.0 * pi * pow(radius, 3); 
     117        double string_vol = edge_separation * pi * string_thickness * string_thickness / 4.0; 
     118        double pearl_vol = 4.0 / 3.0 * pi * radius * radius * radius; 
    107119 
    108120        total_vol = number_of_strings * string_vol; 
     
    124136        double string_sld, double solvent_sld) 
    125137{ 
    126         double value = 0.0; 
    127         double tot_vol = 0.0; 
     138        double value, tot_vol; 
     139         
     140        if (string_thickness >= radius || number_of_pearls <= 0) { 
     141                return NAN; 
     142        } 
    128143         
    129144        value = _pearl_necklace_kernel(q, radius, edge_separation, string_thickness, 
     
    142157                sld, string_sld, solvent_sld)); 
    143158} 
    144  
    145  
    146 double ER(double radius, double edge_separation, 
    147         double string_thickness, double number_of_pearls) 
    148 { 
    149         double tot_vol = form_volume(radius, edge_separation, string_thickness, number_of_pearls); 
    150         double pi = 4.0*atan(1.0); 
    151  
    152     double rad_out = pow((3.0*tot_vol/4.0/pi), 0.33333); 
    153      
    154     return rad_out; 
    155 } 
    156 double VR(double radius, double edge_separation, 
    157         double string_thickness, double number_of_pearls) 
    158 { 
    159         return 1.0; 
    160 } 
  • sasmodels/models/pearl_necklace.py

    r841753c rf12357f  
    5858""" 
    5959 
    60 from numpy import inf 
     60from numpy import inf, pi 
    6161 
    6262name = "pearl_necklace" 
     
    9696 
    9797source = ["lib/Si.c", "pearl_necklace.c"] 
     98# new flag to let the compiler know to never use single precision 
     99single = False 
     100 
     101def volume(radius, edge_separation, string_thickness, number_of_pearls): 
     102    """ 
     103    Calculates the total particle volume of the necklace. 
     104    Redundant with form_volume. 
     105    """ 
     106    number_of_strings = number_of_pearls - 1.0 
     107    string_vol = edge_separation * pi * pow((string_thickness / 2.0), 2.0) 
     108    pearl_vol = 4.0 /3.0 * pi * pow(radius, 3.0) 
     109    total_vol = number_of_strings * string_vol 
     110    total_vol += number_of_pearls * pearl_vol 
     111    return total_vol 
     112 
     113def ER(radius, edge_separation, string_thickness, number_of_pearls): 
     114    """ 
     115    Calculation for effective radius. 
     116    """ 
     117    tot_vol = volume(radius, edge_separation, string_thickness, number_of_pearls) 
     118    rad_out = pow((3.0*tot_vol/4.0/pi), 0.33333) 
     119    return rad_out 
    98120 
    99121# parameters for demo 
     
    114136               string_thickness='thick_string', sld='sld_pearl', 
    115137               string_sld='sld_string', edge_separation='edge_separation') 
     138 
     139tests = [[{}, 0.001, 17380.245], [{}, 'ER', 115.39502]] 
Note: See TracChangeset for help on using the changeset viewer.