static double
fractal_sq(double q, double radius, double fractal_dim, double cor_length)
{
    //calculate S(q),  using Teixeira, Eq(15)
    // mathematica query to check limiting conditions:
    //    lim x->0 of [ x gamma(x-1) sin(arctan(q c (x-1))) (q r)^(-x) (1 + 1/(q c)^2)^((1-x)/2) ]
    // Note: gamma(x) may be unreliable for x<0, so the gamma(D-1) is risky.
    // We instead transform D*gamma(D-1) into gamma(D+1)/(D-1).
    double term;
    if (q == 0.) {
        const double D = fractal_dim;
        term = pow(cor_length/radius, D)*sas_gamma(D+1.);
    } else if (fractal_dim == 0.) {
        term = 1.0;
    } else if (fractal_dim == 1.) {
        term = atan(q*cor_length)/(q*radius);
    } else {
        // q>0, D>0
        const double D = fractal_dim;
        const double Dm1 = fractal_dim - 1.0;
        // Note: for large Dm1, sin(Dm1*atan(q*cor_length) can go negative
        const double t1 = sas_gamma(D+1.)/Dm1*sin(Dm1*atan(q*cor_length));
        const double t2 = pow(q*radius, -D);
        const double t3 = pow(1.0 + 1.0/square(q*cor_length), -0.5*Dm1);
        term = t1 * t2 * t3;
    }
    return 1.0 + term;
}
