source: sasview/src/sas/sascalc/calculator/c_extensions/libfunc.c @ 197260f

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 197260f was 197260f, checked in by wojciech, 8 years ago

Libfunc cleaned up

  • Property mode set to 100644
File size: 6.9 KB
Line 
1// by jcho
2
3#include <math.h>
4
5#include "libfunc.h"
6
7#include <stdio.h>
8
9
10
11//used in Si func
12
13int factorial(int i) {
14
15        int k, j;
16        if (i<2){
17                return 1;
18        }
19
20        k=1;
21
22        for(j=1;j<i;j++) {
23                k=k*(j+1);
24        }
25
26        return k;
27
28}
29
30
31
32// Used in pearl nec model
33
34// Sine integral function: approximated within 1%!!!
35
36// integral of sin(x)/x up to namx term nmax=6 looks the best.
37
38double Si(double x)
39
40{
41        int i;
42        int nmax=6;
43        double out;
44        long double power;
45        double pi = 4.0*atan(1.0);
46
47        if (x >= pi*6.2/4.0){
48                double out_sin = 0.0;
49                double out_cos = 0.0;
50                out = pi/2.0;
51
52                for (i=0; i<nmax-2; i+=1) {
53                        out_cos += pow(-1.0, i) * (double)factorial(2*i) / pow(x, 2*i+1);
54                        out_sin += pow(-1.0, i) * (double)factorial(2*i+1) / pow(x, 2*i+2);
55                }
56
57                out -= cos(x) * out_cos;
58                out -= sin(x) * out_sin;
59                return out;
60        }
61
62        out = 0.0;
63
64        for (i=0; i<nmax; i+=1) {
65                if (i==0) {
66                        out += x;
67                        continue;
68                }
69
70                power = pow(x,(2 * i + 1));
71                out += (double)pow(-1, i) * power / ((2.0 * (double)i + 1.0) * (double)factorial(2 * i + 1));
72
73                //printf ("Si=%g %g %d\n", x, out, i);
74        }
75
76        return out;
77}
78
79
80
81double sinc(double x)
82{
83  if (x==0.0){
84    return 1.0;
85  }
86  return sin(x)/x;
87}
88
89/*
90double gamln(double xx) {
91
92    double x,y,tmp,ser;
93    static double cof[6]={76.18009172947146,-86.50532032941677,
94    24.01409824083091,-1.231739572450155,
95    0.1208650973866179e-2,-0.5395239384953e-5};
96    int j;
97
98    y=x=xx;
99    tmp=x+5.5;
100    tmp -= (x+0.5)*log(tmp);
101    ser=1.000000000190015;
102    for (j=0;j<=5;j++) ser += cof[j]/++y;
103    return -tmp+log(2.5066282746310005*ser/x);
104}
105*/
106// calculate magnetic sld and return total sld
107// bn : contrast (not just sld of the layer)
108// m0: max mag of M; mtheta: angle from x-z plane;
109// mphi: angle (anti-clock-wise)of x-z projection(M) from x axis
110// spinfraci: the fraction of UP among UP+Down (before sample)
111// spinfracf: the fraction of UP among UP+Down (after sample and before detector)
112// spintheta: angle (anti-clock-wise) between neutron spin(up) and x axis
113// Note: all angles are in degrees.
114polar_sld cal_msld(int isangle, double qx, double qy, double bn,
115                                double m01, double mtheta1, double mphi1,
116                                double spinfraci, double spinfracf, double spintheta)
117{
118        //locals
119        double q_x = qx;
120        double q_y = qy;
121        double sld = bn;
122        int is_angle = isangle;
123        double pi = 4.0*atan(1.0);
124        double s_theta = spintheta * pi/180.0;
125        double m_max = m01;
126        double m_phi = mphi1;
127        double m_theta = mtheta1;
128        double in_spin = spinfraci;
129        double out_spin = spinfracf;
130
131        double m_perp = 0.0;
132        double m_perp_z = 0.0;
133        double m_perp_y = 0.0;
134        double m_perp_x = 0.0;
135        double m_sigma_x = 0.0;
136        double m_sigma_z = 0.0;
137        double m_sigma_y = 0.0;
138        //double b_m = 0.0;
139        double q_angle = 0.0;
140        double mx = 0.0;
141        double my = 0.0;
142        double mz = 0.0;
143        polar_sld p_sld;
144        p_sld.uu = sld;
145        p_sld.dd = sld;
146        p_sld.re_ud = 0.0;
147        p_sld.im_ud = 0.0;
148        p_sld.re_du = 0.0;
149        p_sld.im_du = 0.0;
150
151        //No mag means no further calculation
152        if (isangle>0){
153                if (m_max < 1.0e-32){
154                        p_sld.uu = sqrt(sqrt(in_spin * out_spin)) * p_sld.uu;
155                        p_sld.dd = sqrt(sqrt((1.0 - in_spin) * (1.0 - out_spin))) * p_sld.dd;
156                        return p_sld;
157                }
158        }
159        else{
160                if (fabs(m_max)< 1.0e-32 && fabs(m_phi)< 1.0e-32 && fabs(m_theta)< 1.0e-32){
161                        p_sld.uu = sqrt(sqrt(in_spin * out_spin)) * p_sld.uu;
162                        p_sld.dd = sqrt(sqrt((1.0 - in_spin) * (1.0 - out_spin))) * p_sld.dd;
163                        return p_sld;
164                }
165        }
166
167        //These are needed because of the precision of inputs
168        if (in_spin < 0.0) in_spin = 0.0;
169        if (in_spin > 1.0) in_spin = 1.0;
170        if (out_spin < 0.0) out_spin = 0.0;
171        if (out_spin > 1.0) out_spin = 1.0;
172
173        if (q_x == 0.0) q_angle = pi / 2.0;
174        else q_angle = atan(q_y/q_x);
175        if (q_y < 0.0 && q_x < 0.0) q_angle -= pi;
176        else if (q_y > 0.0 && q_x < 0.0) q_angle += pi;
177
178        q_angle = pi/2.0 - q_angle;
179        if (q_angle > pi) q_angle -= 2.0 * pi;
180        else if (q_angle < -pi) q_angle += 2.0 * pi;
181
182        if (fabs(q_x) < 1.0e-16 && fabs(q_y) < 1.0e-16){
183                m_perp = 0.0;
184                }
185        else {
186                m_perp = m_max;
187                }
188        if (is_angle > 0){
189                m_phi *= pi/180.0;
190                m_theta *= pi/180.0;
191                mx = m_perp * cos(m_theta) * cos(m_phi);
192                my = m_perp * sin(m_theta);
193                mz = -(m_perp * cos(m_theta) * sin(m_phi));
194        }
195        else{
196                mx = m_perp;
197                my = m_phi;
198                mz = m_theta;
199        }
200        //ToDo: simplify these steps
201        // m_perp1 -m_perp2
202        m_perp_x = (mx) *  cos(q_angle);
203        m_perp_x -= (my) * sin(q_angle);
204        m_perp_y = m_perp_x;
205        m_perp_x *= cos(-q_angle);
206        m_perp_y *= sin(-q_angle);
207        m_perp_z = mz;
208
209        m_sigma_x = (m_perp_x * cos(-s_theta) - m_perp_y * sin(-s_theta));
210        m_sigma_y = (m_perp_x * sin(-s_theta) + m_perp_y * cos(-s_theta));
211        m_sigma_z = (m_perp_z);
212
213        //Find b
214        p_sld.uu -= m_sigma_x;
215        p_sld.dd += m_sigma_x;
216        p_sld.re_ud = m_sigma_y;
217        p_sld.re_du = m_sigma_y;
218        p_sld.im_ud = m_sigma_z;
219        p_sld.im_du = -m_sigma_z;
220
221        p_sld.uu = sqrt(sqrt(in_spin * out_spin)) * p_sld.uu;
222        p_sld.dd = sqrt(sqrt((1.0 - in_spin) * (1.0 - out_spin))) * p_sld.dd;
223
224        p_sld.re_ud = sqrt(sqrt(in_spin * (1.0 - out_spin))) * p_sld.re_ud;
225        p_sld.im_ud = sqrt(sqrt(in_spin * (1.0 - out_spin))) * p_sld.im_ud;
226        p_sld.re_du = sqrt(sqrt((1.0 - in_spin) * out_spin)) * p_sld.re_du;
227        p_sld.im_du = sqrt(sqrt((1.0 - in_spin) * out_spin)) * p_sld.im_du;
228
229        return p_sld;
230}
231
232
233/** Modifications below by kieranrcampbell@gmail.com
234    Institut Laue-Langevin, July 2012
235**/
236
237/**
238Wojtek's comment Mar 22 2016: The remaing code can mostly likely be deleated
239Keeping it in order to check if it is not breaking anything
240**/
241
242
243#define ITMAX 100
244#define EPS 3.0e-7
245#define FPMIN 1.0e-30
246
247void gser(float *gamser, float a, float x, float *gln) {
248  int n;
249  float sum,del,ap;
250
251  *gln = lgamma(a);
252  if(x <= 0.0) {
253    if (x < 0.0) printf("Error: x less than 0 in routine gser");
254    *gamser = 0.0;
255    return;
256  } else {
257    ap = a;
258    del = sum = 1.0/a;
259
260    for(n=1;n<=ITMAX;n++) {
261      ++ap;
262      del *= x/ap;
263      sum += del;
264      if(fabs(del) < fabs(sum)*EPS) {
265        *gamser = sum * exp(-x + a * log(x) - (*gln));
266        return;
267      }
268    }
269    printf("a too large, ITMAX too small in routine gser");
270    return;
271
272  }
273
274
275}
276
277/**
278   Implements the incomplete gamma function Q(a,x) evaluated by its continued fraction
279   representation
280**/
281void gcf(float *gammcf, float a, float x, float *gln) {
282  int i;
283  float an,b,c,d,del,h;
284
285  *gln = lgamma(a);
286  b = x+1.0-a;
287  c = 1.0/FPMIN;
288  d = 1.0/b;
289  h=d;
290  for (i=1;i <= ITMAX; i++) {
291    an = -i*(i-a);
292    b += 2.0;
293    d = an*d + b;
294    if (fabs(d) < FPMIN) d = FPMIN;
295    c = b+an/c;
296    if (fabs(c) < FPMIN) c = FPMIN;
297    d = 1.0/d;
298    del = d*c;
299    h += del;
300    if (fabs(del-1.0) < EPS) break;
301  }
302  if (i > ITMAX) printf("a too large, ITMAX too small in gcf");
303  *gammcf = exp(-x+a*log(x)-(*gln))*h;
304  return;
305}
306
307/**
308   Represents incomplete error function, P(a,x)
309**/
310float gammp(float a, float x) {
311  float gamser,gammcf,gln;
312  if(x < 0.0 || a <= 0.0) printf("Invalid arguments in routine gammp");
313  if (x < (a+1.0)) {
314    gser(&gamser,a,x,&gln);
315    return gamser;
316  } else {
317    gcf(&gammcf,a,x,&gln);
318    return 1.0 - gammcf;
319  }
320}
321/**
322    Implementation of the error function, erf(x)
323**/
324float erff(float x) {
325  return x < 0.0 ? -gammp(0.5,x*x) : gammp(0.5,x*x);
326}
Note: See TracBrowser for help on using the repository browser.