source: sans/XOP_Dev/MonteCarlo/MonteCarlo.c @ 435

Last change on this file since 435 was 435, checked in by srkline, 14 years ago

Added first pass at MonteCarlo? simulation XOP. Needs a lot of tidying, and later some work threading.

File size: 19.5 KB
Line 
1/*
2 *  MonteCarlo.c
3 *  SANSAnalysis
4 *
5 *  Created by Steve Kline on 10/16/08.
6 *  Copyright 2008 __MyCompanyName__. All rights reserved.
7 *
8 */
9
10
11#include "XOPStandardHeaders.h"                 // Include ANSI headers, Mac headers, IgorXOP.h, XOP.h and XOPSupport.h
12#include "MonteCarlo.h"
13
14static int gCallSpinProcess = 1;                // Set to 1 to all user abort (cmd dot) and background processing.
15
16//////////
17//    PROGRAM Monte_SANS
18//    PROGRAM simulates multiple SANS.
19//       revised 2/12/99  JGB
20//            added calculation of random deviate, and 2D 10/2008 SRK
21
22//    N1 = NUMBER OF INCIDENT NEUTRONS.
23//    N2 = NUMBER INTERACTED IN THE SAMPLE.
24//    N3 = NUMBER ABSORBED.
25//    THETA = SCATTERING ANGLE.
26
27// works fine in the single-threaded case.
28//
29/// currently crashes if threaded. apparently something here is either doing an unknown callback, or is accessing
30// a bad place in memory.
31//
32// the operations SpinProcess() and WaveHandleModified() are callbacks and MUST be commented out before threading.
33// - some locks are non-existent
34// - supposedly safe wave access routines are used
35//
36//
37
38
39int
40Monte_SANSX(MC_ParamsPtr p) {
41        double *inputWave;                              /* pointer to double precision wave data */
42        double *ran_dev;                                /* pointer to double precision wave data */
43        double *nt;                             /* pointer to double precision wave data */
44        double *j1;                             /* pointer to double precision wave data */
45        double *j2;                             /* pointer to double precision wave data */
46        double *nn;                             /* pointer to double precision wave data */
47//      double *MC_linear_data;                         /* pointer to double precision wave data */
48        double *results;                                /* pointer to double precision wave data */
49        double result;                          //return value
50
51        long imon;
52        double r1,r2,xCtr,yCtr,sdd,pixSize,thick,wavelength,sig_incoh,sig_sas;
53        long ind,index,n_index;
54        double qmax,theta_max,q0,zpow;
55        long n1,n2,n3;
56        double dth,zz,xx,yy,phi;
57        double theta,ran,ll,rr,ttot;
58        long done,find_theta,err;               //used as logicals
59        long xPixel,yPixel;
60        double vx,vy,vz,theta_z;
61        double sig_abs,ratio,sig_total;
62        double testQ,testPhi,left,delta,dummy,pi;
63        double sigabs_0,num_bins;
64        long NSingleIncoherent,NSingleCoherent,NScatterEvents,incoherentEvent,coherentEvent;
65        long NDoubleCoherent,NMultipleScatter,isOn;
66
67        // for accessing the 2D wave data, direct method (see the WaveAccess example XOP)
68        waveHndl wavH;
69        int waveType,hState;
70        long numDimensions;
71        long dimensionSizes[MAX_DIMENSIONS+1];
72        char* dataStartPtr;
73        long dataOffset;
74        long numRows, numColumns,numRows_ran_dev;
75        double *dp0, *dp, value[2];                             // Pointers used for double data.
76        long seed;
77        long indices[MAX_DIMENSIONS];
78       
79        char buf[256];
80               
81        /* check that wave handles are all valid */
82        if (p->inputWaveH == NIL) {
83                SetNaN64(&p->result);                                   /* return NaN if wave is not valid */
84                return(NON_EXISTENT_WAVE);
85        }
86        if (p->ran_devH == NIL) {
87                SetNaN64(&p->result);                                   /* return NaN if wave is not valid */
88                return(NON_EXISTENT_WAVE);
89        }       
90        if (p->ntH == NIL) {
91                SetNaN64(&p->result);                                   /* return NaN if wave is not valid */
92                return(NON_EXISTENT_WAVE);
93        }
94        if (p->j1H == NIL) {
95                SetNaN64(&p->result);                                   /* return NaN if wave is not valid */
96                return(NON_EXISTENT_WAVE);
97        }
98        if (p->j2H == NIL) {
99                SetNaN64(&p->result);                                   /* return NaN if wave is not valid */
100                return(NON_EXISTENT_WAVE);
101        }
102        if (p->nnH == NIL) {
103                SetNaN64(&p->result);                                   /* return NaN if wave is not valid */
104                return(NON_EXISTENT_WAVE);
105        }
106        if (p->MC_linear_dataH == NIL) {
107                SetNaN64(&p->result);                                   /* return NaN if wave is not valid */
108                return(NON_EXISTENT_WAVE);
109        }
110        if (p->resultsH == NIL) {
111                SetNaN64(&p->result);                                   /* return NaN if wave is not valid */
112                return(NON_EXISTENT_WAVE);
113        }
114       
115        p->result = 0;
116       
117// trusting that all inputs are DOUBLE PRECISION WAVES!!!
118        inputWave = WaveData(p->inputWaveH);
119        ran_dev = WaveData(p->ran_devH);
120        nt = WaveData(p->ntH);
121        j1 = WaveData(p->j1H);
122        j2 = WaveData(p->j2H);
123        nn = WaveData(p->nnH);
124//      MC_linear_data = WaveData(p->MC_linear_dataH);
125        results = WaveData(p->resultsH);
126       
127        seed = (long)results[0];
128       
129//      sprintf(buf, "input seed = %ld\r", seed);
130//      XOPNotice(buf);
131       
132        if(seed >= 0) {
133                seed = -1234509876;
134        }
135
136        dummy = ran3(&seed);            //initialize the random sequence by passing in a negative value
137        seed = 12348765;                //non-negative after that does nothing
138
139        imon = (int)inputWave[0];
140        r1 = inputWave[1];
141        r2 = inputWave[2];
142        xCtr = inputWave[3];
143        yCtr = inputWave[4];
144        sdd = inputWave[5];
145        pixSize = inputWave[6];
146        thick = inputWave[7];
147        wavelength = inputWave[8];
148        sig_incoh = inputWave[9];
149        sig_sas = inputWave[10];
150               
151        dummy = MDGetWaveScaling(p->ran_devH, 0, &delta, &left);                //0 is the rows
152        if (result = MDGetWaveDimensions(p->ran_devH, &numDimensions, dimensionSizes))
153                return result;
154        numRows_ran_dev = dimensionSizes[0];
155       
156        pi = 4.0*atan(1.0);     
157       
158        // access the 2D wave data for writing using the direct method
159        wavH = p->MC_linear_dataH;
160        if (wavH == NIL)
161                return NOWAV;
162
163//      waveType = WaveType(wavH);
164//      if (waveType & NT_CMPLX)
165//              return NO_COMPLEX_WAVE;
166//      if (waveType==TEXT_WAVE_TYPE)
167//              return NUMERIC_ACCESS_ON_TEXT_WAVE;
168//      if (result = MDGetWaveDimensions(wavH, &numDimensions, dimensionSizes))
169//              return result;
170//      numRows = dimensionSizes[0];
171//      numColumns = dimensionSizes[1];
172       
173//      if (result = MDAccessNumericWaveData(wavH, kMDWaveAccessMode0, &dataOffset))
174//              return result;
175               
176//      hState = MoveLockHandle(wavH);          // So wave data can't move. Remember to call HSetState when done.
177//      dataStartPtr = (char*)(*wavH) + dataOffset;
178//      dp0 = (double*)dataStartPtr;                    // Pointer to the start of the 2D wave data.
179       
180//scattering power and maximum qvalue to bin
181//      zpow = .1               //scattering power, calculated below
182        qmax = 4.0*pi/wavelength;       //maximum Q to bin 1D data. (A-1) (not really used)
183        sigabs_0 = 0.0;         // ignore absorption cross section/wavelength [1/(cm A)]
184        n_index = 50;   // maximum number of scattering events per neutron
185        num_bins = 200;         //number of 1-D bins (not really used)
186       
187//c       total SAS cross-section
188//
189        zpow = sig_sas*thick;                   //since I now calculate the sig_sas from the model
190        sig_abs = sigabs_0 * wavelength;
191        sig_total = sig_abs + sig_sas + sig_incoh;
192//      Print "The TOTAL XSECTION. (CM-1) is ",sig_total
193//      Print "The TOTAL SAS XSECTION. (CM-1) is ",sig_sas
194//      results[0] = sig_total;
195//      results[1] = sig_sas;
196//      RATIO = SIG_ABS / SIG_TOTAL
197        ratio = sig_incoh / sig_total;
198       
199        theta_max = wavelength*qmax/(2*pi);
200//C     SET Theta-STEP SIZE.
201        dth = theta_max/num_bins;
202//      Print "theta bin size = dth = ",dth
203
204//C     INITIALIZE COUNTERS.
205        n1 = 0;
206        n2 = 0;
207        n3 = 0;
208        NSingleIncoherent = 0;
209        NSingleCoherent = 0;
210        NDoubleCoherent = 0;
211        NMultipleScatter = 0;
212        NScatterEvents = 0;
213        isOn = 0;
214       
215//C     MONITOR LOOP - looping over the number of incedent neutrons
216//note that zz, is the z-position in the sample - NOT the scattering power
217// NOW, start the loop, throwing neutrons at the sample.
218        do {
219                ////SpinProcess() IS A CALLBACK, and not good for Threading!
220                if ((n1 % 1000 == 0) && gCallSpinProcess && SpinProcess()) {            // Spins cursor and allows background processing.
221                                result = -1;                                                            // User aborted.
222                                break;
223                }
224       
225                vx = 0.0;                       // Initialize direction vector.
226                vy = 0.0;
227                vz = 1.0;
228               
229                theta = 0.0;            //      Initialize scattering angle.
230                phi = 0.0;                      //      Intialize azimuthal angle.
231                n1 += 1;                        //      Increment total number neutrons counter.
232                done = 0;                       //      True when neutron is absorbed or when  scattered out of the sample.
233                index = 0;                      //      Set counter for number of scattering events.
234                zz = 0.0;                       //      Set entering dimension of sample.
235                incoherentEvent = 0;
236                coherentEvent = 0;
237               
238                do      {                               //      Makes sure position is within circle.
239                        ran = ran3(&seed);              //[0,1]
240                        xx = 2.0*r1*(ran-0.5);          //X beam position of neutron entering sample.
241                        ran = ran3(&seed);              //[0,1]
242                        yy = 2.0*r1*(ran-0.5);          //Y beam position ...
243                        rr = sqrt(xx*xx+yy*yy);         //Radial position of neutron in incident beam.
244                } while(rr>r1);
245
246                do {   //Scattering Loop, will exit when "done" == 1
247                                // keep scattering multiple times until the neutron exits the sample
248                        ran = ran3(&seed);              //[0,1]  RANDOM NUMBER FOR DETERMINING PATH LENGTH
249                        ll = path_len(ran,sig_total);
250                        //Determine new scattering direction vector.
251                        err = NewDirection(&vx,&vy,&vz,theta,phi);              //vx,vy,vz updated, theta, phi unchanged by function
252                                                                       
253                        //X,Y,Z-POSITION OF SCATTERING EVENT.
254                        xx += ll*vx;
255                        yy += ll*vy;
256                        zz += ll*vz;
257                        rr = sqrt(xx*xx+yy*yy);         //radial position of scattering event.
258
259                        //sprintf(buf, "xx,yy,zz,vx,vy,vz,ll = %g %g %g %g %g %g %g\r",xx,yy,zz,vx,vy,vz,ll);
260                        //XOPNotice(buf);
261                                               
262                        //Check whether interaction occurred within sample volume.
263                        if (((zz > 0.0) && (zz < thick)) && (rr < r2)) {
264                                //NEUTRON INTERACTED.
265                                //sprintf(buf,"neutron interacted\r");
266                                //XOPNotice(buf);
267                               
268                                index += 1;                     //Increment counter of scattering events.
269                                if (index == 1) {
270                                        n2 += 1;                //Increment # of scat. neutrons
271                                }
272                                ran = ran3(&seed);              //[0,1]
273                                //Split neutron interactions into scattering and absorption events
274                                if (ran > ratio ) {             //C             NEUTRON SCATTERED coherently
275                                        //sprintf(buf,"neutron scatters coherently\r");
276                                        //XOPNotice(buf);
277                                        coherentEvent = 1;
278                                        find_theta = 0;                 //false
279                                        do {
280                                                // pick a q-value from the deviate function
281                                                // pnt2x truncates the point to an integer before returning the x
282                                                // so get it from the wave scaling instead
283//                                              q0 =left + binarysearchinterp(ran_dev,ran1(seed))*delta;
284                                               
285                                                q0 =left + locate_interp(ran_dev,numRows_ran_dev,ran3(&seed))*delta;
286                                                theta = q0/2/pi*wavelength;             //SAS approximation
287                                               
288                                                find_theta = 1;         //always accept
289
290                                                //sprintf(buf, "after locate_interp call q0 = %g, theta = %g,left = %g,delta = %g\r",q0,theta,left,delta);
291                                                //XOPNotice(buf);
292
293                                        } while(!find_theta);
294                                       
295                                        ran = ran3(&seed);              //[0,1]
296                                        phi = 2.0*pi*ran;                       //Chooses azimuthal scattering angle.
297                                } else {
298                                        //NEUTRON scattered incoherently
299                                        //sprintf(buf,"neutron scatters incoherent\r");
300                                        //XOPNotice(buf);
301                                        incoherentEvent = 1;
302                                  // phi and theta are random over the entire sphere of scattering
303                                        // !can't just choose random theta and phi, won't be random over sphere solid angle
304
305                                        ran = ran3(&seed);              //[0,1]
306                                        theta = acos(2.0*ran-1);
307                       
308                                        ran = ran3(&seed);              //[0,1]
309                                        phi = 2.0*pi*ran;                       //Chooses azimuthal scattering angle.
310                                }               //(ran > ratio)
311                        } else {
312                                //NEUTRON ESCAPES FROM SAMPLE -- bin it somewhere                                                               
313                                done = 1;               //done = true, will exit from loop
314                                //Increment #scattering events array
315                                MemClear(indices, sizeof(indices)); // Must be 0 for unused dimensions.
316                                indices[0] =index;                      //this sets access to nn[index]
317                                if (index <= n_index) {
318                                        if (result = MDGetNumericWavePointValue(p->nnH, indices, value))
319                                                return result;
320                                        value[0] += 1; // add one to the value
321                                        if (result = MDSetNumericWavePointValue(p->nnH, indices, value))
322                                                return result;
323                                //      nn[index] += 1;
324                                }
325                                                                                               
326                                //IF (VZ > 1.0)         // FIX INVALID ARGUMENT
327                                        //VZ = 1.0 - 1.2e-7
328                                //ENDIF
329                                theta_z = acos(vz);             // Angle (= 2theta) WITH respect to z axis.
330                                testQ = 2*pi*sin(theta_z)/wavelength;
331                               
332                                // pick a random phi angle, and see if it lands on the detector
333                                // since the scattering is isotropic, I can safely pick a new, random value
334                                // this would not be true if simulating anisotropic scattering.
335                                testPhi = ran3(&seed)*2*pi;
336                               
337                                // is it on the detector?       
338                                FindPixel(testQ,testPhi,wavelength,sdd,pixSize,xCtr,yCtr,&xPixel,&yPixel);
339                                                                                               
340                                if(xPixel != -1 && yPixel != -1) {
341                                        isOn += 1;
342                                        MemClear(indices, sizeof(indices)); // Must be 0 for unused dimensions.
343                                        indices[0] = xPixel;
344                                        indices[1] = yPixel;
345                                        if (result = MDGetNumericWavePointValue(wavH, indices, value))
346                                                return result;
347                                        value[0] += 1; // Real part
348                                        if (result = MDSetNumericWavePointValue(wavH, indices, value))
349                                                return result;
350                                        //if(index==1)  // only the single scattering events
351                                                //dp = dp0 + xPixel + yPixel*numColumns;                //offset the pointer to the exact memory location
352                                                //*dp += 1;             //increment the value there
353                                        //endif
354                                }
355                               
356
357/*              is this causing me a problem since I'm not locking these? Probably not, since it crashes even if I comment these out... */
358                                if(theta_z < theta_max) {
359                                        //Choose index for scattering angle array.
360                                        //IND = NINT(THETA_z/DTH + 0.4999999)
361                                        ind = round(theta_z/dth + 0.4999999);           //round is eqivalent to nint()
362                                        nt[ind] += 1;                   //Increment bin for angle.
363                                        //Increment angle array for single scattering events.
364                                        if (index == 1) {
365                                                j1[ind] += 1;
366                                        }
367                                        //Increment angle array for double scattering events.
368                                        if (index == 2) {
369                                                j2[ind] += 1;
370                                        }
371                                }
372/**/
373                               
374                                // increment all of the counters now since done==1 here and I'm sure to exit and get another neutron
375                                NScatterEvents += index;                //total number of scattering events
376                                if(index == 1 && incoherentEvent == 1) {
377                                        NSingleIncoherent += 1;
378                                }
379                                if(index == 1 && coherentEvent == 1) {
380                                        NSingleCoherent += 1;
381                                }
382                                if(index == 2 && coherentEvent == 1 && incoherentEvent == 0) {
383                                        NDoubleCoherent += 1;
384                                }
385                                if(index > 1) {
386                                        NMultipleScatter += 1;
387                                }
388                        }
389                 } while (!done);
390        } while(n1 < imon);
391       
392// assign the results to the wave
393
394        MemClear(indices, sizeof(indices)); // Must be 0 for unused dimensions.
395        value[0] = (double)n1;
396        indices[0] = 0;
397        if (result = MDSetNumericWavePointValue(p->resultsH, indices, value))
398                return result;
399        value[0] = (double)n2;
400        indices[0] = 1;
401        if (result = MDSetNumericWavePointValue(p->resultsH, indices, value))
402                return result;
403        value[0] = (double)isOn;
404        indices[0] = 2;
405        if (result = MDSetNumericWavePointValue(p->resultsH, indices, value))
406                return result;
407        value[0] = (double)NScatterEvents;
408        indices[0] = 3;
409        if (result = MDSetNumericWavePointValue(p->resultsH, indices, value))
410                return result;
411        value[0] = (double)NSingleCoherent;
412        indices[0] = 4;
413        if (result = MDSetNumericWavePointValue(p->resultsH, indices, value))
414                return result;
415        value[0] = (double)NDoubleCoherent;
416        indices[0] = 5;
417        if (result = MDSetNumericWavePointValue(p->resultsH, indices, value))
418                return result;
419        value[0] = (double)NMultipleScatter;
420        indices[0] = 6;
421        if (result = MDSetNumericWavePointValue(p->resultsH, indices, value))
422                return result; 
423
424
425//      HSetState((Handle)wavH, hState);                //release the handle of the 2D data wave
426        WaveHandleModified(wavH);                       // Inform Igor that we have changed the wave. (CALLBACK! needed, but not allowed in Threading)
427       
428        return(0);
429}
430////////        end of main function for calculating multiple scattering
431
432int
433FindPixel(double testQ, double testPhi, double lam, double sdd,
434                double pixSize, double xCtr, double yCtr, long *xPixel, long *yPixel) {
435
436        double theta,dy,dx,qx,qy,pi;
437        pi = 4.0*atan(1.0);     
438        //decompose to qx,qy
439        qx = testQ*cos(testPhi);
440        qy = testQ*sin(testPhi);
441
442        //convert qx,qy to pixel locations relative to # of pixels x, y from center
443        theta = 2*asin(qy*lam/4/pi);
444        dy = sdd*tan(theta);
445        *yPixel = round(yCtr + dy/pixSize);
446       
447        theta = 2*asin(qx*lam/4/pi);
448        dx = sdd*tan(theta);
449        *xPixel = round(xCtr + dx/pixSize);
450
451        //if on detector, return xPix and yPix values, otherwise -1
452        if(*yPixel > 127 || *yPixel < 0) {
453                *yPixel = -1;
454        }
455        if(*xPixel > 127 || *xPixel < 0) {
456                *xPixel = -1;
457        }
458       
459        return(0);
460}
461
462
463//calculates new direction (xyz) from an old direction
464//theta and phi don't change
465int
466NewDirection(double *vx, double *vy, double *vz, double theta, double phi) {
467       
468        int err=0;
469        double vx0,vy0,vz0;
470        double nx,ny,mag_xy,tx,ty,tz;
471       
472        //store old direction vector
473        vx0 = *vx;
474        vy0 = *vy;
475        vz0 = *vz;
476       
477        mag_xy = sqrt(vx0*vx0 + vy0*vy0);
478        if(mag_xy < 1e-12) {
479                //old vector lies along beam direction
480                nx = 0;
481                ny = 1;
482                tx = 1;
483                ty = 0;
484                tz = 0;
485        } else {
486                nx = -vy0 / mag_xy;
487                ny = vx0 / mag_xy;
488                tx = -vz0*vx0 / mag_xy;
489                ty = -vz0*vy0 / mag_xy;
490                tz = mag_xy ;
491        }
492       
493        //new scattered direction vector
494        *vx = cos(phi)*sin(theta)*tx + sin(phi)*sin(theta)*nx + cos(theta)*vx0;
495        *vy = cos(phi)*sin(theta)*ty + sin(phi)*sin(theta)*ny + cos(theta)*vy0;
496        *vz = cos(phi)*sin(theta)*tz + cos(theta)*vz0;
497       
498        return(err);
499}
500
501double
502path_len(double aval, double sig_tot) {
503       
504        double retval;
505       
506        retval = -1*log(1-aval)/sig_tot;
507       
508        return(retval);
509}
510
511#define IA 16807
512#define IM 2147483647
513#define AM (1.0/IM)
514#define IQ 127773
515#define IR 2836
516#define NTAB 32
517#define NDIV (1+(IM-1)/NTAB)
518#define EPS 1.2e-7
519#define RNMX (1.0-EPS)
520
521float ran1(long *idum)
522{
523        int j;
524        long k;
525        static long iy=0;
526        static long iv[NTAB];
527        float temp;
528
529        if (*idum <= 0 || !iy) {
530                if (-(*idum) < 1) *idum=1;
531                else *idum = -(*idum);
532                for (j=NTAB+7;j>=0;j--) {
533                        k=(*idum)/IQ;
534                        *idum=IA*(*idum-k*IQ)-IR*k;
535                        if (*idum < 0) *idum += IM;
536                        if (j < NTAB) iv[j] = *idum;
537                }
538                iy=iv[0];
539        }
540        k=(*idum)/IQ;
541        *idum=IA*(*idum-k*IQ)-IR*k;
542        if (*idum < 0) *idum += IM;
543        j=iy/NDIV;
544        iy=iv[j];
545        iv[j] = *idum;
546        if ((temp=AM*iy) > RNMX) return RNMX;
547        else return temp;
548}
549#undef IA
550#undef IM
551#undef AM
552#undef IQ
553#undef IR
554#undef NTAB
555#undef NDIV
556#undef EPS
557#undef RNMX
558
559////////////////////////
560#define MBIG 1000000000
561#define MSEED 161803398
562#define MZ 0
563#define FAC (1.0/MBIG)
564
565float ran3(long *idum)
566{
567        static int inext,inextp;
568        static long ma[56];
569        static int iff=0;
570        long mj,mk;
571        int i,ii,k;
572
573        if (*idum < 0 || iff == 0) {
574                iff=1;
575                mj=MSEED-(*idum < 0 ? -*idum : *idum);
576                mj %= MBIG;
577                ma[55]=mj;
578                mk=1;
579                for (i=1;i<=54;i++) {
580                        ii=(21*i) % 55;
581                        ma[ii]=mk;
582                        mk=mj-mk;
583                        if (mk < MZ) mk += MBIG;
584                        mj=ma[ii];
585                }
586                for (k=1;k<=4;k++)
587                        for (i=1;i<=55;i++) {
588                                ma[i] -= ma[1+(i+30) % 55];
589                                if (ma[i] < MZ) ma[i] += MBIG;
590                        }
591                inext=0;
592                inextp=31;
593                *idum=1;
594        }
595        if (++inext == 56) inext=1;
596        if (++inextp == 56) inextp=1;
597        mj=ma[inext]-ma[inextp];
598        if (mj < MZ) mj += MBIG;
599        ma[inext]=mj;
600        return mj*FAC;
601}
602#undef MBIG
603#undef MSEED
604#undef MZ
605#undef FAC
606
607
608// returns the interpolated point value in xx[0,n-1] that has the value x
609double locate_interp(double xx[], long n, double x)
610{
611        unsigned long ju,jm,jl,j;
612        int ascnd;
613        double pt;
614
615//      char buf[256];
616       
617        jl=0;
618        ju=n-1;
619        ascnd=(xx[n-1] > xx[0]);
620        while (ju-jl > 1) {
621                jm=(ju+jl) >> 1;
622                if (x > xx[jm] == ascnd)
623                        jl=jm;
624                else
625                        ju=jm;
626        }
627        j=jl;           // the point I want is between xx[j] and xx[j+1]
628        pt = (x- xx[j])/(xx[j+1] - xx[j]);              //fractional distance, using linear interpolation
629       
630//      sprintf(buf, "x = %g, j= %ld, pt = %g\r",x,j,pt);
631//      XOPNotice(buf);
632       
633        return(pt+(double)j);
634}
635
636
637
638
639/////////////////////////////
640/*      RegisterFunction()
641       
642        Igor calls this at startup time to find the address of the
643        XFUNCs added by this XOP. See XOP manual regarding "Direct XFUNCs".
644*/
645static long
646RegisterFunction()
647{
648        int funcIndex;
649
650        funcIndex = GetXOPItem(0);              // Which function is Igor asking about?
651        switch (funcIndex) {
652                case 0:                                         //
653                        return((long)Monte_SANSX);
654                        break;
655        }
656        return(NIL);
657}
658
659/*      XOPEntry()
660
661        This is the entry point from the host application to the XOP for all messages after the
662        INIT message.
663*/
664static void
665XOPEntry(void)
666{       
667        long result = 0;
668
669        switch (GetXOPMessage()) {
670                case FUNCADDRS:
671                        result = RegisterFunction();
672                        break;
673        }
674        SetXOPResult(result);
675}
676
677/*      main(ioRecHandle)
678
679        This is the initial entry point at which the host application calls XOP.
680        The message sent by the host must be INIT.
681        main() does any necessary initialization and then sets the XOPEntry field of the
682        ioRecHandle to the address to be called for future messages.
683*/
684HOST_IMPORT void
685main(IORecHandle ioRecHandle)
686{       
687        XOPInit(ioRecHandle);                                                   // Do standard XOP initialization.
688        SetXOPEntry(XOPEntry);                                                  // Set entry point for future calls.
689       
690        if (igorVersion < 600)                          // Requires Igor Pro 6.00 or later.
691                SetXOPResult(OLD_IGOR);                 // OLD_IGOR is defined in WaveAccess.h and there are corresponding error strings in WaveAccess.r and WaveAccessWinCustom.rc.
692        else
693                SetXOPResult(0L);
694}
Note: See TracBrowser for help on using the repository browser.