diff --git a/src/org/labkey/targetedms/TargetedMSModule.java b/src/org/labkey/targetedms/TargetedMSModule.java index 47abcc0f7..590770091 100644 --- a/src/org/labkey/targetedms/TargetedMSModule.java +++ b/src/org/labkey/targetedms/TargetedMSModule.java @@ -60,6 +60,7 @@ import org.labkey.panoramapremium.PanoramaPremiumController; import org.labkey.panoramapremium.QCNotificationSender; import org.labkey.panoramapremium.View.QCSummaryMenuCustomizer; +import org.labkey.targetedms.calculations.quantification.RegressionFit; import org.labkey.targetedms.chart.ComparisonCategory; import org.labkey.targetedms.chart.ReplicateLabelMinimizer; import org.labkey.targetedms.datasource.MsDataSourceUtil; @@ -667,7 +668,7 @@ public Set getUnitTests() TargetedMSController.TestCase.class, PrecursorManager.TestCase.class, CrossLinkedPeptideInfo.TestCase.class, - Protein.TestCase.class + RegressionFit.TestCase.class ); } diff --git a/src/org/labkey/targetedms/calculations/quantification/CalibrationCurve.java b/src/org/labkey/targetedms/calculations/quantification/CalibrationCurve.java index 235b3b4c7..21d788152 100644 --- a/src/org/labkey/targetedms/calculations/quantification/CalibrationCurve.java +++ b/src/org/labkey/targetedms/calculations/quantification/CalibrationCurve.java @@ -14,13 +14,21 @@ */ package org.labkey.targetedms.calculations.quantification; -public class CalibrationCurve { +import org.jetbrains.annotations.Nullable; + +public class CalibrationCurve implements Cloneable { private Double slope; private Double intercept; + private Double turningPoint; private Integer pointCount; private Double quadraticCoefficient; private Double rSquared; private String errorMessage; + private RegressionFit regressionFit; + + public CalibrationCurve(RegressionFit regressionFit) { + this.regressionFit = regressionFit; + } public double getSlope() { return slope == null ? 0 : slope; @@ -38,6 +46,7 @@ public double getIntercept() { return intercept == null ? 0 : intercept; } + public boolean hasIntercept() { return intercept != null; } @@ -45,6 +54,17 @@ public boolean hasIntercept() { public void setIntercept(Double intercept) { this.intercept = intercept; } + public double getTurningPoint() + { + return turningPoint == null ? 0 : turningPoint; + } + public boolean hasTurningPoint() { + return turningPoint != null; + } + public void setTurningPoint(Double turningPoint) + { + this.turningPoint = turningPoint; + } public int getPointCount() { return pointCount == null ? 0 : pointCount; @@ -88,30 +108,25 @@ public void setErrorMessage(String errorMessage) { public Double getY(double x) { - if (hasQuadraticCoefficient()) - { - return x*x*getQuadraticCoefficient() + x*getSlope() + getIntercept(); - } - return x*getSlope() + getIntercept(); + return regressionFit.getY(this, x); } + @Nullable public Double getX(double y) { - if (hasQuadraticCoefficient()) - { - double discriminant = getSlope()*getSlope()- 4*getQuadraticCoefficient()*(getIntercept() - y); - if (discriminant < 0) - { - return Double.NaN; - } - double sqrtDiscriminant = Math.sqrt(discriminant); - return (-getSlope() + sqrtDiscriminant)/2/getQuadraticCoefficient(); - } - return (y - getIntercept())/getSlope(); + return regressionFit.getX(this, y); + } + + public RegressionFit getRegressionFit() { + return regressionFit; + } + + public void setRegressionFit(RegressionFit regressionFit) { + this.regressionFit = regressionFit; } public static CalibrationCurve forNoExternalStandards() { - CalibrationCurve calibrationCurve = new CalibrationCurve(); + CalibrationCurve calibrationCurve = new CalibrationCurve(RegressionFit.NONE); calibrationCurve.setPointCount(0); calibrationCurve.setSlope(1.0); return calibrationCurve; diff --git a/src/org/labkey/targetedms/calculations/quantification/CalibrationCurveDataSet.java b/src/org/labkey/targetedms/calculations/quantification/CalibrationCurveDataSet.java index 53b867b4b..4fdf00433 100644 --- a/src/org/labkey/targetedms/calculations/quantification/CalibrationCurveDataSet.java +++ b/src/org/labkey/targetedms/calculations/quantification/CalibrationCurveDataSet.java @@ -15,6 +15,7 @@ package org.labkey.targetedms.calculations.quantification; import org.apache.commons.math3.fitting.WeightedObservedPoint; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; @@ -100,6 +101,7 @@ public TransitionKeys getFeaturesToQuantifyOn(String label) { return transitionKeys; } + @Nullable public Double getCalculatedConcentration(String label, CalibrationCurve calibrationCurve, Replicate replicate) { if (calibrationCurve == null) { return null; @@ -108,7 +110,11 @@ public Double getCalculatedConcentration(String label, CalibrationCurve calibrat if (y == null) { return null; } - return calibrationCurve.getX(y) * replicate.getSampleDilutionFactor(); + Double x = calibrationCurve.getX(y); + if (x == null) { + return null; + } + return x * replicate.getSampleDilutionFactor(); } /** diff --git a/src/org/labkey/targetedms/calculations/quantification/RegressionFit.java b/src/org/labkey/targetedms/calculations/quantification/RegressionFit.java index d3de70d03..b17c82657 100644 --- a/src/org/labkey/targetedms/calculations/quantification/RegressionFit.java +++ b/src/org/labkey/targetedms/calculations/quantification/RegressionFit.java @@ -15,16 +15,28 @@ package org.labkey.targetedms.calculations.quantification; import org.apache.commons.math3.fitting.WeightedObservedPoint; +import org.apache.commons.math3.optim.InitialGuess; +import org.apache.commons.math3.optim.MaxEval; +import org.apache.commons.math3.optim.PointValuePair; +import org.apache.commons.math3.optim.SimpleValueChecker; +import org.apache.commons.math3.optim.nonlinear.scalar.GoalType; +import org.apache.commons.math3.optim.nonlinear.scalar.ObjectiveFunction; +import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.NelderMeadSimplex; +import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.SimplexOptimizer; import org.apache.commons.math3.stat.descriptive.SummaryStatistics; +import org.jetbrains.annotations.Nullable; +import org.junit.Assert; +import org.junit.Test; import java.util.Arrays; import java.util.List; +import java.util.stream.Collectors; public abstract class RegressionFit { public static final RegressionFit NONE = new RegressionFit("none", "None") { @Override protected CalibrationCurve performFit(List points) { - CalibrationCurve curve = new CalibrationCurve(); + CalibrationCurve curve = new CalibrationCurve(this); curve.setPointCount(0); curve.setSlope(1.0); return curve; @@ -34,7 +46,7 @@ protected CalibrationCurve performFit(List points) { public static final RegressionFit LINEAR = new RegressionFit("linear", "Linear") { @Override protected CalibrationCurve performFit(List points) { - CalibrationCurve curve = new CalibrationCurve(); + CalibrationCurve curve = new CalibrationCurve(this); curve.setPointCount(points.size()); double[][] x = new double[points.size()][]; double[] y = new double[points.size()]; @@ -54,7 +66,7 @@ protected CalibrationCurve performFit(List points) { public static final RegressionFit LINEAR_THROUGH_ZERO = new RegressionFit("linear_through_zero", "Linear through zero") { @Override protected CalibrationCurve performFit(List points) { - CalibrationCurve curve = new CalibrationCurve(); + CalibrationCurve curve = new CalibrationCurve(this); curve.setPointCount(points.size()); double[][] x = new double[points.size()][]; double[] y = new double[points.size()]; @@ -73,7 +85,7 @@ protected CalibrationCurve performFit(List points) { public static final RegressionFit QUADRATIC = new RegressionFit("quadratic", "Quadratic") { @Override protected CalibrationCurve performFit(List points) { - CalibrationCurve curve = new CalibrationCurve(); + CalibrationCurve curve = new CalibrationCurve(this); curve.setPointCount(points.size()); double[][] x = new double[points.size()][]; double[] y = new double[points.size()]; @@ -90,9 +102,164 @@ protected CalibrationCurve performFit(List points) { curve.setQuadraticCoefficient(result[2]); return curve; } + + @Override + public double getY(CalibrationCurve calibrationCurve, double x) + { + return x*x*calibrationCurve.getQuadraticCoefficient() + x*calibrationCurve.getSlope() + calibrationCurve.getIntercept(); + } + + @Override + public Double getX(CalibrationCurve calibrationCurve, double y) + { + double discriminant = calibrationCurve.getSlope()*calibrationCurve.getSlope() + - 4*calibrationCurve.getQuadraticCoefficient()*(calibrationCurve.getIntercept() - y); + if (discriminant < 0) + { + return Double.NaN; + } + double sqrtDiscriminant = Math.sqrt(discriminant); + return (-calibrationCurve.getSlope() + sqrtDiscriminant)/2/calibrationCurve.getQuadraticCoefficient(); + } }; + public static final RegressionFit LINEAR_IN_LOG_SPACE = new RegressionFit("linear_in_log_space", "Linear in Log Space") + { + protected CalibrationCurve performFit(List points) + { + if (points.stream().anyMatch(pt -> pt.getY() <= 0 || pt.getX() <= 0)) + { + CalibrationCurve calibrationCurve = new CalibrationCurve(this); + calibrationCurve.setErrorMessage("Unable to do a regression in log space because one or more points are non-positive."); + return calibrationCurve; + } + var logPoints = points.stream().map(pt->logPoint(pt)).collect(Collectors.toList()); + var calibrationCurve = LINEAR.fit(logPoints); + calibrationCurve.setRegressionFit(this); + return calibrationCurve; + } + + protected WeightedObservedPoint logPoint(WeightedObservedPoint pt) + { + return new WeightedObservedPoint(pt.getWeight(), Math.log(pt.getX()), Math.log(pt.getY())); + } + + @Override + public Double getX(CalibrationCurve calibrationCurve, double y) + { + var x = super.getX(calibrationCurve, Math.log(y)); + return x == null ? null : Math.exp(x); + } + + @Override + public double getY(CalibrationCurve calibrationCurve, double x) + { + var y = super.getY(calibrationCurve, Math.log(x)); + return Math.exp(y); + } + @Override + public Double computeRSquared(CalibrationCurve curve, List points) + { + return LINEAR.computeRSquared(curve, points.stream().map(this::logPoint).collect(Collectors.toList())); + } + }; + + public static final RegressionFit BILINEAR = new RegressionFit("bilinear", "Bilinear") + { + @Override + protected CalibrationCurve performFit(List points) + { + Double bestLod = null; + Double bestScore = Double.MAX_VALUE; + var xValues = points.stream().map(pt -> pt.getX()).distinct().sorted().collect(Collectors.toList()); + for (int i = 0; i < xValues.size() - 1; i++) + { + double stepSize = (xValues.get(i + 1) - xValues.get(i)) / 4; + double initialValue = (xValues.get(i) + xValues.get(i + 1)) / 2; + var simplex = new NelderMeadSimplex(1, stepSize); + var optimizer = new SimplexOptimizer(new SimpleValueChecker(0, 0, 50)); + PointValuePair optimum = optimizer.optimize( + GoalType.MINIMIZE, + MaxEval.unlimited(), + new ObjectiveFunction(multivariatePoints->LodObjectiveFunction(multivariatePoints[0], points)), + simplex, + new InitialGuess(new double[]{initialValue})); + if (optimum.getValue() < bestScore) { + bestLod = optimum.getPoint()[0]; + bestScore = optimum.getValue(); + } + } + if (bestLod == null) + { + var calibrationCurve = LINEAR.performFit(points); + calibrationCurve.setRegressionFit(this); + return calibrationCurve; + } + return getCalibrationCurveWithLod(bestLod, points); + } + + /// + /// Optimization function used when doing NelderMeadSimplex to find the best Limit of Detection. + /// + private static double LodObjectiveFunction(double lod, List WeightedObservedPoints) + { + CalibrationCurve calibrationCurve = getCalibrationCurveWithLod(lod, WeightedObservedPoints); + if (calibrationCurve == null || !calibrationCurve.hasTurningPoint()) + { + return Double.MAX_VALUE; + } + double totalDelta = 0; + double totalWeight = 0; + for (var pt : WeightedObservedPoints) + { + double delta = pt.getY() - calibrationCurve.getY(pt.getX()); + totalWeight += pt.getWeight(); + totalDelta += pt.getWeight() * delta * delta; + } + var score = totalDelta / totalWeight; + return score; + } + private static CalibrationCurve getCalibrationCurveWithLod(double lod, List weightedObservedPoints) + { + var linearPoints = weightedObservedPoints.stream().map(pt -> pt.getX() > lod + ? pt : new WeightedObservedPoint(pt.getWeight(), lod, pt.getY())) + .collect(Collectors.toList()); + if (linearPoints.stream().map(p -> p.getX()).distinct().count() <= 1) + { + return null; + } + var calibrationCurve = LINEAR.fit(linearPoints); + if (null != calibrationCurve.getErrorMessage()) + { + return null; + } + + calibrationCurve.setTurningPoint(lod); + calibrationCurve.setRegressionFit(BILINEAR); + return calibrationCurve; + } + + @Override + public double getY(CalibrationCurve calibrationCurve, double x) + { + if (calibrationCurve.hasTurningPoint() && x < calibrationCurve.getTurningPoint()) + { + x = calibrationCurve.getTurningPoint(); + } + return super.getY(calibrationCurve, x); + } + + @Override + public Double getX(CalibrationCurve calibrationCurve, double y) + { + Double x = super.getX(calibrationCurve, y); + if (x != null && calibrationCurve.hasTurningPoint() && x < calibrationCurve.getTurningPoint()) { + return null; + } + return x; + } + }; private final String name; @@ -113,7 +280,7 @@ public String getLabel() { public CalibrationCurve fit(List points) { if (points.size() == 0) { - CalibrationCurve curve = new CalibrationCurve(); + CalibrationCurve curve = new CalibrationCurve(this); curve.setErrorMessage("Unable to calculate curve, since there are no data points available"); return curve; } @@ -125,7 +292,7 @@ public CalibrationCurve fit(List points) { } return curve; } catch (Exception e) { - CalibrationCurve curve = new CalibrationCurve(); + CalibrationCurve curve = new CalibrationCurve(this); curve.setErrorMessage(e.toString()); return curve; } @@ -157,7 +324,7 @@ public Double computeRSquared(CalibrationCurve curve, List listAll() { - return Arrays.asList(NONE, LINEAR_THROUGH_ZERO, LINEAR, QUADRATIC); + return Arrays.asList(NONE, LINEAR_THROUGH_ZERO, LINEAR, BILINEAR, QUADRATIC, LINEAR_IN_LOG_SPACE); } public static RegressionFit parse(String name) { @@ -168,4 +335,74 @@ public static RegressionFit parse(String name) { .filter(regressionFit->regressionFit.getName().equals(name)).findFirst() .orElse(NONE); } + + public double getY(CalibrationCurve calibrationCurve, double x) + { + return x * calibrationCurve.getSlope() + calibrationCurve.getIntercept(); + } + + @Nullable + public Double getX(CalibrationCurve calibrationCurve, double y) + { + return (y - calibrationCurve.getIntercept()) / calibrationCurve.getSlope(); + } + + public static class TestCase { + @Test + public void testBilinearFit() + { + CalibrationCurve calcurve = RegressionFit.BILINEAR.fit(Arrays.asList(LKPALAVILLER_POINTS)); + Assert.assertTrue(calcurve.hasTurningPoint()); + Assert.assertEquals(11673.593881022069, calcurve.getTurningPoint(), 1); + Assert.assertEquals(1.2771070764E-12, calcurve.getSlope(), 1E-15); + Assert.assertEquals(-1.4118993633E-08, calcurve.getIntercept(), 1E-12); + } + + private static final WeightedObservedPoint[] LKPALAVILLER_POINTS = new WeightedObservedPoint[] + { + new WeightedObservedPoint(1, 33100.0,4.43587139161e-08), + new WeightedObservedPoint(1, 33100.0,1.95494454654e-08), + new WeightedObservedPoint(1, 33100.0,2.27918101526e-08), + new WeightedObservedPoint(1, 23170.0,2.30656418097e-08), + new WeightedObservedPoint(1, 23170.0,5.4350527721e-09), + new WeightedObservedPoint(1, 23170.0,1.23134930273e-08), + new WeightedObservedPoint(1, 16550.0,1.31851525562e-08), + new WeightedObservedPoint(1, 16550.0,3.38514991628e-09), + new WeightedObservedPoint(1, 16550.0,7.84140959374e-09), + new WeightedObservedPoint(1, 9930.0,6.02807861449e-09), + new WeightedObservedPoint(1, 9930.0,4.8092607441e-10), + new WeightedObservedPoint(1, 9930.0,2.59774090514e-09), + new WeightedObservedPoint(1, 3310.0,7.90722974839e-10), + new WeightedObservedPoint(1, 3310.0,9.17255524711e-10), + new WeightedObservedPoint(1, 3310.0,4.5257191949e-10), + new WeightedObservedPoint(1, 2317.0,1.36493396214e-10), + new WeightedObservedPoint(1, 2317.0,6.32731302763e-10), + new WeightedObservedPoint(1, 2317.0,3.39855605838e-10), + new WeightedObservedPoint(1, 1655.0,1.89132927819e-10), + new WeightedObservedPoint(1, 1655.0,1.69052020568e-09), + new WeightedObservedPoint(1, 1655.0,1.72719025457e-10), + new WeightedObservedPoint(1, 993.0,6.7422496619e-10), + new WeightedObservedPoint(1, 993.0,7.82699319274e-10), + new WeightedObservedPoint(1, 993.0,1.06796529348e-09), + new WeightedObservedPoint(1, 331.0,9.71117065365e-10), + new WeightedObservedPoint(1, 331.0,7.33700136294e-10), + new WeightedObservedPoint(1, 331.0,1.01713787044e-09), + new WeightedObservedPoint(1, 231.7,1.94581859484e-10), + new WeightedObservedPoint(1, 231.7,8.71487280515e-10), + new WeightedObservedPoint(1, 231.7,1.99592855031e-10), + new WeightedObservedPoint(1, 165.5,3.1227318896e-10), + new WeightedObservedPoint(1, 165.5,2.01576290459e-09), + new WeightedObservedPoint(1, 165.5,0.0), + new WeightedObservedPoint(1, 99.3,2.35626363707e-10), + new WeightedObservedPoint(1, 99.3,9.74312769554e-10), + new WeightedObservedPoint(1, 99.3,0.0), + new WeightedObservedPoint(1, 33.1,0.0), + new WeightedObservedPoint(1, 33.1,5.53513509328e-10), + new WeightedObservedPoint(1, 33.1,1.31377272904e-10), + new WeightedObservedPoint(1, 0.0,4.45448077834e-10), + new WeightedObservedPoint(1, 0.0,0.0), + new WeightedObservedPoint(1, 0.0,4.41809527853e-10) + }; + + } } diff --git a/src/org/labkey/targetedms/view/CalibrationCurveChart.java b/src/org/labkey/targetedms/view/CalibrationCurveChart.java index e35b4ec6a..42c7d3749 100644 --- a/src/org/labkey/targetedms/view/CalibrationCurveChart.java +++ b/src/org/labkey/targetedms/view/CalibrationCurveChart.java @@ -136,6 +136,9 @@ private JSONObject processCalibrationCurveJson(GeneralMolecule molecule, Replica jsonCurve.put("errorMessage", calibrationCurve.getErrorMessage()); jsonCurve.put("msLevel", quantificationSettings.getMsLevel()); jsonCurve.put("normalizationMethod", quantificationSettings.getNormalizationMethod()); + // Consider (nicksh): This should probably be changed to: + // RegressionFit.parse(quantificationSettings.getRegressionFit()).Label + // so that it says "Linear in Log Space" instead of "linear_in_log_space" jsonCurve.put("regressionFit", quantificationSettings.getRegressionFit()); jsonCurve.put("regressionWeighting", quantificationSettings.getRegressionWeighting()); jsonCurve.put("units", quantificationSettings.getUnits()); diff --git a/test/sampledata/TargetedMS/Quantification/CalibrationScenariosTest/BilinearCalibrationTest.sky.zip b/test/sampledata/TargetedMS/Quantification/CalibrationScenariosTest/BilinearCalibrationTest.sky.zip new file mode 100644 index 000000000..c1eb258fe Binary files /dev/null and b/test/sampledata/TargetedMS/Quantification/CalibrationScenariosTest/BilinearCalibrationTest.sky.zip differ diff --git a/test/sampledata/TargetedMS/Quantification/CalibrationScenariosTest/BilinearCalibrationTest_CalibrationCurves.csv b/test/sampledata/TargetedMS/Quantification/CalibrationScenariosTest/BilinearCalibrationTest_CalibrationCurves.csv new file mode 100644 index 000000000..d09321fd3 --- /dev/null +++ b/test/sampledata/TargetedMS/Quantification/CalibrationScenariosTest/BilinearCalibrationTest_CalibrationCurves.csv @@ -0,0 +1,2 @@ +Protein,Peptide,PeptideModifiedSequence,Slope,Intercept,PointCount,QuadraticCoefficient,RSquared,ErrorMessage +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.11863213095481095,0.0052156222005383373,8,#N/A,0.99990582004748441, diff --git a/test/sampledata/TargetedMS/Quantification/CalibrationScenariosTest/BilinearCalibrationTest_PeptideResultQuantification.csv b/test/sampledata/TargetedMS/Quantification/CalibrationScenariosTest/BilinearCalibrationTest_PeptideResultQuantification.csv new file mode 100644 index 000000000..f6ca2cd82 --- /dev/null +++ b/test/sampledata/TargetedMS/Quantification/CalibrationScenariosTest/BilinearCalibrationTest_PeptideResultQuantification.csv @@ -0,0 +1,26 @@ +Protein,Peptide,PeptideModifiedSequence,NormalizedArea,CalculatedConcentration,Accuracy,Replicate,FileName +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.0735128484935827,0.57570597226361853,#N/A,Solvent_,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,1.5760869648254796,13.241533554036161,#N/A,Double Blank__VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.018130047884580159,#N/A,#N/A,Blank+IS__VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.030189440749964127,0.21051479349164481,10.52573967458224,Cal 1_0_20 ng_mL_VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.022342768317302968,#N/A,#N/A,Cal 2_0_5 ng_mL_VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.0253963199722484,#N/A,#N/A,Cal 3_1 ng_mL_VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.032859993440380736,0.23302600246110911,1.1651300123055455,Cal 4_2 ng_mL_VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.058234623326164747,0.44691940285404019,0.89383880570808039,Cal 5_5 ng_mL_VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.12789225280123315,1.034092784251043,1.034092784251043,Cal 6_10 ng_mL_VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.29979938334876555,2.4831701055799065,0.99326804223196263,Cal 7_25 ng_mL_VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,1.191868117660654,10.002791704990381,1.0002791704990381,Cal 8_100 ng_mL_VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.021534728313018257,#N/A,#N/A,Blank+IS__VIFonly (2),2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.021667376442886997,#N/A,#N/A,QC1__VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.11096829460613331,0.89143364073834264,#N/A,QC2__VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.25158051577480151,2.076713042169898,#N/A,QC3__VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,1.0487072230515475,8.7960284659178321,#N/A,QC4__VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.33176154986960138,2.7525926158525307,#N/A,Unknown 1__VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.39662562204227259,3.2993590917694053,#N/A,Unknown 2__VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.2674029907776817,2.2100873217645827,#N/A,Unknown 3__VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.10645105006000505,0.85335589139867218,#N/A,Unknown 4__VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.056890477297346476,0.43558903208517757,#N/A,Unknown 5__VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.2124651784040815,1.7469934539276557,#N/A,Unknown 6__VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,5.488816914411216,46.223575755369993,#N/A,Unknown 7__VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.079783490028695572,0.62856384040308133,#N/A,Unknown 8__VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,4.3383217635403977,36.525569476539332,#N/A,Unknown 9__VIFonly,2015-08-19 - LCA Skyline Example.wiff diff --git a/test/sampledata/TargetedMS/Quantification/CalibrationScenariosTest/CalibrationExcludedTest.sky.zip b/test/sampledata/TargetedMS/Quantification/CalibrationScenariosTest/CalibrationExcludedTest.sky.zip index b252ba0d8..eba74ace3 100644 Binary files a/test/sampledata/TargetedMS/Quantification/CalibrationScenariosTest/CalibrationExcludedTest.sky.zip and b/test/sampledata/TargetedMS/Quantification/CalibrationScenariosTest/CalibrationExcludedTest.sky.zip differ diff --git a/test/sampledata/TargetedMS/Quantification/CalibrationScenariosTest/CalibrationTest.sky.zip b/test/sampledata/TargetedMS/Quantification/CalibrationScenariosTest/CalibrationTest.sky.zip index 066423267..3944688d2 100644 Binary files a/test/sampledata/TargetedMS/Quantification/CalibrationScenariosTest/CalibrationTest.sky.zip and b/test/sampledata/TargetedMS/Quantification/CalibrationScenariosTest/CalibrationTest.sky.zip differ diff --git a/test/sampledata/TargetedMS/Quantification/CalibrationScenariosTest/LinearInLogSpace.sky.zip b/test/sampledata/TargetedMS/Quantification/CalibrationScenariosTest/LinearInLogSpace.sky.zip new file mode 100644 index 000000000..eed58a01e Binary files /dev/null and b/test/sampledata/TargetedMS/Quantification/CalibrationScenariosTest/LinearInLogSpace.sky.zip differ diff --git a/test/sampledata/TargetedMS/Quantification/CalibrationScenariosTest/LinearInLogSpace_CalibrationCurves.csv b/test/sampledata/TargetedMS/Quantification/CalibrationScenariosTest/LinearInLogSpace_CalibrationCurves.csv new file mode 100644 index 000000000..9f76f34f9 --- /dev/null +++ b/test/sampledata/TargetedMS/Quantification/CalibrationScenariosTest/LinearInLogSpace_CalibrationCurves.csv @@ -0,0 +1,2 @@ +Protein,Peptide,PeptideModifiedSequence,Slope,Intercept,PointCount,QuadraticCoefficient,RSquared,ErrorMessage +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.63724190440325612,-1.8792265227776139,8,#N/A,0.87289186439249755, diff --git a/test/sampledata/TargetedMS/Quantification/CalibrationScenariosTest/LinearInLogSpace_PeptideResultQuantification.csv b/test/sampledata/TargetedMS/Quantification/CalibrationScenariosTest/LinearInLogSpace_PeptideResultQuantification.csv new file mode 100644 index 000000000..13ad0f8c7 --- /dev/null +++ b/test/sampledata/TargetedMS/Quantification/CalibrationScenariosTest/LinearInLogSpace_PeptideResultQuantification.csv @@ -0,0 +1,26 @@ +Protein,Peptide,PeptideModifiedSequence,NormalizedArea,CalculatedConcentration,Accuracy,Replicate,FileName +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.0735128484935827,0.31751231579633055,#N/A,Solvent_,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,1.5760869648254796,38.975324925873963,#N/A,Double Blank__VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.018130047884580159,0.035294320912870977,#N/A,Blank+IS__VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.030189440749964127,0.078564738771548528,3.9282369385774265,Cal 1_0_20 ng_mL_VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.022342768317302968,0.048988782317181088,0.97977564634362169,Cal 2_0_5 ng_mL_VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.0253963199722484,0.059896398377397346,0.59896398377397342,Cal 3_1 ng_mL_VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.032859993440380736,0.089742054308525471,0.44871027154262733,Cal 4_2 ng_mL_VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.058234623326164747,0.22028222774026085,0.4405644554805217,Cal 5_5 ng_mL_VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.12789225280123315,0.75707418138466176,0.75707418138466176,Cal 6_10 ng_mL_VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.29979938334876555,2.8823351252385727,1.152934050095429,Cal 7_25 ng_mL_VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,1.191868117660654,25.139498390747406,2.5139498390747406,Cal 8_100 ng_mL_VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.021534728313018257,0.046237274866163407,#N/A,Blank+IS__VIFonly (2),2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.021667376442886997,0.046684998198915979,#N/A,QC1__VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.11096829460613331,0.60589967649324039,#N/A,QC2__VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.25158051577480151,2.1889672161306266,#N/A,QC3__VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,1.0487072230515475,20.565841638541624,#N/A,QC4__VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.33176154986960138,3.3789727235292819,#N/A,Unknown 1__VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.39662562204227259,4.4718622104069565,#N/A,Unknown 2__VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.2674029907776817,2.4088394912050077,#N/A,Unknown 3__VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.10645105006000505,0.56764544400881733,#N/A,Unknown 4__VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.056890477297346476,0.21235597157795497,#N/A,Unknown 5__VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.2124651784040815,1.6790833433978578,#N/A,Unknown 6__VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,5.488816914411216,276.16649931206666,#N/A,Unknown 7__VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,0.079783490028695572,0.3610335154364277,#N/A,Unknown 8__VIFonly,2015-08-19 - LCA Skyline Example.wiff +TG|1578-1589|z2,VIFDANAPVAVR,VIFDANAPVAVR,4.3383217635403977,190.92369937955652,#N/A,Unknown 9__VIFonly,2015-08-19 - LCA Skyline Example.wiff diff --git a/test/sampledata/TargetedMS/Quantification/CalibrationScenariosTest/MergedDocuments.sky.zip b/test/sampledata/TargetedMS/Quantification/CalibrationScenariosTest/MergedDocuments.sky.zip index ab741a5d7..815a16d92 100644 Binary files a/test/sampledata/TargetedMS/Quantification/CalibrationScenariosTest/MergedDocuments.sky.zip and b/test/sampledata/TargetedMS/Quantification/CalibrationScenariosTest/MergedDocuments.sky.zip differ diff --git a/test/sampledata/TargetedMS/Quantification/CalibrationScenariosTest/p180test_calibration_DukeApril2016.sky.zip b/test/sampledata/TargetedMS/Quantification/CalibrationScenariosTest/p180test_calibration_DukeApril2016.sky.zip index 3caab0925..5d13497c2 100644 Binary files a/test/sampledata/TargetedMS/Quantification/CalibrationScenariosTest/p180test_calibration_DukeApril2016.sky.zip and b/test/sampledata/TargetedMS/Quantification/CalibrationScenariosTest/p180test_calibration_DukeApril2016.sky.zip differ diff --git a/test/src/org/labkey/test/tests/targetedms/AbstractQuantificationTest.java b/test/src/org/labkey/test/tests/targetedms/AbstractQuantificationTest.java index 24bd87513..aaaab65ea 100644 --- a/test/src/org/labkey/test/tests/targetedms/AbstractQuantificationTest.java +++ b/test/src/org/labkey/test/tests/targetedms/AbstractQuantificationTest.java @@ -265,7 +265,7 @@ private void testFiguresOfMerit(String scenario, @Nullable FiguresOfMerit fom) assertTrue("Empty pdf downloaded [" + file.getName() + "]", file.length() > 0); } - protected void runScenario(String scenario, String expectedWeighting, @Nullable FiguresOfMerit fom) throws Exception + protected void runScenario(String scenario, String expectedWeighting, String expectedRegressionFit, @Nullable FiguresOfMerit fom) throws Exception { setupSubfolder(getProjectName(), scenario, FolderType.Experiment); importData(SAMPLEDATA_FOLDER + scenario + ".sky.zip"); @@ -353,7 +353,7 @@ protected void runScenario(String scenario, String expectedWeighting, @Nullable "Unknown", "Excluded", "Calibration Curve", - "Regression Fit: " + (quadratic?"quadratic":"linear"), + "Regression Fit: " + expectedRegressionFit, "Norm. Method: ratio_to_heavy", "Regression Weighting: " + expectedWeighting, "MS Level: All" diff --git a/test/src/org/labkey/test/tests/targetedms/TargetedMSCalibrationCurveTest.java b/test/src/org/labkey/test/tests/targetedms/TargetedMSCalibrationCurveTest.java index 35ec883ca..54c9b85f7 100644 --- a/test/src/org/labkey/test/tests/targetedms/TargetedMSCalibrationCurveTest.java +++ b/test/src/org/labkey/test/tests/targetedms/TargetedMSCalibrationCurveTest.java @@ -53,7 +53,7 @@ public void testMergedDocumentsScenario() throws Exception fom.setLod("0.11"); fom.setCalc("Blank plus 2 * SD"); - runScenario("MergedDocuments", "none", fom); + runScenario("MergedDocuments", "none", "linear", fom); testCalibrationCurveMoleculePrecursorsByReplicate(); } @@ -70,14 +70,14 @@ public void testCalibrationScenario() throws Exception fom.setLod("0.10"); fom.setCalc("Blank plus 3 * SD"); - runScenario("CalibrationTest", "none", fom); + runScenario("CalibrationTest", "none", "quadratic", fom); testCalibrationCurvePrecursorsByReplicate(); } @Test public void testCalibrationExcludeScenario() throws Exception { - runScenario("CalibrationExcludedTest", "none", null); + runScenario("CalibrationExcludedTest", "none", "linear", null); } @Test @@ -91,13 +91,25 @@ public void testP180Scenario() throws Exception fom.setLod("-5.84"); fom.setCalc("Blank plus 2 * SD"); - runScenario("p180test_calibration_DukeApril2016", "1/x", fom); + runScenario("p180test_calibration_DukeApril2016", "1/x", "linear", fom); } @Test public void testDilutionFactorScenario() throws Exception { - runScenario("DilutionFactorTest", "1/(x*x)", null); + runScenario("DilutionFactorTest", "1/(x*x)", "linear",null); + } + + @Test + public void testBilinearFit() throws Exception + { + runScenario("BilinearCalibrationTest", "none", "bilinear",null); + } + + @Test + public void testLinearInLogSpace() throws Exception + { + runScenario("LinearInLogSpace", "none", "linear_in_log_space", null); } @Test diff --git a/test/src/org/labkey/test/tests/targetedms/TargetedMSPrecursorLevelDataTest.java b/test/src/org/labkey/test/tests/targetedms/TargetedMSPrecursorLevelDataTest.java index cf95920ce..f75f644de 100644 --- a/test/src/org/labkey/test/tests/targetedms/TargetedMSPrecursorLevelDataTest.java +++ b/test/src/org/labkey/test/tests/targetedms/TargetedMSPrecursorLevelDataTest.java @@ -67,7 +67,7 @@ public void testUsingPrecursorLevelData() throws Exception fom.setLod("0.11"); fom.setCalc("Blank plus 2 * SD"); - runScenario("MergedDocuments", "none", fom); + runScenario("MergedDocuments", "none", "linear", fom); } @After