//===================================================================== // File: LocalSouthern.java // Class: LocalSouthern // Package: AFLPcore // // Author: James J. Benham // Date: November 26, 2000 // Contact: james_benham@hmc.edu // // Genographer v1.4 - Computer assisted scoring of gels. // Copyright (C) 1999 Montana State University // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; version 2 // of the License. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // // The GNU General Public License is distributed in the file GPL //===================================================================== package AFLPcore; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import AFLPcore.Option; /** * This class implements the Local Southern sizing method described by * E.M. Southern (Southern, E. M. "Measurement of DNA Length by Gel * Electrophoresis." (1979) Analytical Biochemistry 100, * 319-323.) * *
The equation *
* c * L = --------- + Lo * m - Mo ** is used, where L is the size of the unknown fragement, m is * the mobility (scan number) of the fragment, and c, Mo, and * Lo are constants. The constants are determined in the following * manner. Fragments of known size (from the size standard) are used as known * values for L and m. For every set of three standard points, * a curve is defined. Let the point (xi, yi) denote a standard * point, where xi is the mobility of the known fragement and * yi is the size of the known fragement. These three points give us * the following system of equations: *
* c * y1 = ------- + Lo (1) * x1 - Mo **
* c * y2 = ------- + Lo (2) * x2 - Mo **
* c * y3 = ------- + Lo (3) * x3 - Mo ** Solving this system of equations yields: *
* -(-x3 + x2) (-x3 + x1) (x1 - x2) (-y3 + y2) (y1 - y3) (-y2 + y1) * c = ---------------------------------------------------------------- * 2 * (-y1 x3 + y2 x3 - y2 x1 + x2 y1 - x2 y3 + x1 y3) **
* - (-y1 x1 y3 + y1 y3 x3 - y2 x2 y1 + y2 x2 y3 - y2 y3 x3 + y2 y1 x1) * Lo = -------------------------------------------------------------------- * (-y1 x3 + y2 x3 - y2 x1 + x2 y1 - x2 y3 + x1 y3) **
* (-y2 x2 x1 + y2 x2 x3 - y1 x1 x3 + x1 y3 x3 - x2 y3 x3 + x2 y1 x1) * Mo = -------------------------------------------------------------------- * (-y1 x3 + y2 x3 - y2 x1 + x2 y1 - x2 y3 + x1 y3) ** However, a problem is encountered when all three of the standard points * used are on a line. In this case, the denominator (which is the same * for all three constants) becomes 0. When that happens, this class * abandons the equation suggested by E.M. Southern and instead uses a * line for the curve between those two points. * *
To size an unknown fragment, the following method is used. For most * fragements, the average of two curves will be used to find the size. * The first curve will be defined by two standard points below the * unknown fragement and one above. The second curve will be defined by * one standard point below and two above. (Above and below are determined * by scan number.) Remember that one (or both) of these curves can be * linear. In the case that the unknown fragement is near the beginning or * the end of the size standard ranges, only one curve is used. For example, * if the curve with only one size standard point below includes the first * size standard point, the curve with two points below does not exists. * For points smaller than the first size standard point, a line is used. * The line is defined by the first size standard point and by assuming * the size at scan number 0 is 0. For points greater than the largest * size standard point, the curve for the last three points is simply * extended. Note: This is not very accurate at all for points * outside of the defined size standards! For those points inside, * the sizing agrees with that of the ABI software and appears to be * reliable. Therefore, it is recommended that only the points * between defined size standards be used. * *
This class also allows one to convert from base pairs to scan numbers. * This answer is not unique (see below). However, in almost every * case, one of the answers is clearly out of bounds. The bounds are defined * such that if a fragements size is between two standard points, it's scan * number must also be between the two size standards. If the correct value * cannot be determined, the class will print out an error message to the * standard output and then take the smaller value. * *
The conversion back is broken down into three cases, a size * derived from two curves, a line and a curve, and two lines. * For two curves, the size s is defined as: *
* c1/(m - m1) + L1 + c2/(m - m2) + L2 * s = ------------------------------------- * 2 ** solving for m yeilds: *
* -c1m2 - c2m1 2 * m = f + sqrt(-------------- - m1m2 + f ) * 2s - L1 - L2 ** or *
* -c1m2 - c2m1 2 * m = f - sqrt(-------------- - m1m2 + f ) * 2s - L1 - L2 ** where *
* 1 c1 + c2 * f = - ( m1m2 + -----------) * 2 2s - L1 -L2 ** For a curve and a line, the size is determined by: *
* c/(m -mo) + Lo + am + b * s = -------------------------- * 2 ** solving yields: *
* g + sqrt(g^2 - 4a(mo*d + c)) g - sqrt(g^2 - 4a(mo*d + c)) * m = -----------------------------, or m = ------------------------------ * 2a 2a ** where *
* d = 2s - Lo - b g = amo + d ** Finally, for two lines, the solution is trivial and unique. This is * because if points a, b, and c are on a line and points b, c, and d are * on a line, then a and d must be on the same line. * *
Overall, this class performs the conversions between base pairs
* and scan numbers required by the program.
*
* @see Lane
* @see SizeFunction
* @see SizeMgr
* @see FeatureList
*
* @author James J. Benham
* @version 1.0.0
* @date August 10, 1998
*/
public class LocalSouthern extends SizeFunction
{
private static double DEFAULT_MAX_SCAN = 5000;
private static final int SIZE = 0;
private static final int SCAN = 1;
private static final int C = 2;
private static final int Mo = 3;
private static final int Lo = 4;
private static final int LINEAR = 5;
private double lsValues[][];
private int numPoints; // the number of points used for calculations
private double smallM;
private double smallB;
private double maxScan;
public LocalSouthern()
{
name = "Local Southern";
descript = "Size lane based on the method described by " +
"E.M. Southern [1979]";
helpFile = "lsouthern.html";
numPoints = 0;
maxScan = DEFAULT_MAX_SCAN;
}
/**
* Gives the name describing this sizing function.
*
* @return the name
*/
public String getName()
{
return name;
}
/**
* Gives a brief description of this sizing function.
*
* @return a one sentence explination.
*/
public String getDescription()
{
return descript;
}
/**
* Gives the help file that describes the function in more detail
*
* @return a plaintext of html help file.
*/
public String getHelpFile()
{
return helpFile;
}
/**
* There are no options for this sizing function.
*
* @return null
*/
public Option[] getOptions()
{
return null;
}
/**
* Since there are no options, this method doesn't do much. In fact,
* it does absolutely nothing, but it is required by the abstract class
* Operation
, which this class is a child of.
*/
public void setOptions(Option[] opts)
{
}
/**
* This takes a list of peaks with the location containing the size
* in base pairs, and the AREA must contain the scan number of that
* peak. This method must be called since it uses the data points to
* calculate the constants for the different curves. See the class
* description for an explination of the sizing function.
* Some parts of this method are not very efficient, but since it will
* not be run very often, it is not a big problem.
*
* @param standardPeaks a list of peaks with the area containing the
* scan number and the location having the size in bp.
*/
public void init(DataList standardPeaks)
{
// remember how many points we have
numPoints = standardPeaks.size();
// create the array.
lsValues = new double[numPoints][6];
double x1, x2, x3;
double y1, y2, y3;
double denom;
// find the value for the constants C, Mo, and Lo
for(int i = 0; i < (numPoints - 2); i++)
{
// get the values
x1 = ((Peak) standardPeaks.dataAt(i)).getArea();
y1 = ((Peak) standardPeaks.dataAt(i)).getLocation();
x2 = ((Peak) standardPeaks.dataAt(i + 1)).getArea();
y2 = ((Peak) standardPeaks.dataAt(i + 1)).getLocation();
x3 = ((Peak) standardPeaks.dataAt(i + 2)).getArea();
y3 = ((Peak) standardPeaks.dataAt(i + 2)).getLocation();
// Store the size and scan. Do it to i and i + 2, so we compeletely
// fill the array (just i would leave the bottom unfilled and just
// i+2 would leave the top empty) This will cause some values to
// be overwritten, but that isn't a big deal, since they will be
// overwritten with the same value. This method isn't time critical.
lsValues[i][SIZE] = y1;
lsValues[i][SCAN] = x1;
lsValues[i + 2][SIZE] = y3;
lsValues[i + 2][SCAN] = x3;
// The following three values return the solution for each of the
// constants using the three points. The solutions where obtained
// by solving the three simultaneous equations:
// y1 = C/(x1 - Mo) + Lo
// y2 = C/(x2 - Mo) + Lo
// y3 = C/(x3 - Mo) + Lo
// Calculate the denominator here since it is used by all of the
// mehtods. It will also allow us to catch divide by zero errors,
// which means that the size standards are in a straight line.
denom = -y1*x3 + y2*x3 - y2*x1 + x2*y1 - x2*y3 + x1*y3;
if(denom != 0)
{
lsValues[i][Lo] = solveLo(x1, y1, x2, y2, x3, y3, denom);
lsValues[i][Mo] = solveMo(x1, y1, x2, y2, x3, y3, denom);
lsValues[i][C] = solveC(x1, y1, x2, y2, x3, y3, denom);
lsValues[i][LINEAR] = 0;
}
else
{
// it's linear, so use, Mo as the slope and C as the y-intercept
lsValues[i][Mo] = (y2 - y1)/(x2 - x1);
lsValues[i][C] = y1 - lsValues[i][Mo]*x1;
lsValues[i][LINEAR] = 1;
}
}
// Make a line for the smaller sizes.
Peak pk;
if(standardPeaks.isEmpty())
pk = new Peak(100, 0, 100); // hack for an empty lane
else
pk = (Peak) standardPeaks.dataAt(0);
double zeroX = 0;
double zeroY = 0;
smallM = (pk.getLocation() - zeroY)/(pk.getArea() - zeroX);
smallB = zeroY - smallM * zeroX;
/*========DEBUG=
System.out.println("Size Scan Lo Mo C");
for(int i =0; i < numPoints; i++)
{
System.out.println(lsValues[i][SIZE] + " " +
lsValues[i][SCAN] + " " +
lsValues[i][Lo] + " " +
lsValues[i][Mo] + " " +
lsValues[i][C] + " " +
lsValues[i][LINEAR]);
}
=DEBUG=======*/
}
/**
* Sets the maximum scan number to the specified value. This is useful
* to the class since it cannot always tell which possible answer
* for a scan number is correct.
*
* @param max the largest possible scan number that should be returned
* by getScan(double)
.
*
* @see LocalSouthern
*/
public void setMaxScan(int max)
{
maxScan = (double) max;
}
/**
* Gives the size in bp from the scan number, using the method described
* in the class description. This method will probably get a lot of use,
* so it needs to execute as quickly as possible.
*
* @param scan the scan number
*
* @return the size in bp.
*/
public final double getSize(int scan)
{
int index = 0;
int lowerIndex = 0; // index to the group of points with 1 above and 2
// below the specified scan number.
int upperIndex = 0; // index to the group of points with 2 above and 1
// below the specified scan number.
// find the location of the scan number
while( (index < numPoints) && (scan > lsValues[index][SCAN]) )
index++;
// figure out what to do with the index, watching for cases where
// we are close to the end, or off the end entirely
switch(index)
{
case 0:
return smallM*scan + smallB;
// break; // Not needed because of return
case 1:
// We are at the top, so use only the first group of three with 2
// above and one below since the group with 1 above and 2 below
// (less than) does not exist.
lowerIndex = 0;
upperIndex = 0;
break;
default:
// set for the normal cases where we are in the middle
lowerIndex = index - 2;
upperIndex = index - 1;
// look for ones that are on the very top (large) edge
// if so, move the upper one so that we don't fall of the end of
// the array. Remember that the index is the top of a group of THREE
if(index == (numPoints -1))
upperIndex = index - 2;
// watch out for points beyond the last standard point
if(index == numPoints)
{
// just use the last group for now
upperIndex = numPoints - 3;
lowerIndex = numPoints - 3;
}
}
// Now calculate the two values from lowerIndex and upperIndex, and
// then return the average.
// Use the formula L = c/(m-mo) +Lo, where L is the size and m is
// the scan. Except, sometimes it's actually linear, so check first.
// if it is, just use L = m*mo + c
double valueL = 0;
if(lsValues[lowerIndex][LINEAR] == 0)
{
valueL = (lsValues[lowerIndex][C]/(scan - lsValues[lowerIndex][Mo])
+ lsValues[lowerIndex][Lo]);
}
else
{
valueL = lsValues[lowerIndex][Mo]*scan + lsValues[lowerIndex][C];
}
double valueU = 0;
if(lsValues[upperIndex][LINEAR] == 0)
{
valueU = (lsValues[upperIndex][C]/(scan - lsValues[upperIndex][Mo])
+ lsValues[upperIndex][Lo]);
}
else
{
valueU = lsValues[upperIndex][Mo]*scan + lsValues[upperIndex][C];
}
//DEBUG: System.out.println("Convert: scan: " + scan + " to " +
//DEBUG: ((valueL +valueU)/2) + "bp");
if(( (valueL + valueU)/2) < 0.0) {
System.out.println("Error on size, negative value for index " +
scan);
}
return( (valueL + valueU)/2 );
}
/**
* Gives the scan number that will produce the specified size. This method
* will perform the inverse operation compared to getSize
.
* Remember that due to rounding errors, these two methods may not be
* exact inverses. Also, it is likely that this method will be called
* frequently, so it should be as fast as possible. The
* setMaxScan
should be used to assist this method. It will
* tell the method what the largest possible value is, which will help
* it determine which possible scan number is the correct one.
*
* @param size the size in bp
*
* @return the scan number
*
* @exception ScanCalcError occurs when the method cannot determine
* the correct scan number. Since the size is determined by an
* average of two values, the scan number that produces it may
* not be unique. Most of the time one can be discarded, but if not
* this exception will occur. The class description contains more
* info. Currently, this exception is not thrown and output is
* dumped to standard out instead. The smaller of the two values
* is taken so that the program can continue.
*
* @see LocalSouthern
*/
public final int getScan(double size)
{
int index = 0;
int lowerIndex = 0; // index to the group of points with 1 above and 2
// below the specified scan number.
int upperIndex = 0; // index to the group of points with 2 above and 1
// below the specified scan number.
double lower; // bounds for the scan number.
double upper;
// find the location of the scan number
while( (index < numPoints) && (size > lsValues[index][SIZE]) )
index++;
// figure out what to do with the index, watching for cases where
// we are close to the end, or off the end entirely
switch(index)
{
case 0:
//DEBUG: System.err.println("Size too small. size: " + size);
//DEBUG: System.out.println("Convert: " + size + "bp to " +
//DEBUG: ((size-smallB)/smallM));
return (int) Math.round((size - smallB)/smallM);
// break; not needed because of return
case 1:
// We are at the top, so use only the first group of three with 2
// above and one below since the group with 1 above and 2 below
// (less than) does not exist.
lowerIndex = 0;
upperIndex = 0;
// set the bounds
lower = lsValues[0][SCAN];
upper = lsValues[1][SCAN];
break;
default:
// look for ones that are on the very top (large) edge
// if so, move the upper one so that we don't fall of the end of
// the array. Remember that the index is the top of a group of THREE
if(index == (numPoints -1))
{
lowerIndex = index - 2;
upperIndex = index - 2;
lower = lsValues[index -1][SCAN];
upper = lsValues[index][SCAN];
}
else if(index == numPoints)
{
// watch out for points beyond the last standard point
//DEBUG: System.err.println("Size too large.");
// just use the last group for now
upperIndex = numPoints - 3;
lowerIndex = numPoints - 3;
lower = lsValues[index -1][SCAN];
upper = maxScan;
}
else
{
// set for the normal cases where we are in the middle
lowerIndex = index - 2;
upperIndex = index - 1;
lower = lsValues[upperIndex][SCAN];
upper = lsValues[index][SCAN];
}
}
// Now that we have the constants, try to find the scan. See the class
// description for the derivation of the formula, but note that it
// does not provide a UNIQUE answer, so we'll have to guess at which
// value is correct. For example, it had better be positive.
// switch on the linearity of the two functions, make a number
// from the two by 2*lower + upper. This means that the binary will
// be the values of the two. EX both linear 11, lower linear: 10, upper
// linear 01, neither 00.
double a; // values used in the calculations
double f;
double sqrtValue;
double denom;
double scan1 = 0;
double scan2 = 0;
int switchValue = (int) (2*lsValues[lowerIndex][LINEAR] +
lsValues[upperIndex][LINEAR]);
switch(switchValue)
{
case 0: // 00 in binary, neither is linear
denom = 2*size - lsValues[lowerIndex][Lo] - lsValues[upperIndex][Lo];
f = 0.5*(lsValues[lowerIndex][Mo] + lsValues[upperIndex][Mo] +
(lsValues[lowerIndex][C] + lsValues[upperIndex][C])/denom);
sqrtValue = Math.sqrt((-lsValues[lowerIndex][C]*
lsValues[upperIndex][Mo] -
lsValues[upperIndex][C]*
lsValues[lowerIndex][Mo])/denom -
lsValues[lowerIndex][Mo]*
lsValues[upperIndex][Mo] + f*f);
scan1 = f + sqrtValue;
scan2 = f - sqrtValue;
break;
case 1: // 01 in binary, upper one is linear
// see the class description for the formula
a = 2*size - lsValues[lowerIndex][Lo] - lsValues[upperIndex][C];
f = lsValues[upperIndex][Mo]*lsValues[lowerIndex][Mo] + a;
sqrtValue = Math.sqrt(f*f - 4*lsValues[upperIndex][Mo]*
(lsValues[lowerIndex][Mo]*a +
lsValues[lowerIndex][C]));
scan1 = (f + sqrtValue)/(2*lsValues[upperIndex][Mo]);
scan2 = (f - sqrtValue)/(2*lsValues[upperIndex][Mo]);
break;
case 2: // 10 in binary, lower index is linear
// see the class description for the formula
a = 2*size - lsValues[upperIndex][Lo] - lsValues[lowerIndex][C];
f = lsValues[lowerIndex][Mo]*lsValues[upperIndex][Mo] + a;
sqrtValue = Math.sqrt(f*f - 4*lsValues[lowerIndex][Mo]*
(lsValues[upperIndex][Mo]*a +
lsValues[upperIndex][C]));
scan1 = (f + sqrtValue)/(2*lsValues[lowerIndex][Mo]);
scan2 = (f - sqrtValue)/(2*lsValues[lowerIndex][Mo]);
break;
case 3: // 11 in binary, both are linear
// This case is really cool because it actually has a unique solution
// To bad it almost never happens.
// scan = (2*size - C1 - C2)/(m1 + m2);
scan1 = ((2*size - lsValues[lowerIndex][C] - lsValues[upperIndex][C])/
(lsValues[lowerIndex][Mo] + lsValues[upperIndex][Mo]));
// we have what we need, and we don't need to check to see which
// one is real, so just return.
return (int) Math.round(scan1);
// break; // not needed because of return, or at all really
}
// Define an epsilon to get around some nasty floating point stuff
// Sometimes things should be equal (ie scan1 == upper), but fp
// screws up.
double epsilon = 0.000000001;
// Adjust the values by a small amount
upper += epsilon;
lower -= epsilon;
// See if we can find one that is outside the valid regions and one
// that is inside.
if( (scan1 < lower) || (scan1 > upper))
{
// one of them must be correct, and it isn't scan1, so it must
// be scan 2
//DEBUG: System.out.println("Convert: " +size+"bp to " +
//DEBUG: (int)Math.round(scan2));
//if(scan2 < 0.0) System.out.println("Error: returing negative size.");
return (int) Math.round(scan2);
}
else if( (scan2 < lower) || (scan2 > upper))
{
// Not scan2, so it must be scan1
//DEBUG: System.out.println("Convert: " +size+"bp to " +
//DEBUG: (int)Math.round(scan1));
//if(scan1 < 0.0) System.out.println("Error: returing negative size.");
return (int) Math.round(scan1);
}
else
{
// Just take the smaller one, but complain first
System.out.println("WARNING: Local Southern could not determine if "
+ scan1 + " or " + scan2 + " was the correct "
+ "scan number for " + size + "bp. Using smaller"
+ " value.");
if(scan1 < scan2)
return (int) Math.round(scan1);
else
return (int) Math.round(scan2);
// They are both valid. We're screwed, so throw an exception.
//throw new ScanCalcError("Could not determine if " + scan1 +
// " or " + scan2 + " was the correct "
// + "scan number for " + size + "bp.");
}
}
/**
* Gives the value of Lo, based on the three points. Lo, is calculated
* from a formula obtained by solving the following three simultaneous
* equations:
*
* y1 = C/(x1 - Mo) + Lo (1) * y2 = C/(x2 - Mo) + Lo (2) * y3 = C/(x3 - Mo) + Lo (3) ** * @param x1 the x-value of the first point * @param y1 the y-value of the first point * @param x2 the x-value of the second point * @param y2 the y-value of the second point * @param x3 the x-value of the third point * @param y3 the y-value of the third point * @param denom a value that is common to this method as well as *
solveMo
and solveC
. It is equal to
* -y1*x3 + y2*x3 - y2*x1 + x2*y1 - x2*y3 + x1*y3
*
* @return the value of Lo
*/
private double solveLo(double x1, double y1, double x2, double y2,
double x3, double y3, double denom)
{
double ans;
ans = -(-y1*x1*y3 + y1*y3*x3 - y2*x2*y1 + y2*x2*y3 - y2*y3*x3 + y2*y1*x1)/
denom;
return ans;
}
/**
* Gives the value of Mo, based on the three points. Mo, is calculated
* from a formula obtained by solving the following three simultaneous
* equations:
* * y1 = C/(x1 - Mo) + Lo (1) * y2 = C/(x2 - Mo) + Lo (2) * y3 = C/(x3 - Mo) + Lo (3) ** * @param x1 the x-value of the first point * @param y1 the y-value of the first point * @param x2 the x-value of the second point * @param y2 the y-value of the second point * @param x3 the x-value of the third point * @param y3 the y-value of the third point * @param denom a value that is common to this method as well as *
solveLo
and solveC
. It is equal to
* -y1*x3 + y2*x3 - y2*x1 + x2*y1 - x2*y3 + x1*y3
*
* @return the value of Mo
*/
private double solveMo(double x1, double y1, double x2, double y2,
double x3, double y3, double denom)
{
double ans;
ans = (-y2*x2*x1 + y2*x2*x3 - y1*x1*x3 + x1*y3*x3 - x2*y3*x3 + x2*y1*x1)/
denom;
return ans;
}
/**
* Gives the value of C, based on the three points. C, is calculated
* from a formula obtained by solving the following three simultaneous
* equations:
* * y1 = C/(x1 - Mo) + Lo (1) * y2 = C/(x2 - Mo) + Lo (2) * y3 = C/(x3 - Mo) + Lo (3) ** * @param x1 the x-value of the first point * @param y1 the y-value of the first point * @param x2 the x-value of the second point * @param y2 the y-value of the second point * @param x3 the x-value of the third point * @param y3 the y-value of the third point * @param denom a value that is common to this method as well as *
solveMo
and solveLo
. It is equal to
* -y1*x3 + y2*x3 - y2*x1 + x2*y1 - x2*y3 + x1*y3
*
* @return the value of C
*/
private double solveC(double x1, double y1, double x2, double y2,
double x3, double y3, double denom)
{
double ans;
ans = (x3 - x2)*(-x3 + x1)*(x1 - x2)*(-y3 + y2)*(y1 - y3)*(-y2 + y1)/
(denom*denom);
return ans;
}
/**
* Reads in the properties of this class from the specified input stream.
* The stream data should have been created by write
. This
* will retrieve this classes state from the input stream. All current
* data in the class will be replaced.
*
* @param in the input stream with the data for the class.
*
* @exception IOException occurs when a problem is encountered when
* reading from the stream.
*/
public void read(DataInputStream in) throws IOException
{
maxScan = in.readDouble();
smallM = in.readDouble();
smallB = in.readDouble();
numPoints = in.readInt();
lsValues = new double[numPoints][6];
// read in the array
for(int i=0; i < numPoints; i++)
{
for(int j=0; j < (LINEAR + 1); j++)
lsValues[i][j] = in.readDouble();
}
}
/**
* Writes all of the information this class needs to store in order
* to be recreated. This will be used for things like storing the
* class in a file. Therefore, the write should output enough information
* so that read
can recreate the essential properties of this
* class.
*
* @param out the destination to write the data to.
*
* @exception IOException occurs when a problem is encountered when
* writing to the stream.
*/
public void write(DataOutputStream out) throws IOException
{
// write out the values for some of the single value constants
out.writeDouble(maxScan);
out.writeDouble(smallM);
out.writeDouble(smallB);
out.writeInt(numPoints);
// write out the array with all of the values
for(int i=0; i < numPoints; i++)
{
for(int j=0; j < (LINEAR + 1); j++)
out.writeDouble(lsValues[i][j]);
}
}
}