blob: ffa871963727313d17a4cd575260a8ef7f5972f4 [file] [log] [blame]
package org.eclipse.stem.diseasemodels.multipopulation.impl;
/*******************************************************************************
* Copyright (c) 2011 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.Date;
import org.apache.commons.math.ArgumentOutsideDomainException;
import org.apache.commons.math.analysis.interpolation.SplineInterpolator;
import org.apache.commons.math.analysis.polynomials.PolynomialFunction;
import org.apache.commons.math.analysis.polynomials.PolynomialSplineFunction;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.NotificationChain;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.impl.ENotificationImpl;
import org.eclipse.stem.core.common.DoubleValue;
import org.eclipse.stem.core.common.DoubleValueList;
import org.eclipse.stem.core.common.DoubleValueMatrix;
import org.eclipse.stem.core.common.StringValue;
import org.eclipse.stem.core.graph.Node;
import org.eclipse.stem.core.graph.NodeLabel;
import org.eclipse.stem.core.model.STEMTime;
import org.eclipse.stem.diseasemodels.multipopulation.MultiPopulationSeasonalDiseaseModel;
import org.eclipse.stem.diseasemodels.multipopulation.MultipopulationPackage;
import org.eclipse.stem.diseasemodels.standard.DiseaseModelLabelValue;
import org.eclipse.stem.diseasemodels.standard.SEIRLabel;
import org.eclipse.stem.diseasemodels.standard.SEIRLabelValue;
import org.eclipse.stem.diseasemodels.standard.StandardDiseaseModelLabel;
import org.eclipse.stem.diseasemodels.standard.StandardDiseaseModelLabelValue;
import org.eclipse.stem.diseasemodels.standard.StandardPackage;
import org.eclipse.stem.diseasemodels.standard.impl.SEIRLabelValueImpl;
/**
* <!-- begin-user-doc --> An implementation of the model object '
* <em><b>Multi Population Seasonal Disease Model</b></em>'. <!-- end-user-doc
* -->
* <p>
* The following features are implemented:
* <ul>
* <li>
* {@link org.eclipse.stem.diseasemodels.multipopulation.impl.MultiPopulationSeasonalDiseaseModelImpl#getModulationPoints
* <em>Modulation Points</em>}</li>
* <li>
* {@link org.eclipse.stem.diseasemodels.multipopulation.impl.MultiPopulationSeasonalDiseaseModelImpl#getInterpolationType
* <em>Interpolation Type</em>}</li>
* </ul>
* </p>
*
* @generated
*/
public class MultiPopulationSeasonalDiseaseModelImpl extends
MultiPopulationSEIRDiseaseModelImpl implements
MultiPopulationSeasonalDiseaseModel {
/**
* The cached value of the '{@link #getModulationPoints()
* <em>Modulation Points</em>}' containment reference. <!-- begin-user-doc
* --> <!-- end-user-doc -->
*
* @see #getModulationPoints()
* @generated
* @ordered
*/
protected DoubleValueMatrix modulationPoints;
/**
* The default value of the '{@link #isUseSplineInterpolation()
* <em>Use Spline Interpolation</em>}' attribute. <!-- begin-user-doc -->
* <!-- end-user-doc -->
*
* @see #isUseSplineInterpolation()
* @generated
* @ordered
*/
protected static final boolean USE_SPLINE_INTERPOLATION_EDEFAULT = false;
/**
* The cached value of the '{@link #isUseSplineInterpolation()
* <em>Use Spline Interpolation</em>}' attribute. <!-- begin-user-doc -->
* <!-- end-user-doc -->
*
* @see #isUseSplineInterpolation()
* @generated
* @ordered
*/
protected boolean useSplineInterpolation = USE_SPLINE_INTERPOLATION_EDEFAULT;
private PolynomialSplineFunction splineFunction;
private PolynomialSplineFunction linearFunction;
private double[] x;
private double[] y;
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated NOT
*/
public MultiPopulationSeasonalDiseaseModelImpl() {
super();
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
@Override
protected EClass eStaticClass() {
return MultipopulationPackage.Literals.MULTI_POPULATION_SEASONAL_DISEASE_MODEL;
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
public DoubleValueMatrix getModulationPoints() {
return modulationPoints;
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
public NotificationChain basicSetModulationPoints(
DoubleValueMatrix newModulationPoints, NotificationChain msgs) {
DoubleValueMatrix oldModulationPoints = modulationPoints;
modulationPoints = newModulationPoints;
if (eNotificationRequired()) {
ENotificationImpl notification = new ENotificationImpl(
this,
Notification.SET,
MultipopulationPackage.MULTI_POPULATION_SEASONAL_DISEASE_MODEL__MODULATION_POINTS,
oldModulationPoints, newModulationPoints);
if (msgs == null)
msgs = notification;
else
msgs.add(notification);
}
return msgs;
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
public void setModulationPoints(DoubleValueMatrix newModulationPoints) {
if (newModulationPoints != modulationPoints) {
NotificationChain msgs = null;
if (modulationPoints != null)
msgs = ((InternalEObject) modulationPoints)
.eInverseRemove(
this,
EOPPOSITE_FEATURE_BASE
- MultipopulationPackage.MULTI_POPULATION_SEASONAL_DISEASE_MODEL__MODULATION_POINTS,
null, msgs);
if (newModulationPoints != null)
msgs = ((InternalEObject) newModulationPoints)
.eInverseAdd(
this,
EOPPOSITE_FEATURE_BASE
- MultipopulationPackage.MULTI_POPULATION_SEASONAL_DISEASE_MODEL__MODULATION_POINTS,
null, msgs);
msgs = basicSetModulationPoints(newModulationPoints, msgs);
if (msgs != null)
msgs.dispatch();
} else if (eNotificationRequired())
eNotify(new ENotificationImpl(
this,
Notification.SET,
MultipopulationPackage.MULTI_POPULATION_SEASONAL_DISEASE_MODEL__MODULATION_POINTS,
newModulationPoints, newModulationPoints));
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
public boolean isUseSplineInterpolation() {
return useSplineInterpolation;
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
public void setUseSplineInterpolation(boolean newUseSplineInterpolation) {
boolean oldUseSplineInterpolation = useSplineInterpolation;
useSplineInterpolation = newUseSplineInterpolation;
if (eNotificationRequired())
eNotify(new ENotificationImpl(
this,
Notification.SET,
MultipopulationPackage.MULTI_POPULATION_SEASONAL_DISEASE_MODEL__USE_SPLINE_INTERPOLATION,
oldUseSplineInterpolation, useSplineInterpolation));
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
@Override
public NotificationChain eInverseRemove(InternalEObject otherEnd,
int featureID, NotificationChain msgs) {
switch (featureID) {
case MultipopulationPackage.MULTI_POPULATION_SEASONAL_DISEASE_MODEL__MODULATION_POINTS:
return basicSetModulationPoints(null, msgs);
}
return super.eInverseRemove(otherEnd, featureID, msgs);
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
@Override
public Object eGet(int featureID, boolean resolve, boolean coreType) {
switch (featureID) {
case MultipopulationPackage.MULTI_POPULATION_SEASONAL_DISEASE_MODEL__MODULATION_POINTS:
return getModulationPoints();
case MultipopulationPackage.MULTI_POPULATION_SEASONAL_DISEASE_MODEL__USE_SPLINE_INTERPOLATION:
return isUseSplineInterpolation();
}
return super.eGet(featureID, resolve, coreType);
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
@Override
public void eSet(int featureID, Object newValue) {
switch (featureID) {
case MultipopulationPackage.MULTI_POPULATION_SEASONAL_DISEASE_MODEL__MODULATION_POINTS:
setModulationPoints((DoubleValueMatrix) newValue);
return;
case MultipopulationPackage.MULTI_POPULATION_SEASONAL_DISEASE_MODEL__USE_SPLINE_INTERPOLATION:
setUseSplineInterpolation((Boolean) newValue);
return;
}
super.eSet(featureID, newValue);
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
@Override
public void eUnset(int featureID) {
switch (featureID) {
case MultipopulationPackage.MULTI_POPULATION_SEASONAL_DISEASE_MODEL__MODULATION_POINTS:
setModulationPoints((DoubleValueMatrix) null);
return;
case MultipopulationPackage.MULTI_POPULATION_SEASONAL_DISEASE_MODEL__USE_SPLINE_INTERPOLATION:
setUseSplineInterpolation(USE_SPLINE_INTERPOLATION_EDEFAULT);
return;
}
super.eUnset(featureID);
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
@Override
public boolean eIsSet(int featureID) {
switch (featureID) {
case MultipopulationPackage.MULTI_POPULATION_SEASONAL_DISEASE_MODEL__MODULATION_POINTS:
return modulationPoints != null;
case MultipopulationPackage.MULTI_POPULATION_SEASONAL_DISEASE_MODEL__USE_SPLINE_INTERPOLATION:
return useSplineInterpolation != USE_SPLINE_INTERPOLATION_EDEFAULT;
}
return super.eIsSet(featureID);
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
@Override
public String toString() {
if (eIsProxy())
return super.toString();
StringBuffer result = new StringBuffer(super.toString());
result.append(" (useSplineInterpolation: ");
result.append(useSplineInterpolation);
result.append(')');
return result.toString();
}
@Override
public StandardDiseaseModelLabelValue computeDiseaseDeltas(STEMTime time,
StandardDiseaseModelLabelValue currentState,
StandardDiseaseModelLabel diseaseLabel, long timeDelta,
DiseaseModelLabelValue returnValue) {
final SEIRLabelValue currentSEIR = (SEIRLabelValue) currentState;
String thisPopulation = diseaseLabel.getPopulationModelLabel()
.getPopulationIdentifier();
int populationIndex = this.getPopulationIndex(thisPopulation);
double transmissionModulation = computeInterpolationFunctions(time);
EList<DoubleValue> transmissionVector = getTransmissionRate()
.getValueLists().get(populationIndex).getValues();
double thisRecoveryRate = getRecoveryRate().getValues()
.get(populationIndex).getValue();
double thisImmunityLossRate = getImmunityLossRate().getValues()
.get(populationIndex).getValue();
double thisIncubationRate = getIncubationRate().getValues()
.get(populationIndex).getValue();
// iterate over every population (including this one) to compute new
// infections
double numberOfSusceptibleToExposed = 0.0;
double numberSusceptible = currentSEIR.getS();
Node thisNode = diseaseLabel.getNode();
EList<StringValue> groupList = getPopulationGroups().getValues();
for (int i = 0; i < transmissionVector.size(); i++) {
double specificTransmission = transmissionVector.get(i).getValue();
double adjustedTransmission = getAdjustedTransmissionRate(
specificTransmission, timeDelta) * transmissionModulation;
if (!this.isFrequencyDependent())
adjustedTransmission *= getTransmissionRateScaleFactor(diseaseLabel);
// we need to get the disease label for the other population
// to get the on site number of infectious individuals
String nextPop = groupList.get(i).getValue();
for (NodeLabel label : thisNode.getLabels()) {
if (label instanceof SEIRLabel
&& ((SEIRLabel) label).getDecorator() == this) {
SEIRLabel otherDiseaseLabel = (SEIRLabel) label;
String otherPopulation = otherDiseaseLabel.getIdentifier();
if (otherPopulation.equals(nextPop)) {
double onsiteInfectious = ((SEIRLabelValue) otherDiseaseLabel
.getTempValue()).getI();
final double effectiveInfectious = getNormalizedEffectiveInfectious(
thisNode, otherDiseaseLabel, onsiteInfectious,
StandardPackage.Literals.SI_LABEL_VALUE__I);
// add to the new incidence
numberOfSusceptibleToExposed += adjustedTransmission
* numberSusceptible * effectiveInfectious;
}
}
}
}
double numberOfInfectedToRecovered = getAdjustedRecoveryRate(
thisRecoveryRate, timeDelta) * currentSEIR.getI();
double numberOfRecoveredToSusceptible = getAdjustedImmunityLossRate(
thisImmunityLossRate, timeDelta) * currentSEIR.getR();
double numberOfExposedToInfected = getAdjustedIncubationRate(
thisIncubationRate, timeDelta) * currentSEIR.getE();
final double deltaS = -numberOfSusceptibleToExposed
+ numberOfRecoveredToSusceptible;
final double deltaE = numberOfSusceptibleToExposed
- numberOfExposedToInfected;
final double deltaI = numberOfExposedToInfected
- numberOfInfectedToRecovered;
final double deltaR = numberOfInfectedToRecovered
- numberOfRecoveredToSusceptible;
SEIRLabelValueImpl ret = (SEIRLabelValueImpl) returnValue;
ret.setS(deltaS);
ret.setE(deltaE);
ret.setI(deltaI);
ret.setR(deltaR);
ret.setIncidence(numberOfSusceptibleToExposed);
ret.setDiseaseDeaths(0.0);
return ret;
}
private synchronized double computeInterpolationFunctions(STEMTime time) {
boolean pointsChanged = false;
EList<DoubleValueList> points = modulationPoints.getValueLists();
int n = points.size();
int m = 10;
if (x == null || x.length != (2 * m + 1) * n) {
x = new double[(2 * m + 1) * n];
y = new double[(2 * m + 1) * n];
pointsChanged = true;
}
int index = 0;
for (DoubleValueList point : points) {
double nx = point.getValues().get(0).getValue();
double ny = point.getValues().get(1).getValue();
if (x[index] != nx - m * 365.0 || y[index] != ny) {
x[index] = nx - m * 365.0;
y[index] = ny;
pointsChanged = true;
}
index++;
}
if (pointsChanged) {
// The value at 0.0 and 365.0 should be the same in order to have a
// continuous transition between years. Therefore the same sampling
// points are used for several years in a row which leads to a
// periodic function.
for (int j = 1; j <= 2 * m; j++) {
for (int i = 0; i < n; i++) {
x[j * n + i] = x[i] + j * 365.0;
y[j * n + i] = y[i];
}
}
n = (2 * m + 1) * n;
// Spline Interpolation
SplineInterpolator interpolator = new SplineInterpolator();
splineFunction = interpolator.interpolate(x, y);
// Linear Interpolation
PolynomialFunction polynomials[] = new PolynomialFunction[n - 1];
for (int i = 0; i < n - 1; i++) {
final double coefficients[] = new double[2];
coefficients[0] = y[i];
coefficients[1] = (y[i + 1] - y[i]) / (x[i + 1] - x[i]);
polynomials[i] = new PolynomialFunction(coefficients);
}
linearFunction = new PolynomialSplineFunction(x, polynomials);
}
Date date = time.getTime();
Date firstJanuary = new Date(date.getYear(), 0, 1);
double millisecondOfTheYear = date.getTime() - firstJanuary.getTime();
double dayOfTheYear = millisecondOfTheYear / (24 * 60 * 60 * 1000);
// Maximum Day of the Year is 365, otherwise interpolation function may
// not be continuous at transition to next year.
dayOfTheYear = Math.min(dayOfTheYear, 365.0);
if (useSplineInterpolation) {
try {
return Math.max(splineFunction.value(dayOfTheYear), 0.0);
} catch (ArgumentOutsideDomainException e) {
e.printStackTrace();
}
} else {
try {
return Math.max(linearFunction.value(dayOfTheYear), 0.0);
} catch (ArgumentOutsideDomainException e) {
e.printStackTrace();
}
}
return Double.NaN;
}
} // MultiPopulationSeasonalDiseaseModelImpl