Novel Algorithms for Surface Plasmon Resonance Data Processing in a Parallel Multitask Environment

by Lauren Cohen

Montgomery Blair High School

ABSTRACT

Surface plasmon resonance (SPR) allows for the real-time study of the structure and function of biological molecules at surfaces. Novel computational methods were developed to improve the speed and accuracy of an SPR multi-channel imaging technique. Two algorithms for finding minima of SPR reflectivity curves and the corresponding change in thickness of an observed biolayer – a fitting of the curve to a polynomial and a mathematical function of a differential ratio between two integrals of the curve – were programmed, used to analyze sets of simulated data, and compared with theoretical results. The polynomial algorithm was found to be more accurate for changes of less than 100 Å, while the integral algorithm was more accurate for larger shifts. The integral method was also up to 250 times more precise and displayed an almost eightfold increase in speed over the polynomial method. Differences between the theoretical kinetic curve and that produced by the polynomial method were attributed to the design of the simulation. Both are to be further tested under actual experimental conditions.

Table of Contents

Introduction....................................................................................................................................... 4

Methods............................................................................................................................................ 7

Results                                                                                                                                               ............................................................................................................................................. 9

Conclusions..................................................................................................................................... 11

Acknowledgements......................................................................................................................... 12

References...................................................................................................................................... 13

Appendices..................................................................................................................................... 14

            A. Polynomial Curve Fitting Method.................................................................................... 14

            B. Integral Method.............................................................................................................. 19

            C. Simulation Input File........................................................................................................ 21

List of Tables

Table 1         Mean squared error in calculated minimum positions................................................. 10

Table 2         Chi-squared test of calculated minimum positions...................................................... 10

List of Figures

Figure 1       SPR measurements using a glass prism in the Kretschmann configuration..................... 4

Figure 2       Schematic of the SPR device..................................................................................... 4

Figure 3       SP reflection coefficient R as a function of incident angle j.......................................... 5

Figure 4       Theoretical graph of the shift in minimum position over time......................................... 5

Figure 5       Integrals B and A to determine shift............................................................................ 7

Figure 6       Illustration of curve mixing in an SPR simulation.......................................................... 8

Figure 7...... Shifts in minimum positions over time.......................................................................... 9

Introduction

            Surface plasmon resonance (SPR) is a novel method in biochemical research that allows for the real-time study of the structure and function of biological molecules at the interface between surfaces with different electrical properties. Measurements taken of this phenomenon can enable biologists to directly observe the kinetics of interactions between biomolecules, encompassing a wide variety of applications. These include use in drug discovery, gene expression studies, and evaluation of surfaces for biocompatibility [1].

Text Box: FIGURE 1. SPR measurements using a glass prism in the Kretschmann configuration: (a) focused incident light, (b) CCD detector, (c) biolayer, (d) flow cell [1].Text Box: FIGURE 2. Schematic of the SPR device. An attached computer controls the pump, valves, temperature controller, and collection of data from the CCD detector [1].            Surface plasmons, or SPs, are electromagnetic waves propagated at the interface between a metal and a non-metallic medium that have distinct dielectric permeabilities of opposite sign. In biotechnological applications, they are often excited using the Kretschmann configuration (Figs. 1, 2); light from a laser or LED is directed at an angle of incidence j through a glass prism onto a glass substrate containing a biomolecular layer on top of thin gold and chromium layers [1]. The light is then reflected from the biolayer, and its intensity at various angles is recorded by an array of charge-coupled devices [2]. Over time, as various chemicals are pumped through a flow cell in the substrate, reactions take place that change the thickness and the refractive index of the biolayer.

Text Box: FIGURE 3. SP reflection coefficient R as a function of incident angle j [1].            SP reflectivity at a given time is a function of the incident angle j (Fig. 3); the values of these intensities for a range of angles form a polynomial curve with a sharp minimum at a specific angle q. The shift of the SPR minimum position during a reaction is caused by alteration of the refractive index of the biolayer as its thickness changes. It can be theoretically expressed by the function

                                                                                                               (1)

