package dr.evomodel.antigenic.phyloClustering.misc.obsolete;
import dr.evolution.util.*;
import dr.inference.model.*;
import dr.math.MathUtils;
import dr.math.LogTricks;
import dr.math.distributions.NormalDistribution;
import dr.util.*;
import dr.xml.*;
import mpi.Comm;
import java.io.*;
import java.util.*;
import java.util.logging.Logger;
/**
* @author Charles Cheung
* @author Andrew Rambaut
* @author Trevor Bedford
* @author Marc Suchard
* @version $Id$
*/
/*
Both virus locations and serum locations are shifted by the parameter locationDrift.
A location is increased by locationDrift x offset.
Offset is set to 0 for the earliest virus and increasing with difference in date from earliest virus.
This makes the raw virusLocations and serumLocations parameters not directly interpretable.
*/
public class AGLikelihoodCluster extends AbstractModelLikelihood implements Citable {
private static final boolean CHECK_INFINITE = false;
private static final boolean USE_THRESHOLDS = true;
private static final boolean USE_INTERVALS = true;
public final static String AG_LIKELIHOOD = "aglikelihoodcluster";
// column indices in table
private static final int VIRUS_ISOLATE = 0;
private static final int VIRUS_STRAIN = 1;
private static final int VIRUS_DATE = 2;
private static final int SERUM_ISOLATE = 3;
private static final int SERUM_STRAIN = 4;
private static final int SERUM_DATE = 5;
private static final int TITRE = 6;
public enum MeasurementType {
INTERVAL,
POINT,
THRESHOLD,
MISSING
}
public AGLikelihoodCluster(
int mdsDimension,
Parameter mdsPrecisionParameter,
Parameter locationDriftParameter,
Parameter virusDriftParameter,
Parameter serumDriftParameter,
MatrixParameter virusLocationsParameter,
MatrixParameter serumLocationsParameter,
CompoundParameter tipTraitsParameter,
Parameter virusOffsetsParameter,
Parameter serumOffsetsParameter,
Parameter serumPotenciesParameter,
Parameter serumBreadthsParameter,
Parameter virusAviditiesParameter,
DataTable<String[]> dataTable,
boolean mergeSerumIsolates,
double intervalWidth,
double driftInitialLocations,
boolean clusterMeans,
Parameter clusterOffsetsParameter) {
super(AG_LIKELIHOOD);
this.intervalWidth = intervalWidth;
boolean useIntervals = USE_INTERVALS && intervalWidth > 0.0;
int thresholdCount = 0;
double earliestDate = Double.POSITIVE_INFINITY;
for (int i = 0; i < dataTable.getRowCount(); i++) {
String[] values = dataTable.getRow(i);
String virusName = values[VIRUS_STRAIN];
double virusDate = Double.parseDouble(values[VIRUS_DATE]);
int virus = virusNames.indexOf(virusName);
if (virus == -1) {
virusNames.add(virusName);
virusDates.add(virusDate);
virus = virusNames.size() - 1;
}
String serumName = "";
if (mergeSerumIsolates) {
serumName = values[SERUM_STRAIN];
} else {
serumName = values[SERUM_ISOLATE];
}
double serumDate = Double.parseDouble(values[SERUM_DATE]);
int serum = serumNames.indexOf(serumName);
if (serum == -1) {
serumNames.add(serumName);
serumDates.add(serumDate);
serum = serumNames.size() - 1;
}
boolean isThreshold = false;
boolean isLowerThreshold = false;
double rawTitre = Double.NaN;
if (values[TITRE].length() > 0) {
try {
rawTitre = Double.parseDouble(values[TITRE]);
} catch (NumberFormatException nfe) {
// check if threshold below
if (values[TITRE].contains("<")) {
rawTitre = Double.parseDouble(values[TITRE].replace("<",""));
isThreshold = true;
isLowerThreshold = true;
thresholdCount++;
}
// check if threshold above
if (values[TITRE].contains(">")) {
rawTitre = Double.parseDouble(values[TITRE].replace(">",""));
isThreshold = true;
isLowerThreshold = false;
thresholdCount++;
//throw new IllegalArgumentException("Error in measurement: unsupported greater than threshold at row " + (i+1));
}
}
}
if (serumDate < earliestDate) {
earliestDate = serumDate;
}
if (virusDate < earliestDate) {
earliestDate = virusDate;
}
MeasurementType type = (isThreshold ? MeasurementType.THRESHOLD : (useIntervals ? MeasurementType.INTERVAL : MeasurementType.POINT));
Measurement measurement = new Measurement(virus, serum, virusDate, serumDate, type, rawTitre, isLowerThreshold);
if (USE_THRESHOLDS || !isThreshold) {
measurements.add(measurement);
}
}
double[] maxColumnTitres = new double[serumNames.size()];
for (Measurement measurement : measurements) {
double titre = measurement.log2Titre;
if (Double.isNaN(titre)) {
titre = measurement.log2Titre;
}
if (titre > maxColumnTitres[measurement.serum]) {
maxColumnTitres[measurement.serum] = titre;
}
}
this.mdsDimension = mdsDimension;
this.mdsPrecisionParameter = mdsPrecisionParameter;
addVariable(mdsPrecisionParameter);
this.locationDriftParameter = locationDriftParameter;
if (this.locationDriftParameter != null) {
addVariable(locationDriftParameter);
}
this.virusDriftParameter = virusDriftParameter;
if (this.virusDriftParameter != null) {
addVariable(virusDriftParameter);
}
this.serumDriftParameter = serumDriftParameter;
if (this.serumDriftParameter != null) {
addVariable(serumDriftParameter);
}
this.virusLocationsParameter = virusLocationsParameter;
if (this.virusLocationsParameter != null) {
setupLocationsParameter(virusLocationsParameter, virusNames);
}
this.serumLocationsParameter = serumLocationsParameter;
if (this.serumLocationsParameter != null) {
setupLocationsParameter(serumLocationsParameter, serumNames);
}
this.tipTraitsParameter = tipTraitsParameter;
if (tipTraitsParameter != null) {
setupTipTraitsParameter(this.tipTraitsParameter, virusNames);
}
this.virusOffsetsParameter = virusOffsetsParameter;
if (virusOffsetsParameter != null) {
setupOffsetsParameter(virusOffsetsParameter, virusNames, virusDates, earliestDate);
}
this.serumOffsetsParameter = serumOffsetsParameter;
if (serumOffsetsParameter != null) {
setupOffsetsParameter(serumOffsetsParameter, serumNames, serumDates, earliestDate);
}
this.serumPotenciesParameter = setupSerumPotencies(serumPotenciesParameter, maxColumnTitres);
this.serumBreadthsParameter = setupSerumBreadths(serumBreadthsParameter);
this.virusAviditiesParameter = setupVirusAvidities(virusAviditiesParameter);
StringBuilder sb = new StringBuilder();
sb.append("\tAntigenicLikelihood:\n");
sb.append("\t\t" + virusNames.size() + " viruses\n");
sb.append("\t\t" + serumNames.size() + " sera\n");
sb.append("\t\t" + measurements.size() + " assay measurements\n");
if (USE_THRESHOLDS) {
sb.append("\t\t" + thresholdCount + " thresholded measurements\n");
}
if (useIntervals) {
sb.append("\n\t\tAssuming a log 2 measurement interval width of " + intervalWidth + "\n");
}
Logger.getLogger("dr.evomodel").info(sb.toString());
virusLocationChanged = new boolean[this.virusLocationsParameter.getParameterCount()];
serumLocationChanged = new boolean[this.serumLocationsParameter.getParameterCount()];
virusEffectChanged = new boolean[virusNames.size()];
serumEffectChanged = new boolean[serumNames.size()];
logLikelihoods = new double[measurements.size()];
storedLogLikelihoods = new double[measurements.size()];
// driftInitialLocations = 1; //charles added - now specified in the xml
setupInitialLocations(driftInitialLocations);
// loadInitialLocations(virusNames, serumNames);
//System.out.println("Print now!");
// for (int i = 0; i < virusLocationsParameter.getParameterCount(); i++) {
// System.out.print(virusLocationsParameter.getParameter(i).getParameterValue(0) + " ");
// System.out.print(virusLocationsParameter.getParameter(i).getParameterValue(1) + " ");
// }
// System.out.println("");
if(clusterMeans){
this.clusterMeans = clusterMeans;
this.clusterOffsetsParameter = clusterOffsetsParameter;
//if(clusterOffsetsParameter != null){
//System.out.println("virusNames.size()="+ virusNames.size());
//clusterOffsetsParameter.setDimension( virusNames.size());
// for (int i = 0; i < virusNames.size(); i++) {
// clusterOffsetsParameter.setId(virusNames.get(i));
// }
//addVariable(clusterOffsetsParameter);
//}
//stay null
if (clusterOffsetsParameter == null) {
// clusterOffsetsParameter = new Parameter.Default("clusterOffsets");
} else {
//clusterOffsetsParameter.addBounds(new Parameter.DefaultBounds(Double.MAX_VALUE, 0.0, 1000));
addVariable(clusterOffsetsParameter);
clusterOffsetsParameter.setDimension(virusNames.size());
}
System.out.println(" clusterMeans = true");
//System.exit(0);
}
makeDirty();
}
private Parameter setupVirusAvidities(Parameter virusAviditiesParameter) {
// If no row parameter is given, then we will only use the serum effects
if (virusAviditiesParameter != null) {
virusAviditiesParameter.addBounds(new Parameter.DefaultBounds(Double.MAX_VALUE, Double.MIN_VALUE, 1));
virusAviditiesParameter.setDimension(virusNames.size());
addVariable(virusAviditiesParameter);
String[] labelArray = new String[virusNames.size()];
virusNames.toArray(labelArray);
virusAviditiesParameter.setDimensionNames(labelArray);
for (int i = 0; i < virusNames.size(); i++) {
virusAviditiesParameter.setParameterValueQuietly(i, 0.0);
}
}
return virusAviditiesParameter;
}
private Parameter setupSerumPotencies(Parameter serumPotenciesParameter, double[] maxColumnTitres) {
// If no serum potencies parameter is given, make one to hold maximum values for scaling titres...
if (serumPotenciesParameter == null) {
serumPotenciesParameter = new Parameter.Default("serumPotencies");
} else {
serumPotenciesParameter.addBounds(new Parameter.DefaultBounds(Double.MAX_VALUE, 0.0, 1));
addVariable(serumPotenciesParameter);
}
serumPotenciesParameter.setDimension(serumNames.size());
String[] labelArray = new String[serumNames.size()];
serumNames.toArray(labelArray);
serumPotenciesParameter.setDimensionNames(labelArray);
for (int i = 0; i < maxColumnTitres.length; i++) {
serumPotenciesParameter.setParameterValueQuietly(i, maxColumnTitres[i]);
}
return serumPotenciesParameter;
}
private Parameter setupSerumBreadths(Parameter serumBreadthsParameter) {
// If no serum breadths parameter is given, then we will only use the serum potencies
if (serumBreadthsParameter != null) {
serumBreadthsParameter.addBounds(new Parameter.DefaultBounds(Double.MAX_VALUE, 0.0, 1));
serumBreadthsParameter.setDimension(serumNames.size());
addVariable(serumBreadthsParameter);
String[] labelArray = new String[serumNames.size()];
serumNames.toArray(labelArray);
serumBreadthsParameter.setDimensionNames(labelArray);
for (int i = 0; i < serumNames.size(); i++) {
serumBreadthsParameter.setParameterValueQuietly(i, 1.0);
}
}
return serumBreadthsParameter;
}
protected void setupLocationsParameter(MatrixParameter locationsParameter, List<String> strains) {
locationsParameter.setColumnDimension(mdsDimension);
locationsParameter.setRowDimension(strains.size());
for (int i = 0; i < strains.size(); i++) {
locationsParameter.getParameter(i).setId(strains.get(i));
}
addVariable(locationsParameter);
}
private void setupOffsetsParameter(Parameter offsetsParameter, List<String> strainNames, List<Double> strainDates, double earliest) {
offsetsParameter.setDimension(strainNames.size());
String[] labelArray = new String[strainNames.size()];
strainNames.toArray(labelArray);
offsetsParameter.setDimensionNames(labelArray);
for (int i = 0; i < strainNames.size(); i++) {
Double offset = strainDates.get(i) - new Double(earliest);
if (offset == null) {
throw new IllegalArgumentException("Date missing for strain: " + strainNames.get(i));
}
offsetsParameter.setParameterValue(i, offset);
}
addVariable(offsetsParameter);
}
private void setupTipTraitsParameter(CompoundParameter tipTraitsParameter, List<String> strainNames) {
tipIndices = new int[strainNames.size()];
for (int i = 0; i < strainNames.size(); i++) {
tipIndices[i] = -1;
}
for (int i = 0; i < tipTraitsParameter.getParameterCount(); i++) {
Parameter tip = tipTraitsParameter.getParameter(i);
String label = tip.getParameterName();
int index = findStrain(label, strainNames);
if (index != -1) {
if (tipIndices[index] != -1) {
throw new IllegalArgumentException("Duplicated tip name: " + label);
}
tipIndices[index] = i;
// rather than setting these here, we set them when the locations are set so the changes propagate
// through to the diffusion model.
// Parameter location = locationsParameter.getParameter(index);
// for (int dim = 0; dim < mdsDimension; dim++) {
// tip.setParameterValue(dim, location.getParameterValue(dim));
// }
} else {
// The tree may contain viruses not present in the assay data
// throw new IllegalArgumentException("Unmatched tip name in assay data: " + label);
}
}
// we are only setting this parameter not listening to it:
// addVariable(this.tipTraitsParameter);
}
private final int findStrain(String label, List<String> strainNames) {
int index = 0;
for (String strainName : strainNames) {
if (label.startsWith(strainName)) {
return index;
}
index ++;
}
return -1;
}
private void setupInitialLocations(double drift) {
//System.out.println("hihi");
for (int i = 0; i < virusLocationsParameter.getParameterCount(); i++) {
double offset = 0.0;
if (virusOffsetsParameter != null) {
//System.out.print("virus Offset Parameter present"+ ": ");
//System.out.print( virusOffsetsParameter.getParameterValue(i) + " ");
//System.out.print(" drift= " + drift + " ");
offset = drift * virusOffsetsParameter.getParameterValue(i);
}
else{
System.out.println("virus Offeset Parameter NOT present");
}
double r = MathUtils.nextGaussian() + offset;
virusLocationsParameter.getParameter(i).setParameterValue(0, r);
// System.out.println ( virusLocationsParameter.getParameter(i).getParameterValue(0));
if (mdsDimension > 1) {
for (int j = 1; j < mdsDimension; j++) {
r = MathUtils.nextGaussian();
virusLocationsParameter.getParameter(i).setParameterValue(j, r);
}
}
}
for (int i = 0; i < serumLocationsParameter.getParameterCount(); i++) {
double offset = 0.0;
if (serumOffsetsParameter != null) {
offset = drift * serumOffsetsParameter.getParameterValue(i);
}
double r = MathUtils.nextGaussian() + offset;
serumLocationsParameter.getParameter(i).setParameterValue(0, r);
if (mdsDimension > 1) {
for (int j = 1; j < mdsDimension; j++) {
r = MathUtils.nextGaussian();
serumLocationsParameter.getParameter(i).setParameterValue(j, r);
}
}
}
}
//load initial
private void loadInitialLocations(List<String> strainNames, List<String> serumNames) {
FileReader fileReader;
try {
//fileReader = new FileReader("/Users/charles/Documents/research/antigenic/GenoPheno/Gabriela/results/initialCondition/H3N2_mds.virusLocs.log");
fileReader = new FileReader("/Users/charles/Documents/research/antigenic/GenoPheno/Gabriela/results/initialConditionWithInitialLocationDrift/lastIteration/H3N2_mds.virusLocs.log");
/**
* Creating a buffered reader to read the file
*/
BufferedReader bReader = new BufferedReader( fileReader);
String line;
//this routine may give false results if there are extra lines with spaces
line = bReader.readLine();
System.out.println(line);
String namevalue[] = line.split("\t");
line = bReader.readLine();
System.out.println(line);
String datavalue[] = line.split("\t");
for (int i = 0; i < virusLocationsParameter.getParameterCount(); i++) {
int index = findStrain( namevalue[i*2+1], strainNames); //note. namevalue actually has the extra 1 or 2attached to it.. but it doesn't seem to matter
// System.out.println("name: " + virusLocationsParameter.getParameter(i).getParameterName() + " :" + index);
// System.out.println(datavalue[i*2+1]);
virusLocationsParameter.getParameter(index).setParameterValue(0, Double.parseDouble(datavalue[i*2+1]));
virusLocationsParameter.getParameter(index).setParameterValue(1, Double.parseDouble(datavalue[i*2+2]));
//virusLocationsParameter.getParameter(i).setParameterValue(0, 1);
// System.out.print(virusLocationsParameter.getParameter(i).getParameterValue(0) + " ");
// System.out.print(virusLocationsParameter.getParameter(i).getParameterValue(1) + " ");
}
bReader.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
FileReader fileReader2;
try {
//fileReader2 = new FileReader("/Users/charles/Documents/research/antigenic/GenoPheno/Gabriela/results/initialCondition/H3N2.serumLocs.log");
fileReader2 = new FileReader("/Users/charles/Documents/research/antigenic/GenoPheno/Gabriela/results/initialConditionWithInitialLocationDrift/lastIteration/H3N2.serumLocs.log");
/**
* Creating a buffered reader to read the file
*/
BufferedReader bReader2 = new BufferedReader( fileReader2);
String line;
line = bReader2.readLine();
System.out.println(line);
String namevalue[] = line.split("\t");
line = bReader2.readLine();
System.out.println(line);
String datavalue[] = line.split("\t");
// System.out.println(serumLocationsParameter.getParameterCount());
for (int i = 0; i < serumLocationsParameter.getParameterCount(); i++) {
int index = findStrain( namevalue[i*2+1], serumNames);
// System.out.println(datavalue[i*2+1]);
serumLocationsParameter.getParameter(index).setParameterValue(0, Double.parseDouble(datavalue[i*2+1]));
serumLocationsParameter.getParameter(index).setParameterValue(1, Double.parseDouble(datavalue[i*2+2]));
//virusLocationsParameter.getParameter(i).setParameterValue(0, 1);
}
bReader2.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
protected void handleModelChangedEvent(Model model, Object object, int index) {
}
@Override
protected void handleVariableChangedEvent(Variable variable, int index, Variable.ChangeType type) {
if (variable == virusLocationsParameter) {
int loc = index / mdsDimension;
virusLocationChanged[loc] = true;
if (tipTraitsParameter != null && tipIndices[loc] != -1) {
Parameter location = virusLocationsParameter.getParameter(loc);
Parameter tip = tipTraitsParameter.getParameter(tipIndices[loc]);
int dim = index % mdsDimension;
tip.setParameterValue(dim, location.getParameterValue(dim));
}
} else if (variable == serumLocationsParameter) {
int loc = index / mdsDimension;
serumLocationChanged[loc] = true;
} else if (variable == mdsPrecisionParameter) {
setLocationChangedFlags(true);
} else if (variable == locationDriftParameter) {
setLocationChangedFlags(true);
} else if (variable == virusDriftParameter) {
setLocationChangedFlags(true);
} else if (variable == serumDriftParameter) {
setLocationChangedFlags(true);
} else if (variable == serumPotenciesParameter) {
serumEffectChanged[index] = true;
} else if (variable == serumBreadthsParameter) {
serumEffectChanged[index] = true;
} else if (variable == virusAviditiesParameter) {
virusEffectChanged[index] = true;
} else {
// could be a derived class's parameter
// throw new IllegalArgumentException("Unknown parameter");
}
likelihoodKnown = false;
}
@Override
protected void storeState() {
System.arraycopy(logLikelihoods, 0, storedLogLikelihoods, 0, logLikelihoods.length);
}
@Override
protected void restoreState() {
double[] tmp = logLikelihoods;
logLikelihoods = storedLogLikelihoods;
storedLogLikelihoods = tmp;
likelihoodKnown = false;
}
@Override
protected void acceptState() {
}
public Model getModel() {
return this;
}
public double getLogLikelihood() {
//uncommenting for testing only
if (!likelihoodKnown) {
logLikelihood = computeLogLikelihood();
}
// logLikelihood=0; //for testing purpose only
//System.out.println("logLikelihood of AGLikelihoodCluster= " + logLikelihood);
return logLikelihood;
}
// This function can be overwritten to implement other sampling densities, i.e. discrete ranks
private double computeLogLikelihood() {
double precision = mdsPrecisionParameter.getParameterValue(0);
double sd = 1.0 / Math.sqrt(precision);
logLikelihood = 0.0;
int i = 0;
for (Measurement measurement : measurements) {
if (virusLocationChanged[measurement.virus] || serumLocationChanged[measurement.serum] || virusEffectChanged[measurement.virus] || serumEffectChanged[measurement.serum]) {
double expectation = calculateBaseline(measurement.virus, measurement.serum) - computeDistance(measurement.virus, measurement.serum);
switch (measurement.type) {
case INTERVAL: {
double minTitre = measurement.log2Titre;
double maxTitre = measurement.log2Titre + intervalWidth;
logLikelihoods[i] = computeMeasurementIntervalLikelihood(minTitre, maxTitre, expectation, sd);
} break;
case POINT: {
logLikelihoods[i] = computeMeasurementLikelihood(measurement.log2Titre, expectation, sd);
} break;
case THRESHOLD: {
if(measurement.isLowerThreshold){
logLikelihoods[i] = computeMeasurementThresholdLikelihood(measurement.log2Titre, expectation, sd);
}
else{
logLikelihoods[i] = computeMeasurementUpperThresholdLikelihood(measurement.log2Titre, expectation, sd);
}
} break;
case MISSING:
break;
}
}
logLikelihood += logLikelihoods[i];
i++;
}
likelihoodKnown = true;
setLocationChangedFlags(false);
setSerumEffectChangedFlags(false);
setVirusEffectChangedFlags(false);
return logLikelihood;
}
private void setLocationChangedFlags(boolean flag) {
for (int i = 0; i < virusLocationChanged.length; i++) {
virusLocationChanged[i] = flag;
}
for (int i = 0; i < serumLocationChanged.length; i++) {
serumLocationChanged[i] = flag;
}
}
private void setSerumEffectChangedFlags(boolean flag) {
for (int i = 0; i < serumEffectChanged.length; i++) {
serumEffectChanged[i] = flag;
}
}
private void setVirusEffectChangedFlags(boolean flag) {
for (int i = 0; i < virusEffectChanged.length; i++) {
virusEffectChanged[i] = flag;
}
}
// offset virus and serum location when computing
protected double computeDistance(int virus, int serum) {
Parameter vLoc = virusLocationsParameter.getParameter(virus);
Parameter sLoc = serumLocationsParameter.getParameter(serum);
double sum = 0.0;
// first dimension is shifted
double vxOffset = 0.0;
double sxOffset = 0.0;
if(clusterMeans == true){
if(virusDriftParameter!= null && virusOffsetsParameter != null && serumOffsetsParameter != null && clusterOffsetsParameter!=null){
vxOffset = virusDriftParameter.getParameterValue(0)* clusterOffsetsParameter.getParameterValue(virus);
sxOffset = virusDriftParameter.getParameterValue(0) * serumOffsetsParameter.getParameterValue(serum);
//vxOffset = locationDriftParameter.getParameterValue(0)* ;
// System.out.println("clusterOffset =" + clusterOffsetsParameter.getParameterValue(virus));
//System.out.println("offset = " + vxOffset);
}
//overwrite serum drift
if (serumDriftParameter != null && serumOffsetsParameter != null) {
// System.out.println("hihi ya");
sxOffset = serumDriftParameter.getParameterValue(0) * serumOffsetsParameter.getParameterValue(serum);
}
}
else{
if (locationDriftParameter != null && virusOffsetsParameter != null && serumOffsetsParameter != null) {
vxOffset = locationDriftParameter.getParameterValue(0) * virusOffsetsParameter.getParameterValue(virus);
sxOffset = locationDriftParameter.getParameterValue(0) * serumOffsetsParameter.getParameterValue(serum);
}
if (virusDriftParameter != null && virusOffsetsParameter != null) {
vxOffset = virusDriftParameter.getParameterValue(0) * virusOffsetsParameter.getParameterValue(virus);
}
if (serumDriftParameter != null && serumOffsetsParameter != null) {
sxOffset = serumDriftParameter.getParameterValue(0) * serumOffsetsParameter.getParameterValue(serum);
}
}
double vxLoc = vLoc.getParameterValue(0) + vxOffset;
double sxLoc = sLoc.getParameterValue(0) + sxOffset;
// if(virus ==1){
// System.out.println("virus " + virus + " has vxLoc of " + vxLoc + " = " + vLoc.getParameterValue(0) + "+" + vxOffset);
//}
double difference = vxLoc - sxLoc;
sum += difference * difference;
// other dimensions are not
for (int i = 1; i < mdsDimension; i++) {
difference = vLoc.getParameterValue(i) - sLoc.getParameterValue(i);
sum += difference * difference;
}
double dist = Math.sqrt(sum);
if (serumBreadthsParameter != null) {
double serumBreadth = serumBreadthsParameter.getParameterValue(serum);
dist /= serumBreadth;
}
return dist;
}
// Calculates the expected log2 titre when mapDistance = 0
private double calculateBaseline(int virus, int serum) {
double baseline = serumPotenciesParameter.getParameterValue(serum);
if (virusAviditiesParameter != null) {
baseline += virusAviditiesParameter.getParameterValue(virus);
}
return baseline;
}
private static double computeMeasurementLikelihood(double titre, double expectation, double sd) {
double lnL = NormalDistribution.logPdf(titre, expectation, sd);
if (CHECK_INFINITE && Double.isNaN(lnL) || Double.isInfinite(lnL)) {
throw new RuntimeException("infinite point measurement");
}
return lnL;
}
private static double computeMeasurementThresholdLikelihood(double titre, double expectation, double sd) {
// real titre is somewhere between -infinity and measured 'titre'
// want the lower tail of the normal CDF
double lnL = NormalDistribution.cdf(titre, expectation, sd, true); // returns logged CDF
if (CHECK_INFINITE && Double.isNaN(lnL) || Double.isInfinite(lnL)) {
throw new RuntimeException("infinite threshold measurement");
}
return lnL;
}
private static double computeMeasurementUpperThresholdLikelihood(double titre, double expectation, double sd) {
// real titre is somewhere between -infinity and measured 'titre'
// want the lower tail of the normal CDF
double L = NormalDistribution.cdf(titre, expectation, sd, false); // returns CDF
double lnL = Math.log(1-L); //get the upper tail probability, then log it
if (CHECK_INFINITE && Double.isNaN(lnL) || Double.isInfinite(lnL)) {
throw new RuntimeException("infinite threshold measurement");
}
return lnL;
}
private static double computeMeasurementIntervalLikelihood(double minTitre, double maxTitre, double expectation, double sd) {
// real titre is somewhere between measured minTitre and maxTitre
double cdf1 = NormalDistribution.cdf(maxTitre, expectation, sd, true); // returns logged CDF
double cdf2 = NormalDistribution.cdf(minTitre, expectation, sd, true); // returns logged CDF
double lnL = LogTricks.logDiff(cdf1, cdf2);
if (CHECK_INFINITE && Double.isNaN(lnL) || Double.isInfinite(lnL)) {
// this occurs when the interval is in the far tail of the distribution, cdf1 == cdf2
// instead return logPDF of the point
lnL = NormalDistribution.logPdf(minTitre, expectation, sd);
if (CHECK_INFINITE && Double.isNaN(lnL) || Double.isInfinite(lnL)) {
throw new RuntimeException("infinite interval measurement");
}
}
return lnL;
}
public void makeDirty() {
likelihoodKnown = false;
setLocationChangedFlags(true);
}
private class Measurement {
private Measurement(final int virus, final int serum, final double virusDate, final double serumDate, final MeasurementType type, final double titre, final boolean isLowerThreshold) {
this.virus = virus;
this.serum = serum;
this.virusDate = virusDate;
this.serumDate = serumDate;
this.type = type;
this.titre = titre;
this.log2Titre = Math.log(titre) / Math.log(2);
this.isLowerThreshold = isLowerThreshold;
}
final int virus;
final int serum;
final double virusDate;
final double serumDate;
final MeasurementType type;
final double titre;
final double log2Titre;
final boolean isLowerThreshold;
};
private final List<Measurement> measurements = new ArrayList<Measurement>();
private final List<String> virusNames = new ArrayList<String>();
private final List<String> serumNames = new ArrayList<String>();
private final List<Double> virusDates = new ArrayList<Double>();
private final List<Double> serumDates = new ArrayList<Double>();
private final int mdsDimension;
private final double intervalWidth;
private final Parameter mdsPrecisionParameter;
private final Parameter locationDriftParameter;
private final Parameter virusDriftParameter;
private final Parameter serumDriftParameter;
private final MatrixParameter virusLocationsParameter;
private final MatrixParameter serumLocationsParameter;
private final Parameter virusOffsetsParameter;
private final Parameter serumOffsetsParameter;
private final CompoundParameter tipTraitsParameter;
private int[] tipIndices;
private final Parameter virusAviditiesParameter;
private final Parameter serumPotenciesParameter;
private final Parameter serumBreadthsParameter;
private double logLikelihood = 0.0;
private boolean likelihoodKnown = false;
private final boolean[] virusLocationChanged;
private final boolean[] serumLocationChanged;
private final boolean[] serumEffectChanged;
private final boolean[] virusEffectChanged;
private double[] logLikelihoods;
private double[] storedLogLikelihoods;
private boolean clusterMeans = false;
private Parameter clusterOffsetsParameter;
// **************************************************************
// XMLObjectParser
// **************************************************************
public static XMLObjectParser PARSER = new AbstractXMLObjectParser() {
public final static String FILE_NAME = "fileName";
public final static String TIP_TRAIT = "tipTrait";
public final static String VIRUS_LOCATIONS = "virusLocations";
public final static String SERUM_LOCATIONS = "serumLocations";
public static final String MDS_DIMENSION = "mdsDimension";
public static final String MERGE_SERUM_ISOLATES = "mergeSerumIsolates";
public static final String DRIFT_INITIAL_LOCATIONS = "driftInitialLocations";
public static final String INTERVAL_WIDTH = "intervalWidth";
public static final String MDS_PRECISION = "mdsPrecision";
public static final String LOCATION_DRIFT = "locationDrift";
public static final String VIRUS_DRIFT = "virusDrift";
public static final String SERUM_DRIFT = "serumDrift";
public static final String VIRUS_AVIDITIES = "virusAvidities";
public static final String SERUM_POTENCIES = "serumPotencies";
public static final String SERUM_BREADTHS = "serumBreadths";
public final static String VIRUS_OFFSETS = "virusOffsets";
public final static String SERUM_OFFSETS = "serumOffsets";
public final static String CLUSTER_MEANS = "clusterMeans";
public final static String CLUSTER_OFFSETS = "clusterOffsetsParameter";
public String getParserName() {
return AG_LIKELIHOOD;
}
public Object parseXMLObject(XMLObject xo) throws XMLParseException {
String fileName = xo.getStringAttribute(FILE_NAME);
DataTable<String[]> assayTable;
try {
assayTable = DataTable.Text.parse(new FileReader(fileName), true, false);
} catch (IOException e) {
throw new XMLParseException("Unable to read assay data from file: " + e.getMessage());
}
System.out.println("Loaded HI table file: " + fileName);
boolean mergeSerumIsolates = xo.getAttribute(MERGE_SERUM_ISOLATES, false);
boolean cluster_means = xo.getAttribute(CLUSTER_MEANS, false);
int mdsDimension = xo.getIntegerAttribute(MDS_DIMENSION);
double intervalWidth = 0.0;
if (xo.hasAttribute(INTERVAL_WIDTH)) {
intervalWidth = xo.getDoubleAttribute(INTERVAL_WIDTH);
}
double driftInitialLocations = 0.0;
if (xo.hasAttribute(DRIFT_INITIAL_LOCATIONS)) {
driftInitialLocations = xo.getDoubleAttribute(DRIFT_INITIAL_LOCATIONS);
}
CompoundParameter tipTraitParameter = null;
if (xo.hasChildNamed(TIP_TRAIT)) {
tipTraitParameter = (CompoundParameter) xo.getElementFirstChild(TIP_TRAIT);
}
MatrixParameter virusLocationsParameter = null;
if (xo.hasChildNamed(VIRUS_LOCATIONS)) {
virusLocationsParameter = (MatrixParameter) xo.getElementFirstChild(VIRUS_LOCATIONS);
}
MatrixParameter serumLocationsParameter = null;
if (xo.hasChildNamed(SERUM_LOCATIONS)) {
serumLocationsParameter = (MatrixParameter) xo.getElementFirstChild(SERUM_LOCATIONS);
}
Parameter mdsPrecision = (Parameter) xo.getElementFirstChild(MDS_PRECISION);
Parameter locationDrift = null;
if (xo.hasChildNamed(LOCATION_DRIFT)) {
locationDrift = (Parameter) xo.getElementFirstChild(LOCATION_DRIFT);
}
Parameter virusDrift = null;
if (xo.hasChildNamed(VIRUS_DRIFT)) {
virusDrift = (Parameter) xo.getElementFirstChild(VIRUS_DRIFT);
}
Parameter serumDrift = null;
if (xo.hasChildNamed(SERUM_DRIFT)) {
serumDrift = (Parameter) xo.getElementFirstChild(SERUM_DRIFT);
}
Parameter virusOffsetsParameter = null;
if (xo.hasChildNamed(VIRUS_OFFSETS)) {
virusOffsetsParameter = (Parameter) xo.getElementFirstChild(VIRUS_OFFSETS);
}
Parameter serumOffsetsParameter = null;
if (xo.hasChildNamed(SERUM_OFFSETS)) {
serumOffsetsParameter = (Parameter) xo.getElementFirstChild(SERUM_OFFSETS);
}
Parameter serumPotenciesParameter = null;
if (xo.hasChildNamed(SERUM_POTENCIES)) {
serumPotenciesParameter = (Parameter) xo.getElementFirstChild(SERUM_POTENCIES);
}
Parameter serumBreadthsParameter = null;
if (xo.hasChildNamed(SERUM_BREADTHS)) {
serumBreadthsParameter = (Parameter) xo.getElementFirstChild(SERUM_BREADTHS);
}
Parameter virusAviditiesParameter = null;
if (xo.hasChildNamed(VIRUS_AVIDITIES)) {
virusAviditiesParameter = (Parameter) xo.getElementFirstChild(VIRUS_AVIDITIES);
}
Parameter clusterOffsetsParameter = null;
if (xo.hasChildNamed(CLUSTER_OFFSETS)) {
clusterOffsetsParameter = (Parameter) xo.getElementFirstChild(CLUSTER_OFFSETS);
}
AGLikelihoodCluster AGL = new AGLikelihoodCluster(
mdsDimension,
mdsPrecision,
locationDrift,
virusDrift,
serumDrift,
virusLocationsParameter,
serumLocationsParameter,
tipTraitParameter,
virusOffsetsParameter,
serumOffsetsParameter,
serumPotenciesParameter,
serumBreadthsParameter,
virusAviditiesParameter,
assayTable,
mergeSerumIsolates,
intervalWidth,
driftInitialLocations,
cluster_means,
clusterOffsetsParameter);
Logger.getLogger("dr.evomodel").info("Using EvolutionaryCartography model. Please cite:\n" + Utils.getCitationString(AGL));
return AGL;
}
//************************************************************************
// AbstractXMLObjectParser implementation
//************************************************************************
public String getParserDescription() {
return "Provides the likelihood of immunological assay data such as Hemagglutinin inhibition (HI) given vectors of coordinates" +
"for viruses and sera/antisera in some multidimensional 'antigenic' space.";
}
public XMLSyntaxRule[] getSyntaxRules() {
return rules;
}
private final XMLSyntaxRule[] rules = {
AttributeRule.newStringRule(FILE_NAME, false, "The name of the file containing the assay table"),
AttributeRule.newIntegerRule(MDS_DIMENSION, false, "The dimension of the space for MDS"),
AttributeRule.newBooleanRule(MERGE_SERUM_ISOLATES, true, "Should multiple serum isolates from the same strain have their locations merged (defaults to false)"),
AttributeRule.newDoubleRule(INTERVAL_WIDTH, true, "The width of the titre interval in log 2 space"),
AttributeRule.newDoubleRule(DRIFT_INITIAL_LOCATIONS, true, "The degree to drift initial virus and serum locations, defaults to 0.0"),
new ElementRule(TIP_TRAIT, CompoundParameter.class, "Optional parameter of tip locations from the tree", true),
new ElementRule(VIRUS_LOCATIONS, MatrixParameter.class, "Parameter of locations of all virus"),
new ElementRule(SERUM_LOCATIONS, MatrixParameter.class, "Parameter of locations of all sera"),
new ElementRule(VIRUS_OFFSETS, Parameter.class, "Optional parameter for virus dates to be stored", true),
new ElementRule(SERUM_OFFSETS, Parameter.class, "Optional parameter for serum dates to be stored", true),
new ElementRule(SERUM_POTENCIES, Parameter.class, "Optional parameter for serum potencies", true),
new ElementRule(SERUM_BREADTHS, Parameter.class, "Optional parameter for serum breadths", true),
new ElementRule(VIRUS_AVIDITIES, Parameter.class, "Optional parameter for virus avidities", true),
new ElementRule(MDS_PRECISION, Parameter.class, "Parameter for precision of MDS embedding"),
new ElementRule(LOCATION_DRIFT, Parameter.class, "Optional parameter for drifting locations with time", true),
new ElementRule(VIRUS_DRIFT, Parameter.class, "Optional parameter for drifting only virus locations, overrides locationDrift", true),
new ElementRule(SERUM_DRIFT, Parameter.class, "Optional parameter for drifting only serum locations, overrides locationDrift", true),
AttributeRule.newBooleanRule(CLUSTER_MEANS, true, "Should we use cluster means to control the virus locations"),
new ElementRule(CLUSTER_OFFSETS, Parameter.class, "Parameter of cluster offsets of all virus"),
};
public Class getReturnType() {
return AGLikelihoodCluster.class;
}
};
@Override
public Citation.Category getCategory() {
return Citation.Category.TRAIT_MODELS;
}
@Override
public String getDescription() {
return "Bayesian Antigenic Cartography framework";
}
public List<Citation> getCitations() {
return Arrays.asList(new Citation(
new Author[]{
new Author("C", "Cheung"),
new Author("A", "Rambaut"),
new Author("P", "Lemey"),
new Author("MA", "Suchard"),
new Author("T", "Bedford")
},
Citation.Status.IN_PREPARATION
),
CommonCitations.BEDFORD_2015_INTEGRATING);
}
}