- Categories
- Cylinder
- core_multi_shell_cylinder
- core_multi_shell_cylinder.c
core_multi_shell_cylinder - core_multi_shell_cylinder.c
// vd = volume * delta_rho
// besarg = q * R * sin(theta)
// siarg = q * L/2 * cos(theta)
static double _cyl(double vd, double besarg, double siarg)
{
return vd * sas_sinx_x(siarg) * sas_2J1x_x(besarg);
}
static double
form_volume(double radius_core, double length_core,
double n_shells, double thick[], double face[] )
{
// this one gets used by rest of sasview, it needs all the "volume" parameters
double r_out = radius_core;
double h_out = 0.5*length_core;
for (int j=0; j < n_shells; j++){
r_out += thick[j];
h_out += face[j];
}
return M_PI*square(r_out)*2.0*h_out;
}
static double
form_volume_here(double radius, double halflength)
// a quicker local one for these routines
{
return M_PI*square(radius)*2.0*halflength;
}
static double
radius_from_excluded_volume(double radius_tot, double halflength)
{
return 0.5*cbrt(0.75*radius_tot*(4.0*radius_tot*halflength +
(radius_tot + 2.0*halflength)*(M_PI*radius_tot + 2.0*halflength)));
}
static double
radius_from_volume(double radius, double halflength)
{
return cbrt(form_volume_here(radius,halflength)/M_4PI_3);
}
static double
radius_from_diagonal(double radius_outer, double halflength)
{
return sqrt(radius_outer*radius_outer + halflength*halflength);
}
static double
radius_effective(int mode, double radius_core, double length_core,
double n_shells, double thick[], double face[] )
{
double r_out = radius_core;
double h_out = 0.5*length_core;
for (int j=0; j < n_shells; j++){
r_out += thick[j];
h_out += face[j];
}
switch (mode) {
default:
case 1: //cylinder excluded volume
return radius_from_excluded_volume(r_out, h_out);
case 2: // equivalent volume sphere
return radius_from_volume(r_out, h_out);
case 3: // outer radius
return r_out;
case 4: // half outer length
return h_out;
case 5: // half min outer length
return (r_out < h_out ? r_out : h_out );
case 6: // half max outer length
return (r_out > h_out ? r_out : h_out );
case 7: // half outer diagonal
return radius_from_diagonal(r_out, h_out);
}
}
static void
Fq(double q, double *F1, double *F2, double sld_core, double radius_core, double length_core,
double sld_solvent, double sigma,
double n_shells, double sld[], double thick[], double face[] )
{
#define MAX_SHELLS_PLUS_2 12
// the sum over shells in the contrast has to be done inside the integration over angle
// this is messier than onion.c where for spheres the form factor is analytic
// NOTE assume at least one shell
double sin_theta, cos_theta;
double total_F1 = 0.0;
double total_F2 = 0.0;
// avoid repeated calculations and create single loop
// might be able to do double r_out[n_shells] but Paul K wants to keep multiples of 4
// for some possible gpu issues. Since the model's .py file defines the max limit as 10
// shells, need 2 more here (for core & solvent) which nicely makes 12
double r_out[MAX_SHELLS_PLUS_2], h_out[MAX_SHELLS_PLUS_2], vd[MAX_SHELLS_PLUS_2];
int n = (int)(n_shells+0.5);
r_out[0] = radius_core;
// h_out is half length of core or current shell, r_out is its radius
h_out[0] = length_core*0.5;
// first term, for core, needs refer to sld_core and first shell (hence restict model to n>= 1)
vd[0] = form_volume_here(r_out[0], h_out[0]) * ( sld_core - sld[0] );
// loop over first to next to last shells, only do this for n >= 2 shells
// n shells, has n+1 terms, indexed as 0 to n
for (int j=0; j < n-1; j++){
r_out[j+1] = r_out[j] + thick[j];
h_out[j+1] = h_out[j] + face[j];
vd[j+1] = form_volume_here(r_out[j+1], h_out[j+1]) * ( sld[j] - sld[j+1] );
}
// now do the last shell, which needs refer to solvent_sld
r_out[n] = r_out[n-1] + thick[n-1];
h_out[n] = h_out[n-1] + face[n-1];
vd[n] = form_volume_here(r_out[n], h_out[n]) * ( sld[n-1] - sld_solvent );
//
// now we are ready to do the longer loop of the quadrature integration
//printf("n r h = %d %g %g\n", n, r_out[n], h_out[n]);
for (int i=0; i<GAUSS_N ;i++) {
// translate a point in [-1,1] to a point in [0, pi/2]
//const double theta = ( GAUSS_Z[i]*(upper-lower) + upper + lower )/2.0;
const double theta = GAUSS_Z[i]*M_PI_4 + M_PI_4;
SINCOS(theta, sin_theta, cos_theta);
const double qab = q*sin_theta;
const double qc = q*cos_theta;
double f =0.0;
// sum over core and shells, terms j = 0 to n
for (int j=0; j < n+1; j++){
f += _cyl( vd[j], r_out[j]*qab, h_out[j]*qc );
}
total_F1 += GAUSS_W[i] * f * sin_theta;
total_F2 += GAUSS_W[i] * f * f * sin_theta;
}
// end of loops
// approximate interfacial roughness damping
const double atten = exp(-0.25*square(q*sigma));
*F1 = 1.0e-2 * total_F1 * M_PI_4*atten;
*F2 = 1.0e-4 * total_F2 * M_PI_4*square(atten);
}
static double
Iqac(double qab, double qc,
double sld_core, double radius_core, double length_core,
double sld_solvent, double sigma,
double n_shells, double sld[], double thick[], double face[] )
{
int n = (int)(n_shells+0.5);
double r_out = radius_core;
// h_out is half length of core or current shell, r_out is its radius
double h_out = length_core*0.5;
// first term, for core, needs refer to core_sld and first shell (hence restict model to n>= 1)
double vd = form_volume_here(r_out, h_out) * ( sld_core - sld[0]);
double f = _cyl(vd, r_out*qab, h_out*qc);
// loop over first to next to last shells, for n >= 2
for (int j=0; j < n-1; j++){
r_out += thick[j];
h_out += face[j];
vd = form_volume_here(r_out, h_out) * ( sld[j] - sld[j+1] );
f += _cyl(vd, r_out*qab, h_out*qc);
}
// now do the last shell, needs refer to solvent_sld
r_out += thick[n-1];
h_out += face[n-1];
vd = form_volume_here(r_out, h_out) * ( sld[n-1]-sld_solvent );
f += _cyl(vd, r_out*qab, h_out*qc);
// approximate interfacial roughness damping
const double atten = exp(-0.5*(qab*qab + qc*qc)*(sigma*sigma));
return 1.0e-4 * f*f * atten;
}
Back to Model
Download