Text Box: FIGURE 4. Theoretical graph of the shift in minimum position over time.where qo and qf are the initial and final minimum positions and K is the rate at which saturation, or the complete reaction of the biolayer, is achieved (Fig. 4). Further, the change in thickness is linearly proportional to the shift in the minimum position for thin (less than 40 nm) films. The rate of reactions taking place in the biolayer can thus be characterized by calculating the change in SPR minima as a function of time.

            This research developed and investigated the use of two computational methods for calculating the shift in minimum position in parallel with collection of SP reflectivity curves in real time. The first, a modification of a traditional method, fits each curve to a polynomial function and calculates its minimum from the function’s derivative. The second directly calculates the shift from the values of points in each curve. These algorithms were tested with a real-time simulation to determine their accuracy, precision, and efficiency.

            Curve fitting is accomplished by a weighted version of the least squares method [3]. The reflection coefficient Ri of the incident angle ji at a given time can be approximated by a polynomial function such that

                                              .                                         (2)

The least squares method finds values for coefficients a1 through aN that fit M data points in an SP reflectivity curve to an Nth degree polynomial so as to minimize the mean squared error, calculated from

                                                               .                                                           (3)

The coefficients are calculated by constructing an NxN matrix a and a vector b of length N such that

                                                                                                                               (4)

where

                                                                                                                               (5)

and

                                                                  .                                                              (6)

The normal equations they describe are solved by Gauss elimination with backward substitution [4]. Weighting of data points known to have less error, such as those nearer to the minimum of the reflectivity curve, is done by dividing each item in the summations of akj and bk by the variance in ji. C++ functions to perform this curve fitting are in Appendix A.

            The second method uses numerical integration to directly determine the shift in minimum position at each time. The area under an SP reflectivity curve can be divided into two portions, B and A (Fig. 5). After calibrating to choose a division point such that B and A are equal, the shift in the minimum position from its initial value can be given by

                                                                                                                            (7)

where qR is the convergence of incident light, that is, the range of angles at which light hits the biolayer, and s is an empirical constant property of that surface [5]. Subroutines for this method are in Appendix B.

Text Box: FIGURE 5. Integrals B and A to determine shift. The intensities of B and A are initially balanced (area under solid line). A shift in minimum position (dotted line) results in an imbalance that can be used to calculate it [5].            Developing such algorithms for faster and more accurate data collection and processing can be of great benefit to the SPR technique, especially in the parallel, multitask environment of multi-channel imaging systems. Such devices are currently being constructed for use in high-throughput drug screening, biomarker discovery, assay development and validation, and protein characterization, function, and interaction studies.

Methods

            A simulation of SPR data collection and processing in the LabWindows/CVI programming environment was employed for the evaluation of the two algorithms. This application received input of the initial and final thicknesses and refractive indices of the biolayer being modeled, calculated initial and final SP reflectivity curves from these numbers by inserting them into complex matrices, and used them in the generation of curves over the course of a reaction taking place in real time. As each curve was generated, the algorithm being tested was used to determine the shift in minimum position from the initial state at that time [6].

            The simulation first ran a one-minute calibration period in which no reaction took place by generating initial curves with added noise at each time; the minima of these provided a baseline from which to calculate the shift that would take place. As the experiment progressed over time and chemicals were washed over and reacted with the biolayer, changes in the curve were modeled by mixing the two inputted endpoints; the reflectivity at time t at an angle j was

                                                                                    (8)

where K was a user-inputted constant dictating the rate at which the reaction and the subsequent shift in the reflectivity curve occurred (Fig. 6). As each curve was generated, its minimum was determined and stored in a data file for later analysis.

