blob: 87ddf42f322148d78e985fece86645123aaeb8b9 [file] [log] [blame]
package org.eclipse.stem.util.analysis;
/*******************************************************************************
* Copyright (c) 2007, 2008 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
import java.util.ArrayList;
import java.util.List;
import org.eclipse.stem.analysis.impl.ReferenceScenarioDataMapImpl.ReferenceScenarioDataInstance;
/**
* Estimate parameters for an SIR model
*
*
*/
public class SIRparameterEstimator extends ParameterEstimator{
// Unique state for this estimator
double [] r;
static final double MINCUTOFF = 0.005;
/**
* @param data
*/
public SIRparameterEstimator(ReferenceScenarioDataInstance data) {
super(data);
List<Double> sToFit = new ArrayList<Double>();
List<Double> iToFit = new ArrayList<Double>();
List<Double> rToFit = new ArrayList<Double>();
List<Double> sList = data.getStotals();
List<Double> iList = data.getItotals();
List<Double> rList = data.getRtotals();
// ToDo: Why are we skipping the first value?
for (int icount = 1; icount < iList.size(); icount ++) {
iToFit.add(iList.get(icount));
sToFit.add(sList.get(icount));
rToFit.add(rList.get(icount));
}
this.numDataPoints = iToFit.size();
if(numDataPoints < MINSIZE) return;
dataValid = true;
this.p = new double[this.numDataPoints];
this.s = new double[this.numDataPoints];
this.i = new double[this.numDataPoints];
this.r = new double[this.numDataPoints];
this.t = new double[this.numDataPoints];
for (int icount = 0; icount < this.numDataPoints; icount ++) {
s[icount] = sToFit.get(icount).doubleValue();
i[icount] = iToFit.get(icount).doubleValue();
r[icount] = rToFit.get(icount).doubleValue();
p[icount] = s[icount]+i[icount]+r[icount];
t[icount] = icount;
}// for icount
}// constructor
/**
* Estimate the parameters
* @param localDensity
* @param localPopulation
* @param locationID
* @return the ModelParameters estimate
*/
public ModelParameters estimate(double localDensity, double localPopulation, String locationID) {
ModelParameters fittedParms = new ModelParameters();
//double reportBeta1 = 0;
//double reportBeta2 = 0;
int npts = s.length;
assert(npts==i.length);
assert(npts==r.length);
double[] lnS = new double[npts];
double[] dlnS = new double[npts-1];
double[] lnI = new double[npts];
double[] dlnI = new double[npts-1];
double[] lnR = new double[npts];
double[] dlnR = new double[npts-1];
// average values about derivative
double[] sAvg = new double[npts-1];
double[] iAvg = new double[npts-1];
double[] rAvg = new double[npts-1];
double[] pAvg = new double[npts-1];
double[][] dataS = new double[2][npts - 1];
double[][] dataI = new double[2][npts - 1];
double[][] dataR = new double[2][npts - 1];
// get the logarithms
double cutoff = 0.0000000005;
for(int j = 0; j < npts; j++){
if(s[j] >= cutoff) {
lnS[j] = Math.log(s[j]);
} else {
lnS[j] = Math.log(cutoff); // TODO fix this
}
if(i[j] >= cutoff) {
lnI[j] = Math.log(i[j]);
} else {
lnI[j] = Math.log(cutoff); // TODO fix this
}
if(r[j] >= cutoff) {
lnR[j] = Math.log(r[j]);
} else {
lnR[j] = Math.log(cutoff); // TODO fix this
}
}
//derivatives of logarithms and averages of other points
double sMax = 0.0;
double iMax = 0.0;
double rMax = 0.0;
for(int j = 1;j < npts-1;j++)
{
dlnS[j-1] = (lnS[j]-lnS[j-1]); // dt = 1
dlnI[j-1] = (lnI[j]-lnI[j-1]); // dt = 1
dlnR[j-1] = (lnR[j]-lnR[j-1]); // dt = 1
sAvg[j-1] = (s[j] + s[j-1])/2.0;
iAvg[j-1] = (i[j] + i[j-1])/2.0;
rAvg[j-1] = (r[j] + r[j-1])/2.0;
if(sAvg[j-1] >= sMax) sMax = sAvg[j-1];
if(iAvg[j-1] >= iMax) iMax = iAvg[j-1];
if(rAvg[j-1] >= rMax) rMax = rAvg[j-1];
pAvg[j-1] = (p[j] + p[j-1])/2.0;
}
///////////////////////////////////////////////////////////////
// dS/dt-> equation 1.
//x, y for least squares fitting to line y = alpha*x - beta
///////////////////////////////////////////////////////////////
//
List<Double> xList1 = new ArrayList<Double>();
List<Double> yList1 = new ArrayList<Double>();
List<Double> fitList1 = new ArrayList<Double>();
for(int j = 0; j < npts-1; j++){
double sNorm = sAvg[j]/sMax;
double iNorm = iAvg[j]/iMax;
double rNorm = rAvg[j]/rMax;
dataS[0][j] = sNorm;
dataI[0][j] = iNorm;
dataR[0][j] = rNorm;
// by default, selected data is the SAME
dataS[1][j] = sNorm;
dataI[1][j] = iNorm;
dataR[1][j] = rNorm;
if((sNorm<=maxSthreshold)&&(sNorm>=minSthreshold)&&(iNorm>=minIthreshold)&&(rNorm<=maxRthreshold)) {
double numer = (pAvg[j]*rAvg[j]) / sAvg[j];
xList1.add(new Double( numer/ iAvg[j] ) );
yList1.add(new Double( dlnS[j] * (pAvg[j]/iAvg[j]) ));
}else {
// **** for plotting ******
// here we define S*, I*, R*
// NOT Selected = 0.0
dataS[1][j] = 0.0;
dataI[1][j] = 0.0;
dataR[1][j] = 0.0;
////******************/////
}
}
LinearLeastSquaresFit lineFit1 = null;
if(xList1.size() >2) {
lineFit1 = new LinearLeastSquaresFit(xList1,yList1);
// incpt
double beta = -1.0*lineFit1.getIntercept();
double varBeta = lineFit1.getInterceptVariance();
double stdBeta = lineFit1.getInterceptStdDev();
// slope
double alpha = lineFit1.getSlope();
double varAlpha = lineFit1.getSlopeVariance();
double stdAlpha = lineFit1.getSlopeStdDev();
double newbeta = beta;
//reportBeta1 = beta;
if(!useFreqDependantBeta) newbeta *= ((ModelParameters.REFERENCE_POPULATION_DENSITY)/localDensity);
fittedParms.addParameter(Parameter.BETA, new Parameter(Parameter.BETA, newbeta, stdBeta, varBeta));
fittedParms.addParameter(Parameter.ALPHA, new Parameter(Parameter.ALPHA, alpha, stdAlpha, varAlpha));
//Activator.logInformation("beta1 = "+newbeta+", alpha1 = "+alpha);
// fit 1
for (int i = 0; i< xList1.size(); i ++) {
double val = (-lineFit1.getSlope()*xList1.get(i).doubleValue()) + lineFit1.getIntercept();
fitList1.add(new Double(val));
}
}// if fit valid
else {
rejectCount += 1.0;
}
//////////////////////////////////////////////////////
//Equation 2 +> dI/dt second fit for beta and epsilon
List<Double> xList2 = new ArrayList<Double>();
List<Double> yList2 = new ArrayList<Double>();
List<Double> fitList2 = new ArrayList<Double>();
//x, y for least squares fitting to line y = beta*x - epsilon
for(int j = 0; j < npts-1; j++){
double sNorm = sAvg[j]/sMax;
double iNorm = iAvg[j]/iMax;
if((sNorm<=maxSthreshold)&&(sNorm>=minSthreshold)&&(iNorm>=minIthreshold) ) {
double ratio = pAvg[j] / sAvg[j];
xList2.add(new Double( ratio ));
yList2.add(new Double(ratio*dlnI[j]));
}// if data in range
}
// TODO: Plot restricted data
LinearLeastSquaresFit lineFit2 = null;
if(xList2.size() > 2) {
lineFit2 = new LinearLeastSquaresFit(xList2,yList2);
// slope
double gamma = -1.0* lineFit2.getSlope();
double varGamma = lineFit2.getSlopeVariance();
double stdGamma = lineFit2.getSlopeStdDev();
// incpt
double beta2 = lineFit2.getIntercept();
double varBeta2 = lineFit2.getInterceptVariance();
double stdBeta2 = lineFit2.getInterceptStdDev();
double newbeta2 = beta2;
//reportBeta2 = beta2;
if(!useFreqDependantBeta) newbeta2 *= ((ModelParameters.REFERENCE_POPULATION_DENSITY)/localDensity);
fittedParms.addParameter(Parameter.BETA2, new Parameter(Parameter.BETA2, newbeta2, stdBeta2, varBeta2));
fittedParms.addParameter(Parameter.GAMMA, new Parameter(Parameter.GAMMA, gamma, stdGamma, varGamma));
// fit 2
for (int i = 0; i< xList2.size(); i ++) {
double val = (lineFit2.getSlope()*xList2.get(i).doubleValue()) + lineFit2.getIntercept();
fitList2.add(new Double(val));
}
//Activator.logInformation("beta2 = "+newbeta2+", gamma1 = "+gamma);
}// if fit valid
else {
rejectCount += 1.0;
}
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
// Equation 3. find gamma and alpha
// least squares fitting to line y = gamma*x - alpha
List<Double> xList3 = new ArrayList<Double>();
List<Double> yList3 = new ArrayList<Double>();
List<Double> fitList3 = new ArrayList<Double>();
//derivatives of all other points
for(int j = 0;j < npts-1;j++) {
double iNorm = iAvg[j]/iMax;
double rNorm = rAvg[j]/rMax;
if((iNorm>=minIthreshold)&&(rNorm>=minRthreshold)&&(rNorm<=maxRthreshold) ) {
xList3.add(new Double(iAvg[j] / rAvg[j] ) );
yList3.add(new Double(dlnR[j]));
}
}
// TODO: Plot restricted data
LinearLeastSquaresFit lineFit3 = null;
if(xList3.size() > 2) {
lineFit3 = new LinearLeastSquaresFit(xList3,yList3);
// incpt
// TODO why is this coming out negative sometimes?
double alpha2 = Math.abs(-1.0*lineFit3.getIntercept());
double varAlpha2 = lineFit3.getInterceptVariance();
double stdAlpha2 = lineFit3.getInterceptStdDev();
// slope
double gamma2 = lineFit3.getSlope();
double varGamma2 = lineFit3.getSlopeVariance();
double stdGamma2 = lineFit3.getSlopeStdDev();
fittedParms.addParameter(Parameter.ALPHA2, new Parameter(Parameter.ALPHA2, alpha2, stdAlpha2, varAlpha2));
fittedParms.addParameter(Parameter.GAMMA2, new Parameter(Parameter.GAMMA2, gamma2, stdGamma2, varGamma2));
//Activator.logInformation("alpha2 = "+alpha2+", gamma2 = "+gamma2);
// fit 3
for (int i = 0; i< xList3.size(); i ++) {
double val = (lineFit3.getSlope()*xList3.get(i).doubleValue()) + lineFit3.getIntercept();
fitList3.add(new Double(val));
}
} else {
rejectCount += 1.0;
}
fittedParms.addParameter(Parameter.REJECT, new Parameter(Parameter.REJECT, rejectCount));
////////////////////////////////////////////////////////////////////////////////////////////////////
// DONE
////////////////////////////////////////////////////////////////////////////////////////////////////
dataToPlot.add(dataS);
dataToPlot.add(dataI);
dataToPlot.add(dataR);
fittedParms.addSelectedData(locationID, dataToPlot);
double[][] regression1 = getSortedRegression(xList1, yList1);
double[][] regression2 = getSortedRegression(xList2, yList2);
double[][] regression3 = getSortedRegression(xList3, yList3);
double[][] fit1 = getSortedRegression(xList1, fitList1);
double[][] fit2 = getSortedRegression(xList2, fitList2);
double[][] fit3 = getSortedRegression(xList3, fitList3);
regressionValues.add(regression1);
regressionValues.add(regression2);
regressionValues.add(regression3);
fittedValues.add(fit1);
fittedValues.add(fit2);
fittedValues.add(fit3);
fittedParms.addRegressionData(locationID, regressionValues);
fittedParms.addFittedData(locationID, fittedValues);
//Activator.logInformation(""+localPopulation+", "+reportBeta1+", "+reportBeta2);
return fittedParms;
} // estimate
/**
* The control needs this information but must get it through the analyzer from the Estimator
* created by the factory
* SIR models have 3 properties
* @see org.eclipse.stem.util.analysis.ParameterEstimator#getNumProperties()
*/
public int getNumProperties() {
return 3;
}
}