Text Box: FIGURE 6. Illustration of curve mixing in an SPR simulation. Initial and final curves (solid lines) are combined to generate intermediary curves (dotted lines).            For the two methods of data processing under consideration, this simulation was run five times, once each with changes in final thickness of the biolayer of 25, 50, 100, 150, and 200 Å. K for each trial was given as 5, so that full saturation, signified by a complete shift, could be achieved in one minute; s for the integral algorithm was given as 2.11. Refractive indices and other constants used to generate Ro and Rf can be found in Appendix C.

            Results from each simulation were statistically analyzed for accuracy, precision, and efficiency. The mean squared error between the actual and calculated minima served as a measure of accuracy. Precision was derived from taking the chi-squared error in calculated minima from a smoothed curve fit to them. Efficiency was a function of the number of curves generated and analyzed during the one-minute simulation of a reaction.

Results

            Comparison of simulation results for the polynomial fit and integral algorithms showed significant differences in their behavior over the one-minute testing period. Both methods

b

 

a

 
                  

d

 

c

 
                   

e

 

Figure 7. Shifts in minimum positions over time: (a) for a change in final thickness of 25 Å, (b) for a change of 50 Å, (c) for a change of 100 Å, (d) for a change of 150 Å, (e) for a change of 200 Å.

 
           

produced graphs of the shift in minimum position that matched the exponential shape of a theoretical graph for small shifts of 25 and 50 Å (Figs. 7a, 7b). As the size of the shift increased, the shape of the graph of minimum positions calculated with integrals was unaffected. However, the shape of those calculated with the polynomial fit departed from that of the theoretical graph, with the size of the shift increasing less rapidly at the beginning of and near saturation in each trial and more rapidly at mid-saturation (Figs. 7c, 7d, 7e).

Table 1. Mean squared error in calculated minimum positions.

Algorithm

Change in Thickness

25 Å

50 Å

100 Å

150 Å

200 Å

Polynomial

0.000175

0.000777

0.009444

0.117891

0.270464

Integral

0.007092

0.009589

0.001824

0.029313

0.008228

            Table 1 shows that the accuracy of the two methods also varied depending on the change in thickness being measured. For the smaller shifts of 25 and 50 Å, the polynomial fit was found to more closely approximate the theoretical values, producing mean squared errors of a full order of magnitude less than those of the integral method. Greater shifts, however, resulted in the mean squared error in minimums found using integrals being less than that of minimums found from polynomial fits. For the largest shift tested, that of 200 Å, the error in the polynomial algorithm was of two orders of magnitude greater than that in the integral algorithm.

Table 2. Chi-squared test of calculated minimum positions.

Algorithm

Change in Thickness

25 Å

50 Å

100 Å

150 Å

200 Å

Polynomial

6.9255 ´ 10-6

0.00001

0.0008

0.00085

0.00036

Integral

3.6192 ´ 10-6

3.5731 ´ 10-6

3.1856 ´ 10-6

4.2424 ´ 10-6

0.00002

            Performing chi-squared tests against smoothed kinetic curves showed the integral algorithm to be consistently more precise than the polynomial one, as seen in Table 2. For the smallest thickness of 25 Å, the polynomial algorithm recorded almost twice the variation in shift in minimum position as the integral. This difference was more pronounced for larger thicknesses, reaching a maximum of 250 times greater at a thickness of 100 Å.

            The two methods further differed greatly in running time. The polynomial fit algorithm, on the system used to run the simulation, was capable of collecting and analyzing an average of 245 SP reflectivity curves during the one-minute washing period, or approximately one curve every 0.2449 seconds. The integral algorithm, on the other hand, collected and analyzed an average of 1923 curves during that same period, or approximately one curve every 0.0312 seconds; this corresponded to an increase in speed of 785% over the polynomial fitting.

Conclusions

Based on results with simulated data, the integral algorithm appears recommendable for use in SPR experimentation. Its consistently low level of error and high precision in comparison to the polynomial method give credence to its ability to accurately process data on actual reactions. Furthermore, its fast processing speed, an almost eightfold increase over the polynomial method, would enable the collection and analysis of that many more SP reflectivity curves in a given period, allowing detection of multiple biochemical reactions in real time. Testing of this algorithm in actual experimental conditions is now in progress.

The polynomial algorithm surprisingly displayed high variation in accuracy and precision, especially as the change in thickness of the simulated biolayer increased (Fig. 7). Since the algorithm itself is known to accurately find the minimum of a polynomial curve, discrepancies may lie in the nature of the adsorption process that is modeled with Eq. 8. Analysis of the reflectivity curves produced by the simulation program for large changes in thickness reveals that, when the biolayer is only partially reacted, the curve mixing algorithm used to generate data results in a predicted curve with two minima. Such a reflectivity curve can also be detected in real experiments [7].

The integral algorithm does not display this occurrence because it measures area rather than the exact minimum; the difference in area that this method relies on remains the same whether one or two minima are present. The polynomial algorithm, however, does; at mid-saturation, it shifts from following the movement of one minimum position to tracking that of the other. The behavior of the simulation can thus account for differences in shape between the graphs of the theoretical minima and those determined by the polynomial algorithm, which translate into decreased measures of accuracy and precision.

Testing under experimental conditions is therefore necessary to ascertain the true reliability of the polynomial algorithm. These observations can also be applied in future research to create an improved simulation of SPR. Such an application could more accurately predict the behavior of a variety of reactions studied with SPR, allowing confident modeling of experiments before they are performed.

Acknowledgements

I would like to extend my gratitude to my mentor, Dr. Vitalii Silin of the National Institute of Standards and Technology, for providing me with the opportunity to conduct research with him and with guidance throughout my work. I also wish to thank Dr. Glenda Torrence, my senior research advisor, for her continuous support.

References

[1]  Silin, V., & Plant, A. (1997). Biotechnological applications of surface plasmon resonance. Trends in Biotechnology, 15, 353-359.

[2]  Davies, J., & Faulkner, I. (1996). Surface plasmon resonance – Theory and considerations. Surface Analytical Techniques for Probing Biomaterial Processes (Davies, J., ed.). Boca Raton, FL: CRC Press.

[3]  Press, W.H., et al (1988). Numerical recipes in C: The art of scientific computing. Cambridge: Cambridge University Press.

[4]  Sedgewick, R. (1992). Algorithms in C++. Boston: Addison-Wesley.

[5]  Tao, N. J., Boussaad, S., Huang, W. L., Arechabaleta, R. A., and D’Agnese, J. (1999). High resolution surface plasmon resonance spectroscopy. Review of Scientific Instruments, 70, 12, 4656-4660.

[6]  Silin, V.I., Balchytis, G.A., & Yakolev, V.A. (1993). Study on surface plasmon line broadening due to protein adsorption on a modified silver surface. Optics Communications, 97, 19-24.

[7]  Merle, H. J., Alberti, B., Schwendler, M., & Peterson, I. R. (1992). Surface plasmon observation of striations in Langmuir-Blodgett films. Journal of Physics D: Applied Physics, 25, 1556-1558.

Appendices

A   Polynomial Curve Fitting Method

/***
FitDataDeg
-
Finds a polynomial of degree porder from the input data (datain[]) using
the Least     Squares Method and weighting values
-
Returns the polynomial values in dataout[] and the coefficients in coef[].
-
Returns the minimum and halfwidth.
- Performs calculations with degrees in the X axis. ***/

int
FitDataDeg(double XData[], double YData[], double dataoutX[], double dataoutY[],     double
coef[], double *minimum, double *halfwidth, double *intensity,
       int
*numPlotPoints)
{     
       double
z[DATALEN], yy[DATALEN], weight[DATALEN];
       double
mse;
       double
*recoef, *widthCoef;
       double*
ms=&mse;                                                                            
       int
i,k;                                                                                  
       double
f[DATALEN],width=0.0,nwidth=0.0, mserro[DATALEN];                                                  
       double
SPRmax, SPRmin,anglemin,SPRangleMin;
       int
imax, imin, pointNumEnd,ip;                                                  
       double*
pwidth =&width;
       double*
pnwidth =&nwidth;
       double
yLimit, widthPosition, calibration;
       int
porder;
       int
pointNumbeg;
       int
err;
       err
= GetCtrlVal (gOptionsPanel, Options_porder, &porder);
       recoef
= malloc ((porder - 1) * sizeof(double));
       widthCoef
= malloc (porder * sizeof(double));
       err
= GetCtrlVal (gOptionsPanel, Options_ylimit, &yLimit);
       err
= GetCtrlVal (gOptionsPanel, Options_pointnum, &pointNumbeg);
       err
= GetCtrlVal (gOptionsPanel, Options_widthpos, &widthPosition);
       err
= GetCtrlVal (gOptionsPanel, Options_calibration, &calibration);
       MaxMin1D
(YData, DATALEN, &SPRmax, &imax, &SPRmin, &imin);
       anglemin=XData[imin];                               
       for
(i=0,ip=0;i<DATALEN;) {
              if
(YData[i]>yLimit)
                     i++;
              else
{
                     dataoutX[ip]=XData[i]-anglemin;                                  
                     z[ip]=(YData[i]-widthPosition);                                                                                              
                     if
(YData[i] > (SPRmin + 0.02))
                            weight[ip]
= 1;
                     else
                            weight[ip]
= 1 + (SPRmin + 0.02 - YData[i]) / 0.0001;   
                     i=i+pointNumbeg;
                     ip++;
              }
       }
       pointNumEnd=ip;                                                                                      
       if
(pointNumEnd > porder - 1) {
              PolyFit2
(dataoutX, z, weight, pointNumEnd, porder, dataoutY, coef);
              for
(i=0;i<pointNumEnd;++i) {           
                     for
(k=0;k<porder;++k) {
                            if
(k==0)                                                                                                                                             
                                   f[i]=coef[0];               
                            else
{
                                  yy[k]=coef[k]*pow(dataoutX[i],k);
                                   f[i]=f[i]+yy[k];
                           }
                     }                                                                                                                                                     
              }                                                                                                                                                            
              SPRwidth
(coef, &width, &nwidth, porder);
              SPRangleMin=SPRminimum(coef,recoef,width,nwidth,SPRangleMin,
porder);
              Reverse
(recoef, porder-1, recoef);                                                                              
              for
(i=0;i<pointNumEnd;++i) {
                     for
(k=0;k<(porder-1);++k) {                                                                                    
                           if
(k==0) {                                                                                                
                                  f[i]=recoef[0];                                                                                             
                           }
                           else
{
                                  yy[k]=recoef[k]*pow(dataoutX[i],k);                                                                                
                                  f[i]=f[i]+yy[k];
                           }
                     }                                                                                                          
              }                                                                                                                  
              for(ip=0;ip<pointNumEnd;ip++)
{  
                     dataoutX[ip]=dataoutX[ip]+anglemin;                          
                     dataoutY[ip]=(dataoutY[ip]+widthPosition);
                     z[ip]=z[ip]+widthPosition;            
              }
              for
(ip=0;ip<pointNumEnd;++ip) { 
                     mserro[ip]=z[ip]-dataoutY[ip];
              }                           
              *minimum
= (anglemin  + SPRangleMin);
              *halfwidth
= (width+fabs(nwidth));
              *numPlotPoints
= pointNumEnd;
              *intensity
= SPRmin;
       }
       else
{
              *minimum
= 0;
              *halfwidth
= 0;
              *numPlotPoints
= 0;
              *intensity
= 0;
       }
       free
(recoef);
       free
(widthCoef);
       return
0;                                                                                                             
}

/***
PolyFit2
-
Uses normal equations with Gaussian elimination and weighting values to
fit data to    a polynomial of order n.
-
Returns the coefficients of the polynomial in coeff[].
***/

void
PolyFit2 (double x[], double y[], double weight[], int n, int order, double
z[],    double coeff[])
{
       double
*f[DATALEN], *A, *B;
       double
t, u;
       int
i, j, k;
       for
(i = 0; i < order; i++)
              f[i]
= malloc(n * sizeof(double));
       A
= malloc(order * order * sizeof(double));
       B
= malloc(order * sizeof(double));
       for
(i = 0; i < order; i++) {
              for
(j = 0; j < n; j++) {
                     f[i][j]
= 1;
                     for
(k = 0; k < i; k++) {
                           f[i][j]
*= x[j];
                     }
              }
       }
       for
(i = 0; i < order; i++) {
              for
(j = 0; j < order; j++) {
                     t
= 0.0;
                     u
= 0.0;
                     for
(k = 0; k < n; k++) {
                           t
+= f[i][k] * f[j][k] * weight[k] * weight[k];
                           u
+= f[j][k] * y[k] * weight[k] * weight[k];
                     }
                     A[i
* order + j] = t;
                     B[j]
= u;
              }
       }
       LinEqs
(A, B, order, coeff);
       for
(i = 0; i < n; i++) {
              t
= 0.0;
              for
(j = 0; j < order; j++) {
                     u
= 1.0;
                     for
(k = 0; k < j; k++) {
                           u
*= x[i];
                     }
                     t
+= coeff[j] * u;
              }
              z[i]
= t;
       }
       free(f);
       free(A);
       free(B);
       return;
}

/***
SPRwidth
-
Finds the SPR width. Returns a positive width and negative width. Actual
width is      the sum of the two widths (pwidth + fabs(pnwidth))
***/

double
SPRwidth (double coef[], double*  pwidth, double*  pnwidth, int porder)
{                                                                         
       int
i,k,kk;
       double
width, nwidth;
       double
* widthCoef = malloc (porder * sizeof(double));
       double
* positivewidth = malloc (porder * sizeof(double));
       double
* negativewidth = malloc (porder * sizeof(double));
       ComplexNum
* widthRoots = malloc (porder * sizeof(ComplexNum));
       Reverse
(coef, porder, widthCoef);
       CxPolyRoots
(widthCoef, porder, widthRoots);                            
       k=0;
kk=0;                                                     
       for
(i=0; i<(porder-1); ++i) {                                                                          if(widthRoots[i].imaginary
!=0.0)                                            
                     continue;
              if
(widthRoots[i].real>0.0)  {
                     positivewidth[k]=widthRoots[i].real;
                     if
(k==0) {                                             
                            width=positivewidth[k];
                           k++
;                                                  
                            continue;
                     }                                                
                     if
(width>positivewidth[k]) {                                  
                            width=positivewidth[k];
                           k++;
                     }
                     continue;
              }                                                                   
              if
(widthRoots[i].real<0.0)  {                                    
                     negativewidth[kk]=widthRoots[i].real;                               
                     if
(kk==0) {                                                        
                            nwidth=negativewidth[kk];                                         
                            kk++;
                            continue;
                     }
                     if
(nwidth<negativewidth[kk]) {
                            nwidth=negativewidth[kk];       kk++;
                     }          
                    continue;                                                    
              }                                                                   
       }                                                                               
       *pwidth=width;
       *pnwidth=nwidth;
       free(widthCoef);
       free(positivewidth);
       free(negativewidth);
       free(widthRoots);
       return
0;
  }

/***
SPRminimum
-
Chooses the SPR angle minimum
***/

double
SPRminimum (double coef[], double recoef[], double width, double nwidth,
double   SPRangleMin, int porder)
{
       int
i,k;
       double
* tmpCoef = malloc (porder * sizeof(double));
       ComplexNum
* polyRoots = malloc (porder * sizeof(ComplexNum));
       k=0;                                                                             
       for
(i = 0; i < porder; i++)
              tmpCoef[i]
= coef[i];
       for
(i=0; i<porder; ++i) {                                                                            
              if(i==0)
                     continue;
              tmpCoef[i]=tmpCoef[i]*i;                                                         
              k=(porder-1)-i;                                                                  
              recoef[k]=tmpCoef[i];                                                         
       }                                                                               
       CxPolyRoots
(recoef, porder-1, polyRoots);                                                
       for
(i=0; i<(porder-2); i++) {                                                                                                     
              if
(polyRoots[i].imaginary != 0.0)
                     continue;                                                                                                                                                               
              if
(polyRoots[i].real < 0.1*nwidth)
                     continue;
              if
(polyRoots[i].real > 0.1*width)
                     continue;                                                                          
              if
(fabs(polyRoots[i].real) > 0)
                     SPRangleMin=polyRoots[i].real;                                                                                                                                              
       }
       free(tmpCoef);
       free(polyRoots);
       return
SPRangleMin;                                                                                  
}

/***
B   Integral Method
initIntegData
- Must call this
function once before fitting is done. It will initialize variables      needed
to check ranges.
***/

int
initIntegData(void)
{
       firstfit
= 1;
       return
0;
}

/***
IntegData
-
Finds the shift in minimum position between an initial value and the input
(YData[])
-
Returns the minimum and halfwidth.

- Performs calculations
with degrees in the X axis.
***/

int
IntegData(double XData[], double YData[], double *minimum, double *halfwidth,
double *intensity)
{
       double
AData[DATALEN], BData[DATALEN];
       double
A, B;
       double
SPRmax, SPRmin;
       double
dt = (gEndDeg - gStartDeg) / DATALEN;
       int
curCenter;
       int
imax, imin;
       int
i;
       MaxMin1D
(YData, DATALEN, &SPRmax, &imax, &SPRmin, &imin);
       *intensity
= SPRmin;
       if
( firstfit == 1 ) {
              firstfit
= 0;
              *minimum
= initMin = XData[imin];
              curCenter
= 3;
              A
= 999;
              B
= 0;
              while
(A > B) {
                     curCenter++;
                     for
(i = 0; i < curCenter; i++)
                           BData[i]
= YData[i];
                     for
(i = curCenter; i < DATALEN; i++)
                           AData[i-curCenter]
= YData[i];
                     NumericIntegration(BData,
curCenter, dt, 3, &B);
                     NumericIntegration(AData,
DATALEN-curCenter, dt, 3, &A);
              }
              center
= curCenter;
              *halfwidth
= SPRwidth(XData, YData);
       }
       else
{
              for
(i = 0; i < center; i++)
                     BData[i]=YData[i];
              for
(i = center; i < DATALEN; i++)
                     AData[i-center]=YData[i];
              NumericIntegration(BData,
center, dt, 3, &B);
              NumericIntegration(AData,
DATALEN-center, dt, 3, &A);
              *minimum
= initMin - ((A-B)/(A+B)) * (gEndDeg-gStartDeg) / 2.11;
              *halfwidth
= SPRwidth(XData, YData);
       }
       return
0;
}

/***
SPRwidth
-
Finds the SPR width.
***/

double
SPRwidth (double XData[], double YData[])
{     
       double
widthPos;
       double
lwidth, rwidth;
       int
i;
       int
err;
       err
= GetCtrlVal(gOptionsPanel, Options_widthpos, &widthPos);
       i
= 0;
       while
(i < DATALEN && YData[i] > widthPos)
              i++;
       lwidth
= XData[i];
       i
+= 10;
       while
(i < DATALEN && YData[i] < widthPos)
              i++;
       rwidth
= XData[i];
       return
(rwidth - lwidth);
}

C   Simulation Input File

}

 

06          8000.0      760.       3       5.2    0

    807.            36.0           88.            36.0

    173.             6.7          180.9            6.7

    473.            26.6          544.            26.6   Constants defining

             4000.0     1000.       3       3.5          curve shape

     87.           311.0           43.

    178.             3.6            7.

    544.             1.56          26.

H:         .00000010      .00000000      .00000010            Thickness of metal layer in meters

H:         .00000540      .00000000      .00000540            Initial thickness of biolayer in meters

}

 
H:         .00000000      .00000000      .00000000

H:         .00000000      .00000000      .00000000

BI:     6600.          1000.0        1000.0

 4     1.515         0.00          1.            0.00000001

 4     3.6           4.35          1.            0.               Refractive indices and dielectric

 4     0.16400       3.50          1.            0.               constants of chromium, gold, the

 4     1.452         0.00          1.            0.               biolayer, and air

 4     1.3333        0.000         -16.1         0.775

 4     1.3333        0.000         16.00         0.

     68.00           0.00977       78.000            Minimum, increment, and maximum incident angle

     64.000         76.00